diff options
Diffstat (limited to 'src/Canvas.js')
-rw-r--r-- | src/Canvas.js | 127 |
1 files changed, 5 insertions, 122 deletions
diff --git a/src/Canvas.js b/src/Canvas.js index 6dff7bd..f3db3e0 100644 --- a/src/Canvas.js +++ b/src/Canvas.js @@ -1,142 +1,25 @@ -import { clamp } from './modules/Util.js'; - class Canvas { - constructor(rootId) { - const root = document.getElementById(rootId); - + constructor(parentElement) { this.element = document.createElement('canvas'); this.context = this.element.getContext('2d'); - - /* state variables */ - this.scale = 1; - this.zoom = 1; - const ZOOM_SPEED = 1.2; - - this.mouse = { - screenPos: { x: 0, y: 0 }, - drawingPos: { x: 0, y: 0 }, - }; - this.pan = { x: 0, y: 0 }; - this.panning = false; - - /* callbacks */ - this.onDraw = null; - this.onMouseMove = null; - this.onMouseDown = null; - this.onMouseUp = null; - - /* register event listeners */ - - /* mouse movement */ - this.element.addEventListener('mousemove', e => { - this.mouse.screenPos.x = e.offsetX; - this.mouse.screenPos.y = e.offsetY; - - const [xd, yd] = this.screenToDrawingPos(e.offsetX, e.offsetY); - - /* compute movement */ - const dx = e.movementX / (this.zoom * this.scale); - const dy = e.movementY / (this.zoom * this.scale); - - /* pan? */ - if (this.panning) { - this.pan.x += dx; - this.pan.y += dy; - this.setTransform(); - } - - this.mouse.drawingPos.x = xd; - this.mouse.drawingPos.y = yd; - - if (this.onMouseMove) this.onMouseMove(this.mousePos); - }); - - /* clicking */ - this.element.addEventListener('mousedown', e => { - e.preventDefault(); - if (e.button === 1) this.panning = true; - if (this.onMouseDown) this.onMouseDown(e); - }); - this.element.addEventListener('mouseup', e => { - if (e.button === 1) this.panning = false; - if (this.onMouseUp) this.onMouseUp(e); - }); - - /* mouse leave */ - this.element.addEventListener('mouseleave', e => { - this.panning = false; - }); - - /* mouse wheel */ - this.element.addEventListener('wheel', e => { - if (this.panning) return; // don't zoom and pan simultaneously - - const delta = e.deltaY < 0 ? ZOOM_SPEED : 1/ZOOM_SPEED; - const alpha = (1/delta) - 1; - - /* zoom in */ - this.zoom *= delta; - this.zoom = clamp(this.zoom, 1, 1000); - this.setTransform(); - - /* pan to keep mouse in the same place */ - const [mouseX, mouseY] = this.screenToDrawingPos(this.mouse.screenPos.x, this.mouse.screenPos.y); - this.pan.x += mouseX - this.mouse.drawingPos.x; - this.pan.y += mouseY - this.mouse.drawingPos.y; - this.setTransform(); - this.draw(); - }); - - /* finalize setup */ + parentElement.appendChild(this.element); this.fillWindow(); window.addEventListener('resize', () => this.fillWindow()); - root.appendChild(this.element); - } - - setTransform() { - /* clamp pan */ - const xMax = this.pixelsToUnits(this.element.width) - 1; - const yMax = this.pixelsToUnits(this.element.height) - 1; - this.pan.x = clamp(this.pan.x, xMax, 0); - this.pan.y = clamp(this.pan.y, yMax, 0); - - this.context.setTransform(1, 0, 0, 1, 0, 0); - this.context.scale(this.zoom * this.scale, this.zoom * this.scale); - this.context.translate(this.pan.x, this.pan.y); } fillWindow() { const width = window.innerWidth; const height = window.innerHeight; - this.scale = Math.max(width, height); + const scale = Math.min(width, height); this.element.width = width; this.element.height = height; - this.setTransform(); + this.context.setTransform(0.4*scale, 0, 0, -0.4*scale, 0.5*scale, 0.5*scale); this.draw(); } - pixelsToUnits(value) { - return value / this.zoom / this.scale; - } - - unitsToPixels(value) { - return value * this.zoom * this.scale; - } - - screenToDrawingPos(xs, ys) { - const matrix = this.context.getTransform(); - matrix.invertSelf(); - - /* compute drawing-space position */ - const x = matrix.a*xs + matrix.b*ys + matrix.e; - const y = matrix.c*xs + matrix.d*ys + matrix.f; - - return [ x, y ]; - } - draw() { - this.context.clearRect(0, 0, 1, 1); + this.context.clearRect(-1, -1, 2, 2); if (this.onDraw) this.onDraw(this.context); } } |