mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-08 16:24:59 +00:00
Fix graph scrolling bug from #1021
And replicate those changes to the Svelte version.
This commit is contained in:
parent
2cf4ee0fab
commit
8fe8896c4a
4 changed files with 86 additions and 62 deletions
|
@ -175,11 +175,21 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function scroll(e: WheelEvent) {
|
function scroll(e: WheelEvent) {
|
||||||
const scrollX = e.deltaX;
|
const [scrollX, scrollY] = [e.deltaX, e.deltaY];
|
||||||
const scrollY = e.deltaY;
|
|
||||||
|
// If zoom with scroll is enabled: horizontal pan with Ctrl, vertical pan with Shift
|
||||||
|
const zoomWithScroll = $nodeGraph.zoomWithScroll;
|
||||||
|
const zoom = zoomWithScroll ? !e.ctrlKey && !e.shiftKey : e.ctrlKey;
|
||||||
|
const horizontalPan = zoomWithScroll ? e.ctrlKey : !e.ctrlKey && e.shiftKey;
|
||||||
|
|
||||||
|
// Prevent the web page from being zoomed
|
||||||
|
if (e.ctrlKey) e.preventDefault();
|
||||||
|
|
||||||
|
// Always pan horizontally in response to a horizontal scroll wheel movement
|
||||||
|
transform.x -= scrollX / transform.scale;
|
||||||
|
|
||||||
// Zoom
|
// Zoom
|
||||||
if (e.ctrlKey) {
|
if (zoom) {
|
||||||
let zoomFactor = 1 + Math.abs(scrollY) * WHEEL_RATE;
|
let zoomFactor = 1 + Math.abs(scrollY) * WHEEL_RATE;
|
||||||
if (scrollY > 0) zoomFactor = 1 / zoomFactor;
|
if (scrollY > 0) zoomFactor = 1 / zoomFactor;
|
||||||
|
|
||||||
|
@ -199,15 +209,14 @@
|
||||||
transform.x -= (deltaX / transform.scale) * zoomFactor;
|
transform.x -= (deltaX / transform.scale) * zoomFactor;
|
||||||
transform.y -= (deltaY / transform.scale) * zoomFactor;
|
transform.y -= (deltaY / transform.scale) * zoomFactor;
|
||||||
|
|
||||||
// Prevent actually zooming into the page when pinch-zooming on laptop trackpads
|
return;
|
||||||
e.preventDefault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pan
|
// Pan
|
||||||
else if (!e.shiftKey) {
|
if (horizontalPan) {
|
||||||
transform.x -= scrollX / transform.scale;
|
|
||||||
transform.y -= scrollY / transform.scale;
|
|
||||||
} else {
|
|
||||||
transform.x -= scrollY / transform.scale;
|
transform.x -= scrollY / transform.scale;
|
||||||
|
} else {
|
||||||
|
transform.y -= scrollY / transform.scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,13 +227,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move the event listener from the graph to the window so dragging outside the graph area (or even the browser window) works
|
// TODO: Move the event listener from the graph to the window so dragging outside the graph area (or even the whole browser window) works
|
||||||
function pointerDown(e: PointerEvent) {
|
function pointerDown(e: PointerEvent) {
|
||||||
// Exit the add node popup by clicking elsewhere in the graph
|
const [lmb, rmb] = [e.button === 0, e.button === 2];
|
||||||
if (nodeListLocation && !(e.target as HTMLElement).closest("[data-node-list]")) nodeListLocation = undefined;
|
|
||||||
|
|
||||||
// Handle the add node popup on right click
|
const port = (e.target as HTMLDivElement).closest("[data-port]") as HTMLDivElement;
|
||||||
if (e.button === 2) {
|
const node = (e.target as HTMLElement).closest("[data-node]") as HTMLElement | undefined;
|
||||||
|
const nodeId = node?.getAttribute("data-node") || undefined;
|
||||||
|
const nodeList = (e.target as HTMLElement).closest("[data-node-list]") as HTMLElement | undefined;
|
||||||
|
|
||||||
|
// Create the add node popup on right click, then exit
|
||||||
|
if (rmb) {
|
||||||
const graphBounds = graph.div().getBoundingClientRect();
|
const graphBounds = graph.div().getBoundingClientRect();
|
||||||
nodeListLocation = {
|
nodeListLocation = {
|
||||||
x: Math.round(((e.clientX - graphBounds.x) / transform.scale - transform.x) / GRID_SIZE),
|
x: Math.round(((e.clientX - graphBounds.x) / transform.scale - transform.x) / GRID_SIZE),
|
||||||
|
@ -239,20 +252,19 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const port = (e.target as HTMLDivElement).closest("[data-port]") as HTMLDivElement;
|
|
||||||
const node = (e.target as HTMLElement).closest("[data-node]") as HTMLElement | undefined;
|
|
||||||
const nodeId = node?.getAttribute("data-node") || undefined;
|
|
||||||
const nodeList = (e.target as HTMLElement).closest("[data-node-list]") as HTMLElement | undefined;
|
|
||||||
|
|
||||||
// If the user is clicking on the add nodes list, exit here
|
// If the user is clicking on the add nodes list, exit here
|
||||||
if (nodeList) return;
|
if (lmb && nodeList) return;
|
||||||
|
|
||||||
if (e.altKey && nodeId) {
|
// Since the user is clicking elsewhere in the graph, ensure the add nodes list is closed
|
||||||
|
if (lmb) nodeListLocation = undefined;
|
||||||
|
|
||||||
|
// Alt-click sets the clicked node as previewed
|
||||||
|
if (lmb && e.altKey && nodeId) {
|
||||||
editor.instance.togglePreview(BigInt(nodeId));
|
editor.instance.togglePreview(BigInt(nodeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicked on a port dot
|
// Clicked on a port dot
|
||||||
if (port && node) {
|
if (lmb && port && node) {
|
||||||
const isOutput = Boolean(port.getAttribute("data-port") === "output");
|
const isOutput = Boolean(port.getAttribute("data-port") === "output");
|
||||||
|
|
||||||
if (isOutput) linkInProgressFromConnector = port;
|
if (isOutput) linkInProgressFromConnector = port;
|
||||||
|
@ -279,7 +291,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicked on a node
|
// Clicked on a node
|
||||||
if (nodeId) {
|
if (lmb && nodeId) {
|
||||||
let modifiedSelected = false;
|
let modifiedSelected = false;
|
||||||
|
|
||||||
const id = BigInt(nodeId);
|
const id = BigInt(nodeId);
|
||||||
|
@ -306,11 +318,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicked on the graph background
|
// Clicked on the graph background
|
||||||
panning = true;
|
if (lmb && selected.length !== 0) {
|
||||||
if (selected.length !== 0) {
|
|
||||||
selected = [];
|
selected = [];
|
||||||
editor.instance.selectNodes(new BigUint64Array(selected));
|
editor.instance.selectNodes(new BigUint64Array([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LMB clicked on the graph background or MMB clicked anywhere
|
||||||
|
panning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function doubleClick(e: MouseEvent) {
|
function doubleClick(e: MouseEvent) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
UpdateNodeGraph,
|
UpdateNodeGraph,
|
||||||
UpdateNodeTypes,
|
UpdateNodeTypes,
|
||||||
UpdateNodeGraphBarLayout,
|
UpdateNodeGraphBarLayout,
|
||||||
|
UpdateZoomWithScroll,
|
||||||
defaultWidgetLayout,
|
defaultWidgetLayout,
|
||||||
patchWidgetLayout,
|
patchWidgetLayout,
|
||||||
} from "@/wasm-communication/messages";
|
} from "@/wasm-communication/messages";
|
||||||
|
@ -20,6 +21,7 @@ export function createNodeGraphState(editor: Editor) {
|
||||||
links: [] as FrontendNodeLink[],
|
links: [] as FrontendNodeLink[],
|
||||||
nodeTypes: [] as FrontendNodeType[],
|
nodeTypes: [] as FrontendNodeType[],
|
||||||
nodeGraphBarLayout: defaultWidgetLayout(),
|
nodeGraphBarLayout: defaultWidgetLayout(),
|
||||||
|
zoomWithScroll: false as boolean,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up message subscriptions on creation
|
// Set up message subscriptions on creation
|
||||||
|
@ -42,6 +44,12 @@ export function createNodeGraphState(editor: Editor) {
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
editor.subscriptions.subscribeJsMessage(UpdateZoomWithScroll, (updateZoomWithScroll) => {
|
||||||
|
update((state) => {
|
||||||
|
state.zoomWithScroll = updateZoomWithScroll.zoomWithScroll;
|
||||||
|
return state;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
|
|
|
@ -511,19 +511,18 @@ export default defineComponent({
|
||||||
return [pathString, dataType];
|
return [pathString, dataType];
|
||||||
},
|
},
|
||||||
scroll(e: WheelEvent) {
|
scroll(e: WheelEvent) {
|
||||||
const scrollX = e.deltaX;
|
const [scrollX, scrollY] = [e.deltaX, e.deltaY];
|
||||||
const scrollY = e.deltaY;
|
|
||||||
const zoomWithScroll = this.nodeGraph.state.zoomWithScroll;
|
|
||||||
|
|
||||||
let zoom;
|
// If zoom with scroll is enabled: horizontal pan with Ctrl, vertical pan with Shift
|
||||||
let horizontalPan;
|
const zoomWithScroll = this.nodeGraph.state.zoomWithScroll;
|
||||||
if (zoomWithScroll) {
|
const zoom = zoomWithScroll ? !e.ctrlKey && !e.shiftKey : e.ctrlKey;
|
||||||
zoom = !(e.ctrlKey || e.shiftKey);
|
const horizontalPan = zoomWithScroll ? e.ctrlKey : !e.ctrlKey && e.shiftKey;
|
||||||
horizontalPan = e.ctrlKey;
|
|
||||||
} else {
|
// Prevent the web page from being zoomed
|
||||||
zoom = e.ctrlKey;
|
if (e.ctrlKey) e.preventDefault();
|
||||||
horizontalPan = !(e.ctrlKey || e.shiftKey);
|
|
||||||
}
|
// Always pan horizontally in response to a horizontal scroll wheel movement
|
||||||
|
this.transform.x -= scrollX / this.transform.scale;
|
||||||
|
|
||||||
// Zoom
|
// Zoom
|
||||||
if (zoom) {
|
if (zoom) {
|
||||||
|
@ -548,14 +547,13 @@ export default defineComponent({
|
||||||
this.transform.x -= (deltaX / this.transform.scale) * zoomFactor;
|
this.transform.x -= (deltaX / this.transform.scale) * zoomFactor;
|
||||||
this.transform.y -= (deltaY / this.transform.scale) * zoomFactor;
|
this.transform.y -= (deltaY / this.transform.scale) * zoomFactor;
|
||||||
|
|
||||||
// Prevent actually zooming into the page when pinch-zooming on laptop trackpads
|
return;
|
||||||
e.preventDefault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pan
|
// Pan
|
||||||
else if (horizontalPan) {
|
if (horizontalPan) {
|
||||||
this.transform.x -= scrollY / this.transform.scale;
|
this.transform.x -= scrollY / this.transform.scale;
|
||||||
} else {
|
} else {
|
||||||
this.transform.x -= scrollX / this.transform.scale;
|
|
||||||
this.transform.y -= scrollY / this.transform.scale;
|
this.transform.y -= scrollY / this.transform.scale;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -565,13 +563,19 @@ export default defineComponent({
|
||||||
document.removeEventListener("keydown", this.keydown);
|
document.removeEventListener("keydown", this.keydown);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO: Move the event listener from the graph to the window so dragging outside the graph area (or even the browser window) works
|
// TODO: Move the event listener from the graph to the window so dragging outside the graph area (or even the whole browser window) works
|
||||||
pointerDown(e: PointerEvent) {
|
pointerDown(e: PointerEvent) {
|
||||||
// Exit the add node popup by clicking elsewhere in the graph
|
const [lmb, rmb] = [e.button === 0, e.button === 2];
|
||||||
if (this.nodeListLocation && !(e.target as HTMLElement).closest("[data-node-list]")) this.nodeListLocation = undefined;
|
|
||||||
|
|
||||||
// Handle the add node popup on right click
|
const port = (e.target as HTMLDivElement).closest("[data-port]") as HTMLDivElement;
|
||||||
if (e.button === 2) {
|
const node = (e.target as HTMLElement).closest("[data-node]") as HTMLElement | undefined;
|
||||||
|
const nodeId = node?.getAttribute("data-node") || undefined;
|
||||||
|
const nodeList = (e.target as HTMLElement).closest("[data-node-list]") as HTMLElement | undefined;
|
||||||
|
const containerBounds = this.$refs.nodesContainer as HTMLDivElement | undefined;
|
||||||
|
if (!containerBounds) return;
|
||||||
|
|
||||||
|
// Create the add node popup on right click, then exit
|
||||||
|
if (rmb) {
|
||||||
const graphDiv: HTMLDivElement | undefined = (this.$refs.graph as typeof LayoutCol | undefined)?.$el;
|
const graphDiv: HTMLDivElement | undefined = (this.$refs.graph as typeof LayoutCol | undefined)?.$el;
|
||||||
const graph = graphDiv?.getBoundingClientRect() || new DOMRect();
|
const graph = graphDiv?.getBoundingClientRect() || new DOMRect();
|
||||||
this.nodeListLocation = {
|
this.nodeListLocation = {
|
||||||
|
@ -583,22 +587,19 @@ export default defineComponent({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const port = (e.target as HTMLDivElement).closest("[data-port]") as HTMLDivElement;
|
|
||||||
const node = (e.target as HTMLElement).closest("[data-node]") as HTMLElement | undefined;
|
|
||||||
const nodeId = node?.getAttribute("data-node") || undefined;
|
|
||||||
const nodeList = (e.target as HTMLElement).closest("[data-node-list]") as HTMLElement | undefined;
|
|
||||||
const containerBounds = this.$refs.nodesContainer as HTMLDivElement | undefined;
|
|
||||||
if (!containerBounds) return;
|
|
||||||
|
|
||||||
// If the user is clicking on the add nodes list, exit here
|
// If the user is clicking on the add nodes list, exit here
|
||||||
if (nodeList) return;
|
if (lmb && nodeList) return;
|
||||||
|
|
||||||
if (e.altKey && nodeId) {
|
// Since the user is clicking elsewhere in the graph, ensure the add nodes list is closed
|
||||||
|
if (lmb) this.nodeListLocation = undefined;
|
||||||
|
|
||||||
|
// Alt-click sets the clicked node as previewed
|
||||||
|
if (lmb && e.altKey && nodeId) {
|
||||||
this.editor.instance.togglePreview(BigInt(nodeId));
|
this.editor.instance.togglePreview(BigInt(nodeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicked on a port dot
|
// Clicked on a port dot
|
||||||
if (port && node) {
|
if (lmb && port && node) {
|
||||||
const isOutput = Boolean(port.getAttribute("data-port") === "output");
|
const isOutput = Boolean(port.getAttribute("data-port") === "output");
|
||||||
|
|
||||||
if (isOutput) this.linkInProgressFromConnector = port;
|
if (isOutput) this.linkInProgressFromConnector = port;
|
||||||
|
@ -625,7 +626,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicked on a node
|
// Clicked on a node
|
||||||
if (nodeId) {
|
if (lmb && nodeId) {
|
||||||
let modifiedSelected = false;
|
let modifiedSelected = false;
|
||||||
|
|
||||||
const id = BigInt(nodeId);
|
const id = BigInt(nodeId);
|
||||||
|
@ -652,11 +653,13 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicked on the graph background
|
// Clicked on the graph background
|
||||||
this.panning = true;
|
if (lmb && this.selected.length !== 0) {
|
||||||
if (this.selected.length !== 0) {
|
|
||||||
this.selected = [];
|
this.selected = [];
|
||||||
this.editor.instance.selectNodes(new BigUint64Array(this.selected));
|
this.editor.instance.selectNodes(new BigUint64Array([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LMB clicked on the graph background or MMB clicked anywhere
|
||||||
|
this.panning = true;
|
||||||
},
|
},
|
||||||
doubleClick(e: MouseEvent) {
|
doubleClick(e: MouseEvent) {
|
||||||
const node = (e.target as HTMLElement).closest("[data-node]") as HTMLElement | undefined;
|
const node = (e.target as HTMLElement).closest("[data-node]") as HTMLElement | undefined;
|
||||||
|
|
|
@ -117,7 +117,6 @@ fn map_image<MapFn>(mut image_frame: ImageFrame, map_fn: &'any_input MapFn) -> I
|
||||||
where
|
where
|
||||||
MapFn: for<'any_input> Node<'any_input, Color, Output = Color> + 'input,
|
MapFn: for<'any_input> Node<'any_input, Color, Output = Color> + 'input,
|
||||||
{
|
{
|
||||||
let mut image_frame = image_frame;
|
|
||||||
for pixel in &mut image_frame.image.data {
|
for pixel in &mut image_frame.image.data {
|
||||||
*pixel = map_fn.eval(*pixel);
|
*pixel = map_fn.eval(*pixel);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue