Displays a base image and an "x-ray" view of a second image where the mouse is pointing
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

316 řádky
9.9 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. setURL();
  36. load();
  37. try {
  38. localStorage.setItem("base", baseInput);
  39. localStorage.setItem("overlay", overlayInput);
  40. } catch {
  41. console.error("Couldn't set something in local storage :(")
  42. }
  43. });
  44. let url = new URL(window.location);
  45. const overlay = document.querySelector("#overlay");
  46. document.addEventListener("mousemove", e => {
  47. let x = e.clientX - e.target.getBoundingClientRect().x;
  48. let y = e.clientY - e.target.getBoundingClientRect().y;
  49. updateOverlay([[x,y]]);
  50. });
  51. document.addEventListener("touchmove", e => {
  52. let offsetX = e.target.getBoundingClientRect().x;
  53. let offsetY = e.target.getBoundingClientRect().y;
  54. let touches = [];
  55. for (let i=0; i < e.touches.length; i++) {
  56. let x = e.touches[i].clientX - offsetX;
  57. let y = e.touches[i].clientY - offsetY;
  58. touches.push([x,y]);
  59. }
  60. updateOverlay(touches);
  61. });
  62. document.querySelector("#radius-slider").addEventListener("input", e => {
  63. try {
  64. radius = parseInt(e.target.value);
  65. document.querySelector("#radius-input").value = radius;
  66. } catch {
  67. console.warn("That wasn't a valid radius: " + e.target.value);
  68. }
  69. });
  70. document.querySelector("#radius-slider").addEventListener("change", e => {
  71. try {
  72. radius = parseInt(e.target.value);
  73. document.querySelector("#radius-input").value = radius;
  74. } catch {
  75. console.warn("That wasn't a valid radius: " + e.target.value);
  76. }
  77. setURL();
  78. });
  79. document.querySelector("#radius-input").addEventListener("input", e => {
  80. try {
  81. radius = parseInt(e.target.value);
  82. document.querySelector("#radius-slider").value = radius;
  83. } catch {
  84. console.warn("That wasn't a valid radius: " + e.target.value);
  85. }
  86. });
  87. document.querySelector("#radius-input").addEventListener("change", e => {
  88. try {
  89. radius = parseInt(e.target.value);
  90. document.querySelector("#radius-slider").value = radius;
  91. } catch {
  92. console.warn("That wasn't a valid radius: " + e.target.value);
  93. }
  94. setURL();
  95. });
  96. document.querySelector("#softness-slider").addEventListener("input", e => {
  97. try {
  98. softness = parseInt(e.target.value);
  99. document.querySelector("#softness-input").value = softness;
  100. } catch {
  101. console.warn("That wasn't a valid softness: " + e.target.value);
  102. }
  103. });
  104. document.querySelector("#softness-slider").addEventListener("change", e => {
  105. try {
  106. softness = parseInt(e.target.value);
  107. document.querySelector("#softness-input").value = softness;
  108. } catch {
  109. console.warn("That wasn't a valid softness: " + e.target.value);
  110. }
  111. setURL();
  112. });
  113. document.querySelector("#softness-input").addEventListener("input", e => {
  114. try {
  115. softness = parseInt(e.target.value);
  116. document.querySelector("#softness-slider").value = softness;
  117. } catch {
  118. console.warn("That wasn't a valid softness: " + e.target.value);
  119. }
  120. });
  121. document.querySelector("#softness-input").addEventListener("change", e => {
  122. try {
  123. softness = parseInt(e.target.value);
  124. document.querySelector("#softness-slider").value = softness;
  125. } catch {
  126. console.warn("That wasn't a valid softness: " + e.target.value);
  127. }
  128. setURL();
  129. });
  130. // see if we have params already; if so, use them!
  131. const overlayImg = document.querySelector("#overlay-img");
  132. const baseImg = document.querySelector("#base-img");
  133. const baseInput = document.querySelector("#base-url");
  134. const overlayInput = document.querySelector("#overlay-url");
  135. if (url.searchParams.has("base") && url.searchParams.has("overlay")) {
  136. let baseURL = url.searchParams.get("base");
  137. let overlayURL = url.searchParams.get("overlay");
  138. baseImg.src = baseURL;
  139. overlayImg.src = overlayURL;
  140. baseInput.value = baseURL;
  141. overlayInput.value = overlayURL;
  142. load();
  143. } else {
  144. try {
  145. baseInput.value = localStorage.getItem("base");
  146. overlayInput.value = localStorage.getItem("overlay");
  147. } catch {
  148. console.error("Couldn't get something from local storage :(")
  149. }
  150. }
  151. if (url.searchParams.has("radius")) {
  152. try {
  153. radius = parseInt(url.searchParams.get("radius"));
  154. document.querySelector("#radius-slider").value = radius;
  155. document.querySelector("#radius-input").value = radius;
  156. } catch {
  157. console.warn("That was a bogus radius...");
  158. }
  159. }
  160. if (url.searchParams.has("softness")) {
  161. try {
  162. softness = parseInt(url.searchParams.get("softness"));
  163. document.querySelector("#softness-slider").value = softness;
  164. document.querySelector("#softness-input").value = softness;
  165. } catch {
  166. console.warn("That was a bogus softness...");
  167. }
  168. }
  169. });
  170. function load() {
  171. document.querySelector("#menu").classList.remove("start");
  172. const overlayImg = document.querySelector("#overlay-img");
  173. const baseImg = document.querySelector("#base-img");
  174. overlayImg.addEventListener("load", function overlayLoad() {
  175. console.log("The overlay is loaded");
  176. overlayLoaded = true;
  177. if (overlayLoaded && baseLoaded) {
  178. setup();
  179. }
  180. overlayImg.removeEventListener("load", overlayLoad);
  181. })
  182. baseImg.addEventListener("load", function baseLoad() {
  183. console.log("The base is loaded");
  184. baseLoaded = true;
  185. if (overlayLoaded && baseLoaded) {
  186. setup();
  187. }
  188. baseImg.removeEventListener("load", baseLoad);
  189. })
  190. }
  191. function setup() {
  192. const overlay = document.querySelector("#overlay");
  193. const base = document.querySelector("#base");
  194. overlay.classList.remove("hidden");
  195. base.classList.remove("hidden");
  196. const overlayImg = document.querySelector("#overlay-img");
  197. const baseImg = document.querySelector("#base-img");
  198. /** @type {CanvasRenderingContext2D} */
  199. const overlayCtx = overlay.getContext("2d");
  200. /** @type {CanvasRenderingContext2D} */
  201. const baseCtx = base.getContext("2d");
  202. baseCtx.canvas.width = baseImg.width;
  203. baseCtx.canvas.height = baseImg.height;
  204. baseCtx.drawImage(baseImg, 0, 0);
  205. overlayCtx.canvas.width = overlayImg.width;
  206. overlayCtx.canvas.height = overlayImg.height;
  207. console.log("Done");
  208. }
  209. function updateOverlay(points) {
  210. /** @type {CanvasRenderingContext2D} */
  211. const overlayCtx = overlay.getContext("2d");
  212. const overlayImg = document.querySelector("#overlay-img");
  213. const w = overlayCtx.canvas.width;
  214. const h = overlayCtx.canvas.height;
  215. overlayCtx.save();
  216. overlayCtx.globalCompositeOperation = "source-over";
  217. overlayCtx.clearRect(0, 0, w, h);
  218. points.forEach(point => {
  219. const [x,y] = point;
  220. overlayCtx.beginPath();
  221. overlayCtx.ellipse(x, y, radius, radius, 0, 0, 2 * Math.PI);
  222. const gradient = overlayCtx.createRadialGradient(x, y, 0, x, y, radius);
  223. gradient.addColorStop((100-softness)/100, '#000000FF');
  224. gradient.addColorStop(1, '#00000000');
  225. overlayCtx.fillStyle = gradient;
  226. overlayCtx.fill();
  227. })
  228. overlayCtx.globalCompositeOperation = "source-in";
  229. overlayCtx.drawImage(overlayImg, 0, 0);
  230. overlayCtx.restore();
  231. }
  232. function setURL() {
  233. let shareURL = new URL(window.location);
  234. // for some reason, the parser gets confused by urlencoded urls...
  235. // so, to get rid of all parameters, we do this
  236. let keys = Array.from(shareURL.searchParams.keys());
  237. do {
  238. keys = Array.from(shareURL.searchParams.keys());
  239. keys.forEach(key => {
  240. shareURL.searchParams.delete(key);
  241. });
  242. } while (keys.length > 0)
  243. const overlayImg = document.querySelector("#overlay-img");
  244. const baseImg = document.querySelector("#base-img");
  245. shareURL.searchParams.append("base", baseImg.src);
  246. shareURL.searchParams.append("overlay", overlayImg.src);
  247. shareURL.searchParams.append("radius", radius);
  248. shareURL.searchParams.append("softness", softness);
  249. window.history.replaceState(null, "X-Ray Viewer", shareURL);
  250. }