From ca7ba7d39484c1cb09e06dc5fb77bd157b3ed4cf Mon Sep 17 00:00:00 2001 From: Danil Boldyrev Date: Thu, 1 Feb 2024 11:29:06 +0300 Subject: [PATCH 1/6] Fix the startup zoom error --- extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js index df60c1a17..6dc8dabd2 100644 --- a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js +++ b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js @@ -401,7 +401,7 @@ onUiLoaded(async() => { toggleOverlap("off"); fullScreenMode = false; - const closeBtn = targetElement.querySelector("button[aria-label='Remove Image']"); + const closeBtn = targetElement.querySelector("button[aria-label='Clear canvas']"); if (closeBtn) { closeBtn.addEventListener("click", resetZoom); } @@ -479,9 +479,10 @@ onUiLoaded(async() => { // Reset zoom when uploading a new image const fileInput = gradioApp().querySelector( - `${elemId} input[type="file"][accept="image/*"].svelte-116rqfv` + `${elemId} .upload-container input[type="file"][accept="image/*"]` ); fileInput.addEventListener("click", resetZoom); + // Update the zoom level and pan position of the target element based on the values of the zoomLevel, panX and panY variables function updateZoom(newZoomLevel, mouseX, mouseY) { @@ -604,6 +605,8 @@ onUiLoaded(async() => { `${elemId} canvas[key="interface"]` ); + // print(canvas) + if (!canvas) return; if (canvas.offsetWidth > 862 || isExtension) { From 733f8c7c514df6703afc7b89b281ffae2100ac03 Mon Sep 17 00:00:00 2001 From: Danil Boldyrev Date: Thu, 1 Feb 2024 11:46:20 +0300 Subject: [PATCH 2/6] fix fitToScreen and adjustBrushSize funcs in zoom.js --- .../canvas-zoom-and-pan/javascript/zoom.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js index 6dc8dabd2..3b20f1a8f 100644 --- a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js +++ b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js @@ -395,7 +395,7 @@ onUiLoaded(async() => { targetElement.style.transform = `scale(${elemData[elemId].zoomLevel}) translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px)`; const canvas = gradioApp().querySelector( - `${elemId} canvas[key="interface"]` + `${elemId} canvas` ); toggleOverlap("off"); @@ -456,10 +456,10 @@ onUiLoaded(async() => { ) { const input = gradioApp().querySelector( - `${elemId} input[aria-label='Brush radius']` + `${elemId} input[type='range']` ) || gradioApp().querySelector( - `${elemId} button[aria-label="Use brush"]` + `${elemId} button[aria-label="Size button"]` ); if (input) { @@ -602,7 +602,7 @@ onUiLoaded(async() => { // Fullscreen mode function fitToScreen() { const canvas = gradioApp().querySelector( - `${elemId} canvas[key="interface"]` + `${elemId} canvas` ); // print(canvas) @@ -724,7 +724,7 @@ onUiLoaded(async() => { targetElement.isExpanded = false; function autoExpand() { - const canvas = document.querySelector(`${elemId} canvas[key="interface"]`); + const canvas = document.querySelector(`${elemId} canvas`); if (canvas) { if (hasHorizontalScrollbar(targetElement) && targetElement.isExpanded === false) { targetElement.style.visibility = "hidden"; From a08eff391e01be82d611201c4037b48987e45161 Mon Sep 17 00:00:00 2001 From: Danil Boldyrev Date: Thu, 1 Feb 2024 12:13:25 +0300 Subject: [PATCH 3/6] Temporary fix that returns functionality when sending via buttons --- .../canvas-zoom-and-pan/javascript/zoom.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js index 3b20f1a8f..cf4a9ce61 100644 --- a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js +++ b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js @@ -945,6 +945,28 @@ onUiLoaded(async() => { window.applyZoomAndPanIntegration = applyZoomAndPanIntegration; // for any extension + + const img2imgArean = document.querySelector("#img2img_settings") + img2imgArean.addEventListener("mousemove",(e) => { + const tabId = getTabId(elements) + + + // Check for tooltip + if (tabId == "#img2img_sketch" ||tabId == "#inpaint_sketch" || tabId == "#img2maskimg" ) { + const zoomTooltip = document.querySelector(`${tabId} .canvas-tooltip`) + + // If tooltip removed we again add zoom functionality + if(!zoomTooltip) { + console.log("added") + applyZoomAndPan(tabId,false) + } else { + console.log("Not added") + } + + } + + + }) /* The function `applyZoomAndPanIntegration` takes two arguments: From c2ab05889780f02059f33d3c98d16f3735a8971a Mon Sep 17 00:00:00 2001 From: Danil Boldyrev Date: Thu, 1 Feb 2024 15:20:21 +0300 Subject: [PATCH 4/6] Made the zoom functionality work, both for drawing and erasing --- .../canvas-zoom-and-pan/javascript/zoom.js | 156 +++++++++++++++--- 1 file changed, 137 insertions(+), 19 deletions(-) diff --git a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js index cf4a9ce61..3e2875e98 100644 --- a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js +++ b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js @@ -16,6 +16,20 @@ onUiLoaded(async() => { // Helper functions // Get active tab + function debounce(func, wait) { + let timeout; + + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + } + /** * Waits for an element to be present in the DOM. */ @@ -290,6 +304,11 @@ onUiLoaded(async() => { }; let fullScreenMode = false; + // Remove border, cause bags + + const canvasBorder = targetElement.querySelector(".border") + canvasBorder.style.display = "none" + // Create tooltip function createTooltip() { const toolTipElemnt = @@ -854,6 +873,7 @@ onUiLoaded(async() => { elemData[elemId].panY += movementY * panSpeed; // Delayed redraw of an element + const canvas = targetElement.querySelector("canvas") requestAnimationFrame(() => { targetElement.style.transform = `translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px) scale(${elemData[elemId].zoomLevel})`; toggleOverlap("on"); @@ -912,6 +932,105 @@ onUiLoaded(async() => { gradioApp().addEventListener("mousemove", handleMoveByKey); + + // Cursor manipulation script for a painting application. + // The purpose of this code is to create custom cursors (for painting and erasing) + // that can change depending on which button the user presses. + // When the mouse moves over the canvas, the appropriate custom cursor also moves, + // replicating its appearance dynamically based on various CSS properties. + + // This is done because the original cursor is tied to the size of the kanvas, it can not be changed, so I came up with a hack that creates an exact copy that works properly + + function copySpecificStyles(sourceElement, targetElement) { + // List of CSS property names that we want to clone. + const stylesToCopy = ['top', 'left', 'width', 'height',"opacity"]; + + // For each style in our list, copy it from sourceElement to targetElement. + stylesToCopy.forEach(styleName => { + if (sourceElement.style[styleName]) { + targetElement.style[styleName] = sourceElement.style[styleName]; + } + }); + } + + const eraseButton = targetElement.querySelector(`button[aria-label='Erase button']`); + const paintButton = targetElement.querySelector(`button[aria-label='Draw button']`); + + const canvasCursors = targetElement.querySelectorAll("span.svelte-btgkrd"); + const paintCursorCopy = canvasCursors[0].cloneNode(true); + const eraserCursorCopy = canvasCursors[1].cloneNode(true); + + canvasCursors.forEach(cursor => cursor.style.display = "none"); + + targetElement.appendChild(paintCursorCopy); + paintCursorCopy.style.display = "none"; + + targetElement.appendChild(eraserCursorCopy); + eraserCursorCopy.style.display = "none"; + + let activeCursor; + + paintButton.addEventListener('click', () => { + activateTool(paintButton, eraseButton, paintCursorCopy); + }); + + eraseButton.addEventListener('click', () => { + activateTool(eraseButton, paintButton, eraserCursorCopy); + }); + + function activateTool(activeButton, inactiveButton, activeCursorCopy) { + activeButton.classList.add("active"); + inactiveButton.classList.remove("active"); + + if (activeCursor){ + activeCursor.style.display = "none"; + } + + activeCursor = activeCursorCopy; + activeCursor.style.display = "block"; + } + + const canvasAreaEventsHandler = e => { + if (!activeCursor) return; + + const cursorNum = eraseButton.classList.contains("active") ? 1 : 0; + + // Update the styles of the currently active cursor + copySpecificStyles(canvasCursors[cursorNum], activeCursor); + + let offsetXAdjusted = e.offsetX; + let offsetYAdjusted = e.offsetY; + + // Position the cursor based on the current mouse coordinates within target element. + activeCursor.style.transform = + `translate(${offsetXAdjusted}px, ${offsetYAdjusted}px)`; + }; + + const canvasAreaLeaveHandler = () => { + if (activeCursor) { + activeCursor.style.display = "none"; + // Hide the cursor when mouse leaves. + activeCursor.style.opacity = 0; + } + } + + const canvasAreaEnterHandler= () => { + if (activeCursor) { + activeCursor.style.display = "block"; + // Show the cursor when mouse enters. + activeCursor.style.opacity = 1; + } + } + + const canvasArea = targetElement.querySelector("canvas"); + + // Attach event listeners to the target element and canvas area + targetElement.addEventListener("mousemove", canvasAreaEventsHandler); + canvasArea.addEventListener("mouseout", canvasAreaLeaveHandler); + canvasArea.addEventListener("mouseenter", canvasAreaEnterHandler); + + // Additional listener for handling zoom or other transformations which might affect visual representation + targetElement.addEventListener("wheel", canvasAreaEventsHandler); } @@ -946,27 +1065,26 @@ onUiLoaded(async() => { window.applyZoomAndPanIntegration = applyZoomAndPanIntegration; // for any extension - const img2imgArean = document.querySelector("#img2img_settings") - img2imgArean.addEventListener("mousemove",(e) => { - const tabId = getTabId(elements) - - - // Check for tooltip - if (tabId == "#img2img_sketch" ||tabId == "#inpaint_sketch" || tabId == "#img2maskimg" ) { - const zoomTooltip = document.querySelector(`${tabId} .canvas-tooltip`) - - // If tooltip removed we again add zoom functionality - if(!zoomTooltip) { - console.log("added") - applyZoomAndPan(tabId,false) - } else { - console.log("Not added") - } - + const img2imgArea = document.querySelector("#img2img_settings") + const checkForTooltip = (e) => { + const tabId = getTabId(elements); // Make sure that the item is passed correctly to determine the tabId + + if (tabId === "#img2img_sketch" || tabId === "#inpaint_sketch" || tabId === "#img2maskimg") { + const zoomTooltip = document.querySelector(`${tabId} .canvas-tooltip`); + + if (!zoomTooltip) { + applyZoomAndPan(tabId,false); + // resetZoom() + } } + }; + + // Wrapping your function through debounce to reduce the number of calls + const debouncedCheckForTooltip = debounce(checkForTooltip, 20); + + // Assigning an event handler + img2imgArea.addEventListener("mousemove", debouncedCheckForTooltip); - - }) /* The function `applyZoomAndPanIntegration` takes two arguments: From 7eda3319de61525743bc47d56d5b9f43b24017d9 Mon Sep 17 00:00:00 2001 From: Danil Boldyrev Date: Thu, 1 Feb 2024 15:43:01 +0300 Subject: [PATCH 5/6] Remove unused code and lint --- .../canvas-zoom-and-pan/javascript/zoom.js | 386 +++++------------- .../scripts/hotkey_config.py | 1 - 2 files changed, 105 insertions(+), 282 deletions(-) diff --git a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js index 3e2875e98..6ce599659 100644 --- a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js +++ b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js @@ -18,13 +18,13 @@ onUiLoaded(async() => { function debounce(func, wait) { let timeout; - + return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; - + clearTimeout(timeout); timeout = setTimeout(later, wait); }; @@ -179,48 +179,6 @@ onUiLoaded(async() => { return config; } - /** - * The restoreImgRedMask function displays a red mask around an image to indicate the aspect ratio. - * If the image display property is set to 'none', the mask breaks. To fix this, the function - * temporarily sets the display property to 'block' and then hides the mask again after 300 milliseconds - * to avoid breaking the canvas. Additionally, the function adjusts the mask to work correctly on - * very long images. - */ - function restoreImgRedMask(elements) { - const mainTabId = getTabId(elements); - - if (!mainTabId) return; - - const mainTab = gradioApp().querySelector(mainTabId); - const img = mainTab.querySelector("img"); - const imageARPreview = gradioApp().querySelector("#imageARPreview"); - - if (!img || !imageARPreview) return; - - imageARPreview.style.transform = ""; - if (parseFloat(mainTab.style.width) > 865) { - const transformString = mainTab.style.transform; - const scaleMatch = transformString.match( - /scale\(([-+]?[0-9]*\.?[0-9]+)\)/ - ); - let zoom = 1; // default zoom - - if (scaleMatch && scaleMatch[1]) { - zoom = Number(scaleMatch[1]); - } - - imageARPreview.style.transformOrigin = "0 0"; - imageARPreview.style.transform = `scale(${zoom})`; - } - - if (img.style.display !== "none") return; - - img.style.display = "block"; - - setTimeout(() => { - img.style.display = "none"; - }, 400); - } const hotkeysConfigOpts = await waitForOpts(); @@ -236,7 +194,6 @@ onUiLoaded(async() => { canvas_hotkey_grow_brush: "KeyW", canvas_disabled_functions: [], canvas_show_tooltip: true, - canvas_auto_expand: true, canvas_blur_prompt: false, }; @@ -275,18 +232,6 @@ onUiLoaded(async() => { ); const elemData = {}; - // Apply functionality to the range inputs. Restore redmask and correct for long images. - const rangeInputs = elements.rangeGroup ? - Array.from(elements.rangeGroup.querySelectorAll("input")) : - [ - gradioApp().querySelector("#img2img_width input[type='range']"), - gradioApp().querySelector("#img2img_height input[type='range']") - ]; - - for (const input of rangeInputs) { - input?.addEventListener("input", () => restoreImgRedMask(elements)); - } - function applyZoomAndPan(elemId, isExtension = true) { const targetElement = gradioApp().querySelector(elemId); @@ -306,13 +251,12 @@ onUiLoaded(async() => { // Remove border, cause bags - const canvasBorder = targetElement.querySelector(".border") - canvasBorder.style.display = "none" + const canvasBorder = targetElement.querySelector(".border"); + canvasBorder.style.display = "none"; // Create tooltip function createTooltip() { - const toolTipElemnt = - targetElement.querySelector(".image-container"); + const toolTipElemnt = targetElement.querySelector(".image-container"); const tooltip = document.createElement("div"); tooltip.className = "canvas-tooltip"; @@ -375,25 +319,15 @@ onUiLoaded(async() => { // Add a hint element to the target element toolTipElemnt.appendChild(tooltip); + + return tooltip; } //Show tool tip if setting enable - if (hotkeysConfig.canvas_show_tooltip) { - createTooltip(); - } + const canvasTooltip = createTooltip(); - // In the course of research, it was found that the tag img is very harmful when zooming and creates white canvases. This hack allows you to almost never think about this problem, it has no effect on webui. - function fixCanvas() { - const activeTab = getActiveTab(elements).textContent.trim(); - - if (activeTab !== "img2img") { - const img = targetElement.querySelector(`${elemId} img`); - - if (img && img.style.display !== "none") { - img.style.display = "none"; - img.style.visibility = "hidden"; - } - } + if (!hotkeysConfig.canvas_show_tooltip) { + canvasTooltip.style.display = "none"; } // Reset the zoom level and pan position of the target element to their initial values @@ -410,7 +344,6 @@ onUiLoaded(async() => { targetElement.isZoomed = false; - fixCanvas(); targetElement.style.transform = `scale(${elemData[elemId].zoomLevel}) translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px)`; const canvas = gradioApp().querySelector( @@ -425,29 +358,6 @@ onUiLoaded(async() => { closeBtn.addEventListener("click", resetZoom); } - if (canvas && isExtension) { - const parentElement = targetElement.closest('[id^="component-"]'); - if ( - canvas && - parseFloat(canvas.style.width) > parentElement.offsetWidth && - parseFloat(targetElement.style.width) > parentElement.offsetWidth - ) { - fitToElement(); - return; - } - - } - - if ( - canvas && - !isExtension && - parseFloat(canvas.style.width) > 865 && - parseFloat(targetElement.style.width) > 865 - ) { - fitToElement(); - return; - } - targetElement.style.width = ""; } @@ -501,7 +411,7 @@ onUiLoaded(async() => { `${elemId} .upload-container input[type="file"][accept="image/*"]` ); fileInput.addEventListener("click", resetZoom); - + // Update the zoom level and pan position of the target element based on the values of the zoomLevel, panX and panY variables function updateZoom(newZoomLevel, mouseX, mouseY) { @@ -551,67 +461,6 @@ onUiLoaded(async() => { } } - /** - * This function fits the target element to the screen by calculating - * the required scale and offsets. It also updates the global variables - * zoomLevel, panX, and panY to reflect the new state. - */ - - function fitToElement() { - //Reset Zoom - targetElement.style.transform = `translate(${0}px, ${0}px) scale(${1})`; - - let parentElement; - - if (isExtension) { - parentElement = targetElement.closest('[id^="component-"]'); - } else { - parentElement = targetElement.parentElement; - } - - - // Get element and screen dimensions - const elementWidth = targetElement.offsetWidth; - const elementHeight = targetElement.offsetHeight; - - const screenWidth = parentElement.clientWidth; - const screenHeight = parentElement.clientHeight; - - // Get element's coordinates relative to the parent element - const elementRect = targetElement.getBoundingClientRect(); - const parentRect = parentElement.getBoundingClientRect(); - const elementX = elementRect.x - parentRect.x; - - // Calculate scale and offsets - const scaleX = screenWidth / elementWidth; - const scaleY = screenHeight / elementHeight; - const scale = Math.min(scaleX, scaleY); - - const transformOrigin = - window.getComputedStyle(targetElement).transformOrigin; - const [originX, originY] = transformOrigin.split(" "); - const originXValue = parseFloat(originX); - const originYValue = parseFloat(originY); - - const offsetX = - (screenWidth - elementWidth * scale) / 2 - - originXValue * (1 - scale); - const offsetY = - (screenHeight - elementHeight * scale) / 2.5 - - originYValue * (1 - scale); - - // Apply scale and offsets to the element - targetElement.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`; - - // Update global variables - elemData[elemId].zoomLevel = scale; - elemData[elemId].panX = offsetX; - elemData[elemId].panY = offsetY; - - fullScreenMode = false; - toggleOverlap("off"); - } - /** * This function fits the target element to the screen by calculating * the required scale and offsets. It also updates the global variables @@ -759,26 +608,6 @@ onUiLoaded(async() => { targetElement.addEventListener("mousemove", getMousePosition); - //observers - // Creating an observer with a callback function to handle DOM changes - const observer = new MutationObserver((mutationsList, observer) => { - for (let mutation of mutationsList) { - // If the style attribute of the canvas has changed, by observation it happens only when the picture changes - if (mutation.type === 'attributes' && mutation.attributeName === 'style' && - mutation.target.tagName.toLowerCase() === 'canvas') { - targetElement.isExpanded = false; - setTimeout(resetZoom, 10); - } - } - }); - - // Apply auto expand if enabled - if (hotkeysConfig.canvas_auto_expand) { - targetElement.addEventListener("mousemove", autoExpand); - // Set up an observer to track attribute changes - observer.observe(targetElement, {attributes: true, childList: true, subtree: true}); - } - // Handle events only inside the targetElement let isKeyDownHandlerAttached = false; @@ -806,12 +635,6 @@ onUiLoaded(async() => { // Reset zoom when click on another tab elements.img2imgTabs.addEventListener("click", resetZoom); - elements.img2imgTabs.addEventListener("click", () => { - // targetElement.style.width = ""; - if (parseInt(targetElement.style.width) > 865) { - setTimeout(fitToElement, 0); - } - }); targetElement.addEventListener("wheel", e => { // change zoom level @@ -873,7 +696,7 @@ onUiLoaded(async() => { elemData[elemId].panY += movementY * panSpeed; // Delayed redraw of an element - const canvas = targetElement.querySelector("canvas") + const canvas = targetElement.querySelector("canvas"); requestAnimationFrame(() => { targetElement.style.transform = `translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px) scale(${elemData[elemId].zoomLevel})`; toggleOverlap("on"); @@ -932,105 +755,105 @@ onUiLoaded(async() => { gradioApp().addEventListener("mousemove", handleMoveByKey); - - // Cursor manipulation script for a painting application. - // The purpose of this code is to create custom cursors (for painting and erasing) - // that can change depending on which button the user presses. - // When the mouse moves over the canvas, the appropriate custom cursor also moves, - // replicating its appearance dynamically based on various CSS properties. - // This is done because the original cursor is tied to the size of the kanvas, it can not be changed, so I came up with a hack that creates an exact copy that works properly + // Cursor manipulation script for a painting application. + // The purpose of this code is to create custom cursors (for painting and erasing) + // that can change depending on which button the user presses. + // When the mouse moves over the canvas, the appropriate custom cursor also moves, + // replicating its appearance dynamically based on various CSS properties. - function copySpecificStyles(sourceElement, targetElement) { + // This is done because the original cursor is tied to the size of the kanvas, it can not be changed, so I came up with a hack that creates an exact copy that works properly + + function copySpecificStyles(sourceElement, targetElement) { // List of CSS property names that we want to clone. - const stylesToCopy = ['top', 'left', 'width', 'height',"opacity"]; + const stylesToCopy = ['top', 'left', 'width', 'height', "opacity"]; - // For each style in our list, copy it from sourceElement to targetElement. - stylesToCopy.forEach(styleName => { - if (sourceElement.style[styleName]) { - targetElement.style[styleName] = sourceElement.style[styleName]; - } + // For each style in our list, copy it from sourceElement to targetElement. + stylesToCopy.forEach(styleName => { + if (sourceElement.style[styleName]) { + targetElement.style[styleName] = sourceElement.style[styleName]; + } + }); + } + + const eraseButton = targetElement.querySelector(`button[aria-label='Erase button']`); + const paintButton = targetElement.querySelector(`button[aria-label='Draw button']`); + + const canvasCursors = targetElement.querySelectorAll("span.svelte-btgkrd"); + const paintCursorCopy = canvasCursors[0].cloneNode(true); + const eraserCursorCopy = canvasCursors[1].cloneNode(true); + + canvasCursors.forEach(cursor => cursor.style.display = "none"); + + targetElement.appendChild(paintCursorCopy); + paintCursorCopy.style.display = "none"; + + targetElement.appendChild(eraserCursorCopy); + eraserCursorCopy.style.display = "none"; + + let activeCursor; + + paintButton.addEventListener('click', () => { + activateTool(paintButton, eraseButton, paintCursorCopy); }); - } - const eraseButton = targetElement.querySelector(`button[aria-label='Erase button']`); - const paintButton = targetElement.querySelector(`button[aria-label='Draw button']`); + eraseButton.addEventListener('click', () => { + activateTool(eraseButton, paintButton, eraserCursorCopy); + }); - const canvasCursors = targetElement.querySelectorAll("span.svelte-btgkrd"); - const paintCursorCopy = canvasCursors[0].cloneNode(true); - const eraserCursorCopy = canvasCursors[1].cloneNode(true); + function activateTool(activeButton, inactiveButton, activeCursorCopy) { + activeButton.classList.add("active"); + inactiveButton.classList.remove("active"); - canvasCursors.forEach(cursor => cursor.style.display = "none"); + if (activeCursor) { + activeCursor.style.display = "none"; + } - targetElement.appendChild(paintCursorCopy); - paintCursorCopy.style.display = "none"; - - targetElement.appendChild(eraserCursorCopy); - eraserCursorCopy.style.display = "none"; - - let activeCursor; - - paintButton.addEventListener('click', () => { - activateTool(paintButton, eraseButton, paintCursorCopy); - }); - - eraseButton.addEventListener('click', () => { - activateTool(eraseButton, paintButton, eraserCursorCopy); - }); - - function activateTool(activeButton, inactiveButton, activeCursorCopy) { - activeButton.classList.add("active"); - inactiveButton.classList.remove("active"); - - if (activeCursor){ - activeCursor.style.display = "none"; - } - - activeCursor = activeCursorCopy; - activeCursor.style.display = "block"; - } - - const canvasAreaEventsHandler = e => { - if (!activeCursor) return; - - const cursorNum = eraseButton.classList.contains("active") ? 1 : 0; - - // Update the styles of the currently active cursor - copySpecificStyles(canvasCursors[cursorNum], activeCursor); - - let offsetXAdjusted = e.offsetX; - let offsetYAdjusted = e.offsetY; - - // Position the cursor based on the current mouse coordinates within target element. - activeCursor.style.transform = - `translate(${offsetXAdjusted}px, ${offsetYAdjusted}px)`; - }; - - const canvasAreaLeaveHandler = () => { - if (activeCursor) { - activeCursor.style.display = "none"; - // Hide the cursor when mouse leaves. - activeCursor.style.opacity = 0; - } - } - - const canvasAreaEnterHandler= () => { - if (activeCursor) { + activeCursor = activeCursorCopy; activeCursor.style.display = "block"; - // Show the cursor when mouse enters. - activeCursor.style.opacity = 1; } - } - const canvasArea = targetElement.querySelector("canvas"); + const canvasAreaEventsHandler = e => { + if (!activeCursor) return; - // Attach event listeners to the target element and canvas area - targetElement.addEventListener("mousemove", canvasAreaEventsHandler); - canvasArea.addEventListener("mouseout", canvasAreaLeaveHandler); - canvasArea.addEventListener("mouseenter", canvasAreaEnterHandler); + const cursorNum = eraseButton.classList.contains("active") ? 1 : 0; - // Additional listener for handling zoom or other transformations which might affect visual representation - targetElement.addEventListener("wheel", canvasAreaEventsHandler); + // Update the styles of the currently active cursor + copySpecificStyles(canvasCursors[cursorNum], activeCursor); + + let offsetXAdjusted = e.offsetX; + let offsetYAdjusted = e.offsetY; + + // Position the cursor based on the current mouse coordinates within target element. + activeCursor.style.transform = + `translate(${offsetXAdjusted}px, ${offsetYAdjusted}px)`; + }; + + const canvasAreaLeaveHandler = () => { + if (activeCursor) { + activeCursor.style.display = "none"; + // Hide the cursor when mouse leaves. + activeCursor.style.opacity = 0; + } + }; + + const canvasAreaEnterHandler = () => { + if (activeCursor) { + activeCursor.style.display = "block"; + // Show the cursor when mouse enters. + activeCursor.style.opacity = 1; + } + }; + + const canvasArea = targetElement.querySelector("canvas"); + + // Attach event listeners to the target element and canvas area + targetElement.addEventListener("mousemove", canvasAreaEventsHandler); + canvasArea.addEventListener("mouseout", canvasAreaLeaveHandler); + canvasArea.addEventListener("mouseenter", canvasAreaEnterHandler); + + // Additional listener for handling zoom or other transformations which might affect visual representation + targetElement.addEventListener("wheel", canvasAreaEventsHandler); } @@ -1065,23 +888,24 @@ onUiLoaded(async() => { window.applyZoomAndPanIntegration = applyZoomAndPanIntegration; // for any extension - const img2imgArea = document.querySelector("#img2img_settings") + // Return zoom functionality when send img via buttons + const img2imgArea = document.querySelector("#img2img_settings"); const checkForTooltip = (e) => { const tabId = getTabId(elements); // Make sure that the item is passed correctly to determine the tabId - + if (tabId === "#img2img_sketch" || tabId === "#inpaint_sketch" || tabId === "#img2maskimg") { const zoomTooltip = document.querySelector(`${tabId} .canvas-tooltip`); - + if (!zoomTooltip) { - applyZoomAndPan(tabId,false); + applyZoomAndPan(tabId, false); // resetZoom() - } + } } }; - + // Wrapping your function through debounce to reduce the number of calls const debouncedCheckForTooltip = debounce(checkForTooltip, 20); - + // Assigning an event handler img2imgArea.addEventListener("mousemove", debouncedCheckForTooltip); diff --git a/extensions-builtin/canvas-zoom-and-pan/scripts/hotkey_config.py b/extensions-builtin/canvas-zoom-and-pan/scripts/hotkey_config.py index 89b7c31f2..3cef1df24 100644 --- a/extensions-builtin/canvas-zoom-and-pan/scripts/hotkey_config.py +++ b/extensions-builtin/canvas-zoom-and-pan/scripts/hotkey_config.py @@ -11,7 +11,6 @@ shared.options_templates.update(shared.options_section(('canvas_hotkey', "Canvas "canvas_hotkey_reset": shared.OptionInfo("R", "Reset zoom and canvas positon"), "canvas_hotkey_overlap": shared.OptionInfo("O", "Toggle overlap").info("Technical button, neededs for testing"), "canvas_show_tooltip": shared.OptionInfo(True, "Enable tooltip on the canvas"), - "canvas_auto_expand": shared.OptionInfo(True, "Automatically expands an image that does not fit completely in the canvas area, similar to manually pressing the S and R buttons"), "canvas_blur_prompt": shared.OptionInfo(False, "Take the focus off the prompt when working with a canvas"), "canvas_disabled_functions": shared.OptionInfo(["Overlap"], "Disable function that you don't use", gr.CheckboxGroup, {"choices": ["Zoom","Adjust brush size","Hotkey enlarge brush","Hotkey shrink brush","Moving canvas","Fullscreen","Reset Zoom","Overlap"]}), })) From b389727e31389cdde2f6467d544a0e1d4fa3a2b6 Mon Sep 17 00:00:00 2001 From: Danil Boldyrev Date: Thu, 1 Feb 2024 16:00:23 +0300 Subject: [PATCH 6/6] place the cursor next to the original --- .../canvas-zoom-and-pan/javascript/zoom.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js index 6ce599659..b7b03ceae 100644 --- a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js +++ b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js @@ -785,10 +785,14 @@ onUiLoaded(async() => { canvasCursors.forEach(cursor => cursor.style.display = "none"); - targetElement.appendChild(paintCursorCopy); + canvasCursors[0].parentNode.insertBefore(paintCursorCopy, canvasCursors[0].nextSibling); + canvasCursors[1].parentNode.insertBefore(eraserCursorCopy, canvasCursors[1].nextSibling); + + + // targetElement.appendChild(paintCursorCopy); paintCursorCopy.style.display = "none"; - targetElement.appendChild(eraserCursorCopy); + // targetElement.appendChild(eraserCursorCopy); eraserCursorCopy.style.display = "none"; let activeCursor; @@ -805,6 +809,8 @@ onUiLoaded(async() => { activeButton.classList.add("active"); inactiveButton.classList.remove("active"); + // canvasCursors.forEach(cursor => cursor.style.display = "none"); + if (activeCursor) { activeCursor.style.display = "none"; }