Line Drawing Tool

Press Space to snap to right angles

目前為 2020-08-06 提交的版本,檢視 最新版本

// ==UserScript==
// @name        Line Drawing Tool
// @namespace   https://greasyfork.org/users/281093
// @match       https://sketchful.io/
// @grant       none
// @version     1.0
// @license		MIT
// @author      Bell
// @description Press Space to snap to right angles
// ==/UserScript==
/* jshint esversion: 6 */
/* eslint-disable no-undef */

const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");

const lineCanvas = document.createElement("canvas");
const lineCtx = lineCanvas.getContext("2d");
lineCanvas.style.position = "absolute";
lineCanvas.style.cursor = "crosshair";
lineCanvas.style.width = "100%";
lineCanvas.style.display = "none";
lineCanvas.style.userSelect = "none";
lineCanvas.oncontextmenu = () => { return false; };
[lineCanvas.width, lineCanvas.height] = [canvas.width, canvas.height];
canvas.parentElement.insertBefore(lineCanvas, canvas);

lineCanvas.clear = () => {
	lineCtx.clearRect(0, 0, lineCanvas.width, lineCanvas.height);
}

let origin = {};
let realOrigin = {};
let previewPos = {};
let realPos = {};
let canvasHidden = true;
let drawingLine = false;
let snap = false;

document.addEventListener('keydown', (e) => {
	if (e.code === "ShiftLeft" && canvasHidden) {
		lineCanvas.style.display = "";
		canvasHidden = false;
	}
	else if (e.code === "Space") {
		snap = true;
	}
});

document.addEventListener('pointermove', (e) => {
	previewPos = getPos(e);
	realPos = getRealPos(e);
	
	if (canvasHidden || !drawingLine) return;
	lineCanvas.clear();
	drawPreviewLine(previewPos);
});

document.addEventListener('keyup', (e) => {
	if (e.code === "ShiftLeft" && !canvasHidden) {
		lineCanvas.style.display = "none";
		canvasHidden = true;
		resetLineCanvas();
	}
	else if (e.code === "Space") {
		snap = false;
	}
});

lineCanvas.addEventListener('pointerdown', (e) => {
	origin = getPos(e);
	realOrigin = getRealPos(e);
	drawingLine = true;
});

document.addEventListener('pointerup', (e) => {
	if (!drawingLine) return;
	
	lineCanvas.style.pointerEvents = "all";
	drawLine(realOrigin.x, realOrigin.y, realPos.x, realPos.y);
	resetLineCanvas();
});

function resetLineCanvas() {
	drawingLine = false;
	lineCanvas.clear();
}

function getPos(event) {
	const canvasRect = canvas.getBoundingClientRect();
	const canvasScale = canvas.width / canvasRect.width;
	return {
		x: (event.clientX - canvasRect.left) * canvasScale,
		y: (event.clientY - canvasRect.top) * canvasScale,
	};
}

function getRealPos(event) {
    return {
        x: event.clientX,
        y: event.clientY
    };
}

function drawPreviewLine(pos) {
	lineCtx.beginPath();
	lineCtx.moveTo(origin.x, origin.y);
	
	if (snap) {
		if (Math.abs(pos.x - origin.x) < Math.abs(pos.y - origin.y)) {
			lineCtx.lineTo(origin.x, pos.y);
		} else {
			lineCtx.lineTo(pos.x, origin.y);
		}
	} else {
		lineCtx.lineTo(pos.x, pos.y);
	}
	
	lineCtx.stroke();
}

function drawLine(x1, y1, x2, y2) {
	let coords = { x: x1, y: y1 };
	let newCoords = { x: x2, y: y2 };
	
	if (snap) {
		if (Math.abs(x2 - x1) < Math.abs(y2 - y1)) {
			newCoords.x = x1;
		} else {
			newCoords.y = y1;
		}
	}
	
    canvas.dispatchEvent(createMouseEvent("pointerdown", coords));
    canvas.dispatchEvent(createMouseEvent("pointermove", newCoords));
    canvas.dispatchEvent(createMouseEvent("pointerup", newCoords));
}

function createMouseEvent(name, pos) {
    return new MouseEvent(name, {
        bubbles: false,
        clientX: pos.x,
        clientY: pos.y,
        button: 0
    });
}