|
- "use strict";
-
- let overlayLoaded = false;
- let baseLoaded = false;
-
- let running = false;
-
- let radius = 200;
- let softness = 0;
- let darkness = 0;
- let opacity = 100;
-
- let width;
- let height;
-
- let border = true;
- let fitScreen = true;
- let paintMode = false;
- let offsetMode = false;
- let shadow = true;
-
- let firstTime = true;
-
- let scale;
-
- document.addEventListener("DOMContentLoaded", e => {
- document.querySelector("#reset-button").addEventListener("click", reset);
-
- document.querySelector("#show-toolbar").addEventListener("click", e => {
- document.querySelector("#menu").classList.remove("hidden")
- document.querySelector("#show-toolbar").classList.add("hidden")
- setup();
- })
- document.querySelector("#hide-toolbar").addEventListener("click", e => {
- document.querySelector("#menu").classList.add("hidden")
- document.querySelector("#show-toolbar").classList.remove("hidden")
- setup();
- })
- document.querySelector("#show-toolbar").classList.add("hidden")
-
- document.querySelector("#load-button").addEventListener("click", e => {
- console.log("Trying to load...");
- const baseInput = document.querySelector("#base-url").value;
- const overlayInput = document.querySelector("#overlay-url").value;
-
- let success = true;
-
- try {
- let baseURL = new URL(baseInput)
- console.log(baseURL);
- } catch {
- document.querySelector("#base-url").value = "";
- document.querySelector("#base-url").placeholder = "Invalid URL...";
- success = false;
- }
- try {
- let overlayURL = new URL(overlayInput)
- console.log(overlayURL);
- } catch {
- document.querySelector("#overlay-url").value = "";
- document.querySelector("#overlay-url").placeholder = "Invalid URL...";
- success = false;
- }
-
- if (!success) {
- return;
- }
-
- const artistLink = document.querySelector("#artist");
-
- let artistURL = document.querySelector("#artist-url").value;
-
- if (artistURL) {
- artistLink.href = artistURL;
- artistLink.style.removeProperty("display");
- } else {
- artistLink.style.display = "none";
- }
-
- const overlayImg = document.querySelector("#overlay-img");
- const baseImg = document.querySelector("#base-img");
-
- overlayImg.src = overlayInput;
- baseImg.src = baseInput;
- setURL();
-
- load();
-
- try {
- localStorage.setItem("base", baseInput);
- localStorage.setItem("overlay", overlayInput);
- } catch {
- console.error("Couldn't set something in local storage :(")
- }
- });
-
- let url = new URL(window.location);
-
-
- const overlay = document.querySelector("#overlay");
-
- document.addEventListener("mousedown", e => {
- let x = e.clientX - overlay.getBoundingClientRect().x;
- let y = e.clientY - overlay.getBoundingClientRect().y;
- updateOverlay([[x,y]], e.buttons % 2 != 0);
- });
-
- document.addEventListener("mousemove", e => {
- let x = e.clientX - overlay.getBoundingClientRect().x;
- let y = e.clientY - overlay.getBoundingClientRect().y;
- updateOverlay([[x,y]], e.buttons % 2 != 0);
- });
-
- document.addEventListener("touchstart", e => {
- let offsetX = overlay.getBoundingClientRect().x;
- let offsetY = overlay.getBoundingClientRect().y;
-
- let touches = [];
-
- for (let i=0; i < e.touches.length; i++) {
- let x = e.touches[i].clientX - offsetX;
- let y = e.touches[i].clientY - offsetY;
- touches.push([x,y]);
- }
- updateOverlay(touches, true);
- });
-
- document.addEventListener("touchmove", e => {
- let offsetX = overlay.getBoundingClientRect().x;
- let offsetY = overlay.getBoundingClientRect().y;
-
- let touches = [];
-
- for (let i=0; i < e.touches.length; i++) {
- let x = e.touches[i].clientX - offsetX;
- let y = e.touches[i].clientY - offsetY;
- touches.push([x,y]);
- }
- updateOverlay(touches, true);
- });
-
- document.querySelector("#radius-slider").addEventListener("input", e => {
- try {
- radius = parseInt(e.target.value);
- document.querySelector("#radius-input").value = radius;
- } catch {
- console.warn("That wasn't a valid radius: " + e.target.value);
- }
- });
-
- document.querySelector("#radius-slider").addEventListener("change", e => {
- try {
- radius = parseInt(e.target.value);
- document.querySelector("#radius-input").value = radius;
- } catch {
- console.warn("That wasn't a valid radius: " + e.target.value);
- }
- setURL();
- });
-
- document.querySelector("#radius-input").addEventListener("input", e => {
- try {
- radius = parseInt(e.target.value);
- document.querySelector("#radius-slider").value = radius;
- } catch {
- console.warn("That wasn't a valid radius: " + e.target.value);
- }
- });
-
- document.querySelector("#radius-input").addEventListener("change", e => {
- try {
- radius = parseInt(e.target.value);
- document.querySelector("#radius-slider").value = radius;
- } catch {
- console.warn("That wasn't a valid radius: " + e.target.value);
- }
- setURL();
- });
-
- document.querySelector("#softness-slider").addEventListener("input", e => {
- try {
- softness = parseInt(e.target.value);
- document.querySelector("#softness-input").value = softness;
- } catch {
- console.warn("That wasn't a valid softness: " + e.target.value);
- }
- });
-
- document.querySelector("#softness-slider").addEventListener("change", e => {
- try {
- softness = parseInt(e.target.value);
- document.querySelector("#softness-input").value = softness;
- } catch {
- console.warn("That wasn't a valid softness: " + e.target.value);
- }
- setURL();
- });
-
- document.querySelector("#softness-input").addEventListener("input", e => {
- try {
- softness = parseInt(e.target.value);
- document.querySelector("#softness-slider").value = softness;
- } catch {
- console.warn("That wasn't a valid softness: " + e.target.value);
- }
- });
-
- document.querySelector("#softness-input").addEventListener("change", e => {
- try {
- softness = parseInt(e.target.value);
- document.querySelector("#softness-slider").value = softness;
- } catch {
- console.warn("That wasn't a valid softness: " + e.target.value);
- }
- setURL();
- });
-
- document.querySelector("#darkness-slider").addEventListener("input", e => {
- try {
- darkness = parseInt(e.target.value);
- document.querySelector("#darkness-input").value = darkness;
- document.querySelector("#shadow").style.setProperty("--opacity", darkness / 100);
- } catch {
- console.warn("That wasn't a valid darkness: " + e.target.value);
- }
- });
-
- document.querySelector("#darkness-slider").addEventListener("change", e => {
- try {
- darkness = parseInt(e.target.value);
- document.querySelector("#darkness-input").value = darkness;
- document.querySelector("#shadow").style.setProperty("--opacity", darkness / 100);
- } catch {
- console.warn("That wasn't a valid darkness: " + e.target.value);
- }
- setURL();
- });
-
- document.querySelector("#darkness-input").addEventListener("input", e => {
- try {
- darkness = parseInt(e.target.value);
- document.querySelector("#darkness-slider").value = darkness;
- document.querySelector("#shadow").style.setProperty("--opacity", darkness / 100);
- } catch {
- console.warn("That wasn't a valid darkness: " + e.target.value);
- }
- });
-
- document.querySelector("#darkness-input").addEventListener("change", e => {
- try {
- darkness = parseInt(e.target.value);
- document.querySelector("#darkness-slider").value = darkness;
- document.querySelector("#shadow").style.setProperty("--opacity", darkness / 100);
- } catch {
- console.warn("That wasn't a valid darkness: " + e.target.value);
- }
- setURL();
- });
-
- document.querySelector("#opacity-slider").addEventListener("input", e => {
- try {
- opacity = parseInt(e.target.value);
- document.querySelector("#opacity-input").value = opacity;
- document.querySelector("#overlay").style.setProperty("--opacity", opacity / 100);
- } catch {
- console.warn("That wasn't a valid opacity: " + e.target.value);
- }
- });
-
- document.querySelector("#opacity-slider").addEventListener("change", e => {
- try {
- opacity = parseInt(e.target.value);
- document.querySelector("#opacity-input").value = opacity;
- document.querySelector("#overlay").style.setProperty("--opacity", opacity / 100);
- } catch {
- console.warn("That wasn't a valid opacity: " + e.target.value);
- }
- setURL();
- });
-
- document.querySelector("#opacity-input").addEventListener("input", e => {
- try {
- opacity = parseInt(e.target.value);
- document.querySelector("#opacity-slider").value = opacity;
- document.querySelector("#overlay").style.setProperty("--opacity", opacity / 100);
- } catch {
- console.warn("That wasn't a valid opacity: " + e.target.value);
- }
- });
-
- document.querySelector("#opacity-input").addEventListener("change", e => {
- try {
- opacity = parseInt(e.target.value);
- document.querySelector("#opacity-slider").value = opacity;
- document.querySelector("#overlay").style.setProperty("--opacity", opacity / 100);
- } catch {
- console.warn("That wasn't a valid opacity: " + e.target.value);
- }
- setURL();
- });
-
- // see if we have params already; if so, use them!
-
- const overlayImg = document.querySelector("#overlay-img");
- const baseImg = document.querySelector("#base-img");
- const baseInput = document.querySelector("#base-url");
- const overlayInput = document.querySelector("#overlay-url");
-
- const artistInput = document.querySelector("#artist-url");
- const artistLink = document.querySelector("#artist");
-
- if (url.searchParams.has("base") && url.searchParams.has("overlay")) {
- let baseURL = url.searchParams.get("base");
- let overlayURL = url.searchParams.get("overlay");
- let artistURL = null;
-
- if (url.searchParams.has("artist")) {
- artistURL = url.searchParams.get("artist");
- }
-
- baseImg.src = baseURL;
- overlayImg.src = overlayURL;
-
- baseInput.value = baseURL;
- overlayInput.value = overlayURL;
-
- if (artistURL) {
- artistLink.href = artistURL;
- artistInput.value = artistURL;
- artistLink.style.removeProperty("display");
- } else {
- artistLink.style.display = "none";
- }
-
- firstTime = false;
-
- if (url.searchParams.has("radius")) {
- try {
- radius = parseInt(url.searchParams.get("radius"));
- document.querySelector("#radius-slider").value = radius;
- document.querySelector("#radius-input").value = radius;
- } catch {
- console.warn("That was a bogus radius...");
- }
- }
- if (url.searchParams.has("softness")) {
- try {
- softness = parseInt(url.searchParams.get("softness"));
- document.querySelector("#softness-slider").value = softness;
- document.querySelector("#softness-input").value = softness;
- } catch {
- console.warn("That was a bogus softness...");
- }
- }
- if (url.searchParams.has("darkness")) {
- try {
- darkness = parseInt(url.searchParams.get("darkness"));
- document.querySelector("#darkness-slider").value = darkness;
- document.querySelector("#darkness-input").value = darkness;
- document.querySelector("#shadow").style.setProperty("--opacity", darkness / 100);
- } catch {
- console.warn("That was a bogus darkness...");
- }
- }
- if (url.searchParams.has("opacity")) {
- try {
- opacity = parseInt(url.searchParams.get("opacity"));
- document.querySelector("#opacity-slider").value = opacity;
- document.querySelector("#opacity-input").value = opacity;
- document.querySelector("#overlay").style.setProperty("--opacity", opacity / 100);
- } catch {
- console.warn("That was a bogus opacity...");
- }
- }
-
- if (url.searchParams.has("border")) {
- try {
- border = 1 == parseInt(url.searchParams.get("border"));
- } catch {
-
- }
- } else {
- border = false;
- }
-
-
-
- document.querySelector("#menu").classList.add("hidden")
- document.querySelector("#show-toolbar").classList.remove("hidden")
- load();
- } else {
-
- try {
- baseInput.value = localStorage.getItem("base");
- overlayInput.value = localStorage.getItem("overlay");
- } catch {
- console.error("Couldn't get something from local storage :(")
- }
- }
-
-
- document.querySelector("#show-border").checked = border;
-
- window.addEventListener("resize", e => {
- if (running) {
- setup();
- }
- })
-
- document.querySelector("#fullscreen-button").addEventListener("click", function toggleFullScreen() {
- var doc = window.document;
- var docEl = doc.documentElement;
-
- var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen;
- var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen;
-
- if (!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) {
- requestFullScreen.call(docEl);
- }
- else {
- cancelFullScreen.call(doc);
- }
- });
-
- document.querySelector("#show-border").addEventListener("change", e => {
- border = e.target.checked;
- setURL();
- });
-
- document.querySelector("#paint-mode").addEventListener("change", e => {
- paintMode = e.target.checked;
- });
-
- document.querySelector("#offset-mode").addEventListener("change", e => {
- offsetMode = e.target.checked;
- });
-
- document.querySelector("#fit-screen").addEventListener("change", e => {
- fitScreen = e.target.checked;
- setup();
- });
- });
-
- function load() {
- document.querySelector("#menu").classList.remove("start");
- const overlayImg = document.querySelector("#overlay-img");
- const baseImg = document.querySelector("#base-img");
-
- overlayImg.addEventListener("load", function overlayLoad() {
- console.log("The overlay is loaded");
- overlayLoaded = true;
-
- if (overlayLoaded && baseLoaded) {
- setup();
- }
-
- overlayImg.removeEventListener("load", overlayLoad);
- })
- baseImg.addEventListener("load", function baseLoad() {
- console.log("The base is loaded");
- baseLoaded = true;
-
- if (overlayLoaded && baseLoaded) {
- setup();
- }
-
- baseImg.removeEventListener("load", baseLoad);
- })
- }
-
- function reset() {
- running = false;
- baseLoaded = false;
- overlayLoaded = false;
- const overlay = document.querySelector("#overlay");
- const base = document.querySelector("#base");
- const overlayResized = document.querySelector("#overlay-resized");
- const baseResized = document.querySelector("#base-resized");
-
- document.querySelector("#menu").classList.add("start");
-
- overlay.classList.add("hidden");
- base.classList.add("hidden");
-
- }
-
- function setup() {
- running = true;
-
- const overlay = document.querySelector("#overlay");
- const base = document.querySelector("#base");
-
- const overlayResized = document.querySelector("#overlay-resized");
- const baseResized = document.querySelector("#base-resized");
-
- const shadow = document.querySelector("#shadow");
-
- overlay.classList.remove("hidden");
- shadow.classList.remove("hidden");
- base.classList.remove("hidden");
-
- const overlayImg = document.querySelector("#overlay-img");
- const baseImg = document.querySelector("#base-img");
-
- /** @type {CanvasRenderingContext2D} */
- const overlayCtx = overlay.getContext("2d");
- /** @type {CanvasRenderingContext2D} */
- const baseCtx = base.getContext("2d");
- /** @type {CanvasRenderingContext2D} */
- const shadowCtx = shadow.getContext("2d");
- /** @type {CanvasRenderingContext2D} */
- const overlayCtxResized = overlayResized.getContext("2d");
- /** @type {CanvasRenderingContext2D} */
- const baseCtxResized = baseResized.getContext("2d");
-
- const availableWidth = document.querySelector("#fill-div").getBoundingClientRect().width;
- const availableHeight = document.querySelector("#fill-div").getBoundingClientRect().height;
-
- const scaleW = availableWidth / baseImg.width;
- const scaleH = availableHeight / baseImg.height;
- scale = fitScreen ? Math.min(scaleW, scaleH) : 1;
-
- width = fitScreen ? Math.floor(availableWidth * scale / scaleW) : baseImg.width;
- height = fitScreen ? Math.floor(availableHeight * scale / scaleH) : baseImg.height;
- const pixelScale = window.devicePixelRatio;
-
- [baseCtx, baseCtxResized, overlayCtx, overlayCtxResized, shadowCtx].forEach(ctx => {
- ctx.canvas.style.width = width + "px";
- ctx.canvas.style.height = height + "px";
- ctx.canvas.width = width;
- ctx.canvas.height = height;
- ctx.canvas.style.left = (availableWidth - width) / 2 + "px";
- ctx.canvas.style.top = fitScreen ? (availableHeight - height) / 2 + "px" : 0;
- ctx.canvas.width = Math.floor(width * pixelScale);
- ctx.canvas.height = Math.floor(height * pixelScale);
- ctx.scale(pixelScale, pixelScale);
- });
-
- baseCtxResized.drawImage(baseImg, 0, 0, width, height);
- baseCtx.drawImage(baseResized, 0, 0, width, height);
-
- overlayCtxResized.drawImage(overlayImg, 0, 0, width, height);
-
- shadowCtx.fillStyle = "black";
- shadowCtx.fillRect(0, 0, width, height);
-
-
- // if we're starting fresh, set the radius value to be a fraction of the image size
-
- if (firstTime) {
- radius = Math.floor((baseImg.width + baseImg.height) / 10);
- document.querySelector("#radius-input").value = radius;
- document.querySelector("#radius-slider").value = radius;
- firstTime = false;
- }
- // also set up the input ranges
-
- document.querySelector("#radius-input").max = Math.max(baseImg.width, baseImg.height);
- document.querySelector("#radius-slider").max = Math.max(baseImg.width, baseImg.height);
-
- setURL();
-
- console.log("Done");
- }
-
- function ease(t, k) {
- return 1 - Math.pow(2, -k * (1 - t));
- }
-
- function updateOverlay(points, clicked) {
-
- if (!running) {
- return;
- }
-
- const overlay = document.querySelector("#overlay");
- const overlayResized = document.querySelector("#overlay-resized");
-
- /** @type {CanvasRenderingContext2D} */
- const overlayCtx = overlay.getContext("2d");
-
- const w = overlayCtx.canvas.width;
- const h = overlayCtx.canvas.height;
-
-
- overlayCtx.save();
-
- overlayCtx.globalCompositeOperation = "source-over";
-
- if (!paintMode)
- overlayCtx.clearRect(0, 0, w / window.devicePixelRatio, h / window.devicePixelRatio);
-
- if (!paintMode || clicked) {
- points.forEach(point => {
- let [x,y] = point;
-
- if (offsetMode) {
- y -= radius * scale * 1.2;
- }
-
- overlayCtx.beginPath();
- overlayCtx.ellipse(x, y, radius * scale, radius * scale, 0, 0, 2 * Math.PI);
-
- const gradient = overlayCtx.createRadialGradient(x, y, 0, x, y, Math.floor(radius * scale));
-
- const maxOpacity = ease(0, 1 / (0.00001 + softness / 100));
-
- const steps = 20;
- for (let t=0 ; t <= steps; t+= 1) {
- let eased = ease(t/steps, 1 / (0.00001 + softness / 100)) / maxOpacity;
- gradient.addColorStop(t/steps, `rgba(0, 0, 0, ${eased}`);
- }
-
- let eased = ease(0.999, 1 / (0.00001 + softness / 100)) / maxOpacity;
- gradient.addColorStop(0.999, `rgba(0, 0, 0, ${eased}`);
- overlayCtx.fillStyle = gradient;
-
- overlayCtx.fill();
- })
- }
-
-
-
- overlayCtx.globalCompositeOperation = "source-in";
-
- // the resized canvas was already scaled up, so we have to compensate here
-
- overlayCtx.drawImage(overlayResized, 0, 0, w/window.devicePixelRatio, h/window.devicePixelRatio);
-
-
- overlayCtx.globalCompositeOperation = "source-over";
-
-
- if (!paintMode && border) {
- points.forEach(point => {
- let [x, y] = point;
-
- if (offsetMode) {
- y -= radius * scale * 1.2;
- }
-
- overlayCtx.strokeStyle = "#000";
- overlayCtx.lineWidth = 3;
- overlayCtx.beginPath();
- overlayCtx.ellipse(x, y, radius * scale, radius * scale, 0, 0, 2 * Math.PI);
- overlayCtx.stroke();
- });
- }
-
- overlayCtx.restore();
- }
-
- function setURL() {
- let shareURL = new URL(window.location);
-
- // for some reason, the parser gets confused by urlencoded urls...
- // so, to get rid of all parameters, we do this
-
- let keys = Array.from(shareURL.searchParams.keys());
- do {
- keys = Array.from(shareURL.searchParams.keys());
- keys.forEach(key => {
- shareURL.searchParams.delete(key);
- });
- } while (keys.length > 0)
- const artistLink = document.querySelector("#artist");
- const overlayImg = document.querySelector("#overlay-img");
- const baseImg = document.querySelector("#base-img");
-
- shareURL.searchParams.append("base", baseImg.src);
- shareURL.searchParams.append("overlay", overlayImg.src);
-
- if (artistLink.href) {
- shareURL.searchParams.append("artist", artistLink.href);
- }
-
- shareURL.searchParams.append("radius", radius);
- shareURL.searchParams.append("softness", softness);
- shareURL.searchParams.append("darkness", darkness);
- shareURL.searchParams.append("opacity", opacity);
-
- if (border) {
- shareURL.searchParams.append("border", 1);
- }
-
- window.history.replaceState(null, "X-Ray Viewer", shareURL);
- }
|