From 0245f85c2c0bf38faf721f67b44d043e52f6b433 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sun, 18 Jun 2023 19:08:16 +0100 Subject: [PATCH] Add scaling to image feed --- README.md | 1 + js/imageFeed.js | 230 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 168 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 3553c01..6e6831d 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ Moved to: https://github.com/pythongosssss/ComfyUI-WD14-Tagger - ✨ Add Constrain Image node for resizing nodes to a min/max resolution with optional cropping - ✨ Add Show Image On Menu to include the latest image output on the menu - ✨ Add KSamplerAdvanced simple denoise prompt for configuring the node using steps + denoise +- 🎨 Add sizing options to Image Feed ### Other - ♻️ Include [canvas2svg](https://gliffy.github.io/canvas2svg/) for SVG export in assets to prevent downloading at runtime diff --git a/js/imageFeed.js b/js/imageFeed.js index bacd602..dc6345f 100644 --- a/js/imageFeed.js +++ b/js/imageFeed.js @@ -1,66 +1,170 @@ import { api } from "/scripts/api.js"; import { app } from "/scripts/app.js"; +import { $el } from "/scripts/ui.js"; // Adds a list of images that are generated to the bottom of the page +$el("style", { + textContent: ` + .pysssss-image-feed { + min-height: 30px; + max-height: var(--max-height, 200px); + width: 100vw; + position: absolute; + bottom: 0; + background: #333; + overflow: auto; + z-index: 999; + font-family: sans-serif; + font-size: 12px; + } + .pysssss-image-feed-menu { + position: sticky; + top: 0; + height: 0px; + display: flex; + gap: 5px; + padding: 5px 5px 0 5px; + } + .pysssss-image-feed-btn { + cursor: pointer; + } + .pysssss-image-feed-menu section { + border-radius: 5px; + background: rgba(0,0,0,0.6); + padding: 0 5px; + display: flex; + gap: 5px; + align-items: center; + } + .pysssss-image-feed-menu section * { + display: none; + } + .pysssss-image-feed-menu section:hover * { + display: initial; + } + .pysssss-image-feed-menu > * { + min-height: 24px; + } + .pysssss-image-feed-list { + display: grid; + align-items: center; + justify-content: center; + grid-template-columns: repeat( auto-fit, minmax(var(--img-sz), 1fr) ); + } + .pysssss-image-feed-list div { + text-align: center; + } + .pysssss-image-feed-list img { + object-fit: var(--img-fit, contain); + max-width: 100%; + max-height: var(--max-height); + } + .pysssss-image-feed-list img:hover { + filter: brightness(1.2); + }`, + parent: document.body, +}); + app.registerExtension({ name: "pysssss.ImageFeed", setup() { - const imageList = document.createElement("div"); - Object.assign(imageList.style, { - minHeight: "30px", - maxHeight: "300px", - width: "100vw", - position: "absolute", - bottom: 0, - background: "#333", - overflow: "auto", - zIndex: 99 - }); - document.body.append(imageList); - - function makeButton(text, style) { - const btn = document.createElement("button"); - btn.type = "button"; - btn.textContent = text; - Object.assign(btn.style, { - ...style, - height: "20px", + const showButton = $el("button.comfy-settings-btn", { + textContent: "🖼️", + style: { + right: "16px", cursor: "pointer", - position: "absolute", - top: "5px", - fontSize: "12px", - lineHeight: "12px", - }); - imageList.append(btn); - return btn; - } - - const showButton = document.createElement("button"); - const closeButton = makeButton("❌", { - width: "20px", - textIndent: "-4px", - right: "5px", + display: "none", + }, }); - closeButton.onclick = () => { - imageList.style.display = "none"; - showButton.style.display = "unset"; + + const getVal = (n, d) => { + const v = localStorage.getItem("pysssss.ImageFeed." + n); + if (v && !isNaN(+v)) { + return v; + } + return d; }; - const clearButton = makeButton("Clear", { - right: "30px", - }); - clearButton.onclick = () => { - imageList.replaceChildren(closeButton, clearButton); + const saveVal = (n, v) => { + localStorage.setItem("pysssss.ImageFeed." + n, v); }; - showButton.classList.add("comfy-settings-btn"); - showButton.style.right = "16px"; - showButton.style.cursor = "pointer"; - showButton.style.display = "none"; - showButton.textContent = "🖼️"; + const imageFeed = $el("div.pysssss-image-feed", { + parent: document.body, + }); + const imageList = $el("div.pysssss-image-feed-list"); + imageFeed.append( + $el("div.pysssss-image-feed-menu", [ + $el( + "section", + { + textContent: "Feed Size...", + }, + [ + $el("input", { + type: "range", + style: { width: "100px" }, + min: 10, + max: 80, + oninput: (e) => { + e.target.parentElement.title = `Controls the maximum height of the image feed panel (${e.target.value}vh)`; + imageFeed.style.setProperty("--max-height", e.target.value + "vh"); + saveVal("FeedSize", e.target.value); + }, + $: (el) => { + requestAnimationFrame(() => { + el.value = getVal("FeedSize", 25); + el.oninput({ target: el }); + }); + }, + }), + ] + ), + $el( + "section", + { + textContent: "Image Size...", + style: { + marginRight: "auto", + }, + }, + [ + $el("input", { + type: "range", + style: { width: "100px" }, + min: 5, + max: 100, + oninput: (e) => { + e.target.parentElement.title = `Controls the maximum size images in the feed (${e.target.value}vw)`; + imageFeed.style.setProperty("--img-sz", e.target.value + "vw"); + saveVal("ImageSize", e.target.value); + }, + $: (el) => { + requestAnimationFrame(() => { + el.value = getVal("ImageSize", 25); + el.oninput({ target: el }); + }); + }, + }), + ] + ), + $el("button.pysssss-image-feed-btn", { + textContent: "Clear", + onclick: () => imageList.replaceChildren(), + }), + $el("button.pysssss-image-feed-btn", { + textContent: "❌", + onclick: () => { + imageFeed.style.display = "none"; + showButton.style.display = "unset"; + }, + }), + ]), + imageList + ); showButton.onclick = () => { - imageList.style.display = "block"; + imageFeed.style.display = "block"; showButton.style.display = "none"; }; document.querySelector(".comfy-settings-btn").after(showButton); @@ -68,21 +172,21 @@ app.registerExtension({ api.addEventListener("executed", ({ detail }) => { if (detail?.output?.images) { for (const src of detail.output.images) { - const img = document.createElement("img"); - const a = document.createElement("a"); - a.href = `/view?filename=${encodeURIComponent(src.filename)}&type=${src.type}&subfolder=${encodeURIComponent( - src.subfolder - )}&t=${+new Date()}`; - a.target = "_blank"; - Object.assign(img.style, { - height: "120px", - width: "120px", - objectFit: "cover", - }); - - img.src = a.href; - a.append(img); - imageList.prepend(a); + const href = `/view?filename=${encodeURIComponent(src.filename)}&type=${ + src.type + }&subfolder=${encodeURIComponent(src.subfolder)}&t=${+new Date()}`; + imageList.prepend( + $el("div", [ + $el( + "a", + { + target: "_blank", + href, + }, + [$el("img", { src: href })] + ), + ]) + ); } } });