瀏覽代碼

HW19 canvas done

Alyona Brytvina 2 年之前
父節點
當前提交
3af74ef72f
共有 3 個文件被更改,包括 419 次插入0 次删除
  1. 24 0
      HW19/index.html
  2. 363 0
      HW19/main.js
  3. 32 0
      HW19/style.css

+ 24 - 0
HW19/index.html

@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>HW19</title>
+    <link rel="stylesheet" href="style.css">
+</head>
+<body>
+<canvas id='canvas' width=400 height=400></canvas>
+<button 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='rectangle'>Rectangle</option>
+    <option value='ellipse'>Ellipse</option>
+    <option value='select'>Select</option>
+</select>
+<input type='number' id='size' value=10>
+<button id='delete'>Delete...</button>
+<script src="main.js"></script>
+</body>
+</html>

+ 363 - 0
HW19/main.js

@@ -0,0 +1,363 @@
+// const canvas = document.getElementById('canvas');
+// const ctx = canvas.getContext('2d');
+
+
+const canvas = document.getElementById('canvas');
+const ctx = canvas.getContext('2d');
+
+const width = canvas.width;
+const height = canvas.height;
+
+// canvas.onclick = (e) => {
+//     ctx.beginPath();
+//     ctx.arc(e.layerX,  e.layerY, 20, 0, 2 * Math.PI);
+//     ctx.stroke();
+//
+//     ctx.fillStyle = color.value
+//     ctx.fill()
+//     console.log(e);
+//     console.log(color.value, size.value);
+//
+// };
+
+let current;
+let selection = [];
+
+const tools = {
+    graffity: {
+        mousemove(e) { //e.buttons 0b00000x11 & 0b00000100 == x
+            (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;
+        }
+    },
+    ellipse: {
+        mousedown(e) {
+            current = new Ellipse(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;
+        }
+    },
+    rectangle: {
+        mousedown(e) {
+            current = new Rectangle(e.clientX, e.clientY, 0, 0, color.value, +size.value);
+            console.log(e);
+        },
+        mousemove(e) {
+            if (!current) return;
+
+            current.width = e.clientX - current.x;
+            console.log();
+            current.height = e.clientY - current.y;
+
+            Drawable.drawAll();
+        },
+
+        mouseup(e) {
+            current = null;
+        }
+    },
+    select: {
+        click(e) {
+            console.log(e);
+            let found = Drawable.instances.filter(c => c.in && c.in(e.clientX, e.clientY));
+            if (found.length) {
+                if (e.ctrlKey) {
+                    selection.push(found.pop());
+                } else {
+                    selection = [found.pop()];
+                }
+            } else {
+                if (!e.ctrlKey) selection = [];
+            }
+
+            Drawable.drawAll(selection);
+        },
+        mousedown(e) {
+            //
+        },
+        mousemove(e) {
+
+        },
+
+        mouseup(e) {
+            //x,y, w, h прямоугольника
+            //selection - только те элеменеты Drawable.instances которые в границах прямоугольника.
+        },
+    }
+};
+
+
+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) { // x = 100, this.x = 102, w = 5
+        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();
+        if (selected) {
+            ctx.lineWidth = size.value;
+            ctx.strokeStyle = color.value;
+            ctx.stroke();
+        }
+        ctx.strokeStyle = this.color;
+        ctx.lineWidth = this.lineWidth;
+        ctx.stroke();
+
+    }
+    in(x, y) {
+        return (
+            this.distanceTo(x, y) < this.width ||
+            this.distanceTo(x, y) < this.height
+        );
+    }
+}
+
+class Ellipse 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.ellipse(this.x, this.y, this.width / 2, this.height / 2, 0, 0, 2 * Math.PI);
+        ctx.fillStyle = this.color;
+        ctx.fill();
+        ctx.closePath();
+
+        if (selected) {
+            ctx.beginPath();
+            ctx.strokeStyle = color.value;
+            ctx.ellipse(this.x, this.y, this.width / 2, this.height / 2, 0, 0, 2 * Math.PI);
+            ctx.stroke();
+            ctx.closePath();
+        }
+
+    }
+
+    in(x, y) {
+        const rx = this.width / 2;
+        const ry = this.height / 2;
+        const h = this.x + rx;
+        const k = this.y + ry;
+
+        return (
+            ((x - h) ** 2 / (rx) ** 2) + ((y - k) ** 2 / (ry) ** 2)
+        );
+    }
+}
+
+
+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.fillStyle = this.color;
+        ctx.fillRect(this.x, this.y, this.height, this.width);
+        // ctx.lineTo(this.x + this.width, this.y + this.height);
+        ctx.closePath();
+
+        if (selected) {
+            ctx.beginPath();
+            ctx.strokeStyle = color.value;
+            ctx.strokeRect(this.x, this.y, this.height, this.width);
+            ctx.stroke();
+            ctx.closePath();
+        }
+
+    }
+
+    in(x, y) {
+        console.log(x >= this.x && this.y <= y &&
+            this.x <= this.x + this.width &&
+            this.y <= this.y + this.height);
+        return x >= this.x && this.y <= y &&
+            this.x <= this.x + this.width &&
+            this.y <= this.y + this.height;
+
+        // this.distanceTo(x,y) > this.radius //??
+    }
+}
+
+color.onchange = () => {
+    selection.forEach(c => c.color = color.value);
+    Drawable.drawAll(selection);
+};
+
+document.getElementById('delete').onclick = () => {
+    Drawable.instances = Drawable.instances.filter(item => !selection.includes(item));
+    selection = [];
+    Drawable.drawAll();
+};
+
+
+// new Rectangle(10,10,100,100, "red")
+// new Circle(30,30,10, "black")
+// new Ellipse(10, 10, 100, 100, 'red');
+
+////canvas.onmousemove = function(e){
+////}
+
+//undo.onclick = function(){
+//Drawable.instances.pop()
+////Drawable.instances = []
+//Drawable.drawAll()
+//}
+
+
+

+ 32 - 0
HW19/style.css

@@ -0,0 +1,32 @@
+* {
+    box-sizing: border-box;
+    margin: 0;
+    padding: 0;
+}
+
+body {
+    margin: 0;
+    padding: 0;
+}
+
+button{
+    width: 100%;
+    font-size: 2em;
+}
+input, button, select{
+    width: 100%;
+    font-size: 2em;
+}
+
+table {
+    border: 1px;
+    border-collapse: collapse;
+}
+
+td,th {
+    border: 1px solid black;
+}
+
+/*div#content {*/
+/*display: none;*/
+/*}*/