vladislavaSim vor 1 Jahr
Ursprung
Commit
ceb037ec29
2 geänderte Dateien mit 364 neuen und 0 gelöschten Zeilen
  1. 53 0
      painter/index.html
  2. 311 0
      painter/main.js

+ 53 - 0
painter/index.html

@@ -0,0 +1,53 @@
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width">
+  <title>eval</title>
+  <style>
+    * {
+      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;
+    }
+  </style>
+</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>

+ 311 - 0
painter/main.js

@@ -0,0 +1,311 @@
+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){
+            console.log(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, 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
+        }
+    }
+}
+
+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 = '#f0f'
+            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 = '#f0f'
+            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{
+    #width = 0
+    #height = 0
+    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.rx, this.y + this.ry, this.rx, this.ry, 0, 0, 2 * Math.PI)
+        ctx.closePath()
+        if (selected){
+            ctx.lineWidth = 2
+            ctx.fill()
+        }
+        ctx.fillStyle = this.color
+        ctx.fill()
+    }
+
+    in(x, y) {
+        let h = this.x + this.rx
+        let k = this.y + this.ry
+        return Math.pow((x - h), 2)/Math.pow(this.rx, 2) + Math.pow((y - k), 2)/Math.pow(this.ry, 2) <= 1
+    }
+
+    set width(newWidth){
+        if (newWidth < 0){
+            this.#width = -newWidth
+            this.x     += newWidth
+        }
+        else
+            this.#width = newWidth
+    }
+    set height(newHeight){
+        if (newHeight < 0){
+            this.#height = -newHeight
+            this.y      +=  newHeight
+        }
+        else
+            this.#height = newHeight
+    }
+    get width(){
+        return this.#width
+    }
+    get height(){
+        return this.#height
+    }
+    get rx(){
+        return this.#width/2
+    }
+    get ry(){
+        return this.#height/2
+    }
+}
+
+color.onchange = () => {
+    selection.forEach(c => c.color = color.value)
+    Drawable.drawAll(selection)
+}
+undo.onclick = function(){
+    Drawable.instances.pop()
+    Drawable.drawAll()
+}
+document.getElementById('delete').onclick = () =>{
+    Drawable.instances = []
+    Drawable.drawAll()
+}