Early work on Mapp, will move to Github or Gitlab if something becomes of it.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

161 lines
4.1 KiB

import { fabric } from "fabric";
fabric.perfLimitSizeTotal = 134217728;
fabric.maxCacheSideLimit = 65536;
export default class Board {
constructor(id, {grid} = {grid: {}}) {
this.id = id;
this.state = {};
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 = {
...(grid || {}),
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 width = wCount * (size);
const height = hCount * (size);
this.gridGroup.set("left", 0);
this.gridGroup.set("top", 0);
this.gridGroup.set("width", width);
this.gridGroup.set("height", height);
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, height], {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, width, 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();
}
setupPanning() {
const parent = this;
this.canvas.on('mouse:wheel', ({e}) => {
return; // TODO: Fix bugs with the grid when zoomed in/out.
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;
});
}
}