layerchart 0.6.7 → 0.7.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,6 +15,7 @@
15
15
  import { getContext } from 'svelte';
16
16
  import { arc as d3arc } from 'd3-shape';
17
17
  import { scaleLinear } from 'd3-scale';
18
+ import { min, max } from 'd3-array';
18
19
  import { motionStore } from '../stores/motionStore';
19
20
  import { degreesToRadians } from '../utils/math';
20
21
  export let spring = undefined;
@@ -53,7 +54,7 @@ export let padAngle = 0;
53
54
  export let track = false;
54
55
  const { yRange } = getContext('LayerCake');
55
56
  $: scale = scaleLinear().domain(domain).range(range);
56
- $: _outerRadius = outerRadius ?? $yRange[0] / 2;
57
+ $: _outerRadius = outerRadius ?? max($yRange) / 2;
57
58
  $: _innerRadius =
58
59
  (innerRadius > 1
59
60
  ? innerRadius
@@ -61,7 +62,7 @@ $: _innerRadius =
61
62
  ? _outerRadius * innerRadius
62
63
  : innerRadius < 0
63
64
  ? _outerRadius - innerRadius
64
- : innerRadius) ?? $yRange[1];
65
+ : innerRadius) ?? min($yRange);
65
66
  $: arc = d3arc()
66
67
  .innerRadius(_innerRadius)
67
68
  .outerRadius(_outerRadius)
@@ -1,5 +1,6 @@
1
1
  <script>import { getContext } from 'svelte';
2
2
  import { area as d3Area } from 'd3-shape';
3
+ import { max } from 'd3-array';
3
4
  import { interpolatePath } from 'd3-interpolate-path';
4
5
  import { motionStore } from '../stores/motionStore';
5
6
  import Path from './Path.svelte';
@@ -22,7 +23,7 @@ $: tweened_d = motionStore('', { tweened: tweenedOptions });
22
23
  $: {
23
24
  const path = d3Area()
24
25
  .x(x ?? $xGet)
25
- .y0(y0 ?? $yRange[0])
26
+ .y0(y0 ?? max($yRange))
26
27
  .y1(y1 ?? $yGet);
27
28
  if (curve)
28
29
  path.curve(curve);
@@ -1,5 +1,6 @@
1
1
  <script>import { getContext } from 'svelte';
2
2
  import { format } from 'svelte-ux/utils/format';
3
+ import { max } from 'd3-array';
3
4
  import Text from './Text.svelte';
4
5
  import { isScaleBand } from '../utils/scales';
5
6
  const { height, xScale, yRange } = getContext('LayerCake');
@@ -20,7 +21,7 @@ $: tickVals = Array.isArray(ticks)
20
21
 
21
22
  <g class="axis x-axis">
22
23
  {#each tickVals as tick, i}
23
- <g class="tick tick-{tick}" transform="translate({$xScale(tick)},{$yRange[0]})">
24
+ <g class="tick tick-{tick}" transform="translate({$xScale(tick)},{max($yRange)})">
24
25
  {#if gridlines !== false}
25
26
  <line y1={$height * -1} y2="0" x1="0" x2="0" {...gridlines} />
26
27
  {/if}
@@ -2,7 +2,7 @@ import { SvelteComponentTyped } from "svelte";
2
2
  import type { FormatType } from 'svelte-ux/utils/format';
3
3
  declare const __propDef: {
4
4
  props: {
5
- gridlines?: boolean;
5
+ gridlines?: boolean | svelte.JSX.SVGProps<SVGLineElement>;
6
6
  formatTick?: FormatType;
7
7
  ticks?: any;
8
8
  xTick?: any;
@@ -1,5 +1,6 @@
1
1
  <script>import { getContext } from 'svelte';
2
2
  import { format } from 'svelte-ux/utils/format';
3
+ import { min } from 'd3-array';
3
4
  import Text from './Text.svelte';
4
5
  import { isScaleBand } from '../utils/scales';
5
6
  const { padding, xRange, yScale, width } = getContext('LayerCake');
@@ -20,7 +21,7 @@ $: tickVals = Array.isArray(ticks)
20
21
 
21
22
  <g class="axis y-axis" transform="translate({-$padding.left}, 0)">
22
23
  {#each tickVals as tick, i}
23
- <g class="tick tick-{tick}" transform="translate({$xRange[0]}, {$yScale(tick)})">
24
+ <g class="tick tick-{tick}" transform="translate({min($xRange)}, {$yScale(tick)})">
24
25
  {#if gridlines !== false}
25
26
  <line
26
27
  x1={$padding.left}
@@ -2,7 +2,7 @@ import { SvelteComponentTyped } from "svelte";
2
2
  import type { FormatType } from 'svelte-ux/utils/format';
3
3
  declare const __propDef: {
4
4
  props: {
5
- gridlines?: boolean;
5
+ gridlines?: boolean | svelte.JSX.SVGProps<SVGLineElement>;
6
6
  ticks?: number | Function;
7
7
  formatTick?: FormatType;
8
8
  xTick?: number;
@@ -58,11 +58,11 @@ $: getDimensions = (item) => {
58
58
  else if (yValue > 0) {
59
59
  // Positive value
60
60
  yTop = yValue;
61
- yBottom = $yRange[1]; // or `0`?
61
+ yBottom = min($yRange); // or `0`?
62
62
  }
63
63
  else {
64
64
  // Negative value
65
- yTop = $yRange[1]; // or `0`?
65
+ yTop = min($yRange); // or `0`?
66
66
  yBottom = yValue;
67
67
  }
68
68
  return {
@@ -1,4 +1,5 @@
1
1
  <script>import { getContext } from 'svelte';
2
+ import { min, max } from 'd3-array';
2
3
  const { xRange, yScale, yRange } = getContext('LayerCake');
3
4
  export let x = false;
4
5
  export let y = false;
@@ -6,11 +7,11 @@ export let y = false;
6
7
 
7
8
  <g class="baseline">
8
9
  {#if x}
9
- <line x1={0} x2={$xRange[1] || 0} y1={$yScale(0) || 0} y2={$yScale(0) || 0} class="baseline" />
10
+ <line x1={0} x2={max($xRange) || 0} y1={max($yRange)} y2={max($yRange)} class="baseline" />
10
11
  {/if}
11
12
 
12
13
  {#if y}
13
- <line x1={0} x2={0} y1={$yRange[0] || 0} y2={$yRange[1] || 0} class="baseline" />
14
+ <line x1={0} x2={0} y1={min($yRange) || 0} y2={max($yRange) || 0} class="baseline" />
14
15
  {/if}
15
16
  </g>
16
17
 
@@ -4,6 +4,7 @@ export { Svg, Html };
4
4
 
5
5
  <script>import { max, min } from 'd3-array';
6
6
  import { get } from 'lodash-es';
7
+ import { isScaleBand } from '../utils/scales';
7
8
  /**
8
9
  * Resolve a value from data based on the accessor type
9
10
  */
@@ -25,6 +26,7 @@ function getValue(accessor, d) {
25
26
  export let data = [];
26
27
  export let x;
27
28
  export let y;
29
+ export let yScale;
28
30
  /**
29
31
  * xBaseline guaranteed to be visible in xDomain
30
32
  */
@@ -43,8 +45,15 @@ $: if (yBaseline != null) {
43
45
  const yValues = data.flatMap((d) => getValue(y, d));
44
46
  yDomain = [min([yBaseline, ...yValues]), max([yBaseline, ...yValues])];
45
47
  }
48
+ /**
49
+ * Reverse the default y range ([0, height] becomes [height, 0]). By default this is `true` unless using scaleBand y scale.
50
+ * see: https://layercake.graphics/guide#yreverse
51
+ * see: https://github.com/mhkeller/layercake/issues/83
52
+
53
+ */
54
+ $: yReverse = yScale ? !isScaleBand(yScale) : true;
46
55
  </script>
47
56
 
48
- <LayerCake {data} {y} {yDomain} {x} {xDomain} {...$$restProps}>
57
+ <LayerCake {data} {x} {xDomain} {y} {yScale} {yDomain} {yReverse} {...$$restProps}>
49
58
  <slot />
50
59
  </LayerCake>
@@ -7,6 +7,7 @@ declare const __propDef: {
7
7
  data?: any[];
8
8
  x: (string | ((d: any) => number)) | (string | ((d: any) => number))[];
9
9
  y: (string | ((d: any) => number)) | (string | ((d: any) => number))[];
10
+ yScale: Function;
10
11
  xBaseline?: number | null;
11
12
  yBaseline?: number | null;
12
13
  };
@@ -3,7 +3,7 @@ declare const __propDef: {
3
3
  props: {
4
4
  data: any;
5
5
  color?: any;
6
- axis?: 'x' | 'y' | 'both';
6
+ axis?: 'x' | 'y' | 'both' | 'none';
7
7
  };
8
8
  events: {
9
9
  [evt: string]: CustomEvent<any>;
@@ -33,7 +33,7 @@ $: {
33
33
  }
34
34
  dimensions.x = xCoord - (isScaleBand($xScale) ? ($xScale.padding() * $xScale.step()) / 2 : 0);
35
35
  if (axis === 'x') {
36
- dimensions.height = $yRange[0];
36
+ dimensions.height = max($yRange);
37
37
  }
38
38
  }
39
39
  if (axis === 'y' || axis === 'both') {
@@ -55,7 +55,7 @@ $: {
55
55
  }
56
56
  dimensions.y = yCoord - (isScaleBand($yScale) ? ($yScale.padding() * $yScale.step()) / 2 : 0);
57
57
  if (axis === 'y') {
58
- dimensions.width = $xRange[1];
58
+ dimensions.width = max($xRange);
59
59
  }
60
60
  }
61
61
  }
@@ -46,11 +46,11 @@ $: getDimensions = (item) => {
46
46
  else if (yValue > 0) {
47
47
  // Positive value
48
48
  yTop = yValue;
49
- yBottom = $yRange[1]; // or `0`?
49
+ yBottom = min($yRange); // or `0`?
50
50
  }
51
51
  else {
52
52
  // Negative value
53
- yTop = $yRange[1]; // or `0`?
53
+ yTop = min($yRange); // or `0`?
54
54
  yBottom = yValue;
55
55
  }
56
56
  if (yBottom < 0) {
@@ -1,5 +1,6 @@
1
1
  <script>import { getContext } from 'svelte';
2
2
  import { pie as d3pie } from 'd3-shape';
3
+ import { min, max } from 'd3-array';
3
4
  import Arc from './Arc.svelte';
4
5
  import Group from './Group.svelte';
5
6
  import { degreesToRadians } from '../utils/math';
@@ -47,11 +48,11 @@ export let tweened = undefined;
47
48
  */
48
49
  export let offset = 0;
49
50
  const { data: contextData, x, y, xRange, rGet, config } = getContext('LayerCake');
50
- $: resolved_endAngle = endAngle ?? degreesToRadians($config.xRange ? $xRange[1] : range[1]);
51
+ $: resolved_endAngle = endAngle ?? degreesToRadians($config.xRange ? max($xRange) : max(range));
51
52
  let tweened_endAngle = motionStore(0, { spring, tweened });
52
53
  $: tweened_endAngle.set(resolved_endAngle);
53
54
  $: pie = d3pie()
54
- .startAngle(startAngle ?? degreesToRadians($config.xRange ? $xRange[0] : range[0]))
55
+ .startAngle(startAngle ?? degreesToRadians($config.xRange ? min($xRange) : min(range)))
55
56
  .endAngle($tweened_endAngle)
56
57
  .padAngle(padAngle)
57
58
  .value($x);
@@ -5,6 +5,7 @@ See also:
5
5
  */
6
6
  import { getContext } from 'svelte';
7
7
  import { area as d3Area, line as d3Line } from 'd3-shape';
8
+ import { max } from 'd3-array';
8
9
  const { data: contextData, xGet, yGet, yRange } = getContext('LayerCake');
9
10
  // Properties to override what is used from context
10
11
  export let data = undefined; // TODO: Update Type
@@ -25,14 +26,14 @@ $: if (defined)
25
26
  $: clipPathBelow = d3Area()
26
27
  .x(x ?? $xGet)
27
28
  .y0(y0 ?? ((d) => $yGet(d)[0]))
28
- .y1(y1 ?? ((d) => $yRange[0]));
29
+ .y1(y1 ?? ((d) => max($yRange)));
29
30
  $: if (curve)
30
31
  clipPathBelow.curve(curve);
31
32
  $: if (defined)
32
33
  clipPathBelow.defined(defined);
33
34
  $: clipPathAbove = d3Area()
34
35
  .x(x ?? $xGet)
35
- .y0(y0 ?? ((d) => $yRange[0]))
36
+ .y0(y0 ?? ((d) => max($yRange)))
36
37
  .y1(y1 ?? ((d) => $yGet(d)[1]));
37
38
  $: if (curve)
38
39
  clipPathAbove.curve(curve);
@@ -10,8 +10,9 @@ import ChartClipPath from './ChartClipPath.svelte';
10
10
  import { localPoint } from '../utils/event';
11
11
  import { isScaleBand, scaleInvert } from '../utils/scales';
12
12
  import { quadtreeRects } from '../utils/quadtree';
13
+ import { createPropertySortFunc, createSortFunc } from 'svelte-ux/utils/sort';
13
14
  const dispatch = createEventDispatcher();
14
- const { flatData, x, xScale, xGet, xRange, yScale, yGet, yRange, width, height, padding } = getContext('LayerCake');
15
+ const { flatData, x, xScale, xGet, xRange, y, yScale, yGet, yRange, width, height, padding } = getContext('LayerCake');
15
16
  /*
16
17
  TODO: Defaults to consider (if possible to detect scale type, which might not be possible)
17
18
  - scaleTime / scaleLinear: bisect
@@ -22,7 +23,7 @@ const { flatData, x, xScale, xGet, xRange, yScale, yGet, yRange, width, height,
22
23
  - scaleBand, scaleLinear: band (or bounds) - multiple (overlapping) bars
23
24
  - scaleLinear, scaleLinear: voronoi (or quadtree)
24
25
  */
25
- export let mode = 'bisect';
26
+ export let mode = 'bisect-x';
26
27
  export let snapToDataX = false;
27
28
  export let snapToDataY = false;
28
29
  export let findTooltipData = 'closest';
@@ -57,64 +58,109 @@ $: if (tooltip) {
57
58
  $left = tooltip.left + leftOffset;
58
59
  }
59
60
  }
61
+ $: bisectX = bisector((d) => {
62
+ const value = $x(d);
63
+ if (Array.isArray(value)) {
64
+ // `x` accessor with multiple properties (ex. `x={['start', 'end']})`)
65
+ // Using first value. Consider using average, max, etc
66
+ // const midpoint = new Date((value[1].valueOf() + value[0].getTime()) / 2);
67
+ // return midpoint;
68
+ return value[0];
69
+ }
70
+ else {
71
+ return value;
72
+ }
73
+ }).left;
74
+ $: bisectY = bisector((d) => {
75
+ const value = $y(d);
76
+ if (Array.isArray(value)) {
77
+ // `x` accessor with multiple properties (ex. `x={['start', 'end']})`)
78
+ // Using first value. Consider using average, max, etc
79
+ // const midpoint = new Date((value[1].valueOf() + value[0].getTime()) / 2);
80
+ // return midpoint;
81
+ return value[0];
82
+ }
83
+ else {
84
+ return value;
85
+ }
86
+ }).left;
87
+ function findData(previousValue, currentValue, valueAtPoint, accessor) {
88
+ switch (findTooltipData) {
89
+ case 'closest':
90
+ if (currentValue === undefined) {
91
+ return previousValue;
92
+ }
93
+ else if (previousValue === undefined) {
94
+ return currentValue;
95
+ }
96
+ else {
97
+ return Number(valueAtPoint) - Number(accessor(previousValue)) >
98
+ Number(accessor(currentValue)) - Number(valueAtPoint)
99
+ ? currentValue
100
+ : previousValue;
101
+ }
102
+ case 'left':
103
+ return previousValue;
104
+ case 'right':
105
+ default:
106
+ return currentValue;
107
+ }
108
+ }
60
109
  function handleTooltip(event, tooltipData) {
61
110
  const point = localPoint(event.target, event);
62
111
  const localX = point?.x ?? 0;
63
112
  const localY = point?.y ?? 0;
64
113
  // If tooltipData not provided already (voronoi, etc), attempt to find it
114
+ // TODO: When using bisect-x/y/band, values should be sorted. Tyipcally are for `x`, but not `y` (and band depends on if x or y scale)
65
115
  if (tooltipData == null) {
66
116
  if (mode === 'quadtree') {
67
117
  tooltipData = quadtree.find(localX, localY, radius);
68
118
  }
69
- else {
70
- // `x` value at mouse/touch coordinate
71
- const valueAtPoint = scaleInvert($xScale, localX);
119
+ else if (mode === 'bisect-band') {
120
+ // `x` and `y` values at mouse/touch coordinate
121
+ const xValueAtPoint = scaleInvert($xScale, localX);
122
+ const yValueAtPoint = scaleInvert($yScale, localY);
72
123
  if (isScaleBand($xScale)) {
73
- tooltipData = $flatData.find((d) => $x(d) === valueAtPoint);
124
+ // Find point closest to pointer within the x band
125
+ const bandData = $flatData
126
+ .filter((d) => $x(d) === xValueAtPoint)
127
+ .sort(createSortFunc($y)); // sort for bisect
128
+ const index = bisectY(bandData, yValueAtPoint, 1);
129
+ const previousValue = bandData[index - 1];
130
+ const currentValue = bandData[index];
131
+ tooltipData = findData(previousValue, currentValue, yValueAtPoint, $y);
132
+ }
133
+ else if (isScaleBand($yScale)) {
134
+ // Find point closest to pointer within the y band
135
+ const bandData = $flatData
136
+ .filter((d) => $y(d) === yValueAtPoint)
137
+ .sort(createSortFunc($x)); // sort for bisect
138
+ const index = bisectX(bandData, xValueAtPoint, 1);
139
+ const previousValue = bandData[index - 1];
140
+ const currentValue = bandData[index];
141
+ tooltipData = findData(previousValue, currentValue, xValueAtPoint, $x);
74
142
  }
75
143
  else {
76
- // continuous scale (linear, time, etc). Use bisector to find closest data to mouse location
77
- const bisectX = bisector((d) => {
78
- const value = $x(d);
79
- if (Array.isArray(value)) {
80
- // `x` accessor with multiple properties (ex. `x={['start', 'end']})`)
81
- // Using first value. Consider using average, max, etc
82
- // const midpoint = new Date((value[1].valueOf() + value[0].getTime()) / 2);
83
- // return midpoint;
84
- return value[0];
85
- }
86
- else {
87
- return value;
88
- }
89
- }).left;
90
- const index = bisectX($flatData, valueAtPoint, 1);
91
- const data0 = $flatData[index - 1];
92
- const data1 = $flatData[index];
93
- switch (findTooltipData) {
94
- case 'closest':
95
- if (data1 === undefined) {
96
- tooltipData = data0;
97
- }
98
- else if (data0 === undefined) {
99
- tooltipData = data1;
100
- }
101
- else {
102
- tooltipData =
103
- Number(valueAtPoint) - Number($x(data0)) >
104
- Number($x(data1)) - Number(valueAtPoint)
105
- ? data1
106
- : data0;
107
- }
108
- break;
109
- case 'left':
110
- tooltipData = data0;
111
- break;
112
- case 'right':
113
- default:
114
- tooltipData = data1;
115
- }
144
+ // TODO: Support `bisect-band` without band? Fallback to bisect?
116
145
  }
117
146
  }
147
+ else if (mode === 'bisect-x') {
148
+ // `x` value at mouse/touch coordinate
149
+ const xValueAtPoint = scaleInvert($xScale, localX);
150
+ const index = bisectX($flatData, xValueAtPoint, 1);
151
+ const previousValue = $flatData[index - 1];
152
+ const currentValue = $flatData[index];
153
+ console.log({ index, previousValue, currentValue });
154
+ tooltipData = findData(previousValue, currentValue, xValueAtPoint, $x);
155
+ }
156
+ else if (mode === 'bisect-y') {
157
+ // `y` value at mouse/touch coordinate
158
+ const yValueAtPoint = scaleInvert($yScale, localY);
159
+ const index = bisectY($flatData, yValueAtPoint, 1);
160
+ const previousValue = $flatData[index - 1];
161
+ const currentValue = $flatData[index];
162
+ tooltipData = findData(previousValue, currentValue, yValueAtPoint, $y);
163
+ }
118
164
  }
119
165
  if (tooltipData) {
120
166
  tooltip = {
@@ -143,7 +189,7 @@ $: if (mode === 'voronoi') {
143
189
  point.data = d;
144
190
  return point;
145
191
  });
146
- voronoi = Delaunay.from(points).voronoi([0, 0, $width, $height]);
192
+ voronoi = Delaunay.from(points).voronoi([0, 0, Math.max($width, 0), Math.max($height, 0)]); // width and/or height can sometimes be negative (when loading data remotely and updately)
147
193
  }
148
194
  let quadtree;
149
195
  $: if (mode === 'quadtree') {
@@ -182,7 +228,8 @@ $: if (mode === 'quadtree') {
182
228
  }
183
229
  let rects = [];
184
230
  $: if (mode === 'bounds' || mode === 'band') {
185
- rects = $flatData.map((d) => {
231
+ rects = $flatData
232
+ .map((d) => {
186
233
  const xValue = $xGet(d);
187
234
  const yValue = $yGet(d);
188
235
  const x = Array.isArray(xValue) ? min(xValue) : xValue;
@@ -219,7 +266,8 @@ $: if (mode === 'bounds' || mode === 'band') {
219
266
  data: d
220
267
  };
221
268
  }
222
- });
269
+ })
270
+ .sort(createPropertySortFunc('x'));
223
271
  // console.log({ rects });
224
272
  }
225
273
  </script>
@@ -246,7 +294,7 @@ $: if (mode === 'bounds' || mode === 'band') {
246
294
  </Svg>
247
295
  {/if}
248
296
 
249
- {#if mode === 'bisect' || mode === 'quadtree'}
297
+ {#if ['bisect-x', 'bisect-y', 'bisect-band', 'quadtree'].indexOf(mode) != -1}
250
298
  <Html>
251
299
  <div
252
300
  class="absolute"
@@ -266,7 +314,8 @@ $: if (mode === 'bounds' || mode === 'band') {
266
314
  <g class="tooltip-voronoi">
267
315
  <path
268
316
  d={voronoi.renderCell(i)}
269
- style:fill="transparent"
317
+ style:fill={debug ? 'red' : 'transparent'}
318
+ style:fill-opacity={debug ? 0.1 : 0}
270
319
  style:stroke={debug ? 'red' : 'transparent'}
271
320
  on:mousemove={(e) => handleTooltip(e, point.data)}
272
321
  on:mouseleave={hideTooltip}
@@ -283,7 +332,8 @@ $: if (mode === 'bounds' || mode === 'band') {
283
332
  y={rect.y}
284
333
  width={rect.width}
285
334
  height={rect.height}
286
- style:fill="transparent"
335
+ style:fill={debug ? 'red' : 'transparent'}
336
+ style:fill-opacity={debug ? 0.1 : 0}
287
337
  style:stroke={debug ? 'red' : 'transparent'}
288
338
  on:mousemove={(e) => handleTooltip(e, rect.data)}
289
339
  on:mouseleave={hideTooltip}
@@ -303,8 +353,9 @@ $: if (mode === 'bounds' || mode === 'band') {
303
353
  y={rect.y}
304
354
  width={rect.width}
305
355
  height={rect.height}
356
+ style:fill={debug ? 'red' : 'transparent'}
357
+ style:fill-opacity={debug ? 0.1 : 0}
306
358
  stroke="red"
307
- fill="none"
308
359
  />
309
360
  {/each}
310
361
  </g>
@@ -1,7 +1,7 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
2
  declare const __propDef: {
3
3
  props: {
4
- mode?: 'bisect' | 'voronoi' | 'quadtree' | 'bounds' | 'band';
4
+ mode?: 'bisect-x' | 'bisect-y' | 'band' | 'bisect-band' | 'bounds' | 'voronoi' | 'quadtree';
5
5
  snapToDataX?: boolean;
6
6
  snapToDataY?: boolean;
7
7
  findTooltipData?: 'closest' | 'left' | 'right';
package/package.json CHANGED
@@ -3,11 +3,11 @@
3
3
  "author": "Sean Lynch <techniq35@gmail.com>",
4
4
  "license": "MIT",
5
5
  "repository": "techniq/layerchart",
6
- "version": "0.6.7",
6
+ "version": "0.7.0",
7
7
  "devDependencies": {
8
8
  "@rollup/plugin-dsv": "^2.0.3",
9
- "@sveltejs/adapter-vercel": "^1.0.0-next.58",
10
- "@sveltejs/kit": "^1.0.0-next.350",
9
+ "@sveltejs/adapter-vercel": "^1.0.0-next.59",
10
+ "@sveltejs/kit": "^1.0.0-next.354",
11
11
  "@tailwindcss/typography": "^0.5.2",
12
12
  "@types/d3-array": "^3.0.3",
13
13
  "@types/d3-delaunay": "^6.0.1",
@@ -20,16 +20,16 @@
20
20
  "@types/lodash-es": "^4.17.6",
21
21
  "autoprefixer": "^10.4.7",
22
22
  "mdsvex": "^0.10.6",
23
- "prettier": "^2.6.2",
23
+ "prettier": "^2.7.1",
24
24
  "prettier-plugin-svelte": "^2.7.0",
25
25
  "prism-themes": "^1.9.0",
26
26
  "svelte": "^3.48.0",
27
27
  "svelte-check": "^2.7.2",
28
28
  "svelte-preprocess": "^4.10.7",
29
29
  "svelte2tsx": "^0.5.10",
30
- "tailwindcss": "^3.1.0",
30
+ "tailwindcss": "^3.1.4",
31
31
  "tslib": "^2.4.0",
32
- "typescript": "^4.7.3",
32
+ "typescript": "^4.7.4",
33
33
  "unist-util-visit": "^4.1.0",
34
34
  "vite-plugin-sveld": "^1.0.3"
35
35
  },
@@ -49,7 +49,7 @@
49
49
  "date-fns": "^2.28.0",
50
50
  "layercake": "^6.1.0",
51
51
  "lodash-es": "^4.17.21",
52
- "svelte-ux": "^0.5.1"
52
+ "svelte-ux": "^0.6.5"
53
53
  },
54
54
  "exports": {
55
55
  "./package.json": "./package.json",
package/utils/scales.d.ts CHANGED
@@ -3,7 +3,7 @@ import { MotionOptions } from '../stores/motionStore';
3
3
  /**
4
4
  * Implemenation for missing `scaleBand().invert()`
5
5
  *
6
- * See: https://stackoverflow.com/a/50846323/191902
6
+ * See: https://stackoverflow.com/questions/38633082/d3-getting-invert-value-of-band-scales
7
7
  * https://github.com/d3/d3-scale/pull/64
8
8
  * https://github.com/vega/vega-scale/blob/master/src/scaleBand.js#L118
9
9
  * https://observablehq.com/@d3/ordinal-brushing
package/utils/scales.js CHANGED
@@ -1,17 +1,18 @@
1
1
  import { derived } from 'svelte/store';
2
2
  import { tweened, spring } from 'svelte/motion';
3
+ import { min } from 'd3-array';
3
4
  import { motionStore } from '../stores/motionStore';
4
5
  /**
5
6
  * Implemenation for missing `scaleBand().invert()`
6
7
  *
7
- * See: https://stackoverflow.com/a/50846323/191902
8
+ * See: https://stackoverflow.com/questions/38633082/d3-getting-invert-value-of-band-scales
8
9
  * https://github.com/d3/d3-scale/pull/64
9
10
  * https://github.com/vega/vega-scale/blob/master/src/scaleBand.js#L118
10
11
  * https://observablehq.com/@d3/ordinal-brushing
11
12
  */
12
13
  export function scaleBandInvert(scale) {
13
14
  const domain = scale.domain();
14
- const paddingOuter = scale(domain[0]);
15
+ const paddingOuter = scale(min(domain));
15
16
  const eachBand = scale.step();
16
17
  return function (value) {
17
18
  // TODO: Should this use Math.round to better select? https://stackoverflow.com/questions/38633082/d3-getting-invert-value-of-band-scales/50846323#comment104743795_50846323