Line Drawing Tool

Press Space to snap to right angles

目前为 2020-08-06 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Line Drawing Tool
  3. // @namespace https://greasyfork.org/users/281093
  4. // @match https://sketchful.io/
  5. // @grant none
  6. // @version 1.0
  7. // @license MIT
  8. // @author Bell
  9. // @description Press Space to snap to right angles
  10. // ==/UserScript==
  11. /* jshint esversion: 6 */
  12. /* eslint-disable no-undef */
  13.  
  14. const canvas = document.querySelector("#canvas");
  15. const ctx = canvas.getContext("2d");
  16.  
  17. const lineCanvas = document.createElement("canvas");
  18. const lineCtx = lineCanvas.getContext("2d");
  19. lineCanvas.style.position = "absolute";
  20. lineCanvas.style.cursor = "crosshair";
  21. lineCanvas.style.width = "100%";
  22. lineCanvas.style.display = "none";
  23. lineCanvas.style.userSelect = "none";
  24. lineCanvas.oncontextmenu = () => { return false; };
  25. [lineCanvas.width, lineCanvas.height] = [canvas.width, canvas.height];
  26. canvas.parentElement.insertBefore(lineCanvas, canvas);
  27.  
  28. lineCanvas.clear = () => {
  29. lineCtx.clearRect(0, 0, lineCanvas.width, lineCanvas.height);
  30. }
  31.  
  32. let origin = {};
  33. let realOrigin = {};
  34. let previewPos = {};
  35. let realPos = {};
  36. let canvasHidden = true;
  37. let drawingLine = false;
  38. let snap = false;
  39.  
  40. document.addEventListener('keydown', (e) => {
  41. if (e.code === "ShiftLeft" && canvasHidden) {
  42. lineCanvas.style.display = "";
  43. canvasHidden = false;
  44. }
  45. else if (e.code === "Space") {
  46. snap = true;
  47. }
  48. });
  49.  
  50. document.addEventListener('pointermove', (e) => {
  51. previewPos = getPos(e);
  52. realPos = getRealPos(e);
  53. if (canvasHidden || !drawingLine) return;
  54. lineCanvas.clear();
  55. drawPreviewLine(previewPos);
  56. });
  57.  
  58. document.addEventListener('keyup', (e) => {
  59. if (e.code === "ShiftLeft" && !canvasHidden) {
  60. lineCanvas.style.display = "none";
  61. canvasHidden = true;
  62. resetLineCanvas();
  63. }
  64. else if (e.code === "Space") {
  65. snap = false;
  66. }
  67. });
  68.  
  69. lineCanvas.addEventListener('pointerdown', (e) => {
  70. origin = getPos(e);
  71. realOrigin = getRealPos(e);
  72. drawingLine = true;
  73. });
  74.  
  75. document.addEventListener('pointerup', (e) => {
  76. if (!drawingLine) return;
  77. lineCanvas.style.pointerEvents = "all";
  78. drawLine(realOrigin.x, realOrigin.y, realPos.x, realPos.y);
  79. resetLineCanvas();
  80. });
  81.  
  82. function resetLineCanvas() {
  83. drawingLine = false;
  84. lineCanvas.clear();
  85. }
  86.  
  87. function getPos(event) {
  88. const canvasRect = canvas.getBoundingClientRect();
  89. const canvasScale = canvas.width / canvasRect.width;
  90. return {
  91. x: (event.clientX - canvasRect.left) * canvasScale,
  92. y: (event.clientY - canvasRect.top) * canvasScale,
  93. };
  94. }
  95.  
  96. function getRealPos(event) {
  97. return {
  98. x: event.clientX,
  99. y: event.clientY
  100. };
  101. }
  102.  
  103. function drawPreviewLine(pos) {
  104. lineCtx.beginPath();
  105. lineCtx.moveTo(origin.x, origin.y);
  106. if (snap) {
  107. if (Math.abs(pos.x - origin.x) < Math.abs(pos.y - origin.y)) {
  108. lineCtx.lineTo(origin.x, pos.y);
  109. } else {
  110. lineCtx.lineTo(pos.x, origin.y);
  111. }
  112. } else {
  113. lineCtx.lineTo(pos.x, pos.y);
  114. }
  115. lineCtx.stroke();
  116. }
  117.  
  118. function drawLine(x1, y1, x2, y2) {
  119. let coords = { x: x1, y: y1 };
  120. let newCoords = { x: x2, y: y2 };
  121. if (snap) {
  122. if (Math.abs(x2 - x1) < Math.abs(y2 - y1)) {
  123. newCoords.x = x1;
  124. } else {
  125. newCoords.y = y1;
  126. }
  127. }
  128. canvas.dispatchEvent(createMouseEvent("pointerdown", coords));
  129. canvas.dispatchEvent(createMouseEvent("pointermove", newCoords));
  130. canvas.dispatchEvent(createMouseEvent("pointerup", newCoords));
  131. }
  132.  
  133. function createMouseEvent(name, pos) {
  134. return new MouseEvent(name, {
  135. bubbles: false,
  136. clientX: pos.x,
  137. clientY: pos.y,
  138. button: 0
  139. });
  140. }