feat(svelte): add background
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
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;
|
||||
|
||||
75
packages/svelte/src/lib/plugins/Background/Background.svelte
Normal file
75
packages/svelte/src/lib/plugins/Background/Background.svelte
Normal file
@@ -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]
|
||||
}`}
|
||||
/>
|
||||
2
packages/svelte/src/lib/plugins/Background/index.ts
Normal file
2
packages/svelte/src/lib/plugins/Background/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { BackgroundVariant } from './types';
|
||||
export { default as Background } from './Background.svelte';
|
||||
5
packages/svelte/src/lib/plugins/Background/types.ts
Normal file
5
packages/svelte/src/lib/plugins/Background/types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export enum BackgroundVariant {
|
||||
Lines = 'lines',
|
||||
Dots = 'dots',
|
||||
Cross = 'cross'
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import Panel from '$lib/container/Panel.svelte';
|
||||
import type { PanelPosition } from '@reactflow/system';
|
||||
|
||||
import Panel from '$lib/container/Panel.svelte';
|
||||
import { useStore } from '$lib/store';
|
||||
import ControlButton from './ControlButton.svelte';
|
||||
import PlusIcon from './Icons/Plus.svelte';
|
||||
import MinusIcon from './Icons/Minus.svelte';
|
||||
@@ -14,8 +15,6 @@
|
||||
export let showFitView = true;
|
||||
export let showInteractive = true;
|
||||
|
||||
import { useStore } from '$lib/store';
|
||||
|
||||
const { zoomIn, zoomOut, fitView } = useStore();
|
||||
|
||||
const isInteractive = true;
|
||||
2
packages/svelte/src/lib/plugins/Controls/index.ts
Normal file
2
packages/svelte/src/lib/plugins/Controls/index.ts
Normal file
@@ -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;
|
||||
nodeOrigin?: NodeOrigin;
|
||||
transform?: Transform;
|
||||
id?: string;
|
||||
};
|
||||
|
||||
export type EdgeWithData = EdgePosition & {
|
||||
@@ -49,9 +50,10 @@ type SvelteFlowStore = {
|
||||
}>;
|
||||
transformStore: Writable<Transform>;
|
||||
edgesWithDataStore: Readable<EdgeWithData[]>;
|
||||
idStore: Writable<string>;
|
||||
zoomIn: (options?: ViewportHelperFunctionOptions) => void;
|
||||
zoomOut: (options?: ViewportHelperFunctionOptions) => void;
|
||||
fitView: (options?: ViewportHelperFunctionOptions) => void;
|
||||
fitView: (options?: ViewportHelperFunctionOptions) => boolean;
|
||||
updateNodePositions: (
|
||||
nodeDragItems: NodeDragItem[],
|
||||
positionChanged?: boolean,
|
||||
@@ -65,7 +67,8 @@ export function createStore({
|
||||
edges = [],
|
||||
transform = [0, 0, 1],
|
||||
nodeOrigin = [0, 0],
|
||||
fitView: fitViewOnInit = false
|
||||
fitView: fitViewOnInit = false,
|
||||
id = '1'
|
||||
}: CreateStoreProps): SvelteFlowStore {
|
||||
const nodesStore = writable(nodes.map((n) => ({ ...n, positionAbsolute: n.position })));
|
||||
const edgesStore = writable(edges);
|
||||
@@ -76,6 +79,7 @@ export function createStore({
|
||||
zoom: null,
|
||||
selection: null
|
||||
});
|
||||
const idStore = writable(id);
|
||||
|
||||
let fitViewOnInitDone = false;
|
||||
|
||||
@@ -187,27 +191,8 @@ export function createStore({
|
||||
|
||||
const { zoom: d3Zoom, selection: d3Selection } = get(d3Store);
|
||||
|
||||
const nextFitViewOnInitDone =
|
||||
fitViewOnInitDone ||
|
||||
(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;
|
||||
fitViewOnInitDone =
|
||||
fitViewOnInitDone || (fitViewOnInit && !!d3Zoom && !!d3Selection && _fitView());
|
||||
|
||||
nodesStore.set(nextNodes);
|
||||
}
|
||||
@@ -229,21 +214,24 @@ export function createStore({
|
||||
|
||||
function _fitView() {
|
||||
const { zoom: d3Zoom, selection: d3Selection } = get(d3Store);
|
||||
if (d3Zoom && d3Selection) {
|
||||
fitView(
|
||||
{
|
||||
nodes: get(nodesStore),
|
||||
width: get(widthStore),
|
||||
height: get(heightStore),
|
||||
minZoom: 0.2,
|
||||
maxZoom: 2,
|
||||
d3Selection,
|
||||
d3Zoom,
|
||||
nodeOrigin: get(nodeOriginStore)
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
if (!d3Zoom || !d3Selection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fitView(
|
||||
{
|
||||
nodes: get(nodesStore),
|
||||
width: get(widthStore),
|
||||
height: get(heightStore),
|
||||
minZoom: 0.2,
|
||||
maxZoom: 2,
|
||||
d3Selection,
|
||||
d3Zoom,
|
||||
nodeOrigin: get(nodeOriginStore)
|
||||
},
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -254,6 +242,7 @@ export function createStore({
|
||||
heightStore,
|
||||
widthStore,
|
||||
edgesWithDataStore,
|
||||
idStore,
|
||||
updateNodePositions,
|
||||
updateNodeDimensions,
|
||||
zoomIn,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
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 xNodes = 10;
|
||||
@@ -59,6 +59,7 @@
|
||||
|
||||
<SvelteFlow {nodes} {edges} fitView >
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
</SvelteFlow>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user