layerchart 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Arc.svelte +2 -2
- package/components/Area.svelte +2 -2
- package/components/AxisX.svelte +1 -1
- package/components/AxisY.svelte +1 -1
- package/components/Bars.svelte +1 -2
- package/components/Circle.svelte +4 -4
- package/components/CircleClipPath.svelte +21 -0
- package/components/CircleClipPath.svelte.d.ts +26 -0
- package/components/ClipPath.svelte +10 -0
- package/components/ClipPath.svelte.d.ts +21 -0
- package/components/Group.svelte +10 -3
- package/components/Group.svelte.d.ts +5 -0
- package/components/Labels.svelte +1 -1
- package/components/Line.svelte +5 -5
- package/components/Link.svelte +35 -0
- package/components/Link.svelte.d.ts +28 -0
- package/components/Path.svelte +2 -2
- package/components/Pie.svelte +2 -2
- package/components/Rect.svelte +10 -7
- package/components/Rect.svelte.d.ts +4 -2
- package/components/RectClipPath.svelte +22 -0
- package/components/RectClipPath.svelte.d.ts +27 -0
- package/components/Sankey.svelte +39 -0
- package/components/Sankey.svelte.d.ts +33 -0
- package/components/Treemap.svelte +105 -0
- package/components/Treemap.svelte.d.ts +35 -0
- package/package.json +19 -4
- package/stores/motionStore.d.ts +2 -2
- package/stores/motionStore.js +2 -2
- package/utils/graph.d.ts +24 -0
- package/utils/graph.js +60 -0
- package/utils/treemap.d.ts +6 -0
- package/utils/treemap.js +16 -0
package/components/Arc.svelte
CHANGED
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
import { getContext } from 'svelte';
|
|
16
16
|
import { arc as d3arc } from 'd3-shape';
|
|
17
17
|
import { scaleLinear } from 'd3-scale';
|
|
18
|
-
import {
|
|
18
|
+
import { createMotionStore } from '../stores/motionStore';
|
|
19
19
|
import { degreesToRadians } from '../utils/math';
|
|
20
20
|
export let spring = undefined;
|
|
21
21
|
export let tweened = undefined;
|
|
22
22
|
export let value = 0;
|
|
23
|
-
let tweened_value =
|
|
23
|
+
let tweened_value = createMotionStore(value, { spring, tweened });
|
|
24
24
|
$: tweened_value.set(value);
|
|
25
25
|
export let domain = [0, 100];
|
|
26
26
|
/**
|
package/components/Area.svelte
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script >import { getContext } from 'svelte';
|
|
2
2
|
import { area as d3Area } from 'd3-shape';
|
|
3
3
|
import { interpolatePath } from 'd3-interpolate-path';
|
|
4
|
-
import {
|
|
4
|
+
import { createMotionStore } from '../stores/motionStore';
|
|
5
5
|
import Path from './Path.svelte';
|
|
6
6
|
const { data: contextData, xGet, yGet, yRange } = getContext('LayerCake');
|
|
7
7
|
// Properties to override what is used from context
|
|
@@ -18,7 +18,7 @@ export let color = 'var(--color-blue-500)';
|
|
|
18
18
|
export let opacity = 0.3;
|
|
19
19
|
export let line = false;
|
|
20
20
|
$: tweenedOptions = tweened ? { interpolate: interpolatePath, ...tweened } : false;
|
|
21
|
-
$: tweened_d =
|
|
21
|
+
$: tweened_d = createMotionStore('', { tweened: tweenedOptions });
|
|
22
22
|
$: {
|
|
23
23
|
const path = d3Area()
|
|
24
24
|
.x(x ?? $xGet)
|
package/components/AxisX.svelte
CHANGED
|
@@ -32,7 +32,7 @@ $: tickVals = Array.isArray(ticks)
|
|
|
32
32
|
rotate={315}
|
|
33
33
|
textAnchor="end"
|
|
34
34
|
verticalAnchor="middle"
|
|
35
|
-
style="font-size: 10px; stroke:
|
|
35
|
+
style="font-size: 10px; stroke: white; stroke-width: 2px;"
|
|
36
36
|
value={format(tick, formatTick ?? $xScale.tickFormat?.())}
|
|
37
37
|
/>
|
|
38
38
|
</g>
|
package/components/AxisY.svelte
CHANGED
|
@@ -46,7 +46,7 @@ $: tickVals = Array.isArray(ticks)
|
|
|
46
46
|
dy={dyTick}
|
|
47
47
|
textAnchor="end"
|
|
48
48
|
verticalAnchor="middle"
|
|
49
|
-
style="font-size: 10px;"
|
|
49
|
+
style="font-size: 10px; stroke: white; stroke-width: 2px;"
|
|
50
50
|
value={format(tick, formatTick ?? $yScale.tickFormat?.())}
|
|
51
51
|
/>
|
|
52
52
|
</g>
|
package/components/Bars.svelte
CHANGED
|
@@ -31,7 +31,6 @@ export let spring = undefined;
|
|
|
31
31
|
export let tweened = undefined;
|
|
32
32
|
// See: https://svelte.dev/repl/7000c5ce05b84cd98ccbfb2768b4be3d?version=3.38.3
|
|
33
33
|
export let groupBy = undefined;
|
|
34
|
-
// export let delay = 300;
|
|
35
34
|
// $: console.log({ $data, $flatData, groupBy, stackBy })
|
|
36
35
|
$: groupKeys = unique($flatData.map((d) => d[groupBy]));
|
|
37
36
|
$: x1Scale = scaleBand().domain(groupKeys).range([0, $xScale.bandwidth()]).paddingInner(0.2);
|
|
@@ -42,7 +41,7 @@ $: getDimensions = (item) => {
|
|
|
42
41
|
// const width = $xScale.bandwidth
|
|
43
42
|
// ? $xScale.bandwidth()
|
|
44
43
|
// : Math.max(0, $xGet(d)[1] - $xGet(d)[0]);
|
|
45
|
-
const width = (groupBy ? x1Scale.bandwidth() : $xScale.bandwidth()) + widthOffset;
|
|
44
|
+
const width = Math.max(0, (groupBy ? x1Scale.bandwidth() : $xScale.bandwidth()) + widthOffset);
|
|
46
45
|
const yValue = _y(item);
|
|
47
46
|
let yTop = 0;
|
|
48
47
|
let yBottom = 0;
|
package/components/Circle.svelte
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<script >import {
|
|
1
|
+
<script >import { createMotionStore } from '../stores/motionStore';
|
|
2
2
|
export let cx;
|
|
3
3
|
export let cy;
|
|
4
4
|
export let r;
|
|
5
5
|
export let spring = undefined;
|
|
6
6
|
export let tweened = undefined;
|
|
7
|
-
let tweened_cx =
|
|
8
|
-
let tweened_cy =
|
|
9
|
-
let tweened_r =
|
|
7
|
+
let tweened_cx = createMotionStore(cx, { spring, tweened });
|
|
8
|
+
let tweened_cy = createMotionStore(cy, { spring, tweened });
|
|
9
|
+
let tweened_r = createMotionStore(r, { spring, tweened });
|
|
10
10
|
$: tweened_cx.set(cx);
|
|
11
11
|
$: tweened_cy.set(cy);
|
|
12
12
|
$: tweened_r.set(r);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script >import { uniqueId } from 'svelte-ux/utils/string';
|
|
2
|
+
import ClipPath from './ClipPath.svelte';
|
|
3
|
+
import Circle from './Circle.svelte';
|
|
4
|
+
/** Unique id for clipPath */
|
|
5
|
+
export let id = uniqueId('clipPath-');
|
|
6
|
+
export let cx = 0;
|
|
7
|
+
export let cy = 0;
|
|
8
|
+
export let r;
|
|
9
|
+
export let spring = undefined;
|
|
10
|
+
export let tweened = undefined;
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<ClipPath {id}>
|
|
14
|
+
<Circle {cx} {cy} {r} {spring} {tweened} />
|
|
15
|
+
</ClipPath>
|
|
16
|
+
|
|
17
|
+
{#if $$slots.default}
|
|
18
|
+
<g style="clip-path: url(#{id})">
|
|
19
|
+
<slot {id} />
|
|
20
|
+
</g>
|
|
21
|
+
{/if}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
/** Unique id for clipPath */ id?: string;
|
|
6
|
+
cx?: number;
|
|
7
|
+
cy?: number;
|
|
8
|
+
r: number;
|
|
9
|
+
spring?: boolean | Parameters<typeof springStore>[1];
|
|
10
|
+
tweened?: boolean | Parameters<typeof tweenedStore>[1];
|
|
11
|
+
};
|
|
12
|
+
events: {
|
|
13
|
+
[evt: string]: CustomEvent<any>;
|
|
14
|
+
};
|
|
15
|
+
slots: {
|
|
16
|
+
default: {
|
|
17
|
+
id: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare type CircleClipPathProps = typeof __propDef.props;
|
|
22
|
+
export declare type CircleClipPathEvents = typeof __propDef.events;
|
|
23
|
+
export declare type CircleClipPathSlots = typeof __propDef.slots;
|
|
24
|
+
export default class CircleClipPath extends SvelteComponentTyped<CircleClipPathProps, CircleClipPathEvents, CircleClipPathSlots> {
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
[x: string]: any;
|
|
5
|
+
id?: string;
|
|
6
|
+
};
|
|
7
|
+
events: {
|
|
8
|
+
[evt: string]: CustomEvent<any>;
|
|
9
|
+
};
|
|
10
|
+
slots: {
|
|
11
|
+
default: {
|
|
12
|
+
id: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare type ClipPathProps = typeof __propDef.props;
|
|
17
|
+
export declare type ClipPathEvents = typeof __propDef.events;
|
|
18
|
+
export declare type ClipPathSlots = typeof __propDef.slots;
|
|
19
|
+
export default class ClipPath extends SvelteComponentTyped<ClipPathProps, ClipPathEvents, ClipPathSlots> {
|
|
20
|
+
}
|
|
21
|
+
export {};
|
package/components/Group.svelte
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script >import { getContext } from 'svelte';
|
|
2
|
+
import { createMotionStore } from '../stores/motionStore';
|
|
3
|
+
const { width, height } = getContext('LayerCake');
|
|
2
4
|
/**
|
|
3
5
|
* Translate x
|
|
4
6
|
*/
|
|
@@ -11,16 +13,21 @@ export let y = undefined;
|
|
|
11
13
|
* Center within chart
|
|
12
14
|
*/
|
|
13
15
|
export let center = false;
|
|
14
|
-
|
|
16
|
+
export let spring = undefined;
|
|
17
|
+
export let tweened = undefined;
|
|
18
|
+
let tweened_x = createMotionStore(x, { spring, tweened });
|
|
19
|
+
let tweened_y = createMotionStore(y, { spring, tweened });
|
|
20
|
+
$: tweened_x.set(x);
|
|
21
|
+
$: tweened_y.set(y);
|
|
15
22
|
let transform = undefined;
|
|
16
23
|
$: if (x != null || y != null) {
|
|
17
|
-
transform = `translate(${
|
|
24
|
+
transform = `translate(${$tweened_x ?? 0}, ${$tweened_y ?? 0})`;
|
|
18
25
|
}
|
|
19
26
|
$: if (center) {
|
|
20
27
|
transform = `translate(${$width / 2}, ${$height / 2})`;
|
|
21
28
|
}
|
|
22
29
|
</script>
|
|
23
30
|
|
|
24
|
-
<g {transform} {...$$restProps}>
|
|
31
|
+
<g {transform} {...$$restProps} on:click>
|
|
25
32
|
<slot />
|
|
26
33
|
</g>
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
|
|
2
3
|
declare const __propDef: {
|
|
3
4
|
props: {
|
|
4
5
|
[x: string]: any;
|
|
5
6
|
x?: number;
|
|
6
7
|
y?: number;
|
|
7
8
|
center?: boolean;
|
|
9
|
+
spring?: boolean | Parameters<typeof springStore>[1];
|
|
10
|
+
tweened?: boolean | Parameters<typeof tweenedStore>[1];
|
|
8
11
|
};
|
|
9
12
|
events: {
|
|
13
|
+
click: MouseEvent;
|
|
14
|
+
} & {
|
|
10
15
|
[evt: string]: CustomEvent<any>;
|
|
11
16
|
};
|
|
12
17
|
slots: {
|
package/components/Labels.svelte
CHANGED
package/components/Line.svelte
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
<script >import {
|
|
1
|
+
<script >import { createMotionStore } from '../stores/motionStore';
|
|
2
2
|
export let x1;
|
|
3
3
|
export let y1;
|
|
4
4
|
export let x2;
|
|
5
5
|
export let y2;
|
|
6
6
|
export let spring = undefined;
|
|
7
7
|
export let tweened = undefined;
|
|
8
|
-
let tweened_x1 =
|
|
9
|
-
let tweened_y1 =
|
|
10
|
-
let tweened_x2 =
|
|
11
|
-
let tweened_y2 =
|
|
8
|
+
let tweened_x1 = createMotionStore(x1, { spring, tweened });
|
|
9
|
+
let tweened_y1 = createMotionStore(y1, { spring, tweened });
|
|
10
|
+
let tweened_x2 = createMotionStore(x2, { spring, tweened });
|
|
11
|
+
let tweened_y2 = createMotionStore(y2, { spring, tweened });
|
|
12
12
|
$: tweened_x1.set(x1);
|
|
13
13
|
$: tweened_y1.set(y1);
|
|
14
14
|
$: tweened_x2.set(x2);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script >import { linkHorizontal } from 'd3-shape';
|
|
2
|
+
import { interpolatePath } from 'd3-interpolate-path';
|
|
3
|
+
import { createMotionStore } from '../stores/motionStore';
|
|
4
|
+
// Properties to override what is used from context
|
|
5
|
+
export let data = undefined; // TODO: Update Type
|
|
6
|
+
/**
|
|
7
|
+
* Update source and target accessors to be compatibke with d3-sankey. see: https://github.com/d3/d3-sankey#sankeyLinkHorizontal
|
|
8
|
+
*/
|
|
9
|
+
export let sankey = false;
|
|
10
|
+
export let source = sankey ? (d) => [d.source.x1, d.y0] : (d) => d.source;
|
|
11
|
+
export let target = sankey ? (d) => [d.target.x0, d.y1] : (d) => d.target;
|
|
12
|
+
export let tweened = undefined;
|
|
13
|
+
export let color = 'black';
|
|
14
|
+
export let width = undefined;
|
|
15
|
+
$: tweenedOptions = tweened ? { interpolate: interpolatePath, ...tweened } : false;
|
|
16
|
+
$: tweened_d = createMotionStore('', { tweened: tweenedOptions });
|
|
17
|
+
$: {
|
|
18
|
+
const link = linkHorizontal().source(source).target(target);
|
|
19
|
+
const d = link(data);
|
|
20
|
+
tweened_d.set(d);
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
|
25
|
+
<path
|
|
26
|
+
class="path-link"
|
|
27
|
+
d={$tweened_d}
|
|
28
|
+
stroke={color}
|
|
29
|
+
stroke-width={width}
|
|
30
|
+
fill="none"
|
|
31
|
+
on:click
|
|
32
|
+
on:mouseover
|
|
33
|
+
on:mouseout
|
|
34
|
+
{...$$restProps}
|
|
35
|
+
/>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { tweened as tweenedStore } from 'svelte/motion';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
[x: string]: any;
|
|
6
|
+
data?: any;
|
|
7
|
+
sankey?: boolean;
|
|
8
|
+
source?: (d: any) => any;
|
|
9
|
+
target?: (d: any) => any;
|
|
10
|
+
tweened?: boolean | Parameters<typeof tweenedStore>[1];
|
|
11
|
+
color?: string;
|
|
12
|
+
width?: any;
|
|
13
|
+
};
|
|
14
|
+
events: {
|
|
15
|
+
click: MouseEvent;
|
|
16
|
+
mouseover: MouseEvent;
|
|
17
|
+
mouseout: MouseEvent;
|
|
18
|
+
} & {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {};
|
|
22
|
+
};
|
|
23
|
+
export declare type LinkProps = typeof __propDef.props;
|
|
24
|
+
export declare type LinkEvents = typeof __propDef.events;
|
|
25
|
+
export declare type LinkSlots = typeof __propDef.slots;
|
|
26
|
+
export default class Link extends SvelteComponentTyped<LinkProps, LinkEvents, LinkSlots> {
|
|
27
|
+
}
|
|
28
|
+
export {};
|
package/components/Path.svelte
CHANGED
|
@@ -6,7 +6,7 @@ import { getContext } from 'svelte';
|
|
|
6
6
|
import { line as d3Line } from 'd3-shape';
|
|
7
7
|
// import { interpolateString } from 'd3-interpolate';
|
|
8
8
|
import { interpolatePath } from 'd3-interpolate-path';
|
|
9
|
-
import {
|
|
9
|
+
import { createMotionStore } from '../stores/motionStore';
|
|
10
10
|
const { data: contextData, xGet, yGet, zGet } = getContext('LayerCake');
|
|
11
11
|
// Properties to override what is used from context
|
|
12
12
|
export let data = undefined; // TODO: Update Type
|
|
@@ -19,7 +19,7 @@ export let defined = undefined;
|
|
|
19
19
|
export let color = 'black';
|
|
20
20
|
export let width = undefined;
|
|
21
21
|
$: tweenedOptions = tweened ? { interpolate: interpolatePath, ...tweened } : false;
|
|
22
|
-
$: tweened_d =
|
|
22
|
+
$: tweened_d = createMotionStore('', { tweened: tweenedOptions });
|
|
23
23
|
$: {
|
|
24
24
|
const path = d3Line()
|
|
25
25
|
.x(x ?? $xGet)
|
package/components/Pie.svelte
CHANGED
|
@@ -3,7 +3,7 @@ import { pie as d3pie } from 'd3-shape';
|
|
|
3
3
|
import Arc from './Arc.svelte';
|
|
4
4
|
import Group from './Group.svelte';
|
|
5
5
|
import { degreesToRadians } from '../utils/math';
|
|
6
|
-
import {
|
|
6
|
+
import { createMotionStore } from '../stores/motionStore';
|
|
7
7
|
/*
|
|
8
8
|
TODO:
|
|
9
9
|
- [ ] Offset (always, on hover)
|
|
@@ -48,7 +48,7 @@ export let tweened = undefined;
|
|
|
48
48
|
export let offset = 0;
|
|
49
49
|
const { data: contextData, x, y, xRange, rGet, config } = getContext('LayerCake');
|
|
50
50
|
$: resolved_endAngle = endAngle ?? degreesToRadians($config.xRange ? $xRange[1] : range[1]);
|
|
51
|
-
let tweened_endAngle =
|
|
51
|
+
let tweened_endAngle = createMotionStore(0, { spring, tweened });
|
|
52
52
|
$: tweened_endAngle.set(resolved_endAngle);
|
|
53
53
|
$: pie = d3pie()
|
|
54
54
|
.startAngle(startAngle ?? degreesToRadians($config.xRange ? $xRange[0] : range[0]))
|
package/components/Rect.svelte
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
<script >import {
|
|
2
|
-
export let x;
|
|
3
|
-
export let y;
|
|
1
|
+
<script >import { createMotionStore } from '../stores/motionStore';
|
|
2
|
+
export let x = 0;
|
|
3
|
+
export let y = 0;
|
|
4
4
|
export let width;
|
|
5
5
|
export let height;
|
|
6
6
|
export let spring = undefined;
|
|
7
7
|
export let tweened = undefined;
|
|
8
|
-
let tweened_x =
|
|
9
|
-
let tweened_y =
|
|
10
|
-
let tweened_width =
|
|
11
|
-
let tweened_height =
|
|
8
|
+
let tweened_x = createMotionStore(x, { spring, tweened });
|
|
9
|
+
let tweened_y = createMotionStore(y, { spring, tweened });
|
|
10
|
+
let tweened_width = createMotionStore(width, { spring, tweened });
|
|
11
|
+
let tweened_height = createMotionStore(height, { spring, tweened });
|
|
12
12
|
$: tweened_x.set(x);
|
|
13
13
|
$: tweened_y.set(y);
|
|
14
14
|
$: tweened_width.set(width);
|
|
15
15
|
$: tweened_height.set(height);
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
|
+
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
|
18
19
|
<rect
|
|
19
20
|
x={$tweened_x}
|
|
20
21
|
y={$tweened_y}
|
|
@@ -22,4 +23,6 @@ $: tweened_height.set(height);
|
|
|
22
23
|
height={$tweened_height}
|
|
23
24
|
{...$$restProps}
|
|
24
25
|
on:click
|
|
26
|
+
on:mouseover
|
|
27
|
+
on:mouseout
|
|
25
28
|
/>
|
|
@@ -3,8 +3,8 @@ import type { spring as springStore, tweened as tweenedStore } from 'svelte/moti
|
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
5
|
[x: string]: any;
|
|
6
|
-
x
|
|
7
|
-
y
|
|
6
|
+
x?: number;
|
|
7
|
+
y?: number;
|
|
8
8
|
width: number;
|
|
9
9
|
height: number;
|
|
10
10
|
spring?: boolean | Parameters<typeof springStore>[1];
|
|
@@ -12,6 +12,8 @@ declare const __propDef: {
|
|
|
12
12
|
};
|
|
13
13
|
events: {
|
|
14
14
|
click: MouseEvent;
|
|
15
|
+
mouseover: MouseEvent;
|
|
16
|
+
mouseout: MouseEvent;
|
|
15
17
|
} & {
|
|
16
18
|
[evt: string]: CustomEvent<any>;
|
|
17
19
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script >import { uniqueId } from 'svelte-ux/utils/string';
|
|
2
|
+
import ClipPath from './ClipPath.svelte';
|
|
3
|
+
import Rect from './Rect.svelte';
|
|
4
|
+
/** Unique id for clipPath */
|
|
5
|
+
export let id = uniqueId('clipPath-');
|
|
6
|
+
export let x = 0;
|
|
7
|
+
export let y = 0;
|
|
8
|
+
export let width;
|
|
9
|
+
export let height;
|
|
10
|
+
export let spring = undefined;
|
|
11
|
+
export let tweened = undefined;
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<ClipPath {id}>
|
|
15
|
+
<Rect {x} {y} {width} {height} {spring} {tweened} />
|
|
16
|
+
</ClipPath>
|
|
17
|
+
|
|
18
|
+
{#if $$slots.default}
|
|
19
|
+
<g style="clip-path: url(#{id})">
|
|
20
|
+
<slot {id} />
|
|
21
|
+
</g>
|
|
22
|
+
{/if}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
/** Unique id for clipPath */ id?: string;
|
|
6
|
+
x?: number;
|
|
7
|
+
y?: number;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
spring?: boolean | Parameters<typeof springStore>[1];
|
|
11
|
+
tweened?: boolean | Parameters<typeof tweenedStore>[1];
|
|
12
|
+
};
|
|
13
|
+
events: {
|
|
14
|
+
[evt: string]: CustomEvent<any>;
|
|
15
|
+
};
|
|
16
|
+
slots: {
|
|
17
|
+
default: {
|
|
18
|
+
id: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export declare type RectClipPathProps = typeof __propDef.props;
|
|
23
|
+
export declare type RectClipPathEvents = typeof __propDef.events;
|
|
24
|
+
export declare type RectClipPathSlots = typeof __propDef.slots;
|
|
25
|
+
export default class RectClipPath extends SvelteComponentTyped<RectClipPathProps, RectClipPathEvents, RectClipPathSlots> {
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script >// https://github.com/d3/d3-sankey
|
|
2
|
+
import { createEventDispatcher, getContext } from 'svelte';
|
|
3
|
+
import { sankey as d3Sankey, sankeyLeft, sankeyCenter, sankeyRight, sankeyJustify } from 'd3-sankey';
|
|
4
|
+
const dispatch = createEventDispatcher();
|
|
5
|
+
const { data, width, height, padding } = getContext('LayerCake');
|
|
6
|
+
export let nodes = (d) => d.nodes;
|
|
7
|
+
export let nodeId = (d) => d.index;
|
|
8
|
+
/**
|
|
9
|
+
* see: https://github.com/d3/d3-sankey#alignments
|
|
10
|
+
*/
|
|
11
|
+
export let nodeAlign = sankeyJustify;
|
|
12
|
+
export let nodeWidth = 4;
|
|
13
|
+
export let nodePadding = 10;
|
|
14
|
+
export let nodeSort = undefined;
|
|
15
|
+
export let links = (d) => d.links;
|
|
16
|
+
export let linkSort = undefined;
|
|
17
|
+
$: sankey = d3Sankey()
|
|
18
|
+
.size([$width, $height])
|
|
19
|
+
.nodes(nodes)
|
|
20
|
+
.nodeId(nodeId)
|
|
21
|
+
.nodeAlign(nodeAlign === 'left'
|
|
22
|
+
? sankeyLeft
|
|
23
|
+
: nodeAlign === 'center'
|
|
24
|
+
? sankeyCenter
|
|
25
|
+
: nodeAlign === 'right'
|
|
26
|
+
? sankeyRight
|
|
27
|
+
: nodeAlign === 'justify'
|
|
28
|
+
? sankeyJustify
|
|
29
|
+
: nodeAlign)
|
|
30
|
+
.nodeWidth(nodeWidth)
|
|
31
|
+
.nodePadding(nodePadding)
|
|
32
|
+
.nodeSort(nodeSort)
|
|
33
|
+
.links(links)
|
|
34
|
+
.linkSort(linkSort);
|
|
35
|
+
$: sankeyData = sankey($data);
|
|
36
|
+
$: dispatch('update', sankeyData);
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<slot nodes={sankeyData.nodes} links={sankeyData.links} />
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import { type SankeyNode } from 'd3-sankey';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
nodes?: (d: any) => any;
|
|
6
|
+
nodeId?: (d: any) => any;
|
|
7
|
+
/**
|
|
8
|
+
* see: https://github.com/d3/d3-sankey#alignments
|
|
9
|
+
*/ nodeAlign?: "center" | "left" | "right" | "justify" | ((node: SankeyNode<any, any>, n: number) => number);
|
|
10
|
+
nodeWidth?: number;
|
|
11
|
+
nodePadding?: number;
|
|
12
|
+
nodeSort?: any;
|
|
13
|
+
links?: (d: any) => any;
|
|
14
|
+
linkSort?: any;
|
|
15
|
+
};
|
|
16
|
+
events: {
|
|
17
|
+
update: CustomEvent<any>;
|
|
18
|
+
} & {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {
|
|
22
|
+
default: {
|
|
23
|
+
nodes: any;
|
|
24
|
+
links: any;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export declare type SankeyProps = typeof __propDef.props;
|
|
29
|
+
export declare type SankeyEvents = typeof __propDef.events;
|
|
30
|
+
export declare type SankeySlots = typeof __propDef.slots;
|
|
31
|
+
export default class Sankey extends SvelteComponentTyped<SankeyProps, SankeyEvents, SankeySlots> {
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<script >/**
|
|
2
|
+
* TODO:
|
|
3
|
+
* - [ ] Improve zoomable nested (apply extent ratio? const extentRatio = ($extents.y1 - $extents.y0) / $height;
|
|
4
|
+
*/
|
|
5
|
+
import { getContext } from 'svelte';
|
|
6
|
+
import { tweened } from 'svelte/motion';
|
|
7
|
+
import { cubicOut } from 'svelte/easing';
|
|
8
|
+
import * as d3 from 'd3-hierarchy';
|
|
9
|
+
import { scaleLinear } from 'd3-scale';
|
|
10
|
+
import { group } from 'd3-array';
|
|
11
|
+
import Group from './Group.svelte';
|
|
12
|
+
import RectClipPath from './RectClipPath.svelte';
|
|
13
|
+
import { aspectTile } from '../utils/treemap';
|
|
14
|
+
const { data, width, height } = getContext('LayerCake');
|
|
15
|
+
export let tile = d3.treemapSquarify;
|
|
16
|
+
export let padding = 0;
|
|
17
|
+
export let paddingInner = 0;
|
|
18
|
+
export let paddingOuter = 0;
|
|
19
|
+
export let paddingTop = 0;
|
|
20
|
+
export let paddingBottom = 0;
|
|
21
|
+
export let paddingLeft = undefined;
|
|
22
|
+
export let paddingRight = undefined;
|
|
23
|
+
export let selected = null;
|
|
24
|
+
$: tileFunc =
|
|
25
|
+
tile === 'squarify'
|
|
26
|
+
? d3.treemapSquarify
|
|
27
|
+
: tile === 'resquarify'
|
|
28
|
+
? d3.treemapResquarify
|
|
29
|
+
: tile === 'binary'
|
|
30
|
+
? d3.treemapBinary
|
|
31
|
+
: tile === 'dice'
|
|
32
|
+
? d3.treemapDice
|
|
33
|
+
: tile === 'slice'
|
|
34
|
+
? d3.treemapSlice
|
|
35
|
+
: tile === 'sliceDice'
|
|
36
|
+
? d3.treemapSliceDice
|
|
37
|
+
: tile;
|
|
38
|
+
$: treemap = d3.treemap().size([$width, $height]).tile(aspectTile(tileFunc, $width, $height));
|
|
39
|
+
$: if (padding) {
|
|
40
|
+
treemap.padding(padding);
|
|
41
|
+
}
|
|
42
|
+
$: if (paddingInner) {
|
|
43
|
+
treemap.paddingInner(paddingInner);
|
|
44
|
+
}
|
|
45
|
+
$: if (paddingOuter) {
|
|
46
|
+
treemap.paddingOuter(paddingOuter);
|
|
47
|
+
}
|
|
48
|
+
$: if (paddingTop) {
|
|
49
|
+
treemap.paddingTop(paddingTop);
|
|
50
|
+
}
|
|
51
|
+
$: if (paddingBottom) {
|
|
52
|
+
treemap.paddingBottom(paddingBottom);
|
|
53
|
+
}
|
|
54
|
+
$: if (paddingLeft) {
|
|
55
|
+
treemap.paddingLeft(paddingLeft);
|
|
56
|
+
}
|
|
57
|
+
$: if (paddingLeft) {
|
|
58
|
+
treemap.paddingRight(paddingRight);
|
|
59
|
+
}
|
|
60
|
+
$: root = treemap($data);
|
|
61
|
+
$: selected = root; // set initial selection
|
|
62
|
+
// group nodes by height so can be rendered lowest to highest
|
|
63
|
+
$: nodesByHeight = group(root, (d) => d.height);
|
|
64
|
+
const duration = 800;
|
|
65
|
+
const extents = tweened(undefined, { easing: cubicOut, duration });
|
|
66
|
+
$: $extents = selected
|
|
67
|
+
? {
|
|
68
|
+
x0: selected.x0,
|
|
69
|
+
y0: selected.y0,
|
|
70
|
+
x1: selected.x1,
|
|
71
|
+
y1: selected.y1
|
|
72
|
+
}
|
|
73
|
+
: {
|
|
74
|
+
x0: 0,
|
|
75
|
+
y0: 0,
|
|
76
|
+
x1: $width,
|
|
77
|
+
y1: $height
|
|
78
|
+
};
|
|
79
|
+
$: xScale = scaleLinear().domain([$extents.x0, $extents.x1]).rangeRound([0, $width]);
|
|
80
|
+
$: yScale = scaleLinear().domain([$extents.y0, $extents.y1]).rangeRound([0, $height]);
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<RectClipPath width={$width} height={$height}>
|
|
84
|
+
{#each Array.from(nodesByHeight) as [height, nodes]}
|
|
85
|
+
<g>
|
|
86
|
+
{#each nodes as node}
|
|
87
|
+
{@const nodeWidth = xScale(node.x1) - xScale(node.x0)}
|
|
88
|
+
{@const nodeHeight = yScale(node.y1) - yScale(node.y0)}
|
|
89
|
+
<Group x={xScale(node.x0)} y={yScale(node.y0)}>
|
|
90
|
+
<RectClipPath width={nodeWidth} height={nodeHeight}>
|
|
91
|
+
<slot
|
|
92
|
+
{node}
|
|
93
|
+
rect={{
|
|
94
|
+
x: 0, // applied by Group
|
|
95
|
+
y: 0, // applied by Group
|
|
96
|
+
width: nodeWidth,
|
|
97
|
+
height: nodeHeight
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
100
|
+
</RectClipPath>
|
|
101
|
+
</Group>
|
|
102
|
+
{/each}
|
|
103
|
+
</g>
|
|
104
|
+
{/each}
|
|
105
|
+
</RectClipPath>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import * as d3 from 'd3-hierarchy';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
tile?: typeof d3.treemapSquarify | 'binary' | 'squarify' | 'resquarify' | 'dice' | 'slice' | 'sliceDice';
|
|
6
|
+
padding?: number;
|
|
7
|
+
paddingInner?: number;
|
|
8
|
+
paddingOuter?: number;
|
|
9
|
+
paddingTop?: number;
|
|
10
|
+
paddingBottom?: number;
|
|
11
|
+
paddingLeft?: any;
|
|
12
|
+
paddingRight?: any;
|
|
13
|
+
selected?: any;
|
|
14
|
+
};
|
|
15
|
+
events: {
|
|
16
|
+
[evt: string]: CustomEvent<any>;
|
|
17
|
+
};
|
|
18
|
+
slots: {
|
|
19
|
+
default: {
|
|
20
|
+
node: d3.HierarchyRectangularNode<unknown>;
|
|
21
|
+
rect: {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
width: any;
|
|
25
|
+
height: any;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare type TreemapProps = typeof __propDef.props;
|
|
31
|
+
export declare type TreemapEvents = typeof __propDef.events;
|
|
32
|
+
export declare type TreemapSlots = typeof __propDef.slots;
|
|
33
|
+
export default class Treemap extends SvelteComponentTyped<TreemapProps, TreemapEvents, TreemapSlots> {
|
|
34
|
+
}
|
|
35
|
+
export {};
|
package/package.json
CHANGED
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
"author": "Sean Lynch <techniq35@gmail.com>",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": "techniq/layerchart",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.3.0",
|
|
7
7
|
"devDependencies": {
|
|
8
|
-
"@sveltejs/adapter-
|
|
8
|
+
"@sveltejs/adapter-vercel": "^1.0.0-next.47",
|
|
9
9
|
"@sveltejs/kit": "^1.0.0-next.303",
|
|
10
10
|
"@tailwindcss/typography": "^0.5.2",
|
|
11
11
|
"@types/d3-array": "^3.0.2",
|
|
12
|
+
"@types/d3-dsv": "^3.0.0",
|
|
13
|
+
"@types/d3-hierarchy": "^3.0.2",
|
|
14
|
+
"@types/d3-sankey": "^0.11.2",
|
|
12
15
|
"@types/d3-scale": "^4.0.2",
|
|
13
16
|
"@types/d3-shape": "^3.0.2",
|
|
14
17
|
"@types/lodash-es": "^4.17.6",
|
|
@@ -32,13 +35,17 @@
|
|
|
32
35
|
"dependencies": {
|
|
33
36
|
"@mdi/js": "^6.6.96",
|
|
34
37
|
"d3-array": "^3.1.1",
|
|
38
|
+
"d3-dsv": "^3.0.1",
|
|
39
|
+
"d3-hierarchy": "^3.1.2",
|
|
35
40
|
"d3-interpolate-path": "^2.2.3",
|
|
41
|
+
"d3-sankey": "^0.12.3",
|
|
36
42
|
"d3-scale": "^4.0.2",
|
|
43
|
+
"d3-scale-chromatic": "^3.0.0",
|
|
37
44
|
"d3-shape": "^3.1.0",
|
|
38
45
|
"date-fns": "^2.28.0",
|
|
39
46
|
"layercake": "^6.1.0",
|
|
40
47
|
"lodash-es": "^4.17.21",
|
|
41
|
-
"svelte-ux": "^0.
|
|
48
|
+
"svelte-ux": "^0.4.7"
|
|
42
49
|
},
|
|
43
50
|
"exports": {
|
|
44
51
|
"./package.json": "./package.json",
|
|
@@ -51,6 +58,8 @@
|
|
|
51
58
|
"./components/Baseline.svelte": "./components/Baseline.svelte",
|
|
52
59
|
"./components/Chart.svelte": "./components/Chart.svelte",
|
|
53
60
|
"./components/Circle.svelte": "./components/Circle.svelte",
|
|
61
|
+
"./components/CircleClipPath.svelte": "./components/CircleClipPath.svelte",
|
|
62
|
+
"./components/ClipPath.svelte": "./components/ClipPath.svelte",
|
|
54
63
|
"./components/ConnectedPoints.svelte": "./components/ConnectedPoints.svelte",
|
|
55
64
|
"./components/Group.svelte": "./components/Group.svelte",
|
|
56
65
|
"./components/HighlightLine.svelte": "./components/HighlightLine.svelte",
|
|
@@ -58,14 +67,18 @@
|
|
|
58
67
|
"./components/Labels.svelte": "./components/Labels.svelte",
|
|
59
68
|
"./components/Line.svelte": "./components/Line.svelte",
|
|
60
69
|
"./components/LinearGradient.svelte": "./components/LinearGradient.svelte",
|
|
70
|
+
"./components/Link.svelte": "./components/Link.svelte",
|
|
61
71
|
"./components/Path.svelte": "./components/Path.svelte",
|
|
62
72
|
"./components/Pattern.svelte": "./components/Pattern.svelte",
|
|
63
73
|
"./components/Pie.svelte": "./components/Pie.svelte",
|
|
64
74
|
"./components/Points.svelte": "./components/Points.svelte",
|
|
65
75
|
"./components/Rect.svelte": "./components/Rect.svelte",
|
|
76
|
+
"./components/RectClipPath.svelte": "./components/RectClipPath.svelte",
|
|
77
|
+
"./components/Sankey.svelte": "./components/Sankey.svelte",
|
|
66
78
|
"./components/Text.svelte": "./components/Text.svelte",
|
|
67
79
|
"./components/Threshold.svelte": "./components/Threshold.svelte",
|
|
68
80
|
"./components/Tooltip.svelte": "./components/Tooltip.svelte",
|
|
81
|
+
"./components/Treemap.svelte": "./components/Treemap.svelte",
|
|
69
82
|
"./components": "./components/index.js",
|
|
70
83
|
"./docs/Blockquote.svelte": "./docs/Blockquote.svelte",
|
|
71
84
|
"./docs/Code.svelte": "./docs/Code.svelte",
|
|
@@ -77,6 +90,7 @@
|
|
|
77
90
|
"./stores/motionStore": "./stores/motionStore.js",
|
|
78
91
|
"./utils/event": "./utils/event.js",
|
|
79
92
|
"./utils/genData": "./utils/genData.js",
|
|
93
|
+
"./utils/graph": "./utils/graph.js",
|
|
80
94
|
"./utils": "./utils/index.js",
|
|
81
95
|
"./utils/math": "./utils/math.js",
|
|
82
96
|
"./utils/path": "./utils/path.js",
|
|
@@ -84,7 +98,8 @@
|
|
|
84
98
|
"./utils/scales": "./utils/scales.js",
|
|
85
99
|
"./utils/stack": "./utils/stack.js",
|
|
86
100
|
"./utils/string": "./utils/string.js",
|
|
87
|
-
"./utils/ticks": "./utils/ticks.js"
|
|
101
|
+
"./utils/ticks": "./utils/ticks.js",
|
|
102
|
+
"./utils/treemap": "./utils/treemap.js"
|
|
88
103
|
},
|
|
89
104
|
"svelte": "./index.js"
|
|
90
105
|
}
|
package/stores/motionStore.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { spring, tweened } from 'svelte/motion';
|
|
2
2
|
/**
|
|
3
|
-
* Convenient wrapper to
|
|
3
|
+
* Convenient wrapper to create a motion store (spring(), tweened()) based on properties, or fall back to basic writable() store
|
|
4
4
|
*/
|
|
5
|
-
export declare function
|
|
5
|
+
export declare function createMotionStore(value: any, options: {
|
|
6
6
|
spring?: boolean | Parameters<typeof spring>[1];
|
|
7
7
|
tweened?: boolean | Parameters<typeof tweened>[1];
|
|
8
8
|
}): import("svelte/motion").Tweened<unknown> | import("svelte/motion").Spring<any> | import("svelte/store").Writable<any>;
|
package/stores/motionStore.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { writable } from 'svelte/store';
|
|
2
2
|
import { spring, tweened } from 'svelte/motion';
|
|
3
3
|
/**
|
|
4
|
-
* Convenient wrapper to
|
|
4
|
+
* Convenient wrapper to create a motion store (spring(), tweened()) based on properties, or fall back to basic writable() store
|
|
5
5
|
*/
|
|
6
|
-
export function
|
|
6
|
+
export function createMotionStore(value, options) {
|
|
7
7
|
if (options.spring) {
|
|
8
8
|
return spring(value, options.spring === true ? undefined : options.spring);
|
|
9
9
|
}
|
package/utils/graph.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SankeyGraph, SankeyNodeMinimal } from 'd3-sankey';
|
|
2
|
+
import type { hierarchy as d3Hierarchy } from 'd3-hierarchy';
|
|
3
|
+
/**
|
|
4
|
+
* Convert CSV rows in format: 'source,target,value' to SankeyGraph
|
|
5
|
+
*/
|
|
6
|
+
export declare function graphFromCsv(csv: string): SankeyGraph<any, any>;
|
|
7
|
+
/**
|
|
8
|
+
* Convert d3-hierarchy to graph (nodes/links)
|
|
9
|
+
*/
|
|
10
|
+
export declare function graphFromHierarchy(hierarchy: ReturnType<typeof d3Hierarchy>): {
|
|
11
|
+
nodes: import("d3-hierarchy").HierarchyNode<unknown>[];
|
|
12
|
+
links: {
|
|
13
|
+
value: number;
|
|
14
|
+
source: import("d3-hierarchy").HierarchyNode<unknown>;
|
|
15
|
+
target: import("d3-hierarchy").HierarchyNode<unknown>;
|
|
16
|
+
}[];
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Create graph from node (and target node/links downward)
|
|
20
|
+
*/
|
|
21
|
+
export declare function graphFromNode(node: SankeyNodeMinimal<any, any>): {
|
|
22
|
+
nodes: SankeyNodeMinimal<any, any>[];
|
|
23
|
+
links: any[];
|
|
24
|
+
};
|
package/utils/graph.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { csvParseRows } from 'd3-dsv';
|
|
2
|
+
/**
|
|
3
|
+
* Convert CSV rows in format: 'source,target,value' to SankeyGraph
|
|
4
|
+
*/
|
|
5
|
+
export function graphFromCsv(csv) {
|
|
6
|
+
const links = csvParseRows(csv, ([source, target, value /*, linkColor = color*/]) => source && target
|
|
7
|
+
? {
|
|
8
|
+
source,
|
|
9
|
+
target,
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
value: !value || isNaN((value = +value)) ? 1 : value
|
|
12
|
+
// color: linkColor,
|
|
13
|
+
}
|
|
14
|
+
: null);
|
|
15
|
+
const nodeByName = new Map();
|
|
16
|
+
for (const link of links) {
|
|
17
|
+
if (!nodeByName.has(link.source)) {
|
|
18
|
+
nodeByName.set(link.source, { name: link.source });
|
|
19
|
+
}
|
|
20
|
+
if (!nodeByName.has(link.target)) {
|
|
21
|
+
nodeByName.set(link.target, { name: link.target });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return { nodes: Array.from(nodeByName.values()), links };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert d3-hierarchy to graph (nodes/links)
|
|
28
|
+
*/
|
|
29
|
+
export function graphFromHierarchy(hierarchy) {
|
|
30
|
+
return {
|
|
31
|
+
nodes: hierarchy.descendants(),
|
|
32
|
+
links: hierarchy.links().map((link) => ({ ...link, value: link.target.value }))
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create graph from node (and target node/links downward)
|
|
37
|
+
*/
|
|
38
|
+
export function graphFromNode(node) {
|
|
39
|
+
const nodes = [node];
|
|
40
|
+
const links = [];
|
|
41
|
+
node.sourceLinks.forEach((link) => {
|
|
42
|
+
nodes.push(link.target);
|
|
43
|
+
links.push(link);
|
|
44
|
+
if (link.target.sourceLinks.length) {
|
|
45
|
+
const targetData = graphFromNode(link.target);
|
|
46
|
+
// Only add new nodes
|
|
47
|
+
targetData.nodes.forEach((node) => {
|
|
48
|
+
if (!nodes.includes(node)) {
|
|
49
|
+
nodes.push(node);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
targetData.links.forEach((link) => {
|
|
53
|
+
if (!links.includes(link)) {
|
|
54
|
+
links.push(link);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return { nodes, links };
|
|
60
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This custom tiling function adapts the built-in binary tiling function
|
|
3
|
+
* for the appropriate aspect ratio when the treemap is zoomed-in.
|
|
4
|
+
* see: https://observablehq.com/@d3/zoomable-treemap#tile and https://observablehq.com/@d3/stretched-treemap
|
|
5
|
+
*/
|
|
6
|
+
export declare function aspectTile(tile: any, width: any, height: any): (node: any, x0: any, y0: any, x1: any, y1: any) => void;
|
package/utils/treemap.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This custom tiling function adapts the built-in binary tiling function
|
|
3
|
+
* for the appropriate aspect ratio when the treemap is zoomed-in.
|
|
4
|
+
* see: https://observablehq.com/@d3/zoomable-treemap#tile and https://observablehq.com/@d3/stretched-treemap
|
|
5
|
+
*/
|
|
6
|
+
export function aspectTile(tile, width, height) {
|
|
7
|
+
return (node, x0, y0, x1, y1) => {
|
|
8
|
+
tile(node, 0, 0, width, height);
|
|
9
|
+
for (const child of node.children) {
|
|
10
|
+
child.x0 = x0 + (child.x0 / width) * (x1 - x0);
|
|
11
|
+
child.x1 = x0 + (child.x1 / width) * (x1 - x0);
|
|
12
|
+
child.y0 = y0 + (child.y0 / height) * (y1 - y0);
|
|
13
|
+
child.y1 = y0 + (child.y1 / height) * (y1 - y0);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|