您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Hotkey based on page drawer.
// ==UserScript== // @name Draw on page using a pen or mouse // @namespace http://tampermonkey.net/ // @version 0.1.0 // @description Hotkey based on page drawer. // @author @alexrintt // @match http*://*/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // @license MIT // ==/UserScript== (function () { window.onload = () => { const CANVAS_ID = `__on__page__drawing__` const SUPPORT_CANVAS_ID = `__on__page__drawing__support__` const CANVAS_COMMON_CLASS = `__on__page__drawing__class__` const RADIUS_CONFIG_LOCAL_KEY = `drawing__radius__size___` const canvasStyle = ` <style> .${CANVAS_COMMON_CLASS} { touch-action: none; box-sizing: border-box; position: fixed; top: 0;. left: 0; bottom: 0; right: 0; z-index: 10000; width: 100%; height: 100%; visibility: hidden; } #${CANVAS_ID} { background: rgba(0,0,0,0.4); } </style> ` const canvasHtml = ` <canvas class="${CANVAS_COMMON_CLASS}" id="${CANVAS_ID}"></canvas> <canvas class="${CANVAS_COMMON_CLASS}" id="${SUPPORT_CANVAS_ID}"></canvas> ` window.document.body.insertAdjacentHTML(`beforeend`, canvasHtml) window.document.head.insertAdjacentHTML(`beforeend`, canvasStyle) const canvas = window.document.getElementById(CANVAS_ID) const support = window.document.getElementById(SUPPORT_CANVAS_ID) const canvasPhysicalSize = canvas.getBoundingClientRect() const supportPhysicalSize = support.getBoundingClientRect() canvas.width = canvasPhysicalSize.width canvas.height = canvasPhysicalSize.height support.width = supportPhysicalSize.width support.height = supportPhysicalSize.height let recording = false const ctx = canvas.getContext(`2d`) const sctx = support.getContext(`2d`) let stack = [] let lastPos = undefined let radius = Number(window.localStorage.getItem(RADIUS_CONFIG_LOCAL_KEY)) || (() => { window.localStorage.setItem(RADIUS_CONFIG_LOCAL_KEY, 5) return 5 })() function drawPointerCircle(x, y) { if (!isCanvasVisible()) return sctx.clearRect(0, 0, support.width, support.height) sctx.beginPath() sctx.strokeStyle = 'orange'; sctx.arc(x, y, radius, 0, Math.PI * 2, false); sctx.stroke() } function getPointerEventCoord(e) { let x, y switch (e.pointerType) { case `mouse`: x = e.x y = e.y break case `pen`: x = e.x y = e.y break } return { x, y } } function record(e) { e.stopPropagation() const { x, y } = getPointerEventCoord(e) lastPos = { x, y } const hasPenPressureWhenApplicable = e.pointerType === `pen` ? e .pressure > 0 : true drawPointerCircle(x, y) if (!recording || !hasPenPressureWhenApplicable) return pushStackPoint(x, y) } function clearCanvas() { ctx.clearRect(0, 0, canvas.width, canvas.height); } function drawStack() { const entries = stack.filter(e => e.enabled) for (const entry of entries) { const points = entry.points.filter(p => p && p.x && p.y) const radiusAvg = entry.points.map(p => p.radius || 0).reduce((acc, e) => acc + e, 0) / entry.points.length if (points.length) { ctx.lineWidth = radiusAvg ctx.strokeStyle = "rgb(255, 255, 255)" ctx.fillStyle = "rgb(255, 255, 255)" drawPoints(ctx, points) } } } // https://stackoverflow.com/a/10568043/11793117. function drawPoints(ctx, points) { // draw a basic circle instead if (points.length < 6) { var b = points[0]; ctx.beginPath(); ctx.arc(b.x, b.y, ctx.lineWidth / 2, 0, Math.PI * 2, !0); ctx.closePath(); ctx.fill(); return } ctx.beginPath(); ctx.moveTo(points[0].x, points[0].y); // draw a bunch of quadratics, using the average of two points as the control point let i = 1 for (; i < points.length - 2; i++) { var c = (points[i].x + points[i + 1].x) / 2, d = (points[i].y + points[i + 1].y) / 2; ctx.quadraticCurveTo(points[i].x, points[i].y, c, d) } ctx.quadraticCurveTo(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y); ctx.stroke(); } const KEY_Z = 90 const KEY_Y = 89 const KEY_ESC = 27 const KEY_BACKSPACE = 8 const KEY_D = 68 const KEY_NUMPAD_PLUS = 107 const KEY_NUMPAD_MINUS = 109 const KEY_C = 67 let visible = false function hideCanvas() { visible = false canvas.style.visibility = "hidden" support.style.visibility = "hidden" } function showCanvas() { visible = true canvas.style.visibility = "visible" support.style.visibility = "visible" } function isCanvasVisible() { return visible } function toggleCanvasVisibility() { if (isCanvasVisible()) { hideCanvas() } else { showCanvas() } } function onKeyUp() { } function onKeyDown(e) { if (e.keyCode === KEY_ESC || e.keyCode === KEY_BACKSPACE) { clearStack() } else { if (e.shiftKey && e.ctrlKey) { if (e.keyCode === KEY_Z) { redo() } } else if (e.shiftKey) { if (e.keyCode === KEY_C) { clearStack() } else if (e.keyCode === KEY_D) { toggleCanvasVisibility() } else if (e.keyCode === KEY_NUMPAD_PLUS) { radius += 2 drawPointerCircle(lastPos.x, lastPos.y) window.localStorage.setItem(RADIUS_CONFIG_LOCAL_KEY, radius) } else if (e.keyCode === KEY_NUMPAD_MINUS) { radius -= 2 drawPointerCircle(lastPos.x, lastPos.y) window.localStorage.setItem(RADIUS_CONFIG_LOCAL_KEY, radius) } } else if (e.ctrlKey) { if (e.keyCode === KEY_Z) { undo() } else if (e.keyCode === KEY_Y) { redo() } } } } function redraw() { clearCanvas() drawStack() } function undo() { const last = stack.map(e => e.enabled).lastIndexOf(true) if (last === -1) return // ignore, there no drawing undo. stack[last].enabled = false redraw() } function clearStack() { stack = [] redraw() } function redo() { const first = stack.findIndex(e => !e.enabled) if (first === -1) return // There nothing to redo. stack[first].enabled = true redraw() } function pushStackPoint(x, y) { if (!recording || !isCanvasVisible()) return // Remove disabled old entries since this current push call overrides it. stack = stack.filter(e => e.enabled) if (!stack.length) pushStackEntry() stack[stack.length - 1] = { ...stack[stack.length - 1], points: [...((stack[stack.length - 1] || {}).points || []), { x, y, radius }] } redraw() } function pushStackEntry() { stack.push({ points: [], enabled: true }) } function startRecording() { recording = true pushStackEntry() } function stopRecording() { recording = false } window.addEventListener('pointerdown', startRecording) window.addEventListener('pointermove', record) window.addEventListener('pointerup', stopRecording) window.addEventListener('keydown', onKeyDown) window.addEventListener('keyup', onKeyUp) window.onclick = console.log } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址