import { fabric } from "fabric"; fabric.perfLimitSizeTotal = 134217728; fabric.maxCacheSideLimit = 65536; export default class Board { constructor(id) { this.id = id; this.state = {a: 32}; this.containerElement = document.getElementById(id); if (this.containerElement == null) { throw new Error(`Container ${this.id} not found`) } this.canvasElement = document.createElement("canvas"); this.containerElement.appendChild(this.canvasElement); this.canvas = new fabric.Canvas(this.canvasElement, {backgroundColor: "#555"}); this.gridGroup = new fabric.Group(); this.canvas.add(this.gridGroup); this.gridOptions = { enabled: true, size: 64, hightlightInterval: 8, lineColor: "#444", highlightColor: "#333", }; this.setupPanning(); } destroy() { this.canvasElement.remove(); } resize(width, height) { this.canvas.setHeight(height); this.canvas.setWidth(width); this.redrawGrid(); this.moveGrid(); this.canvas.renderAll(); } redrawGrid() { const {enabled, size, hightlightInterval, lineColor, highlightColor} = this.gridOptions; for (const obj of this.gridGroup.getObjects().slice()) { this.gridGroup.remove(obj); } if (!enabled) { return; } const wCount = Math.ceil((this.canvas.getWidth() / this.canvas.getZoom()) / size) + (hightlightInterval * 2); const hCount = Math.ceil((this.canvas.getHeight() / this.canvas.getZoom()) / size) + (hightlightInterval * 2); const width2 = wCount * (size); const height2 = hCount * (size); this.gridGroup.set("left", 0); this.gridGroup.set("top", 0); this.gridGroup.set("width", width2); this.gridGroup.set("height", height2); this.gridGroup.set("selectable", false); this.gridGroup.set("hoverCursor", "default"); for (let i = 0; i <= wCount; ++i) { let x = i * size; let line = new fabric.Line([x, 0, x, height2], {stroke: lineColor, strokeWidth: 2, selectable: false}); if (i % hightlightInterval == 0) { line.set("stroke", highlightColor); } this.gridGroup.addWithUpdate(line); } for (let i = 0; i <= hCount; ++i) { let y = i * size; let line = new fabric.Line([0, y, width2, y], {stroke: lineColor, strokeWidth: 2, selectable: false}); if (i % hightlightInterval == 0) { line.set("stroke", highlightColor); } this.gridGroup.addWithUpdate(line); } } moveGrid() { const size = this.gridOptions.size * this.gridOptions.hightlightInterval; const [x, y] = this.canvas.viewportTransform.slice(4).map(n => -n); const xOffset = (x % size) + size; const yOffset = (y % size) + size; this.gridGroup.set("left", x - xOffset); this.gridGroup.set("top", y - yOffset); this.gridGroup.setCoords(); console.log(this.gridGroup); } setupPanning() { const parent = this; this.canvas.on('mouse:wheel', ({e}) => { if (e.shiftKey === false) { return; } let delta = e.deltaY; let zoom = this.canvas.getZoom(); zoom = zoom - delta/1000; if (zoom > 5) { zoom = 5; } if (zoom < 0.25) { zoom = 0.25; } this.canvas.setZoom(zoom); this.redrawGrid(); this.moveGrid(); e.preventDefault(); e.stopPropagation(); }) this.canvas.on('mouse:down', function(opt) { var evt = opt.e; if (evt.shiftKey === true) { this.isDragging = true; this.selection = false; this.lastPosX = evt.clientX; this.lastPosY = evt.clientY; } }); this.canvas.on('mouse:move', function(opt) { if (this.isDragging) { var e = opt.e; this.viewportTransform[4] += e.clientX - this.lastPosX; this.viewportTransform[5] += e.clientY - this.lastPosY; this.requestRenderAll(); this.lastPosX = e.clientX; this.lastPosY = e.clientY; parent.moveGrid(); } }); this.canvas.on('mouse:up', function(opt) { this.isDragging = false; this.selection = true; }); } }