feat(svelte): add background

This commit is contained in:
moklick
2023-02-19 18:07:50 +01:00
parent 90ac61a6bd
commit 51fd1cc01a
10 changed files with 135 additions and 42 deletions

View File

@@ -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;

View 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>

View File

@@ -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} />

View File

@@ -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]
}`}
/>

View File

@@ -0,0 +1,2 @@
export { BackgroundVariant } from './types';
export { default as Background } from './Background.svelte';

View File

@@ -0,0 +1,5 @@
export enum BackgroundVariant {
Lines = 'lines',
Dots = 'dots',
Cross = 'cross'
}

View File

@@ -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;

View File

@@ -0,0 +1,2 @@
export { default as Controls } from './Controls.svelte';
export { default as ControlButton } from './ControlButton.svelte';

View File

@@ -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,

View File

@@ -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>