Browse Source

homework18 done

holevchuk.evgeny 1 year ago
parent
commit
2f4fb77b84
7 changed files with 688 additions and 1 deletions
  1. 1 1
      hw10/rgb.html
  2. 32 0
      hw18/index.css
  3. 28 0
      hw18/index.html
  4. 312 0
      hw18/index.js
  5. 4 0
      hw18/jquery-3.1.1.min.js
  6. 305 0
      hw18/nb.js
  7. 6 0
      hw18/papaparse.min.js

+ 1 - 1
hw10/rgb.html

@@ -27,6 +27,6 @@
 		<div id='container1'></div>
 		<div id='container2'></div>
 		<div id="rgb_box"></div>
-		<script src='index.js'></script>
+		<script src='rgb.js'></script>
 	</body>
 </html>

+ 32 - 0
hw18/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;*/
+/*}*/

+ 28 - 0
hw18/index.html

@@ -0,0 +1,28 @@
+<!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="jquery-3.1.1.min.js"></script>
+	<script src="papaparse.min.js"></script>
+	<script src="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='graffity'>Graffity</option>
+	<option value='circle'>Circle</option>
+	<option value='line'>Line</option>
+	<option value='rectangle'>Rectangle</option>
+	<option selected value='ellipse'>Ellipse</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>

+ 312 - 0
hw18/index.js

@@ -0,0 +1,312 @@
+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
+		}
+	},
+	ellipse: {
+		mousedown(e){
+			current = new Ellipse(e.layerX, e.layerY, 1, 1, color.value)
+		},
+		mousemove(e){
+			if (!current) return;
+
+			current.radiusX = e.layerX - current.x;
+			current.radiusY = e.layerY - current.y;
+			Drawable.drawAll()
+		},
+
+		mouseup(e){
+			console.log(e)
+			if(current.radiusX < 0 || current.radiusY < 0) {
+				console.log('1111')
+			}
+			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: {
+		mousedown(e){
+			current = new Rectangle(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;
+		ctx.fill();
+		if (selected){
+			ctx.lineWidth = 2
+			ctx.stroke();
+		}
+	}
+
+	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 Ellipse extends Drawable {
+	constructor(x,y, radiusX, radiusY, color){
+		super()
+		this.x          = x;
+		this.y          = y;
+		this.radiusX    = radiusX;
+		this.radiusY    = radiusY;
+		this.color      = color;
+
+
+		this.draw();
+	}
+
+	draw(selected){
+		ctx.beginPath();
+		ctx.ellipse(this.x, this.y, this.radiusX, this.radiusY, 0, 0, 2 * Math.PI, false);
+		ctx.closePath();
+		ctx.fillStyle = this.color;
+		ctx.fill();
+		if (selected){
+			ctx.lineWidth = 2
+			ctx.stroke();
+		}
+	}
+
+	in(x,y){
+		return Math.pow((x - this.x), 2) / Math.pow(this.radiusX, 2) + Math.pow((y - this.y), 2) / Math.pow(this.radiusY, 2) <= 1;
+	}
+}
+
+
+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();
+	}
+
+	in(x,y){
+		//Гарри Поттер и орден Арктангенса
+	}
+}
+
+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.fillStyle = this.color;
+		ctx.fillRect(this.x, this.y, this.width, this.height);
+	}
+
+	in(x,y){
+		let left = this.x;
+		let	right = this.x + this.width;
+		let	top = this.y;
+		let	bottom = this.y + this.height;
+		return right >= x && left <= x && bottom >= y && top <= y;
+	}
+}
+
+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()
+//}

File diff suppressed because it is too large
+ 4 - 0
hw18/jquery-3.1.1.min.js


+ 305 - 0
hw18/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;
+}

File diff suppressed because it is too large
+ 6 - 0
hw18/papaparse.min.js