您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Press Space to snap to right angles
// ==UserScript== // @name Line Drawing Tool // @namespace https://greasyfork.org/users/281093 // @match https://sketchful.io/ // @grant none // @version 1.3.3 // @license MIT // @author Bell // @description Press Space to snap to right angles // ==/UserScript== /* jshint esversion: 6 */ const canvas = document.querySelector('#canvas'); 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.style.zIndex = '2'; 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 (!isDrawing()) return; if (e.code === 'ShiftLeft' && canvasHidden) { lineCanvas.style.display = ''; disableScroll(); canvasHidden = false; } else if (e.code === 'Space' && !snap && !canvasHidden) { snap = true; document.dispatchEvent(createMouseEvent('pointermove', realPos)); } }); document.addEventListener('keyup', (e) => { if (e.code === 'ShiftLeft' && !canvasHidden) { lineCanvas.style.display = 'none'; canvasHidden = true; enableScroll(); resetLineCanvas(); document.removeEventListener('pointermove', savePos); document.removeEventListener('pointerup', pointerUpDraw); } else if (e.code === 'Space' && snap) { snap = false; document.dispatchEvent(createMouseEvent('pointermove', realPos)); } }); function savePos(e) { previewPos = getPos(e); realPos = getRealPos(e); if (canvasHidden || !drawingLine) return; lineCanvas.clear(); drawPreviewLine(previewPos); e.preventDefault(); } lineCanvas.addEventListener('pointerdown', (e) => { origin = getPos(e); realOrigin = getRealPos(e); drawingLine = true; document.addEventListener('pointerup', pointerUpDraw); document.addEventListener('pointermove', savePos); }); function pointerUpDraw(e) { document.removeEventListener('pointermove', savePos); document.removeEventListener('pointerup', pointerUpDraw); drawLine(realOrigin.x, realOrigin.y, realPos.x, realPos.y); previewPos = getPos(e); realPos = getRealPos(e); 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) { const coords = { x: x1, y: y1 }; const 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, true)); } function createMouseEvent(name, pos, bubbles = false) { return new MouseEvent(name, { bubbles: bubbles, clientX: pos.x, clientY: pos.y, button: 0 }); } const keys = { 32: 1, 37: 1, 38: 1, 39: 1, 40: 1 }; function preventDefault(e) { e.preventDefault(); } function preventDefaultForScrollKeys(e) { if (keys[e.keyCode]) { preventDefault(e); return false; } } function isDrawing() { return document.querySelector('#gameTools').style.display !== 'none' && document.querySelector('body > div.game').style.display !== 'none' && document.activeElement.tagName !== 'INPUT'; } let supportsPassive = false; try { window.addEventListener('test', null, Object.defineProperty({}, 'passive', { get: function() { supportsPassive = true; return true; } })); } catch(e) { console.log(e); } const wheelOpt = supportsPassive ? { passive: false } : false; const wheelEvent = 'onwheel' in document.createElement('div') ? 'wheel' : 'mousewheel'; function disableScroll() { window.addEventListener('DOMMouseScroll', preventDefault, false); window.addEventListener(wheelEvent, preventDefault, wheelOpt); window.addEventListener('touchmove', preventDefault, wheelOpt); window.addEventListener('keydown', preventDefaultForScrollKeys, false); } function enableScroll() { window.removeEventListener('DOMMouseScroll', preventDefault, false); window.removeEventListener(wheelEvent, preventDefault, wheelOpt); window.removeEventListener('touchmove', preventDefault, wheelOpt); window.removeEventListener('keydown', preventDefaultForScrollKeys, false); }