layerchart 0.2.3 → 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.
@@ -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 { getMotionStore } from '../stores/motionStore';
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 = getMotionStore(value, { spring, tweened });
23
+ let tweened_value = createMotionStore(value, { spring, tweened });
24
24
  $: tweened_value.set(value);
25
25
  export let domain = [0, 100];
26
26
  /**
@@ -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 { getMotionStore } from '../stores/motionStore';
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 = getMotionStore('', { tweened: tweenedOptions });
21
+ $: tweened_d = createMotionStore('', { tweened: tweenedOptions });
22
22
  $: {
23
23
  const path = d3Area()
24
24
  .x(x ?? $xGet)
@@ -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;
@@ -1,12 +1,12 @@
1
- <script >import { getMotionStore } from '../stores/motionStore';
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 = getMotionStore(cx, { spring, tweened });
8
- let tweened_cy = getMotionStore(cy, { spring, tweened });
9
- let tweened_r = getMotionStore(r, { spring, tweened });
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,10 @@
1
+ <script >import { uniqueId } from 'svelte-ux/utils/string';
2
+ /** Unique id for clipPath */
3
+ export let id = uniqueId('clipPath-');
4
+ </script>
5
+
6
+ <defs>
7
+ <clipPath {id} {...$$restProps}>
8
+ <slot {id} />
9
+ </clipPath>
10
+ </defs>
@@ -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 {};
@@ -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
- const { width, height } = getContext('LayerCake');
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(${x ?? 0}, ${y ?? 0})`;
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: {
@@ -1,14 +1,14 @@
1
- <script >import { getMotionStore } from '../stores/motionStore';
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 = getMotionStore(x1, { spring, tweened });
9
- let tweened_y1 = getMotionStore(y1, { spring, tweened });
10
- let tweened_x2 = getMotionStore(x2, { spring, tweened });
11
- let tweened_y2 = getMotionStore(y2, { spring, tweened });
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 {};
@@ -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 { getMotionStore } from '../stores/motionStore';
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 = getMotionStore('', { tweened: tweenedOptions });
22
+ $: tweened_d = createMotionStore('', { tweened: tweenedOptions });
23
23
  $: {
24
24
  const path = d3Line()
25
25
  .x(x ?? $xGet)
@@ -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 { getMotionStore } from '../stores/motionStore';
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 = getMotionStore(0, { spring, tweened });
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]))
@@ -1,20 +1,21 @@
1
- <script >import { getMotionStore } from '../stores/motionStore';
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 = getMotionStore(x, { spring, tweened });
9
- let tweened_y = getMotionStore(y, { spring, tweened });
10
- let tweened_width = getMotionStore(width, { spring, tweened });
11
- let tweened_height = getMotionStore(height, { spring, tweened });
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: number;
7
- y: number;
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.2.3",
6
+ "version": "0.3.0",
7
7
  "devDependencies": {
8
- "@sveltejs/adapter-static": "^1.0.0-next.29",
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.3.2"
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
  }
@@ -1,8 +1,8 @@
1
1
  import { spring, tweened } from 'svelte/motion';
2
2
  /**
3
- * Convenient wrapper to get motion store based on properties, or fall back to basic writable() store
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 getMotionStore(value: any, options: {
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>;
@@ -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 get motion store based on properties, or fall back to basic writable() store
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 getMotionStore(value, options) {
6
+ export function createMotionStore(value, options) {
7
7
  if (options.spring) {
8
8
  return spring(value, options.spring === true ? undefined : options.spring);
9
9
  }
@@ -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;
@@ -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
+ }