layerchart 0.17.2 → 0.18.1

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.
@@ -1,18 +1,25 @@
1
1
  <script>import { getContext } from 'svelte';
2
2
  import { format as formatValue, cls } from 'svelte-ux';
3
- import { max, min } from 'd3-array';
3
+ import { extent } from 'd3-array';
4
4
  import Text from './Text.svelte';
5
5
  import { isScaleBand } from '../utils/scales';
6
6
  const { xScale, yScale, xRange, yRange, width } = getContext('LayerCake');
7
+ /** Location of axis */
7
8
  export let placement;
9
+ /** Draw a rule line. Use Rule component for greater rendering order control */
10
+ export let rule = false;
11
+ /** Draw a grid lines */
12
+ export let grid = false;
8
13
  /** Control the number of ticks*/
9
14
  export let ticks = placement === 'left' || placement === 'right' ? 4 : undefined;
10
- export let gridlines = false;
15
+ /** Length of the tick line */
11
16
  export let tickSize = 4;
12
17
  export let format = undefined;
13
18
  export let labelProps = undefined;
14
19
  $: orientation = ['top', 'bottom'].includes(placement) ? 'horizontal' : 'vertical';
15
20
  $: scale = orientation === 'horizontal' ? $xScale : $yScale;
21
+ $: [xRangeMin, xRangeMax] = extent($xRange);
22
+ $: [yRangeMin, yRangeMax] = extent($yRange);
16
23
  $: tickVals = Array.isArray(ticks)
17
24
  ? ticks
18
25
  : isScaleBand(scale)
@@ -23,21 +30,21 @@ function getCoords(tick) {
23
30
  case 'top':
24
31
  return {
25
32
  x: $xScale(tick) + (isScaleBand($xScale) ? $xScale.bandwidth() / 2 : 0),
26
- y: min($yRange)
33
+ y: xRangeMin
27
34
  };
28
35
  case 'bottom':
29
36
  return {
30
37
  x: $xScale(tick) + (isScaleBand($xScale) ? $xScale.bandwidth() / 2 : 0),
31
- y: max($yRange)
38
+ y: yRangeMax
32
39
  };
33
40
  case 'left':
34
41
  return {
35
- x: min($xRange),
42
+ x: xRangeMin,
36
43
  y: $yScale(tick) + (isScaleBand($yScale) ? $yScale.bandwidth() / 2 : 0)
37
44
  };
38
45
  case 'right':
39
46
  return {
40
- x: max($xRange),
47
+ x: xRangeMax,
41
48
  y: $yScale(tick) + (isScaleBand($yScale) ? $yScale.bandwidth() / 2 : 0)
42
49
  };
43
50
  }
@@ -75,19 +82,44 @@ function getDefaultLabelProps() {
75
82
  </script>
76
83
 
77
84
  <g class="Axis placement-{placement}">
85
+ {#if rule !== false}
86
+ {@const lineProps = typeof rule === 'object' ? rule : null}
87
+ {#if orientation === 'vertical'}
88
+ <line
89
+ x1={placement === 'right' ? xRangeMax : xRangeMin}
90
+ x2={placement === 'right' ? xRangeMax : xRangeMin}
91
+ y1={$yRange[0] || 0}
92
+ y2={$yRange[1] || 0}
93
+ {...lineProps}
94
+ class={cls('rule stroke-gray-400', lineProps?.class)}
95
+ />
96
+ {/if}
97
+
98
+ {#if orientation === 'horizontal'}
99
+ <line
100
+ x1={$xRange[0] || 0}
101
+ x2={$xRange[1] || 0}
102
+ y1={placement === 'top' ? yRangeMin : yRangeMax}
103
+ y2={placement === 'top' ? yRangeMin : yRangeMax}
104
+ {...lineProps}
105
+ class={cls('rule stroke-gray-400', lineProps?.class)}
106
+ />
107
+ {/if}
108
+ {/if}
109
+
78
110
  {#each tickVals as tick, i}
79
111
  {@const tickCoords = getCoords(tick)}
80
112
  <g>
81
- {#if gridlines !== false}
82
- {@const lineProps = typeof gridlines === 'object' ? gridlines : null}
113
+ {#if grid !== false}
114
+ {@const lineProps = typeof grid === 'object' ? grid : null}
83
115
  {#if orientation === 'horizontal'}
84
116
  <line
85
117
  x1={tickCoords.x}
86
- y1={min($yRange)}
118
+ y1={yRangeMin}
87
119
  x2={tickCoords.x}
88
- y2={max($yRange)}
120
+ y2={yRangeMax}
89
121
  {...lineProps}
90
- class={cls('gridline stroke-gray-200', lineProps?.class)}
122
+ class={cls('grid stroke-gray-200', lineProps?.class)}
91
123
  />
92
124
  {:else if orientation === 'vertical'}
93
125
  <line
@@ -96,11 +128,12 @@ function getDefaultLabelProps() {
96
128
  x2={$width}
97
129
  y2={tickCoords.y}
98
130
  {...lineProps}
99
- class={cls('gridline stroke-gray-200', lineProps?.class)}
131
+ class={cls('grid stroke-gray-200', lineProps?.class)}
100
132
  />
101
133
  {/if}
102
134
  {/if}
103
135
 
136
+ <!-- Tick marks -->
104
137
  {#if orientation === 'horizontal'}
105
138
  <line
106
139
  x1={tickCoords.x}
@@ -5,10 +5,11 @@ import { type FormatType } from 'svelte-ux';
5
5
  import Text from './Text.svelte';
6
6
  declare const __propDef: {
7
7
  props: {
8
- placement: 'top' | 'bottom' | 'left' | 'right';
9
- /** Control the number of ticks*/ ticks?: number | Function | undefined;
10
- gridlines?: boolean | SVGAttributes<SVGLineElement> | undefined;
11
- tickSize?: number | undefined;
8
+ /** Location of axis */ placement: 'top' | 'bottom' | 'left' | 'right';
9
+ /** Draw a rule line. Use Rule component for greater rendering order control */ rule?: boolean | SVGAttributes<SVGLineElement> | undefined;
10
+ /** Draw a grid lines */ grid?: boolean | SVGAttributes<SVGLineElement> | undefined;
11
+ /** Control the number of ticks*/ ticks?: number | any[] | Function | undefined;
12
+ /** Length of the tick line */ tickSize?: number | undefined;
12
13
  format?: FormatType;
13
14
  labelProps?: ComponentProps<Text> | undefined;
14
15
  };
@@ -0,0 +1,14 @@
1
+ <script>import { getContext } from 'svelte';
2
+ const { width, height, padding } = getContext('LayerCake');
3
+ /** Include padding area */
4
+ export let full = false;
5
+ </script>
6
+
7
+ <rect
8
+ x={full ? -$padding.left : 0}
9
+ y={full ? -$padding.top : 0}
10
+ width={$width + (full ? $padding.left + $padding.right : 0)}
11
+ height={$height + (full ? $padding.top + $padding.bottom : 0)}
12
+ on:click
13
+ {...$$restProps}
14
+ />
@@ -0,0 +1,19 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ [x: string]: any;
5
+ full?: boolean | undefined;
6
+ };
7
+ events: {
8
+ click: MouseEvent;
9
+ } & {
10
+ [evt: string]: CustomEvent<any>;
11
+ };
12
+ slots: {};
13
+ };
14
+ export type FrameProps = typeof __propDef.props;
15
+ export type FrameEvents = typeof __propDef.events;
16
+ export type FrameSlots = typeof __propDef.slots;
17
+ export default class Frame extends SvelteComponentTyped<FrameProps, FrameEvents, FrameSlots> {
18
+ }
19
+ export {};
@@ -3,6 +3,7 @@ import { max, min } from 'd3-array';
3
3
  import { isScaleBand } from '../utils/scales';
4
4
  import Rect from './Rect.svelte';
5
5
  import { tooltipContext } from './TooltipContext.svelte';
6
+ import { firstValue } from '../utils/rect';
6
7
  const { flatData, x, xScale, xDomain, xRange, xGet, yScale, yDomain, yRange, yGet } = getContext('LayerCake');
7
8
  const tooltip = tooltipContext();
8
9
  export let axis = isScaleBand($yScale) ? 'y' : 'x';
@@ -14,8 +15,8 @@ let dimensions = {
14
15
  };
15
16
  $: {
16
17
  if ($tooltip.data) {
17
- let xCoord = $xGet($tooltip.data);
18
- let yCoord = $yGet($tooltip.data);
18
+ let xCoord = firstValue($xGet($tooltip.data));
19
+ let yCoord = firstValue($yGet($tooltip.data));
19
20
  if (axis === 'x' || axis === 'both') {
20
21
  if (isScaleBand($xScale)) {
21
22
  dimensions.width = $xScale.step();
@@ -103,17 +103,20 @@ else {
103
103
  <div
104
104
  class={cls(
105
105
  'inline-block',
106
- {
107
- 'top-left': 'absolute top-0 left-0',
108
- top: 'absolute top-0 left-1/2 -translate-x-1/2',
109
- 'top-right': 'absolute top-0 right-0',
110
- left: 'absolute top-1/2 left-0 -translate-y-1/2',
111
- center: 'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2',
112
- right: 'absolute top-1/2 right-0 -translate-y-1/2',
113
- 'bottom-left': 'absolute bottom-0 left-0',
114
- bottom: 'absolute bottom-0 left-1/2 -translate-x-1/2',
115
- 'bottom-right': 'absolute bottom-0 right-0'
116
- }[placement],
106
+ placement && [
107
+ 'absolute',
108
+ {
109
+ 'top-left': 'top-0 left-0',
110
+ top: 'top-0 left-1/2 -translate-x-1/2',
111
+ 'top-right': 'top-0 right-0',
112
+ left: 'top-1/2 left-0 -translate-y-1/2',
113
+ center: 'top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2',
114
+ right: 'top-1/2 right-0 -translate-y-1/2',
115
+ 'bottom-left': 'bottom-0 left-0',
116
+ bottom: 'bottom-0 left-1/2 -translate-x-1/2',
117
+ 'bottom-right': 'bottom-0 right-0'
118
+ }[placement]
119
+ ],
117
120
  classes.root
118
121
  )}
119
122
  {...$$restProps}
@@ -0,0 +1,48 @@
1
+ <script>import { getContext } from 'svelte';
2
+ import { cls } from 'svelte-ux';
3
+ import { extent } from 'd3-array';
4
+ import Line from './Line.svelte';
5
+ const { xScale, yScale, xRange, yRange } = getContext('LayerCake');
6
+ $: [xRangeMin, xRangeMax] = extent($xRange);
7
+ $: [yRangeMin, yRangeMax] = extent($yRange);
8
+ /**
9
+ * Create a vertical `x` line
10
+ * - If true or 'left', will draw at chart left (xRange[0])
11
+ * - If 'right', will draw at chart right (xRange[1])
12
+ * - Use `0` for baseline (yScale(0))
13
+ * - Use number | Date value for annotation (yScale(value))
14
+ */
15
+ export let x = false;
16
+ /**
17
+ * Create a horizontal `y` line
18
+ * - If true or 'bottom', will draw at chart bottom (yRange[0])
19
+ * - If 'top', will draw at chart top (yRange[1])
20
+ * - Use `0` for baseline (xScale(0))
21
+ * - Use number | Date value for annotation (xScale(value))
22
+ */
23
+ export let y = false;
24
+ </script>
25
+
26
+ <g class="rule">
27
+ {#if x !== false}
28
+ <Line
29
+ x1={x === true || x === 'left' ? xRangeMin : x === 'right' ? xRangeMax : $xScale(x)}
30
+ x2={x === true || x === 'left' ? xRangeMin : x === 'right' ? xRangeMax : $xScale(x)}
31
+ y1={$yRange[0] || 0}
32
+ y2={$yRange[1] || 0}
33
+ {...$$restProps}
34
+ class={cls('stroke-gray-400', $$props.class)}
35
+ />
36
+ {/if}
37
+
38
+ {#if y !== false}
39
+ <Line
40
+ x1={$xRange[0] || 0}
41
+ x2={$xRange[1] || 0}
42
+ y1={y === true || y === 'bottom' ? yRangeMax : y === 'top' ? yRangeMin : $yScale(y)}
43
+ y2={y === true || y === 'bottom' ? yRangeMax : y === 'top' ? yRangeMin : $yScale(y)}
44
+ {...$$restProps}
45
+ class={cls('stroke-gray-400', $$props.class)}
46
+ />
47
+ {/if}
48
+ </g>
@@ -0,0 +1,18 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ [x: string]: any;
5
+ x?: number | boolean | "left" | "right" | Date | undefined;
6
+ y?: number | boolean | "top" | "bottom" | Date | undefined;
7
+ };
8
+ events: {
9
+ [evt: string]: CustomEvent<any>;
10
+ };
11
+ slots: {};
12
+ };
13
+ export type RuleProps = typeof __propDef.props;
14
+ export type RuleEvents = typeof __propDef.events;
15
+ export type RuleSlots = typeof __propDef.slots;
16
+ export default class Rule extends SvelteComponentTyped<RuleProps, RuleEvents, RuleSlots> {
17
+ }
18
+ export {};
@@ -27,6 +27,7 @@ import { localPoint } from '../utils/event';
27
27
  import { isScaleBand, scaleInvert } from '../utils/scales';
28
28
  import { quadtreeRects } from '../utils/quadtree';
29
29
  import { createPropertySortFunc, createSortFunc } from 'svelte-ux/utils/sort';
30
+ import { firstValue } from '../utils/rect';
30
31
  const dispatch = createEventDispatcher();
31
32
  const { flatData, x, xScale, xGet, xRange, y, yScale, yGet, yRange, width, height, padding } = getContext('LayerCake');
32
33
  /*
@@ -237,8 +238,8 @@ let rects = [];
237
238
  $: if (mode === 'bounds' || mode === 'band') {
238
239
  rects = $flatData
239
240
  .map((d) => {
240
- const xValue = $xGet(d);
241
- const yValue = $yGet(d);
241
+ const xValue = firstValue($xGet(d));
242
+ const yValue = firstValue($yGet(d));
242
243
  const x = Array.isArray(xValue) ? min(xValue) : xValue;
243
244
  const y = Array.isArray(yValue) ? max(yValue) : yValue;
244
245
  const xOffset = isScaleBand($xScale) ? ($xScale.padding() * $xScale.step()) / 2 : 0;
@@ -3,7 +3,6 @@ export { default as Area } from './Area.svelte';
3
3
  export { default as AreaStack } from './AreaStack.svelte';
4
4
  export { default as Axis } from './Axis.svelte';
5
5
  export { default as Bars } from './Bars.svelte';
6
- export { default as Baseline } from './Baseline.svelte';
7
6
  export { default as Blur } from './Blur.svelte';
8
7
  export { default as Bounds } from './Bounds.svelte';
9
8
  export { default as Chart } from './Chart.svelte';
@@ -14,6 +13,7 @@ export { default as ClipPath } from './ClipPath.svelte';
14
13
  export { default as ClipPathUse } from './ClipPathUse.svelte';
15
14
  export { default as ColorRamp } from './ColorRamp.svelte';
16
15
  export { default as ConnectedPoints } from './ConnectedPoints.svelte';
16
+ export { default as Frame } from './Frame.svelte';
17
17
  export { default as GeoContext } from './GeoContext.svelte';
18
18
  export { default as GeoPath } from './GeoPath.svelte';
19
19
  export { default as GeoPoint } from './GeoPoint.svelte';
@@ -35,6 +35,7 @@ export { default as Pie } from './Pie.svelte';
35
35
  export { default as Points } from './Points.svelte';
36
36
  export { default as Rect } from './Rect.svelte';
37
37
  export { default as RectClipPath } from './RectClipPath.svelte';
38
+ export { default as Rule } from './Rule.svelte';
38
39
  export { default as Sankey } from './Sankey.svelte';
39
40
  export { default as Text } from './Text.svelte';
40
41
  export { default as Threshold } from './Threshold.svelte';
@@ -3,7 +3,6 @@ export { default as Area } from './Area.svelte';
3
3
  export { default as AreaStack } from './AreaStack.svelte';
4
4
  export { default as Axis } from './Axis.svelte';
5
5
  export { default as Bars } from './Bars.svelte';
6
- export { default as Baseline } from './Baseline.svelte';
7
6
  export { default as Blur } from './Blur.svelte';
8
7
  export { default as Bounds } from './Bounds.svelte';
9
8
  export { default as Chart } from './Chart.svelte';
@@ -14,6 +13,7 @@ export { default as ClipPath } from './ClipPath.svelte';
14
13
  export { default as ClipPathUse } from './ClipPathUse.svelte';
15
14
  export { default as ColorRamp } from './ColorRamp.svelte';
16
15
  export { default as ConnectedPoints } from './ConnectedPoints.svelte';
16
+ export { default as Frame } from './Frame.svelte';
17
17
  export { default as GeoContext } from './GeoContext.svelte';
18
18
  export { default as GeoPath } from './GeoPath.svelte';
19
19
  export { default as GeoPoint } from './GeoPoint.svelte';
@@ -35,6 +35,7 @@ export { default as Pie } from './Pie.svelte';
35
35
  export { default as Points } from './Points.svelte';
36
36
  export { default as Rect } from './Rect.svelte';
37
37
  export { default as RectClipPath } from './RectClipPath.svelte';
38
+ export { default as Rule } from './Rule.svelte';
38
39
  export { default as Sankey } from './Sankey.svelte';
39
40
  export { default as Text } from './Text.svelte';
40
41
  export { default as Threshold } from './Threshold.svelte';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { Svg, Html } from 'layercake';
2
- export * from './components/index.js';
3
- export * from './utils/index.js';
2
+ export * from './components';
3
+ export * from './utils';
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { Svg, Html } from 'layercake';
2
- export * from './components/index.js';
3
- export * from './utils/index.js';
2
+ export * from './components';
3
+ export * from './utils';
@@ -8,6 +8,15 @@ export declare function getRandomNumber(min: number, max: number): number;
8
8
  * see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random#getting_a_random_integer_between_two_values_inclusive
9
9
  */
10
10
  export declare function getRandomInteger(min: number, max: number, includeMax?: boolean): number;
11
+ export declare function createSeries(options: {
12
+ count?: number;
13
+ min: number;
14
+ max: number;
15
+ keys?: Array<string>;
16
+ value?: 'number' | 'integer';
17
+ }): {
18
+ x: number;
19
+ }[];
11
20
  export declare function createDateSeries(options: {
12
21
  count?: number;
13
22
  min: number;
@@ -16,6 +16,23 @@ export function getRandomInteger(min, max, includeMax = true) {
16
16
  max = Math.floor(max);
17
17
  return Math.floor(Math.random() * (max - min + (includeMax ? 1 : 0)) + min);
18
18
  }
19
+ export function createSeries(options) {
20
+ const count = options.count ?? 10;
21
+ const min = options.min;
22
+ const max = options.max;
23
+ const keys = options.keys ?? ['y'];
24
+ return Array.from({ length: count }).map((_, i) => {
25
+ return {
26
+ x: options.value === 'integer' ? getRandomInteger(min, max) : getRandomNumber(min, max),
27
+ ...Object.fromEntries(keys.map((key) => {
28
+ return [
29
+ key,
30
+ options.value === 'integer' ? getRandomInteger(min, max) : getRandomNumber(min, max)
31
+ ];
32
+ }))
33
+ };
34
+ });
35
+ }
19
36
  export function createDateSeries(options) {
20
37
  const now = startOfToday();
21
38
  const count = options.count ?? 10;
@@ -1,4 +1,4 @@
1
- import type { SankeyGraph, SankeyNodeMinimal } from 'd3-sankey';
1
+ import type { SankeyExtraProperties, SankeyGraph, SankeyLink, SankeyNodeMinimal } from 'd3-sankey';
2
2
  import type { hierarchy as d3Hierarchy } from 'd3-hierarchy';
3
3
  /**
4
4
  * Convert CSV rows in format: 'source,target,value' to SankeyGraph
@@ -22,3 +22,7 @@ export declare function graphFromNode(node: SankeyNodeMinimal<any, any>): {
22
22
  nodes: SankeyNodeMinimal<any, any>[];
23
23
  links: any[];
24
24
  };
25
+ /**
26
+ * Get distinct nodes from link.source and link.target
27
+ */
28
+ export declare function nodesFromLinks<N extends SankeyExtraProperties, L extends SankeyExtraProperties>(links: Array<SankeyLink<N, L>>): any[];
@@ -12,16 +12,7 @@ export function graphFromCsv(csv) {
12
12
  // color: linkColor,
13
13
  }
14
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 };
15
+ return { nodes: nodesFromLinks(links), links };
25
16
  }
26
17
  /**
27
18
  * Convert d3-hierarchy to graph (nodes/links)
@@ -58,3 +49,18 @@ export function graphFromNode(node) {
58
49
  });
59
50
  return { nodes, links };
60
51
  }
52
+ /**
53
+ * Get distinct nodes from link.source and link.target
54
+ */
55
+ export function nodesFromLinks(links) {
56
+ const nodesByName = new Map();
57
+ for (const link of links) {
58
+ if (!nodesByName.has(link.source)) {
59
+ nodesByName.set(link.source, { name: link.source });
60
+ }
61
+ if (!nodesByName.has(link.target)) {
62
+ nodesByName.set(link.target, { name: link.target });
63
+ }
64
+ }
65
+ return Array.from(nodesByName.values());
66
+ }
@@ -1,5 +1,5 @@
1
- export { graphFromCsv, graphFromHierarchy, graphFromNode } from './graph';
2
- export { findAncestor } from './hierarchy';
3
- export { degreesToRadians, radiansToDegrees } from './math';
4
- export { createStackData, stackOffsetSeparated } from './stack';
5
- export { getMajorTicks, getMinorTicks } from './ticks';
1
+ export * from './graph';
2
+ export * from './hierarchy';
3
+ export * from './math';
4
+ export * from './stack';
5
+ export * from './ticks';
@@ -1,5 +1,5 @@
1
- export { graphFromCsv, graphFromHierarchy, graphFromNode } from './graph';
2
- export { findAncestor } from './hierarchy';
3
- export { degreesToRadians, radiansToDegrees } from './math';
4
- export { createStackData, stackOffsetSeparated } from './stack';
5
- export { getMajorTicks, getMinorTicks } from './ticks';
1
+ export * from './graph';
2
+ export * from './hierarchy';
3
+ export * from './math';
4
+ export * from './stack';
5
+ export * from './ticks';
@@ -12,8 +12,18 @@ type DimensionGetterOptions = {
12
12
  };
13
13
  export declare function createDimensionGetter(context: any, options?: DimensionGetterOptions): import("svelte/store").Readable<(item: any) => {
14
14
  x: any;
15
+ y: number;
16
+ width: number;
17
+ height: number;
18
+ } | {
19
+ x: number;
15
20
  y: any;
16
21
  width: number;
17
22
  height: number;
18
23
  }>;
24
+ /**
25
+ * If value is an array, returns first item, else returns original value
26
+ * Useful when x/y getters for band scale are an array (such as for histograms)
27
+ */
28
+ export declare function firstValue(value: number | number[]): number;
19
29
  export {};
@@ -13,7 +13,7 @@ export function createDimensionGetter(context, options) {
13
13
  const y1Scale = groupBy
14
14
  ? groupScaleBand($yScale, $flatData, groupBy, options?.groupPadding)
15
15
  : null;
16
- const y = $yGet(item) + (y1Scale ? y1Scale(item[groupBy]) : 0) + padding / 2;
16
+ const y = firstValue($yGet(item)) + (y1Scale ? y1Scale(item[groupBy]) : 0) + padding / 2;
17
17
  const height = Math.max(0, $yScale.bandwidth ? (y1Scale ? y1Scale.bandwidth() : $yScale.bandwidth()) - padding : 0);
18
18
  const _x = options?.x
19
19
  ? typeof options.x === 'string'
@@ -55,7 +55,7 @@ export function createDimensionGetter(context, options) {
55
55
  const x1Scale = groupBy
56
56
  ? groupScaleBand($xScale, $flatData, groupBy, options?.groupPadding)
57
57
  : null;
58
- const x = $xGet(item) + (x1Scale ? x1Scale(item[groupBy]) : 0) + padding / 2;
58
+ const x = firstValue($xGet(item)) + (x1Scale ? x1Scale(item[groupBy]) : 0) + padding / 2;
59
59
  const width = Math.max(0, $xScale.bandwidth ? (x1Scale ? x1Scale.bandwidth() : $xScale.bandwidth()) - padding : 0);
60
60
  const _y = options?.y
61
61
  ? typeof options.y === 'string'
@@ -95,3 +95,10 @@ export function createDimensionGetter(context, options) {
95
95
  };
96
96
  });
97
97
  }
98
+ /**
99
+ * If value is an array, returns first item, else returns original value
100
+ * Useful when x/y getters for band scale are an array (such as for histograms)
101
+ */
102
+ export function firstValue(value) {
103
+ return Array.isArray(value) ? value[0] : value;
104
+ }
@@ -0,0 +1,11 @@
1
+ import { type ThresholdNumberArrayGenerator } from 'd3-array';
2
+ /**
3
+ * Useful threshold function when using Dates
4
+ * https://observablehq.com/@d3/d3-bin-time-thresholds
5
+ */
6
+ export declare function thresholdTime(n: number): ThresholdNumberArrayGenerator<number>;
7
+ /**
8
+ * Explicit threshold chunks without nicing (not recommended)
9
+ * see: https://observablehq.com/@d3/d3-bin#bin26
10
+ */
11
+ export declare function thresholdChunks(chunks: number): (data: number[], min: number, max: number) => number[];
@@ -0,0 +1,19 @@
1
+ import { range } from 'd3-array';
2
+ import { scaleTime } from 'd3-scale';
3
+ /**
4
+ * Useful threshold function when using Dates
5
+ * https://observablehq.com/@d3/d3-bin-time-thresholds
6
+ */
7
+ export function thresholdTime(n) {
8
+ // TODO: Unable to satifiy `ThresholdNumberArrayGenerator<Value extends number>` with `Date`
9
+ return (data, min, max) => {
10
+ return scaleTime().domain([min, max]).ticks(n);
11
+ };
12
+ }
13
+ /**
14
+ * Explicit threshold chunks without nicing (not recommended)
15
+ * see: https://observablehq.com/@d3/d3-bin#bin26
16
+ */
17
+ export function thresholdChunks(chunks) {
18
+ return (data, min, max) => range(chunks).map((t) => min + (t / chunks) * (max - min));
19
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "author": "Sean Lynch <techniq35@gmail.com>",
4
4
  "license": "MIT",
5
5
  "repository": "techniq/layerchart",
6
- "version": "0.17.2",
6
+ "version": "0.18.1",
7
7
  "scripts": {
8
8
  "dev": "vite dev",
9
9
  "build": "vite build",
@@ -13,13 +13,16 @@
13
13
  "check": "svelte-check --tsconfig ./tsconfig.json",
14
14
  "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
15
15
  "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. .",
16
- "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ."
16
+ "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. .",
17
+ "changeset": "changeset",
18
+ "version": "changeset version"
17
19
  },
18
20
  "devDependencies": {
19
21
  "@rollup/plugin-dsv": "^3.0.2",
20
22
  "@sveltejs/adapter-vercel": "^3.0.1",
21
- "@sveltejs/kit": "^1.20.5",
23
+ "@sveltejs/kit": "^1.22.0",
22
24
  "@sveltejs/package": "^2.1.0",
25
+ "@svitejs/changesets-changelog-github-compact": "^1.1.0",
23
26
  "@tailwindcss/typography": "^0.5.9",
24
27
  "@types/d3-array": "^3.0.5",
25
28
  "@types/d3-delaunay": "^6.0.1",
@@ -45,8 +48,8 @@
45
48
  "svelte-preprocess": "^5.0.4",
46
49
  "svelte2tsx": "^0.6.16",
47
50
  "tailwindcss": "^3.3.2",
48
- "tslib": "^2.5.3",
49
- "typescript": "^5.1.3",
51
+ "tslib": "^2.6.0",
52
+ "typescript": "^5.1.6",
50
53
  "unist-util-visit": "^4.1.2",
51
54
  "us-atlas": "^3.0.1",
52
55
  "vite": "^4.3.9",
@@ -54,6 +57,7 @@
54
57
  },
55
58
  "type": "module",
56
59
  "dependencies": {
60
+ "@changesets/cli": "^2.26.2",
57
61
  "@mdi/js": "^7.2.96",
58
62
  "@vercel/analytics": "^1.0.1",
59
63
  "d3-array": "^3.2.4",
@@ -75,7 +79,7 @@
75
79
  "lodash-es": "^4.17.21",
76
80
  "shapefile": "^0.6.6",
77
81
  "svelte": "^3.59.1",
78
- "svelte-ux": "^0.43.3",
82
+ "svelte-ux": "^0.43.5",
79
83
  "topojson-client": "^3.1.0"
80
84
  },
81
85
  "main": "./dist/index.js",
@@ -1,30 +0,0 @@
1
- <script>import { min, max } from 'd3-array';
2
- import { getContext } from 'svelte';
3
- import { cls } from 'svelte-ux';
4
- import { isScaleBand } from '../utils/scales';
5
- const { xScale, yScale, xRange, yRange } = getContext('LayerCake');
6
- export let x = false;
7
- export let y = false;
8
- </script>
9
-
10
- <g class="baseline">
11
- {#if x}
12
- <line
13
- x1={0}
14
- x2={max($xRange) || 0}
15
- y1={isScaleBand($yScale) ? max($yRange) : $yScale(0) || 0}
16
- y2={isScaleBand($yScale) ? max($yRange) : $yScale(0) || 0}
17
- class={cls('stroke-gray-400', $$props.class)}
18
- />
19
- {/if}
20
-
21
- {#if y}
22
- <line
23
- x1={isScaleBand($xScale) ? min($xRange) : $xScale(0) || 0}
24
- x2={isScaleBand($xScale) ? min($xRange) : $xScale(0) || 0}
25
- y1={min($yRange) || 0}
26
- y2={max($yRange) || 0}
27
- class={cls('stroke-gray-400', $$props.class)}
28
- />
29
- {/if}
30
- </g>
@@ -1,18 +0,0 @@
1
- import { SvelteComponentTyped } from "svelte";
2
- declare const __propDef: {
3
- props: {
4
- [x: string]: any;
5
- x?: boolean | undefined;
6
- y?: boolean | undefined;
7
- };
8
- events: {
9
- [evt: string]: CustomEvent<any>;
10
- };
11
- slots: {};
12
- };
13
- export type BaselineProps = typeof __propDef.props;
14
- export type BaselineEvents = typeof __propDef.events;
15
- export type BaselineSlots = typeof __propDef.slots;
16
- export default class Baseline extends SvelteComponentTyped<BaselineProps, BaselineEvents, BaselineSlots> {
17
- }
18
- export {};