cleaned up code for onlyRenderVisibleElements
This commit is contained in:
@@ -344,11 +344,11 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
}
|
||||
|
||||
const updateConnection: UpdateConnection = (newConnection: ConnectionState) => {
|
||||
store.rawConnection = { ...newConnection };
|
||||
store._connection = { ...newConnection };
|
||||
};
|
||||
|
||||
function cancelConnection() {
|
||||
store.rawConnection = initialConnection;
|
||||
store._connection = initialConnection;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
|
||||
@@ -53,12 +53,13 @@ import type {
|
||||
IsValidConnection,
|
||||
Edge,
|
||||
Node,
|
||||
EdgeLayouted
|
||||
EdgeLayouted,
|
||||
InternalNode
|
||||
} from '$lib/types';
|
||||
|
||||
import type { StoreSignals } from './types';
|
||||
import { MediaQuery } from 'svelte/reactivity';
|
||||
import { gatherLayoutedEdges, getVisibleNodes } from './visibleElements';
|
||||
import { getLayoutedEdges, getVisibleNodes, type EdgeLayoutAllOptions } from './visibleElements';
|
||||
|
||||
export const initialNodeTypes = {
|
||||
input: InputNode,
|
||||
@@ -75,7 +76,6 @@ export const initialEdgeTypes = {
|
||||
};
|
||||
|
||||
export const getInitialStore = (signals: StoreSignals) => {
|
||||
const previousLayoutedEdges = new Map<string, EdgeLayouted>();
|
||||
// We use a class here, because Svelte adds getters & setter for us.
|
||||
// Inline classes have some performance implications but we just call it once (max twice).
|
||||
class SvelteFlowStore {
|
||||
@@ -112,47 +112,47 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
connectionLookup: ConnectionLookup = new Map();
|
||||
edgeLookup: EdgeLookup = new Map();
|
||||
|
||||
_prevVisibleEdges = new Map<string, EdgeLayouted>();
|
||||
visible = $derived.by(() => {
|
||||
// We need to access this._nodes to trigger on changes
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
this._nodes;
|
||||
const {
|
||||
// We need to access this._nodes to trigger on changes
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_nodes,
|
||||
_edges: edges,
|
||||
_prevVisibleEdges: previousEdges,
|
||||
nodeLookup,
|
||||
connectionMode,
|
||||
onerror,
|
||||
onlyRenderVisibleElements
|
||||
} = this;
|
||||
|
||||
// We either add all or only visible nodes to visibleNodes here.
|
||||
let visibleNodes = new Map();
|
||||
let layoutedEdges = new Map<string, EdgeLayouted>();
|
||||
// TODO: is there a more elegant solution??
|
||||
if (this.onlyRenderVisibleElements) {
|
||||
const transform: Transform = [this.viewport.x, this.viewport.y, this.viewport.zoom];
|
||||
getVisibleNodes(this.nodeLookup, transform, this.width, this.height).forEach((node) => {
|
||||
visibleNodes.set(node.id, node);
|
||||
});
|
||||
layoutedEdges = gatherLayoutedEdges(
|
||||
this._edges,
|
||||
this.nodeLookup,
|
||||
previousLayoutedEdges,
|
||||
this.connectionMode,
|
||||
this.onerror,
|
||||
true,
|
||||
let visibleNodes: Map<string, InternalNode>;
|
||||
let visibleEdges: Map<string, EdgeLayouted>;
|
||||
|
||||
const options = { edges, previousEdges, nodeLookup, connectionMode, onerror };
|
||||
|
||||
if (onlyRenderVisibleElements) {
|
||||
// We only subscribe to viewport, width, height if onlyRenderVisibleElements is true
|
||||
const { viewport, width, height } = this;
|
||||
const transform: Transform = [viewport.x, viewport.y, viewport.zoom];
|
||||
|
||||
visibleNodes = getVisibleNodes(nodeLookup, transform, width, height);
|
||||
visibleEdges = getLayoutedEdges({
|
||||
...options,
|
||||
onlyRenderVisible: true,
|
||||
visibleNodes,
|
||||
transform,
|
||||
this.width,
|
||||
this.height,
|
||||
visibleNodes
|
||||
);
|
||||
width,
|
||||
height
|
||||
});
|
||||
} else {
|
||||
visibleNodes = this.nodeLookup;
|
||||
layoutedEdges = gatherLayoutedEdges(
|
||||
this._edges,
|
||||
this.nodeLookup,
|
||||
previousLayoutedEdges,
|
||||
this.connectionMode,
|
||||
this.onerror,
|
||||
false
|
||||
);
|
||||
visibleEdges = getLayoutedEdges(options as EdgeLayoutAllOptions);
|
||||
}
|
||||
|
||||
return {
|
||||
nodes: visibleNodes,
|
||||
edges: layoutedEdges
|
||||
edges: visibleEdges
|
||||
};
|
||||
});
|
||||
|
||||
@@ -196,7 +196,8 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
nodeTypes: NodeTypes = $derived({ ...initialNodeTypes, ...signals.props.nodeTypes });
|
||||
edgeTypes: EdgeTypes = $derived({ ...initialEdgeTypes, ...signals.props.edgeTypes });
|
||||
|
||||
// _viewport is the internal viewport. We either return signals.viewport or _viewport
|
||||
// _viewport is the internal viewport.
|
||||
// when binding to viewport, we operate on signals.viewport instead
|
||||
_viewport: Viewport = $state(signals.props.initialViewport ?? { x: 0, y: 0, zoom: 1 });
|
||||
get viewport() {
|
||||
return signals.viewport ?? this._viewport;
|
||||
@@ -208,27 +209,29 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
this._viewport = viewport;
|
||||
}
|
||||
|
||||
connectionMode: ConnectionMode = $derived(
|
||||
signals.props.connectionMode ?? ConnectionMode.Strict
|
||||
);
|
||||
rawConnection: ConnectionState = $state(initialConnection);
|
||||
// _connection is viewport independent and originating from XYHandle
|
||||
_connection: ConnectionState = $state(initialConnection);
|
||||
// We derive a viewport dependent connection here
|
||||
connection: ConnectionState = $derived.by(() => {
|
||||
if (this.rawConnection.inProgress) {
|
||||
if (this._connection.inProgress) {
|
||||
return {
|
||||
...this.rawConnection,
|
||||
to: pointToRendererPoint(this.rawConnection.to, [
|
||||
...this._connection,
|
||||
to: pointToRendererPoint(this._connection.to, [
|
||||
this.viewport.x,
|
||||
this.viewport.y,
|
||||
this.viewport.zoom
|
||||
])
|
||||
};
|
||||
} else {
|
||||
return { ...this.rawConnection };
|
||||
return this._connection;
|
||||
}
|
||||
});
|
||||
connectionLineType: ConnectionLineType = $derived(
|
||||
signals.props.connectionLineType ?? ConnectionLineType.Bezier
|
||||
);
|
||||
connectionMode: ConnectionMode = $derived(
|
||||
signals.props.connectionMode ?? ConnectionMode.Strict
|
||||
);
|
||||
connectionRadius: number = $derived(signals.props.connectionRadius ?? 20);
|
||||
isValidConnection: IsValidConnection = $derived(
|
||||
signals.props.isValidConnection ?? (() => true)
|
||||
@@ -258,14 +261,14 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
edgesInitialized: boolean = $state(false);
|
||||
viewportInitialized: boolean = $state(false);
|
||||
|
||||
initialNodesLength: number = signals.nodes?.length ?? 0;
|
||||
initialEdgesLength: number = signals.edges?.length ?? 0;
|
||||
_initialNodesLength: number = signals.nodes?.length ?? 0;
|
||||
_initialEdgesLength: number = signals.edges?.length ?? 0;
|
||||
initialized: boolean = $derived.by(() => {
|
||||
let initialized = false;
|
||||
// if it hasn't been initialised check if it's now
|
||||
if (this.initialNodesLength === 0) {
|
||||
if (this._initialNodesLength === 0) {
|
||||
initialized = this.viewportInitialized;
|
||||
} else if (this.initialEdgesLength === 0) {
|
||||
} else if (this._initialEdgesLength === 0) {
|
||||
initialized = this.viewportInitialized && this.nodesInitialized;
|
||||
} else {
|
||||
initialized = this.viewportInitialized && this.nodesInitialized && this.edgesInitialized;
|
||||
@@ -273,13 +276,14 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
|
||||
return initialized;
|
||||
});
|
||||
prefersDark = new MediaQuery(
|
||||
|
||||
_prefersDark = new MediaQuery(
|
||||
'(prefers-color-scheme: dark)',
|
||||
signals.props.colorModeSSR === 'dark'
|
||||
);
|
||||
colorMode: ColorModeClass = $derived(
|
||||
signals.props.colorMode === 'system'
|
||||
? this.prefersDark.current
|
||||
? this._prefersDark.current
|
||||
? 'dark'
|
||||
: 'light'
|
||||
: (signals.props.colorMode ?? 'light')
|
||||
|
||||
@@ -16,42 +16,43 @@ export function getVisibleNodes(
|
||||
width: number,
|
||||
height: number
|
||||
) {
|
||||
return getNodesInside(nodeLookup, { x: 0, y: 0, width: width, height: height }, transform, true);
|
||||
const visibleNodes = new Map<string, InternalNode>();
|
||||
getNodesInside(nodeLookup, { x: 0, y: 0, width: width, height: height }, transform, true).forEach(
|
||||
(node) => {
|
||||
visibleNodes.set(node.id, node);
|
||||
}
|
||||
);
|
||||
return visibleNodes;
|
||||
}
|
||||
|
||||
// TODO: is this what we want?
|
||||
export function gatherLayoutedEdges(
|
||||
edges: Edge[],
|
||||
nodeLookup: NodeLookup,
|
||||
previousLayoutedEdges: Map<string, EdgeLayouted>,
|
||||
connectionMode: ConnectionMode,
|
||||
onerror: OnError,
|
||||
onlyRenderVisibleElements: true,
|
||||
transform: Transform,
|
||||
width: number,
|
||||
height: number,
|
||||
visibleNodes: Map<string, InternalNode>
|
||||
): Map<string, EdgeLayouted>;
|
||||
export function gatherLayoutedEdges(
|
||||
edges: Edge[],
|
||||
nodeLookup: NodeLookup,
|
||||
previousLayoutedEdges: Map<string, EdgeLayouted>,
|
||||
connectionMode: ConnectionMode,
|
||||
onerror: OnError,
|
||||
onlyRenderVisibleElements: false
|
||||
): Map<string, EdgeLayouted>;
|
||||
export function gatherLayoutedEdges(
|
||||
edges: Edge[],
|
||||
nodeLookup: NodeLookup,
|
||||
previousLayoutedEdges: Map<string, EdgeLayouted>,
|
||||
connectionMode: ConnectionMode,
|
||||
onerror: OnError,
|
||||
onlyRenderVisibleElements?: boolean,
|
||||
transform?: Transform,
|
||||
width?: number,
|
||||
height?: number,
|
||||
visibleNodes?: Map<string, InternalNode>
|
||||
): Map<string, EdgeLayouted> {
|
||||
export interface EdgeLayoutBaseOptions {
|
||||
edges: Edge[];
|
||||
previousEdges: Map<string, EdgeLayouted>;
|
||||
nodeLookup: NodeLookup;
|
||||
connectionMode: ConnectionMode;
|
||||
onerror: OnError;
|
||||
}
|
||||
|
||||
export interface EdgeLayoutAllOptions extends EdgeLayoutBaseOptions {
|
||||
onlyRenderVisible: never;
|
||||
visibleNodes: never;
|
||||
transform: never;
|
||||
width: never;
|
||||
height: never;
|
||||
}
|
||||
|
||||
export interface EdgeLayoutOnlyVisibleOptions extends EdgeLayoutBaseOptions {
|
||||
visibleNodes: Map<string, InternalNode>;
|
||||
transform: Transform;
|
||||
width: number;
|
||||
height: number;
|
||||
onlyRenderVisible: true;
|
||||
}
|
||||
|
||||
export type EdgeLayoutOptions = EdgeLayoutAllOptions | EdgeLayoutOnlyVisibleOptions;
|
||||
|
||||
export function getLayoutedEdges(options: EdgeLayoutOptions): Map<string, EdgeLayouted> {
|
||||
const { edges, nodeLookup, previousEdges, connectionMode, onerror, onlyRenderVisible } = options;
|
||||
const layoutedEdges = new Map<string, EdgeLayouted>();
|
||||
for (const edge of edges) {
|
||||
const sourceNode = nodeLookup.get(edge.source);
|
||||
@@ -61,7 +62,8 @@ export function gatherLayoutedEdges(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (onlyRenderVisibleElements) {
|
||||
if (onlyRenderVisible) {
|
||||
const { visibleNodes, transform, width, height } = options;
|
||||
if (
|
||||
isEdgeVisible({
|
||||
sourceNode,
|
||||
@@ -82,7 +84,7 @@ export function gatherLayoutedEdges(
|
||||
// the current and previous edge are the same
|
||||
// and the source and target node are the same
|
||||
// and references to internalNodes are the same
|
||||
const previous = previousLayoutedEdges.get(edge.id);
|
||||
const previous = previousEdges.get(edge.id);
|
||||
if (
|
||||
previous &&
|
||||
edge === previous.edge &&
|
||||
@@ -99,7 +101,7 @@ export function gatherLayoutedEdges(
|
||||
targetNode,
|
||||
sourceHandle: edge.sourceHandle || null,
|
||||
targetHandle: edge.targetHandle || null,
|
||||
connectionMode: connectionMode,
|
||||
connectionMode,
|
||||
onError: onerror
|
||||
});
|
||||
|
||||
@@ -121,7 +123,5 @@ export function gatherLayoutedEdges(
|
||||
}
|
||||
}
|
||||
|
||||
previousLayoutedEdges = layoutedEdges;
|
||||
|
||||
return layoutedEdges;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user