feat(svelte): add background
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import SvelteFlow from '$lib/container/SvelteFlow.svelte';
|
import SvelteFlow from '$lib/container/SvelteFlow.svelte';
|
||||||
export { default as Controls } from '$lib/plugins/Controls/index.svelte';
|
export { Controls, ControlButton } from '$lib/plugins/Controls';
|
||||||
|
export { Background, BackgroundVariant } from '$lib/plugins/Background';
|
||||||
|
|
||||||
export default SvelteFlow;
|
export default SvelteFlow;
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import cc from 'classcat';
|
||||||
|
|
||||||
|
import DotPattern from './DotPattern.svelte';
|
||||||
|
import LinePattern from './LinePattern.svelte';
|
||||||
|
import { useStore } from '$lib/store';
|
||||||
|
import { BackgroundVariant } from './types';
|
||||||
|
|
||||||
|
export let variant: BackgroundVariant = BackgroundVariant.Dots;
|
||||||
|
export let gap = 20;
|
||||||
|
export let size: number = 1;
|
||||||
|
export let lineWidth = 1;
|
||||||
|
export let color: string = '#ccc';
|
||||||
|
|
||||||
|
let className: string = '';
|
||||||
|
export { className as class };
|
||||||
|
|
||||||
|
const defaultColor = {
|
||||||
|
[BackgroundVariant.Dots]: '#91919a',
|
||||||
|
[BackgroundVariant.Lines]: '#eee',
|
||||||
|
[BackgroundVariant.Cross]: '#e2e2e2',
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultSize = {
|
||||||
|
[BackgroundVariant.Dots]: 1,
|
||||||
|
[BackgroundVariant.Lines]: 1,
|
||||||
|
[BackgroundVariant.Cross]: 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { transformStore, idStore } = useStore();
|
||||||
|
const patternColor = color || defaultColor[variant];
|
||||||
|
const patternSize = size || defaultSize[variant];
|
||||||
|
const isDots = variant === BackgroundVariant.Dots;
|
||||||
|
const isCross = variant === BackgroundVariant.Cross;
|
||||||
|
const gapXY: number[] = Array.isArray(gap) ? gap : [gap, gap];
|
||||||
|
|
||||||
|
$: patternId = `background-pattern-${$idStore}`;
|
||||||
|
$: scaledGap = [gapXY[0] * $transformStore[2] || 1, gapXY[1] * $transformStore[2] || 1];
|
||||||
|
$: scaledSize = patternSize * $transformStore[2];
|
||||||
|
$: patternDimensions = (isCross ? [scaledSize, scaledSize] : scaledGap) as [number, number];
|
||||||
|
$: patternOffset = isDots
|
||||||
|
? [scaledSize / 2, scaledSize / 2]
|
||||||
|
: [patternDimensions[0] / 2, patternDimensions[1] / 2];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class={cc(['react-flow__background', className])} >
|
||||||
|
<pattern
|
||||||
|
id={patternId}
|
||||||
|
x={$transformStore[0] % scaledGap[0]}
|
||||||
|
y={$transformStore[1] % scaledGap[1]}
|
||||||
|
width={scaledGap[0]}
|
||||||
|
height={scaledGap[1]}
|
||||||
|
patternUnits="userSpaceOnUse"
|
||||||
|
patternTransform={`translate(-${patternOffset[0]},-${patternOffset[1]})`}
|
||||||
|
>
|
||||||
|
{#if isDots}
|
||||||
|
<DotPattern color={patternColor} radius={scaledSize / 2} />
|
||||||
|
{:else}
|
||||||
|
<LinePattern dimensions={patternDimensions } color={patternColor} lineWidth={lineWidth} />
|
||||||
|
{/if}
|
||||||
|
</pattern>
|
||||||
|
<rect x="0" y="0" width="100%" height="100%" fill={`url(#${patternId})`} />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.react-flow__background {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let radius = 5;
|
||||||
|
export let color = "#000";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<circle cx={radius} cy={radius} r={radius} fill={color} />
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let lineWidth = 1;
|
||||||
|
export let color = "#777";
|
||||||
|
export let dimensions: [number, number];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<path
|
||||||
|
stroke={color}
|
||||||
|
stroke-width={lineWidth}
|
||||||
|
d={`M${dimensions[0] / 2} 0 V${dimensions[1]} M0 ${dimensions[1] / 2} H${
|
||||||
|
dimensions[0]
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { BackgroundVariant } from './types';
|
||||||
|
export { default as Background } from './Background.svelte';
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export enum BackgroundVariant {
|
||||||
|
Lines = 'lines',
|
||||||
|
Dots = 'dots',
|
||||||
|
Cross = 'cross'
|
||||||
|
}
|
||||||
+2
-3
@@ -1,7 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Panel from '$lib/container/Panel.svelte';
|
|
||||||
import type { PanelPosition } from '@reactflow/system';
|
import type { PanelPosition } from '@reactflow/system';
|
||||||
|
|
||||||
|
import Panel from '$lib/container/Panel.svelte';
|
||||||
|
import { useStore } from '$lib/store';
|
||||||
import ControlButton from './ControlButton.svelte';
|
import ControlButton from './ControlButton.svelte';
|
||||||
import PlusIcon from './Icons/Plus.svelte';
|
import PlusIcon from './Icons/Plus.svelte';
|
||||||
import MinusIcon from './Icons/Minus.svelte';
|
import MinusIcon from './Icons/Minus.svelte';
|
||||||
@@ -14,8 +15,6 @@
|
|||||||
export let showFitView = true;
|
export let showFitView = true;
|
||||||
export let showInteractive = true;
|
export let showInteractive = true;
|
||||||
|
|
||||||
import { useStore } from '$lib/store';
|
|
||||||
|
|
||||||
const { zoomIn, zoomOut, fitView } = useStore();
|
const { zoomIn, zoomOut, fitView } = useStore();
|
||||||
|
|
||||||
const isInteractive = true;
|
const isInteractive = true;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { default as Controls } from './Controls.svelte';
|
||||||
|
export { default as ControlButton } from './ControlButton.svelte';
|
||||||
@@ -31,6 +31,7 @@ type CreateStoreProps = {
|
|||||||
fitView: boolean;
|
fitView: boolean;
|
||||||
nodeOrigin?: NodeOrigin;
|
nodeOrigin?: NodeOrigin;
|
||||||
transform?: Transform;
|
transform?: Transform;
|
||||||
|
id?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EdgeWithData = EdgePosition & {
|
export type EdgeWithData = EdgePosition & {
|
||||||
@@ -49,9 +50,10 @@ type SvelteFlowStore = {
|
|||||||
}>;
|
}>;
|
||||||
transformStore: Writable<Transform>;
|
transformStore: Writable<Transform>;
|
||||||
edgesWithDataStore: Readable<EdgeWithData[]>;
|
edgesWithDataStore: Readable<EdgeWithData[]>;
|
||||||
|
idStore: Writable<string>;
|
||||||
zoomIn: (options?: ViewportHelperFunctionOptions) => void;
|
zoomIn: (options?: ViewportHelperFunctionOptions) => void;
|
||||||
zoomOut: (options?: ViewportHelperFunctionOptions) => void;
|
zoomOut: (options?: ViewportHelperFunctionOptions) => void;
|
||||||
fitView: (options?: ViewportHelperFunctionOptions) => void;
|
fitView: (options?: ViewportHelperFunctionOptions) => boolean;
|
||||||
updateNodePositions: (
|
updateNodePositions: (
|
||||||
nodeDragItems: NodeDragItem[],
|
nodeDragItems: NodeDragItem[],
|
||||||
positionChanged?: boolean,
|
positionChanged?: boolean,
|
||||||
@@ -65,7 +67,8 @@ export function createStore({
|
|||||||
edges = [],
|
edges = [],
|
||||||
transform = [0, 0, 1],
|
transform = [0, 0, 1],
|
||||||
nodeOrigin = [0, 0],
|
nodeOrigin = [0, 0],
|
||||||
fitView: fitViewOnInit = false
|
fitView: fitViewOnInit = false,
|
||||||
|
id = '1'
|
||||||
}: CreateStoreProps): SvelteFlowStore {
|
}: CreateStoreProps): SvelteFlowStore {
|
||||||
const nodesStore = writable(nodes.map((n) => ({ ...n, positionAbsolute: n.position })));
|
const nodesStore = writable(nodes.map((n) => ({ ...n, positionAbsolute: n.position })));
|
||||||
const edgesStore = writable(edges);
|
const edgesStore = writable(edges);
|
||||||
@@ -76,6 +79,7 @@ export function createStore({
|
|||||||
zoom: null,
|
zoom: null,
|
||||||
selection: null
|
selection: null
|
||||||
});
|
});
|
||||||
|
const idStore = writable(id);
|
||||||
|
|
||||||
let fitViewOnInitDone = false;
|
let fitViewOnInitDone = false;
|
||||||
|
|
||||||
@@ -187,27 +191,8 @@ export function createStore({
|
|||||||
|
|
||||||
const { zoom: d3Zoom, selection: d3Selection } = get(d3Store);
|
const { zoom: d3Zoom, selection: d3Selection } = get(d3Store);
|
||||||
|
|
||||||
const nextFitViewOnInitDone =
|
fitViewOnInitDone =
|
||||||
fitViewOnInitDone ||
|
fitViewOnInitDone || (fitViewOnInit && !!d3Zoom && !!d3Selection && _fitView());
|
||||||
(fitViewOnInit &&
|
|
||||||
!fitViewOnInitDone &&
|
|
||||||
!!d3Zoom &&
|
|
||||||
!!d3Selection &&
|
|
||||||
fitView(
|
|
||||||
{
|
|
||||||
nodes: get(nodesStore),
|
|
||||||
width: get(widthStore),
|
|
||||||
height: get(heightStore),
|
|
||||||
minZoom: 0.2,
|
|
||||||
maxZoom: 2,
|
|
||||||
d3Selection,
|
|
||||||
d3Zoom,
|
|
||||||
nodeOrigin: get(nodeOriginStore)
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
));
|
|
||||||
|
|
||||||
fitViewOnInitDone = nextFitViewOnInitDone;
|
|
||||||
|
|
||||||
nodesStore.set(nextNodes);
|
nodesStore.set(nextNodes);
|
||||||
}
|
}
|
||||||
@@ -229,21 +214,24 @@ export function createStore({
|
|||||||
|
|
||||||
function _fitView() {
|
function _fitView() {
|
||||||
const { zoom: d3Zoom, selection: d3Selection } = get(d3Store);
|
const { zoom: d3Zoom, selection: d3Selection } = get(d3Store);
|
||||||
if (d3Zoom && d3Selection) {
|
|
||||||
fitView(
|
if (!d3Zoom || !d3Selection) {
|
||||||
{
|
return false;
|
||||||
nodes: get(nodesStore),
|
|
||||||
width: get(widthStore),
|
|
||||||
height: get(heightStore),
|
|
||||||
minZoom: 0.2,
|
|
||||||
maxZoom: 2,
|
|
||||||
d3Selection,
|
|
||||||
d3Zoom,
|
|
||||||
nodeOrigin: get(nodeOriginStore)
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fitView(
|
||||||
|
{
|
||||||
|
nodes: get(nodesStore),
|
||||||
|
width: get(widthStore),
|
||||||
|
height: get(heightStore),
|
||||||
|
minZoom: 0.2,
|
||||||
|
maxZoom: 2,
|
||||||
|
d3Selection,
|
||||||
|
d3Zoom,
|
||||||
|
nodeOrigin: get(nodeOriginStore)
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -254,6 +242,7 @@ export function createStore({
|
|||||||
heightStore,
|
heightStore,
|
||||||
widthStore,
|
widthStore,
|
||||||
edgesWithDataStore,
|
edgesWithDataStore,
|
||||||
|
idStore,
|
||||||
updateNodePositions,
|
updateNodePositions,
|
||||||
updateNodeDimensions,
|
updateNodeDimensions,
|
||||||
zoomIn,
|
zoomIn,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Node, Edge } from '@reactflow/system';
|
import type { Node, Edge } from '@reactflow/system';
|
||||||
|
|
||||||
import SvelteFlow, { Controls } from '../lib/index';
|
import SvelteFlow, { Controls, Background, BackgroundVariant } from '../lib/index';
|
||||||
|
|
||||||
const yNodes = 10;
|
const yNodes = 10;
|
||||||
const xNodes = 10;
|
const xNodes = 10;
|
||||||
@@ -59,6 +59,7 @@
|
|||||||
|
|
||||||
<SvelteFlow {nodes} {edges} fitView >
|
<SvelteFlow {nodes} {edges} fitView >
|
||||||
<Controls />
|
<Controls />
|
||||||
|
<Background variant={BackgroundVariant.Dots} />
|
||||||
</SvelteFlow>
|
</SvelteFlow>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
Reference in New Issue
Block a user