Draw on Page

Allows you to draw directly on webpages when you press Shift+Alt+D

当前为 2023-03-20 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Draw on Page
  3. // @version 1.2
  4. // @description Allows you to draw directly on webpages when you press Shift+Alt+D
  5. // @author someRandomGuy2
  6. // @match *://*/*
  7. // @grant none
  8. // @license Apache-2.0
  9. // @namespace https://greasyfork.org/users/117222
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. let container;
  16. let drawingCanvas;
  17. let contextMenuContainer;
  18. let contextMenu;
  19. let enabled = false;
  20. let color = "#ff0000";
  21.  
  22. const brushes = {
  23. pen: function(X, startX, startY, endX, endY, pressure) {
  24. X.fillStyle = color;
  25. const movementX = endX - startX;
  26. const movementY = endY - startY;
  27. const step = 2;
  28. const distance = Math.sqrt(movementX * movementX + movementY * movementY);
  29. const size = 4 * pressure;
  30. const halfSize = size / 2;
  31. const distanceStep = Math.max(0.2, halfSize);
  32.  
  33. for (let i = 0; i < distance; i += distanceStep) {
  34. const x = startX * (1 - i / distance) + endX * (i / distance);
  35. const y = startY * (1 - i / distance) + endY * (i / distance);
  36. X.fillRect(x - halfSize, y - halfSize, size, size);
  37. }
  38. X.fillRect(endX - halfSize, endY - halfSize, size, size);
  39. },
  40.  
  41. eraser: function(X, startX, startY, endX, endY, pressure) {
  42. const movementX = endX - startX;
  43. const movementY = endY - startY;
  44. const step = 2;
  45. const distance = Math.sqrt(movementX * movementX + movementY * movementY);
  46. const size = 50 * pressure;
  47. const halfSize = size / 2;
  48. const distanceStep = Math.max(0.2, halfSize);
  49.  
  50. for (let i = 0; i < distance; i += distanceStep) {
  51. const x = startX * (1 - i / distance) + endX * (i / distance);
  52. const y = startY * (1 - i / distance) + endY * (i / distance);
  53. X.clearRect(x - halfSize, y - halfSize, size, size);
  54. }
  55. X.clearRect(endX - halfSize, endY - halfSize, size, size);
  56. },
  57. };
  58.  
  59. function toggleDrawable() {
  60. initIfNotAlready();
  61. if (enabled) {
  62. enabled = false;
  63. container.classList.add("tm-drawing-canvas-fallthrough");
  64. } else {
  65. enabled = true;
  66. container.classList.remove("tm-drawing-canvas-fallthrough");
  67. }
  68. }
  69.  
  70. function initIfNotAlready() {
  71. if (container) { return; }
  72. container = document.createElement("div");
  73. container.classList.add("tm-drawing-canvas-container");
  74.  
  75. drawingCanvas = document.createElement("canvas");
  76. drawingCanvas.classList.add("tm-drawing-canvas");
  77. container.appendChild(drawingCanvas);
  78. drawingCanvas.width = innerWidth * devicePixelRatio;
  79. drawingCanvas.height = innerHeight * devicePixelRatio;
  80.  
  81. const X = drawingCanvas.getContext("2d");
  82.  
  83. contextMenuContainer = document.createElement("div");
  84. contextMenuContainer.classList.add("tm-drawing-canvas-context-menu-container");
  85.  
  86. contextMenu = document.createElement("div");
  87. contextMenuContainer.appendChild(contextMenu);
  88. contextMenu.classList.add("tm-drawing-canvas-context-menu");
  89.  
  90. const clearCanvasOption = document.createElement("div");
  91. clearCanvasOption.innerText = "Clear canvas";
  92. contextMenu.appendChild(clearCanvasOption);
  93.  
  94. const saveCanvasOption = document.createElement("div");
  95. saveCanvasOption.innerText = "Save canvas";
  96. contextMenu.appendChild(saveCanvasOption);
  97.  
  98. const changeColor = document.createElement("div");
  99. const colorPicker = document.createElement("input");
  100. colorPicker.type = "color";
  101. colorPicker.value = color;
  102. changeColor.appendChild(colorPicker);
  103. contextMenu.appendChild(changeColor);
  104.  
  105. const dropShadowToggle = document.createElement("div");
  106. dropShadowToggle.innerText = "Toggle drop shadow";
  107. contextMenu.appendChild(dropShadowToggle);
  108.  
  109. let mouseDown = false;
  110.  
  111. drawingCanvas.addEventListener("pointerdown", function() { mouseDown = true; });
  112. drawingCanvas.addEventListener("pointerup", function() { mouseDown = false; });
  113.  
  114. drawingCanvas.addEventListener("pointermove", function(event) {
  115. if (!mouseDown) { return; }
  116. const brush = event.shiftKey ? brushes.eraser : brushes.pen;
  117. const scaleX = drawingCanvas.width / innerWidth;
  118. const scaleY = drawingCanvas.height / innerHeight;
  119. const startX = (event.x - event.movementX) * scaleX;
  120. const startY = (event.y - event.movementY) * scaleY;
  121. const endX = event.x * scaleX;
  122. const endY = event.y * scaleY;
  123.  
  124. brush(X, startX, startY, endX, endY, event.pressure);
  125. });
  126.  
  127. drawingCanvas.addEventListener("contextmenu", function(event) {
  128. contextMenu.style.top = event.clientY + "px";
  129. contextMenu.style.left = event.clientX + "px";
  130. container.appendChild(contextMenuContainer);
  131. event.preventDefault();
  132. });
  133.  
  134. function addContextMenuItemClickListener(elm, func) {
  135. elm.addEventListener("click", func);
  136. elm.addEventListener("mouseup", ev => func(ev, true));
  137. }
  138.  
  139. function closeContextMenu() {
  140. container.removeChild(contextMenuContainer);
  141. }
  142.  
  143. addContextMenuItemClickListener(contextMenuContainer, function(event, mouseupShortcutClick) {
  144. if (mouseupShortcutClick) {
  145. if (event.target != contextMenuContainer && event.target != contextMenu) {
  146. closeContextMenu();
  147. }
  148. } else {
  149. closeContextMenu();
  150. }
  151. });
  152.  
  153. addContextMenuItemClickListener(clearCanvasOption, function() {
  154. // clear canvas
  155. X.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height);
  156. drawingCanvas.width = innerWidth * devicePixelRatio;
  157. drawingCanvas.height = innerHeight * devicePixelRatio;
  158. });
  159.  
  160. addContextMenuItemClickListener(saveCanvasOption, function() {
  161. drawingCanvas.toBlob(blob => open(URL.createObjectURL(blob)))
  162. });
  163.  
  164. addContextMenuItemClickListener(dropShadowToggle, function() {
  165. drawingCanvas.classList.toggle("no-drop-shadow");
  166. });
  167.  
  168. addContextMenuItemClickListener(changeColor, function(event, mouseupShortcutClick) {
  169. if (event.target == changeColor || mouseupShortcutClick) {
  170. colorPicker.click();
  171. }
  172. event.stopPropagation();
  173. });
  174.  
  175. colorPicker.addEventListener("change", function() {
  176. color = colorPicker.value;
  177. closeContextMenu();
  178. });
  179.  
  180. drawingCanvas.addEventListener("touchmove", function(event) { });
  181.  
  182. const style = document.createElement("style");
  183. style.innerHTML = `
  184. .tm-drawing-canvas-container {
  185. z-index: 99999;
  186. position: fixed;
  187. top: 0;
  188. left: 0;
  189. width: 100vw;
  190. height: 100vh;
  191. font-size: 14px;
  192. font-family: sans;
  193. line-height: 1.15;
  194. color: #000;
  195. }
  196.  
  197. .tm-drawing-canvas-container.tm-drawing-canvas-fallthrough {
  198. pointer-events: none;
  199. }
  200.  
  201. .tm-drawing-canvas {
  202. position: aboslute;
  203. top: 0;
  204. left: 0;
  205. width: 100%;
  206. height: 100%;
  207. cursor: crosshair;
  208. filter: drop-shadow(0px 0px 8px background);
  209. }
  210.  
  211. .tm-drawing-canvas.no-drop-shadow {
  212. filter: none;
  213. }
  214.  
  215. .tm-drawing-canvas-context-menu-container {
  216. position: fixed;
  217. top: 0;
  218. left: 0;
  219. width: 100%;
  220. height: 100%;
  221. }
  222.  
  223. .tm-drawing-canvas-context-menu {
  224. position: absolute;
  225. display: inline-block;
  226. background-color: #fff;
  227. padding-top: 4px;
  228. padding-bottom: 4px;
  229. margin-top: 1px;
  230. border: 1px solid #00000040;
  231. box-shadow: #00000038 0px 1px 16px, #0000002e 0px 1px 8px;
  232. }
  233.  
  234. .tm-drawing-canvas-context-menu div {
  235. padding: 4px;
  236. cursor: pointer;
  237. }
  238.  
  239. .tm-drawing-canvas-context-menu div:hover {
  240. background-color: #ccc;
  241. }
  242. `;
  243. document.head.appendChild(style);
  244. document.body.appendChild(container);
  245. }
  246.  
  247. addEventListener("keydown", function(event) {
  248. if (event.code == "KeyD" && event.altKey && event.shiftKey) {
  249. toggleDrawable();
  250. }
  251. });
  252. })();