import h from '../Util/DomUtil.js'; import { dist, AABB, QuadTree } from '../Geometry/Geometry.js'; class Canvas { constructor(parentId) { const parentElement= document.getElementById(parentId); this.canvas = h('canvas', parentElement.width, parentElement.height); this.context = this.canvas.getContext('2d'); /* state */ this.movingPoint = false; this.selectedPoint = null; /* callbacks */ this.onMovePoint = (original, now) => console.log(original, now); /* transform */ this.scale = 1; this.pan = { x: 0, y: 0 }; /* mouse */ this.mouse = { x: 0, y: 0 }; /* retrieving points */ this.points = []; this.tree = new QuadTree(this.canvas.width, this.canvas.height); /* event listeners */ this.canvas.addEventListener('mousemove', e => { this.mouse.x = e.offsetX; this.mouse.y = e.offsetY; if (this.movingPoint) this.render(); }); this.canvas.addEventListener('click', e => { if (this.movingPoint) { this.dropPoint(); } else { const pt = this.getClickedPoint( { x: e.offsetX, y: e.offsetY }, 10 ); if (pt) this.grabPoint(pt); } }); /* attach to parent */ parentElement.appendChild(this.canvas); } /* transform a point to internal coordinates */ transform(x, y) { return [ (this.scale * x) - this.pan.x, (this.scale * y) - this.pan.y, ]; } /* data updates */ updatePoints(points) { this.points = []; this.tree = new QuadTree(this.canvas.width, this.canvas.height); for (let pt of points) this.insertPoint(pt); this.render(); } insertPoint(pt) { this.tree.insert(pt); this.points.push(pt); } /* drawing */ drawPoint(pt) { const ct = this.context; ct.save(); ct.beginPath(); const [x, y] = this.transform(pt.x, pt.y); console.log(x,y); ct.arc(x, y, 10/this.scale, 0, 2*Math.PI); ct.closePath(); ct.fill(); ct.restore(); } render() { this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); for (let pt of this.points) this.drawPoint(pt); if (this.movingPoint) { const [x, y] = this.transform(this.mouse.x, this.mouse.y); this.drawPoint({x, y}); } } /* handling input */ grabPoint(pt) { this.tree.root.remove(pt); this.points = this.points.filter(point => (point.x !== pt.x || point.y !== pt.y)); console.log(this.points); this.selectedPoint = pt; this.movingPoint = true; this.render(); } dropPoint() { const [x, y] = this.transform(this.mouse.x, this.mouse.y); this.onMovePoint(this.selectedPoint, {x, y}); this.movingPoint = false; this.selectedPoint = null; } getClickedPoint(clickLocation, maxDistance) { const [ x, y ] = this.transform(clickLocation.x, clickLocation.y); const clickPoint = { x, y }; const closest = this.tree.closest(clickPoint); if (!closest) return null; if (dist(closest, clickPoint) < maxDistance) return closest; return null; } } export default Canvas;