Illia Kozyr 1 vuosi sitten
vanhempi
commit
9efc6f6ef7
6 muutettua tiedostoa jossa 686 lisäystä ja 0 poistoa
  1. 32 0
      HW 19/index.css
  2. 29 0
      HW 19/index.html
  3. 310 0
      HW 19/index.js
  4. 4 0
      HW 19/jquery-3.1.1.min.js
  5. 305 0
      HW 19/nb.js
  6. 6 0
      HW 19/papaparse.min.js

+ 32 - 0
HW 19/index.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;*/
+/*}*/

+ 29 - 0
HW 19/index.html

@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width">
+        <title>eval</title>
+        <link href="index.css" rel="stylesheet" type="text/css" />
+        <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/4.1.3/papaparse.min.js"></script>
+        <script src="http://gitlab.a-level.com.ua/gitgod/nanobind/raw/master/static/nb.js"></script>
+    </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='ellipse'>Ellipse</option>
+            <option value='line'>Line</option>
+            <option value='rectangle'>Rectangle</option>
+            <option value='graffity'>Graffity</option>
+            <option value='circle'>Circle</option>
+            <option value='select'>Select</option>
+        </select>
+        <input type='number' id='size' value=10>
+        <button id='delete'>Delete...</button>
+        <script src="index.js"></script>
+    </body>
+</html>
+

+ 310 - 0
HW 19/index.js

@@ -0,0 +1,310 @@
+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 0b00000x11 & 0b00000100 == x
+            (e.buttons & 0b001) && new Circle(e.layerX, e.layerY, +size.value, color.value)
+        }
+    },
+    circle: {
+        mousedown(e){
+            current = new Circle(e.layerX,e.layerY, 1, color.value)
+        },
+        mousemove(e){
+            if (!current) return;
+
+            current.radius = current.distanceTo(e.layerX, e.layerY)
+            Drawable.drawAll()
+        },
+
+        mouseup(e){
+            current = null
+        }
+    },
+    line: { //ctrl-c ctrl-v в rectangle. Так же добавьте его в <select id='tool'>
+        mousedown(e){
+            current = new Line(e.layerX, e.layerY, 0, 0, color.value, +size.value)
+        },
+        mousemove(e){
+            if (!current) return;
+
+            current.width = e.layerX - current.x
+            current.height = e.layerY - current.y
+
+            Drawable.drawAll()
+        },
+
+        mouseup(e){
+            current = null
+        }
+    },
+    rectangle: { //ctrl-c ctrl-v в rectangle. Так же добавьте его в <select id='tool'>
+        mousedown(e){
+            current = new Rectangle(e.layerX, e.layerY, 0, 0, color.value)
+        },
+        mousemove(e){
+            if (!current) return;
+
+            current.width = e.layerX - current.x
+            current.height = e.layerY - current.y
+
+            Drawable.drawAll()
+        },
+
+        mouseup(e){
+            current = null
+        }
+    },
+    ellipse: { //ctrl-c ctrl-v в rectangle. Так же добавьте его в <select id='tool'>
+        mousedown(e){
+            current = new Ellipse(e.layerX, e.layerY, 0, 0, color.value, +size.value)
+        },
+        mousemove(e){
+            if (!current) return;
+
+            current.width = e.layerX - current.x
+            current.height = e.layerY - 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.layerX, e.layerY))
+            if (found.length){
+                if (e.ctrlKey){
+                    selection.push(found.pop())
+                }
+                else {
+                    selection = [found.pop()]
+                }
+            }
+            else {
+                if (!e.ctrlKey) selection = []
+            }
+
+            console.log('selection', 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 {
+    //__proto__: Drawable.prototype
+    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 { //смочь скопировать в Rectangle и поменять отприсовку
+    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
+        ctx.stroke();
+    }
+}
+
+class Rectangle extends Drawable { //смочь скопировать в Rectangle и поменять отрисовку
+    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.rect(this.x,this.y,this.width,this.height);
+		ctx.closePath();
+		ctx.fillStyle = this.color;
+		if (selected){
+            ctx.lineWidth = 2
+            ctx.stroke();
+        }
+        ctx.fill();
+    }
+    
+	in(x,y){
+        return x > this.x && x < this.x+this.width &&
+			y > this.y && y < this.y+this.height;//условие попадания x,y в прямоугольник
+    }
+}
+//Ellipse по аналогии
+//
+class Ellipse extends Drawable { //смочь скопировать в Ellipse и поменять отрисовку
+    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.ellipse(this.x,this.y, Math.abs(this.width), Math.abs(this.height), 0, 0, 2 * Math.PI)
+		ctx.closePath();
+        ctx.fillStyle = this.color;
+		if (selected){
+            ctx.lineWidth = 2
+            ctx.stroke();
+        }
+        ctx.fill();
+    }    
+	
+	in(x,y){
+        return (Math.pow(x-this.x,2)/Math.pow(this.width,2)+
+			Math.pow(y-this.y,2)/Math.pow(this.height,2))<=1; //условие попадания x,y в ellipse
+    }
+}
+
+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 Line(0,0,100,100, "red")
+////new Circle(30,30,10, "red")
+
+////canvas.onmousemove = function(e){
+////}
+
+//undo.onclick = function(){
+    //Drawable.instances.pop()
+    ////Drawable.instances = []
+    //Drawable.drawAll()
+//}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 4 - 0
HW 19/jquery-3.1.1.min.js


+ 305 - 0
HW 19/nb.js

@@ -0,0 +1,305 @@
+/*
+Copyright 2016-100500 Ivan Grynkin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 
+to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
+and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+DEALINGS IN THE SOFTWARE. 
+*/
+
+function nbInit(a,b){
+    var root=document, $s=a;
+
+    var dom = null;
+    var closure = null;
+
+    function searchElement(root, selector){
+        if ((selector.indexOf('|dom') === selector.length - 4) && (selector.length > 4)){
+            selector = selector.slice(0,selector.length - 4)
+            dom      = true;
+        }
+        if ((selector.indexOf('|closure') === selector.length - 8) && (selector.length > 8)){
+            selector = selector.slice(0,selector.length - 8)
+            closure  = true;
+        }
+        if (root === document){
+            var items = [root.getElementById(selector)]; 
+        }
+        else {
+            items = root.querySelectorAll("#" + selector); 
+        }
+        items     = items[0]     ? items :  root.querySelectorAll(selector);
+        items     = items.length ? items :  root === document ? root.getElementsByName(selector) : root.querySelectorAll("[name='" + selector + "']"); 
+        items     = items.length ? items :  root.getElementsByClassName(selector); 
+        return items;
+    }
+
+    if (a instanceof HTMLElement){
+        root = a;
+        $s   = b;
+    }
+    else if (typeof a === "string"){
+        root = searchElement(document, a)[0];
+        $s   = b;
+    }
+    if (b instanceof HTMLElement){
+        root = b;
+    }
+    else if (typeof b === "string"){
+        root = searchElement(document, a)[0];
+    }
+    if (typeof $s === "undefined"){
+        $s = {}
+    }
+
+    function nBind(callback, prop, direction){
+        direction = direction || "write";
+        for (var selector in $s){
+            var result = [];
+            selector = prop || selector; //change selector to passed if it
+
+            var items = searchElement(root, selector);
+            for (var i=0,item=items[i];i<items.length;i++,item=items[i]){
+                if (direction == "write" &&  Array.isArray($s[selector]) && (item.children.length == 0 || (items.length == $s[selector].length && items.length > 1))){
+                    if (closure){
+                        callback(item, $s, selector, $s[selector]);
+                    }
+                    else {
+                        callback(item, $s, selector, $s[selector][i]);
+                    }
+                }
+                else {
+                    var res = callback(item, $s, selector);
+                    if (typeof res !== "undefined"){
+                        result.push(res)
+                    }
+                }
+            }
+
+            
+            $s[selector] = result.length ? (result.length == 1 ? result[0] : result) : $s[selector];
+
+            if (prop) return;  //exit if selector passed, no iteration
+        }
+    }
+
+    function recursiveObjectSet(item, value){
+        if (typeof item === 'undefined'){
+            return;
+        }
+        for (var key in value){
+            if (typeof value[key] !== 'object'){
+                item[key] = value[key];
+            }
+            else {
+                recursiveObjectSet(item[key], value[key]);
+            }
+        }
+    }
+
+    function syncToDOM(prop){
+        nBind(function (item, $s, selector, value, key, thisByClass){
+            value = typeof value === 'undefined' ? $s[selector] : value;
+            var keyExists = typeof key !== 'undefined';
+            if (closure){
+                item.nbData = value[0].apply(item, value.slice(1))
+                return;
+            }
+            if ((!item.children.length && !Array.isArray(value) && typeof value === 'object') || thisByClass || dom){ //hash array on single leaf node -> set attrs on the tag
+                recursiveObjectSet(item,value);
+                if (!thisByClass && !dom){
+                    item.nbData = value;
+                }
+                return;
+            }
+            if (keyExists && "value" in item){ //if hash key-value pair. Usable for select > option
+                item.value = key;
+            }
+            if (typeof value === "boolean" && item.type !== 'checkbox'){ //boolean means visibility, except checkbox
+                if (value){
+                    item.style.display = "originalDisplay" in item ? item.originalDisplay : "";
+                }
+                else {
+                    item.originalDisplay = "originalDisplay" in item ? item.originalDisplay : item.style.display;
+                    item.style.display   = "none";
+                }
+                return;
+            }
+            if (item.type === 'radio' && !keyExists){ //radiogroup set
+                if (item.value === value){ //only item with right value to set
+                    item.checked = true;
+                }
+                return;
+            }
+            if (item.type === 'checkbox' && !keyExists){ //checkbox setting by boolean
+                item.checked = !!value;
+                return;
+            }
+            if (item.children.length && typeof value === "object"){ //recursive fill
+                item.copy = item.copy || item.cloneNode(true); //original node
+                item.nbData = value;
+                var originalChildren = item.copy.children;
+                var i = 0;
+                var isArray = Array.isArray(value);      //different logic for array and objects
+                if (!isArray){ // if first key in array find as class name in one of subnodes
+                    var classFound = false;
+                    for (var key in value){
+                        if (item.getElementsByClassName(key).length){
+                            classFound = true;
+                            break;
+                        }
+                    }
+                    if (classFound){
+                        for (var key in value){
+                            var classSubnodes = item.getElementsByClassName(key);
+                            for (var i=0;i<classSubnodes.length;i++){
+                                arguments.callee(classSubnodes[i], $s, selector, value[key]); // recursively fill subnode with that data. No reason to pass a key, because key are class selector, not value for option
+                            }
+                            if (item.classList.contains(key)){
+                                arguments.callee(item, $s, selector, value[key], undefined, true); // recursively fill subnode with that data. No reason to pass a key, because key are class selector, not value for option
+                            }
+                        }
+                        return;
+                    }
+                }
+                item.innerHTML = "";                     //remove sub nodes
+                for (var key in value){ //otherwise iterate over array or object
+                    var newNode = originalChildren[i].cloneNode(true);
+                    item.appendChild(newNode);
+                    if (isArray){
+                        arguments.callee(newNode, $s, selector, value[key]);
+                    }
+                    else {
+                        arguments.callee(newNode, $s, selector, value[key], key);
+                    }
+                    i = (i +1) % originalChildren.length;
+                }
+                return;
+            }
+            if (!keyExists){ //default logic: set text or value to data value
+                item[("value" in item) && item.tagName !== 'LI' ? "value" : "innerText"] = value;
+            }
+            else {
+                item.innerText = value; // do not try to overwrite value on option nodes
+            }
+        },prop, "write");
+    }
+
+    function syncFromDOM(prop){
+        nBind(function(item, $s, selector){
+            if (closure){
+                return item.nbData()
+            }
+            if (item.type === 'radio'){
+                if (item.checked) 
+                    return item.value; 
+                return;
+            }
+            if (item.type === 'checkbox'){
+                return item.checked;
+            }
+            if (item.tagName === 'SELECT'){
+                return item.value;
+            }
+            if ("nbData" in item){
+                var value = item.nbData;
+                var isArray = Array.isArray(value);      //different logic for array and objects
+                if (item.children.length && typeof value === "object"){ //recursive fill
+                    if (!isArray){ // if first key in array find as class name in one of subnodes
+                        var classFound = false;
+                        for (var key in value){
+                            if (item.getElementsByClassName(key).length){
+                                classFound = true;
+                                break;
+                            }
+                        }
+                        if (classFound){
+                            for (var key in value){
+                                var classSubnodes = item.getElementsByClassName(key);
+                                for (var i=0;i<classSubnodes.length;i++){
+                                    value[key] = arguments.callee(classSubnodes[i], $s, selector); // recursively fill subnode with that data. No reason to pass a key, because key are class selector, not value for option
+                                }
+                            }
+                            return value;
+                        }
+                    }
+                    else{
+                        value.length = 0;
+                        for (var key=0;key<item.children.length;key++){ //otherwise iterate over array or object
+                            value[key] = arguments.callee(item.children[key], $s, selector);
+                        }
+                        return value;
+                    }
+                    //else {
+                        //for (var key in value){
+                            //value[key] = arguments.callee(item.children[key], $s, selector);
+                        //}
+                    //}
+                }
+                if (!isArray && typeof value === 'object' && item.children.length === 0){ //hash array on single leaf node -> set attrs on the tag
+                    for (var key in value){
+                        value[key] = item[key];
+                    }
+                    return value;
+                }
+                if (!isArray && typeof value === 'object'){ //hash array on single leaf node -> set attrs on the tag
+                    value = {};
+                    for (var i=0;i<item.children.length;i++){
+                        var childItem = item.children[i];
+                        value[childItem.value] = childItem.innerText;
+                    }
+                    return value;
+                }
+            }
+            if ("value" in item){
+                return item.value;
+            }
+            return item.innerText; 
+        },prop, "read");
+    }
+
+    syncToDOM();
+
+    var scopeProxy = new Proxy($s,{
+        get(target, prop){
+            //if (!(prop in target) && (document.getElementById(prop) || 
+                                      //document.querySelectorAll(prop).length || 
+                                      //document.getElementsByName(prop).length ||
+                                      //document.getElementsByClassName(prop).length)){
+                target[prop] = null;
+            //}
+            syncFromDOM(prop);
+            dom = null;
+            closure = null;
+            return target[prop];
+        },
+        set(target, prop, value){
+            //syncFromDOM();
+            target[prop] = value
+            syncToDOM(prop);
+            dom = null;
+            closure = null;
+            return true;
+        },
+    })
+
+    return scopeProxy;
+}
+
+function nbGetData(el){
+    while (!('nbData' in el)){
+        if (el.parentElement){
+            el = el.parentElement;
+        }
+        else {
+            return null;
+        }
+    }
+    return el.nbData;
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 6 - 0
HW 19/papaparse.min.js