Browse Source

done hw canvas

unknown 3 years ago
commit
5f7fe689a7
5 changed files with 380 additions and 0 deletions
  1. 3 0
      .vscode/settings.json
  2. 0 0
      README.md
  3. 44 0
      html-css/css/index.css
  4. 27 0
      html-css/index.html
  5. 306 0
      javascript/hw.js

+ 3 - 0
.vscode/settings.json

@@ -0,0 +1,3 @@
+{
+	"liveServer.settings.port": 5501
+}

+ 0 - 0
README.md


+ 44 - 0
html-css/css/index.css

@@ -0,0 +1,44 @@
+* {
+    box-sizing: border-box;   
+    margin: 0;
+    padding: 0;
+}
+
+body {
+    margin: 0;
+    padding: 0;
+}
+
+ .btnUndo , .btnDelete{
+    width: 100%;
+    font-size: 2em;
+}
+ .btnUndo {
+     background-color: green;
+}
+ .btnDelete{
+
+    background-color: red;
+}
+
+input, .btnUndo, .btnDelete, select{
+    width: 100%;
+    font-size: 2em;
+}
+
+table {
+    border: 1px;
+    border-collapse: collapse;
+}
+
+td,th {
+    border: 1px solid black;
+}
+
+canvas {
+    border: solid 2px black;
+}
+
+.canvasInterface{
+    width: 21%;
+}

+ 27 - 0
html-css/index.html

@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html lang="en" lang="uk">
+	<head>
+		<meta charset="UTF-8" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<link rel="stylesheet" href="./css/index.css" />
+		<title>Document-js</title>
+	</head>
+	<body>
+		<canvas id="canvas" width="400" height="400"></canvas>
+		<div class="canvasInterface">
+			<button class="btnUndo" id="undo">UNDO</button>
+			<input type="color" id="color" />
+			<select id="tool">
+				<option value="graffity">Graffity</option>
+				<option value="circle">Circle</option>
+				<option value="line">Line</option>
+				<option value="select">Select</option>
+				<option value="rectangle">Rectangle</option>
+				<option value="ellipse">Ellipse</option>
+				<input type="number" id="size" value="10" />
+				<button class="btnDelete" id="delete">Delete...</button>
+			</select>
+		</div>
+	</body>
+	<script src="../javascript/hw.js" type="module"></script>
+</html>

+ 306 - 0
javascript/hw.js

@@ -0,0 +1,306 @@
+const canvas = document.getElementById('canvas');
+const ctx = canvas.getContext('2d');
+
+const width = canvas.width;
+const height = canvas.height;
+
+let current;
+let selection = [];
+
+const tools = {
+	graffity: {
+		mousemove(e) {
+			e.buttons & 1 &&
+				new Circle(e.clientX, e.clientY, +size.value, color.value);
+		},
+	},
+	circle: {
+		mousedown(e) {
+			current = new Circle(e.clientX, e.clientY, 1, color.value);
+		},
+		mousemove(e) {
+			if (!current) return;
+
+			current.radius = current.distanceTo(e.clientX, e.clientY);
+			Drawable.drawAll();
+		},
+		mouseup(e) {
+			current = null;
+		},
+	},
+	line: {
+		mousedown(e) {
+			current = new Line(e.clientX, e.clientY, 0, 0, color.value, +size.value);
+		},
+		mousemove(e) {
+			if (!current) return;
+
+			current.width = e.clientX - current.x;
+			current.height = e.clientY - current.y;
+
+			Drawable.drawAll();
+		},
+		mouseup(e) {
+			current = null;
+		},
+	},
+	select: {
+		click(e) {
+			let found = Drawable.instances.filter(
+				(c) => c.in && c.in(e.clientX, e.clientY)
+			);
+			if (found.length) {
+				if (e.altKey) {
+					selection.push(found.pop());
+				} else {
+					selection = [found.pop()];
+				}
+			} else {
+				if (!e.altKey) selection = [];
+			}
+
+			Drawable.drawAll(selection);
+		},
+		mousedown(e) {},
+		mousemove(e) {},
+		mouseup(e) {},
+	},
+	rectangle: {
+		mousedown(e) {
+			current = new Rectangle(e.clientX, e.clientY, 0, 0, color.value);
+		},
+		mousemove(e) {
+			if (!current) return;
+			current.width = e.clientX - current.x;
+			current.height = e.clientY - current.y;
+			Drawable.drawAll();
+		},
+		mouseup(e) {
+			current = null;
+		},
+	},
+	ellipse: {
+		mousedown(e) {
+			current = new Ellipse(e.clientX, e.clientY, 1, 1, color.value);
+		},
+		mousemove(e) {
+			if (!current) return;
+			const width = e.clientX - current.x;
+			const height = e.clientY - current.y;
+			current.width = width ? width : width * -1;
+			current.height = height ? height : height * -1;
+			Drawable.drawAll();
+		},
+		mouseup(e) {
+			current = null;
+		},
+	},
+};
+
+function superHandler(evt) {
+	let t = tools[tool.value];
+	if (typeof t[evt.type] === 'function') t[evt.type].call(this, evt);
+}
+
+canvas.onmousemove = superHandler;
+canvas.onmouseup = superHandler;
+canvas.onmousedown = superHandler;
+canvas.onclick = superHandler;
+
+function Drawable() {
+	Drawable.addInstance(this);
+}
+
+const distance = (x1, y1, x2, y2) => ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5;
+
+Drawable.prototype.draw = function () {};
+
+Drawable.prototype.distanceTo = function (x, y) {
+	if (typeof this.x !== 'number' || typeof this.y !== 'number') {
+		return NaN;
+	}
+	return distance(this.x, this.y, x, y);
+};
+
+Drawable.instances = [];
+
+Drawable.addInstance = function (item) {
+	Drawable.instances.push(item);
+};
+
+Drawable.drawAll = function (selection = []) {
+	ctx.clearRect(0, 0, width, height);
+	Drawable.forAll((item) => item.draw());
+	selection.forEach((item) => item.draw(true));
+};
+
+Drawable.forAll = function (callback) {
+	for (var i = 0; i < Drawable.instances.length; i++) {
+		callback(Drawable.instances[i]);
+	}
+};
+
+class Circle extends Drawable {
+	constructor(x, y, radius, color) {
+		super();
+		this.x = x;
+		this.y = y;
+		this.radius = radius;
+		this.color = color;
+		this.draw();
+	}
+
+	draw(selected) {
+		ctx.beginPath();
+		ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
+		ctx.closePath();
+		ctx.fillStyle = this.color;
+		if (selected) {
+			ctx.lineWidth = 2;
+			ctx.stroke();
+		}
+		ctx.fill();
+	}
+
+	in(x, y) {
+		return this.distanceTo(x, y) < this.radius;
+	}
+
+	inBounds(x, y, w, h) {
+		return this.x >= x && this.x <= x + w && this.y >= y && this.y <= y + h;
+	}
+}
+
+class Line extends Drawable {
+	constructor(x, y, width, height, color, lineWidth) {
+		super();
+		this.x = x;
+		this.y = y;
+		this.width = width;
+		this.height = height;
+		this.color = color;
+		this.lineWidth = lineWidth;
+		this.draw();
+	}
+
+	draw(selected) {
+		ctx.beginPath();
+		ctx.moveTo(this.x, this.y);
+		ctx.lineTo(this.x + this.width, this.y + this.height);
+		ctx.closePath();
+		ctx.strokeStyle = this.color;
+		ctx.lineWidth = this.lineWidth;
+		if (selected) {
+			ctx.strokeStyle = '#1f600e';
+			ctx.stroke();
+		}
+		ctx.stroke();
+	}
+
+	in(x, y) {
+		let rotateLine = Math.atan2(this.height, this.width);
+		let rotCursor = Math.atan2(y - this.y, x - this.x);
+		let distanceToPoint = distance(x, y, this.x, this.y);
+		let angleLine = rotCursor - rotateLine;
+		let rotateX = Math.cos(angleLine) * distanceToPoint;
+		let rotateY = Math.sin(angleLine) * distanceToPoint;
+		return (
+			rotateX >= 0 &&
+			rotateX <= this.length &&
+			rotateY <= this.lineWidth / 2 &&
+			rotateY >= -this.lineWidth / 2
+		);
+	}
+
+	get length() {
+		return this.distanceTo(this.x + this.width, this.y + this.height);
+	}
+}
+
+class Rectangle extends Drawable {
+	constructor(x, y, width, height, color) {
+		super();
+		this.x = x;
+		this.y = y;
+		this.width = width;
+		this.height = height;
+		this.color = color;
+		this.draw();
+	}
+
+	draw(selected) {
+		ctx.beginPath();
+		ctx.moveTo(this.x, this.y);
+		ctx.fillRect(this.x, this.y, this.width, this.height);
+		if (selected) {
+			ctx.rect(this.x, this.y, this.width, this.height);
+			ctx.strokeStyle = '#1f600e';
+			ctx.stroke();
+		}
+		ctx.fillStyle = this.color;
+		ctx.stroke();
+	}
+
+	in(x, y) {
+		return (
+			x >= this.x &&
+			x <= this.x + this.width &&
+			y >= this.y &&
+			y <= this.y + this.height
+		);
+	}
+}
+
+class Ellipse extends Drawable {
+	constructor(x, y, width, height, color) {
+		super();
+		this.x = x ? x : x * -1;
+		this.y = y ? y : y * -1;
+		this.width = width;
+		this.height = height;
+		this.color = color;
+		this.draw();
+	}
+
+	draw() {
+		this.width = this.width > 0 ? this.width : this.width * -1;
+		this.height = this.height > 0 ? this.height : this.height * -1;
+		ctx.beginPath();
+		ctx.moveTo(this.x, this.y);
+		ctx.ellipse(
+			this.x,
+			this.y,
+			this.height,
+			this.width,
+			Math.PI / 2,
+			0,
+			2 * Math.PI
+		);
+		ctx.closePath();
+		ctx.fillStyle = this.color;
+		ctx.fill();
+	}
+
+	in(x, y) {
+		return this.distanceTo(x, y) < this.radius;
+	}
+
+	inBounds(x, y, w, h) {
+		return this.x >= x && this.x <= x + w && this.y >= y && this.y <= y + h;
+	}
+}
+
+document.getElementById('delete').onclick = () => {
+	Drawable.instances = [];
+	Drawable.drawAll();
+};
+
+document.getElementById('undo').onclick = function () {
+	Drawable.instances.pop();
+	Drawable.drawAll();
+};
+
+color.onchange = () => {
+	selection.forEach((c) => (c.color = color.value));
+	Drawable.drawAll(selection);
+};