Displays a base image and an "x-ray" view of a second image where the mouse is pointing
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

273 行
8.3 KiB

  1. "use strict";
  2. let overlayLoaded = false;
  3. let baseLoaded = false;
  4. let radius = 200;
  5. let softness = 25;
  6. document.addEventListener("DOMContentLoaded", e => {
  7. document.querySelector("#load-button").addEventListener("click", e => {
  8. console.log("Trying to load...");
  9. const baseInput = document.querySelector("#base-url").value;
  10. const overlayInput = document.querySelector("#overlay-url").value;
  11. let success = true;
  12. try {
  13. let baseURL = new URL(baseInput)
  14. console.log(baseURL);
  15. } catch {
  16. document.querySelector("#base-url").value = "";
  17. document.querySelector("#base-url").placeholder = "Invalid URL...";
  18. success = false;
  19. }
  20. try {
  21. let overlayURL = new URL(overlayInput)
  22. console.log(overlayURL);
  23. } catch {
  24. document.querySelector("#overlay-url").value = "";
  25. document.querySelector("#overlay-url").placeholder = "Invalid URL...";
  26. success = false;
  27. }
  28. if (!success) {
  29. return;
  30. }
  31. const overlayImg = document.querySelector("#overlay-img");
  32. const baseImg = document.querySelector("#base-img");
  33. overlayImg.src = overlayInput;
  34. baseImg.src = baseInput;
  35. load();
  36. try {
  37. localStorage.setItem("base", baseInput);
  38. localStorage.setItem("overlay", overlayInput);
  39. } catch {
  40. console.error("Couldn't set something in local storage :(")
  41. }
  42. });
  43. let url = new URL(window.location);
  44. const overlay = document.querySelector("#overlay");
  45. overlay.addEventListener("mousemove", e => {
  46. let x = e.clientX - e.target.getBoundingClientRect().x;
  47. let y = e.clientY - e.target.getBoundingClientRect().y;
  48. updateOverlay([[x,y]]);
  49. });
  50. overlay.addEventListener("touchmove", e => {
  51. let offsetX = e.target.getBoundingClientRect().x;
  52. let offsetY = e.target.getBoundingClientRect().y;
  53. let touches = [];
  54. for (let i=0; i < e.touches.length; i++) {
  55. let x = e.touches[i].clientX - offsetX;
  56. let y = e.touches[i].clientY - offsetY;
  57. touches.push([x,y]);
  58. }
  59. updateOverlay(touches);
  60. });
  61. document.querySelector("#radius-slider").addEventListener("input", e => {
  62. try {
  63. radius = parseInt(e.target.value);
  64. document.querySelector("#radius-input").value = radius;
  65. } catch {
  66. console.warn("That wasn't a valid radius: " + e.target.value);
  67. }
  68. });
  69. document.querySelector("#radius-input").addEventListener("input", e => {
  70. try {
  71. radius = parseInt(e.target.value);
  72. document.querySelector("#radius-slider").value = radius;
  73. } catch {
  74. console.warn("That wasn't a valid radius: " + e.target.value);
  75. }
  76. });
  77. document.querySelector("#softness-slider").addEventListener("input", e => {
  78. try {
  79. softness = parseInt(e.target.value);
  80. document.querySelector("#softness-input").value = softness;
  81. } catch {
  82. console.warn("That wasn't a valid softness: " + e.target.value);
  83. }
  84. });
  85. document.querySelector("#softness-input").addEventListener("input", e => {
  86. try {
  87. softness = parseInt(e.target.value);
  88. document.querySelector("#softness-slider").value = softness;
  89. } catch {
  90. console.warn("That wasn't a valid softness: " + e.target.value);
  91. }
  92. });
  93. // see if we have params already; if so, use them!
  94. const overlayImg = document.querySelector("#overlay-img");
  95. const baseImg = document.querySelector("#base-img");
  96. const baseInput = document.querySelector("#base-url");
  97. const overlayInput = document.querySelector("#overlay-url");
  98. if (url.searchParams.has("base") && url.searchParams.has("overlay")) {
  99. let baseURL = url.searchParams.get("base");
  100. let overlayURL = url.searchParams.get("overlay");
  101. baseImg.src = baseURL;
  102. overlayImg.src = overlayURL;
  103. baseInput.value = baseURL;
  104. overlayInput.value = overlayURL;
  105. load();
  106. } else {
  107. try {
  108. baseInput.value = localStorage.getItem("base");
  109. overlayInput.value = localStorage.getItem("overlay");
  110. } catch {
  111. console.error("Couldn't get something from local storage :(")
  112. }
  113. }
  114. if (url.searchParams.has("radius")) {
  115. try {
  116. radius = parseInt(url.searchParams.get("radius"));
  117. document.querySelector("#radius").value = radius;
  118. } catch {
  119. console.warn("That was a bogus radius...");
  120. }
  121. }
  122. if (url.searchParams.has("softness")) {
  123. try {
  124. softness = parseInt(url.searchParams.get("softness"));
  125. document.querySelector("#softness").value = softness;
  126. } catch {
  127. console.warn("That was a bogus softness...");
  128. }
  129. }
  130. document.querySelector("#share-button").addEventListener("click", e => {
  131. let shareURL = new URL(window.location);
  132. // for some reason, the parser gets confused by urlencoded urls...
  133. // so, to get rid of all parameters, we do this
  134. let keys = Array.from(shareURL.searchParams.keys());
  135. do {
  136. keys = Array.from(shareURL.searchParams.keys());
  137. keys.forEach(key => {
  138. shareURL.searchParams.delete(key);
  139. });
  140. } while (keys.length > 0)
  141. shareURL.searchParams.append("base", baseImg.src);
  142. shareURL.searchParams.append("overlay", overlayImg.src);
  143. shareURL.searchParams.append("radius", radius);
  144. shareURL.searchParams.append("softness", softness);
  145. console.log(shareURL);
  146. window.location = shareURL;
  147. });
  148. });
  149. function load() {
  150. document.querySelector("#menu").classList.remove("start");
  151. const overlayImg = document.querySelector("#overlay-img");
  152. const baseImg = document.querySelector("#base-img");
  153. overlayImg.addEventListener("load", function overlayLoad() {
  154. console.log("The overlay is loaded");
  155. overlayLoaded = true;
  156. if (overlayLoaded && baseLoaded) {
  157. setup();
  158. }
  159. overlayImg.removeEventListener("load", overlayLoad);
  160. })
  161. baseImg.addEventListener("load", function baseLoad() {
  162. console.log("The base is loaded");
  163. baseLoaded = true;
  164. if (overlayLoaded && baseLoaded) {
  165. setup();
  166. }
  167. baseImg.removeEventListener("load", baseLoad);
  168. })
  169. }
  170. function setup() {
  171. const overlay = document.querySelector("#overlay");
  172. const base = document.querySelector("#base");
  173. overlay.classList.remove("hidden");
  174. base.classList.remove("hidden");
  175. const overlayImg = document.querySelector("#overlay-img");
  176. const baseImg = document.querySelector("#base-img");
  177. /** @type {CanvasRenderingContext2D} */
  178. const overlayCtx = overlay.getContext("2d");
  179. /** @type {CanvasRenderingContext2D} */
  180. const baseCtx = base.getContext("2d");
  181. baseCtx.canvas.width = baseImg.width;
  182. baseCtx.canvas.height = baseImg.height;
  183. baseCtx.drawImage(baseImg, 0, 0);
  184. overlayCtx.canvas.width = overlayImg.width;
  185. overlayCtx.canvas.height = overlayImg.height;
  186. console.log("Done");
  187. }
  188. function updateOverlay(points) {
  189. /** @type {CanvasRenderingContext2D} */
  190. const overlayCtx = overlay.getContext("2d");
  191. const overlayImg = document.querySelector("#overlay-img");
  192. const w = overlayCtx.canvas.width;
  193. const h = overlayCtx.canvas.height;
  194. overlayCtx.save();
  195. overlayCtx.globalCompositeOperation = "source-over";
  196. overlayCtx.clearRect(0, 0, w, h);
  197. points.forEach(point => {
  198. const [x,y] = point;
  199. overlayCtx.beginPath();
  200. overlayCtx.ellipse(x, y, radius, radius, 0, 0, 2 * Math.PI);
  201. const gradient = overlayCtx.createRadialGradient(x, y, 0, x, y, radius);
  202. gradient.addColorStop((100-softness)/100, '#000000FF');
  203. gradient.addColorStop(1, '#00000000');
  204. overlayCtx.fillStyle = gradient;
  205. overlayCtx.fill();
  206. })
  207. overlayCtx.globalCompositeOperation = "source-in";
  208. overlayCtx.drawImage(overlayImg, 0, 0);
  209. overlayCtx.restore();
  210. }