layerchart 0.33.0 → 0.35.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.
@@ -18,7 +18,7 @@ export let grid = false;
18
18
  /** Control the number of ticks*/
19
19
  export let ticks = placement === 'left' || placement === 'right' ? 4 : undefined;
20
20
  /** Length of the tick line */
21
- export let tickSize = 4;
21
+ export let tickLength = 4;
22
22
  export let format = undefined;
23
23
  export let labelProps = undefined;
24
24
  export let spring = undefined;
@@ -38,9 +38,11 @@ $: [xRangeMin, xRangeMax] = extent($xRange);
38
38
  $: [yRangeMin, yRangeMax] = extent($yRange);
39
39
  $: tickVals = Array.isArray(ticks)
40
40
  ? ticks
41
- : isScaleBand(scale)
42
- ? scale.domain()
43
- : scale.ticks(typeof ticks === 'function' ? ticks(scale) : ticks);
41
+ : typeof ticks === 'function'
42
+ ? ticks(scale)
43
+ : isScaleBand(scale)
44
+ ? scale.domain()
45
+ : scale.ticks(ticks);
44
46
  function getCoords(tick) {
45
47
  switch (placement) {
46
48
  case 'top':
@@ -164,9 +166,22 @@ function getDefaultLabelProps(tick) {
164
166
  {/if}
165
167
  {/if}
166
168
 
167
- {#each tickVals as tick (tick)}
169
+ {#each tickVals as tick, index (tick)}
168
170
  {@const tickCoords = getCoords(tick)}
169
171
  {@const radialTickCoords = pointRadial(tickCoords.x, tickCoords.y)}
172
+ {@const textLabelProps = {
173
+ x: orientation === 'angle' ? radialTickCoords[0] : tickCoords.x,
174
+ y: orientation === 'angle' ? radialTickCoords[1] : tickCoords.y,
175
+ value: formatValue(tick, format ?? scale.tickFormat?.() ?? ((v) => v)),
176
+ ...getDefaultLabelProps(tick),
177
+ tweened,
178
+ spring,
179
+ ...labelProps,
180
+ class: cls(
181
+ 'label text-[10px] stroke-surface-100 [stroke-width:2px] font-light',
182
+ labelProps?.class
183
+ ),
184
+ }}
170
185
 
171
186
  <g in:transitionIn={transitionInParams}>
172
187
  {#if grid !== false}
@@ -222,7 +237,7 @@ function getDefaultLabelProps(tick) {
222
237
  x1={tickCoords.x}
223
238
  y1={tickCoords.y}
224
239
  x2={tickCoords.x}
225
- y2={tickCoords.y + (placement === 'top' ? -tickSize : tickSize)}
240
+ y2={tickCoords.y + (placement === 'top' ? -tickLength : tickLength)}
226
241
  {tweened}
227
242
  {spring}
228
243
  class="tick stroke-surface-content/50"
@@ -231,7 +246,7 @@ function getDefaultLabelProps(tick) {
231
246
  <Line
232
247
  x1={tickCoords.x}
233
248
  y1={tickCoords.y}
234
- x2={tickCoords.x + (placement === 'left' ? -tickSize : tickSize)}
249
+ x2={tickCoords.x + (placement === 'left' ? -tickLength : tickLength)}
235
250
  y2={tickCoords.y}
236
251
  {tweened}
237
252
  {spring}
@@ -239,19 +254,9 @@ function getDefaultLabelProps(tick) {
239
254
  />
240
255
  {/if}
241
256
 
242
- <Text
243
- x={orientation === 'angle' ? radialTickCoords[0] : tickCoords.x}
244
- y={orientation === 'angle' ? radialTickCoords[1] : tickCoords.y}
245
- value={formatValue(tick, format ?? scale.tickFormat?.() ?? ((v) => v))}
246
- {...getDefaultLabelProps(tick)}
247
- {tweened}
248
- {spring}
249
- {...labelProps}
250
- class={cls(
251
- 'label text-[10px] stroke-surface-100 [stroke-width:2px] font-light',
252
- labelProps?.class
253
- )}
254
- />
257
+ <slot name="label" labelProps={textLabelProps} {index}>
258
+ <Text {...textLabelProps} />
259
+ </slot>
255
260
  </g>
256
261
  {/each}
257
262
  </g>
@@ -11,7 +11,7 @@ declare const __propDef: {
11
11
  /** Draw a rule line. Use Rule component for greater rendering order control */ rule?: boolean | SVGAttributes<SVGLineElement> | undefined;
12
12
  /** Draw a grid lines */ grid?: boolean | SVGAttributes<SVGLineElement> | undefined;
13
13
  /** Control the number of ticks*/ ticks?: number | any[] | Function | undefined;
14
- /** Length of the tick line */ tickSize?: number | undefined;
14
+ /** Length of the tick line */ tickLength?: number | undefined;
15
15
  format?: FormatType | undefined;
16
16
  labelProps?: Partial<ComponentProps<Text>> | undefined;
17
17
  spring?: boolean | Parameters<typeof springStore>[1];
@@ -22,7 +22,12 @@ declare const __propDef: {
22
22
  events: {
23
23
  [evt: string]: CustomEvent<any>;
24
24
  };
25
- slots: {};
25
+ slots: {
26
+ label: {
27
+ labelProps: any;
28
+ index: any;
29
+ };
30
+ };
26
31
  };
27
32
  export type AxisProps = typeof __propDef.props;
28
33
  export type AxisEvents = typeof __propDef.events;
@@ -1,13 +1,15 @@
1
1
  <script>import { getContext } from 'svelte';
2
2
  import RectClipPath from './RectClipPath.svelte';
3
3
  const { width, height, padding } = getContext('LayerCake');
4
+ /** Whether clipping should include chart padding (ex. axis) */
5
+ export let includePadding = false;
4
6
  </script>
5
7
 
6
8
  <RectClipPath
7
- x={-$padding.left}
8
- y={-$padding.top}
9
- width={$width + $padding.left + $padding.right}
10
- height={$height + $padding.top + $padding.bottom}
9
+ x={includePadding ? -$padding.left : 0}
10
+ y={includePadding ? -$padding.top : 0}
11
+ width={$width + (includePadding ? $padding.left + $padding.right : 0)}
12
+ height={$height + (includePadding ? $padding.top + $padding.bottom : 0)}
11
13
  on:click
12
14
  {...$$restProps}
13
15
  >
@@ -2,6 +2,7 @@ import { SvelteComponentTyped } from "svelte";
2
2
  declare const __propDef: {
3
3
  props: {
4
4
  [x: string]: any;
5
+ includePadding?: boolean | undefined;
5
6
  };
6
7
  events: {
7
8
  click: CustomEvent<any>;
@@ -0,0 +1,49 @@
1
+ <script>import { getContext } from 'svelte';
2
+ import { forceSimulation } from 'd3-force';
3
+ const { data } = getContext('LayerCake');
4
+ export let forces;
5
+ export let alpha = 1;
6
+ export let alphaTarget = 0;
7
+ export let alphaDecay = 1 - Math.pow(0.001, 1 / 300);
8
+ export let alphaMin = 0.001;
9
+ export let velocityDecay = 0.4;
10
+ /** Clone data since simulation mutates original */
11
+ export let cloneData = false;
12
+ let _static = false;
13
+ /** If true, will only update nodes after simulation has completed */
14
+ export { _static as static };
15
+ let simulation = forceSimulation(cloneData ? structuredClone($data) : $data);
16
+ $: {
17
+ simulation
18
+ .alpha(alpha)
19
+ .alphaTarget(alphaTarget)
20
+ .alphaMin(alphaMin)
21
+ .alphaDecay(alphaDecay)
22
+ .velocityDecay(velocityDecay)
23
+ .restart();
24
+ if (_static) {
25
+ // TODO: Not sure why it needs to be recreated when static
26
+ simulation = forceSimulation(cloneData ? structuredClone($data) : $data);
27
+ simulation.stop();
28
+ Object.entries(forces).forEach(([name, force]) => {
29
+ simulation.force(name, force);
30
+ });
31
+ for (let i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) {
32
+ simulation.tick();
33
+ }
34
+ nodes = simulation.nodes();
35
+ }
36
+ else {
37
+ // When variables change, set forces and restart the simulation
38
+ Object.entries(forces).forEach(([name, force]) => {
39
+ simulation.force(name, force);
40
+ });
41
+ }
42
+ }
43
+ let nodes = [];
44
+ simulation.on('tick', () => {
45
+ nodes = simulation.nodes();
46
+ });
47
+ </script>
48
+
49
+ <slot {nodes} {simulation} />
@@ -0,0 +1,29 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ import { type Force } from 'd3-force';
3
+ declare const __propDef: {
4
+ props: {
5
+ forces: Record<string, Force<any, any>>;
6
+ alpha?: number | undefined;
7
+ alphaTarget?: number | undefined;
8
+ alphaDecay?: number | undefined;
9
+ alphaMin?: number | undefined;
10
+ velocityDecay?: number | undefined;
11
+ /** Clone data since simulation mutates original */ cloneData?: boolean | undefined;
12
+ /** If true, will only update nodes after simulation has completed */ static?: boolean | undefined;
13
+ };
14
+ events: {
15
+ [evt: string]: CustomEvent<any>;
16
+ };
17
+ slots: {
18
+ default: {
19
+ nodes: any[];
20
+ simulation: import("d3-force").Simulation<import("d3-force").SimulationNodeDatum, undefined>;
21
+ };
22
+ };
23
+ };
24
+ export type ForceSimulationProps = typeof __propDef.props;
25
+ export type ForceSimulationEvents = typeof __propDef.events;
26
+ export type ForceSimulationSlots = typeof __propDef.slots;
27
+ export default class ForceSimulation extends SvelteComponentTyped<ForceSimulationProps, ForceSimulationEvents, ForceSimulationSlots> {
28
+ }
29
+ export {};
@@ -9,4 +9,4 @@ export let precision = 6;
9
9
  $: geojson = geoCircle().radius(radius).center(center).precision(precision)();
10
10
  </script>
11
11
 
12
- <GeoPath {geojson} {...$$restProps} />
12
+ <GeoPath {geojson} {...$$restProps} on:mousemove on:mouseleave on:click />
@@ -7,6 +7,10 @@ declare const __propDef: {
7
7
  precision?: number | undefined;
8
8
  };
9
9
  events: {
10
+ mousemove: MouseEvent;
11
+ mouseleave: MouseEvent;
12
+ click: CustomEvent<any>;
13
+ } & {
10
14
  [evt: string]: CustomEvent<any>;
11
15
  };
12
16
  slots: {};
@@ -1,8 +1,10 @@
1
1
  <script>import { createEventDispatcher, getContext } from 'svelte';
2
- import { geoPath as d3geoPath } from 'd3-geo';
2
+ import {} from 'd3-geo';
3
3
  import { scaleCanvas } from 'layercake';
4
4
  import { cls } from 'svelte-ux';
5
5
  import { geoContext } from './GeoContext.svelte';
6
+ import { curveLinearClosed } from 'd3-shape';
7
+ import { geoCurvePath } from '../utils/geo.js';
6
8
  export let geojson;
7
9
  export let fill = undefined;
8
10
  export let stroke = undefined;
@@ -13,11 +15,21 @@ export let render = undefined;
13
15
  * Tooltip context to setup mouse events to show tooltip for related data
14
16
  */
15
17
  export let tooltip = undefined;
18
+ /**
19
+ * Curve of path drawn. Imported via d3-shape.
20
+ *
21
+ * @example
22
+ * import { curveCatmullRom } from 'd3-shape';
23
+ * <GeoPath curve={curveCatmullRom} />
24
+ *
25
+ * @type {CurveFactory | CurveFactoryLineOnly | undefined}
26
+ */
27
+ export let curve = curveLinearClosed;
16
28
  const dispatch = createEventDispatcher();
17
- const { rGet, width, height } = getContext('LayerCake');
29
+ const { width, height } = getContext('LayerCake');
18
30
  const canvas = getContext('canvas');
19
31
  const geo = geoContext();
20
- $: geoPath = d3geoPath($geo);
32
+ $: geoPath = geoCurvePath($geo, curve);
21
33
  $: renderContext = canvas ? 'canvas' : 'svg';
22
34
  $: ctx = canvas?.ctx;
23
35
  $: if (renderContext === 'canvas' && $ctx) {
@@ -25,12 +37,13 @@ $: if (renderContext === 'canvas' && $ctx) {
25
37
  scaleCanvas($ctx, $width, $height);
26
38
  $ctx.clearRect(0, 0, $width, $height);
27
39
  if (render) {
40
+ geoPath = geoCurvePath($geo, curve, $ctx);
28
41
  render($ctx, { geoPath });
29
42
  }
30
43
  else {
31
44
  $ctx.beginPath();
32
45
  // Set the context here since setting it in `$: geoPath` is a circular reference
33
- geoPath.context($ctx);
46
+ geoPath = geoCurvePath($geo, curve, $ctx);
34
47
  geoPath(geojson);
35
48
  $ctx.fillStyle = fill || 'transparent';
36
49
  $ctx.fill();
@@ -1,6 +1,7 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
- import { type GeoPath, type GeoPermissibleObjects } from 'd3-geo';
2
+ import { type GeoPermissibleObjects } from 'd3-geo';
3
3
  import type { TooltipContextValue } from './TooltipContext.svelte';
4
+ import { type CurveFactory, type CurveFactoryLineOnly } from 'd3-shape';
4
5
  declare const __propDef: {
5
6
  props: {
6
7
  [x: string]: any;
@@ -12,6 +13,7 @@ declare const __propDef: {
12
13
  geoPath: any;
13
14
  }) => any) | undefined;
14
15
  tooltip?: TooltipContextValue | undefined;
16
+ curve?: CurveFactory | CurveFactoryLineOnly | undefined;
15
17
  };
16
18
  events: {
17
19
  mousemove: MouseEvent;
@@ -22,7 +24,7 @@ declare const __propDef: {
22
24
  };
23
25
  slots: {
24
26
  default: {
25
- geoPath: GeoPath<any, GeoPermissibleObjects>;
27
+ geoPath: (object: GeoPermissibleObjects) => string | undefined;
26
28
  };
27
29
  };
28
30
  };
@@ -0,0 +1,12 @@
1
+ <script>import { geoContext } from './GeoContext.svelte';
2
+ import { isVisible } from '../utils/geo.js';
3
+ /** Latitude */
4
+ export let lat;
5
+ /** Longitude */
6
+ export let long;
7
+ const geo = geoContext();
8
+ </script>
9
+
10
+ {#if isVisible($geo)([long, lat])}
11
+ <slot />
12
+ {/if}
@@ -0,0 +1,19 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ /** Latitude */ lat: number;
5
+ /** Longitude */ long: number;
6
+ };
7
+ events: {
8
+ [evt: string]: CustomEvent<any>;
9
+ };
10
+ slots: {
11
+ default: {};
12
+ };
13
+ };
14
+ export type GeoVisibleProps = typeof __propDef.props;
15
+ export type GeoVisibleEvents = typeof __propDef.events;
16
+ export type GeoVisibleSlots = typeof __propDef.slots;
17
+ export default class GeoVisible extends SvelteComponentTyped<GeoVisibleProps, GeoVisibleEvents, GeoVisibleSlots> {
18
+ }
19
+ export {};
@@ -0,0 +1,53 @@
1
+ <script>import { createEventDispatcher, getContext } from 'svelte';
2
+ import { cls } from 'svelte-ux';
3
+ import { min } from 'd3-array';
4
+ import { Delaunay } from 'd3-delaunay';
5
+ import { geoVoronoi } from 'd3-geo-voronoi';
6
+ import GeoPath from './GeoPath.svelte';
7
+ import { geoContext } from './GeoContext.svelte';
8
+ import Spline from './Spline.svelte';
9
+ import { curveLinearClosed } from 'd3-shape';
10
+ const { flatData, x: xContext, y: yContext } = getContext('LayerCake');
11
+ const geo = geoContext();
12
+ /** Override data instead of using context */
13
+ export let data = undefined;
14
+ export let curve = curveLinearClosed;
15
+ export let classes = {};
16
+ const dispatch = createEventDispatcher();
17
+ $: points = (data ?? $flatData).map((d) => {
18
+ const xValue = $xContext(d);
19
+ const yValue = $yContext(d);
20
+ const x = Array.isArray(xValue) ? min(xValue) : xValue;
21
+ const y = Array.isArray(yValue) ? min(yValue) : yValue;
22
+ const point = [x, y];
23
+ point.data = d;
24
+ return point;
25
+ });
26
+ </script>
27
+
28
+ <g {...$$restProps} class={cls(classes.root, $$props.class)}>
29
+ {#if $geo}
30
+ {@const polygon = geoVoronoi().hull(points)}
31
+ <GeoPath
32
+ geojson={polygon}
33
+ {curve}
34
+ class={cls('fill-transparent', classes.path)}
35
+ on:mousemove={(e) => dispatch('mousemove', { event: e, points, polygon })}
36
+ on:mouseleave
37
+ on:click={(e) => dispatch('click', { points, polygon })}
38
+ />
39
+ {:else}
40
+ {@const delaunay = Delaunay.from(points)}
41
+ {@const polygon = delaunay.hullPolygon()}
42
+ <Spline
43
+ data={polygon}
44
+ x={(d) => d[0]}
45
+ y={(d) => d[1]}
46
+ {curve}
47
+ class={cls('fill-transparent', classes.path)}
48
+ on:mousemove={(e) => dispatch('mousemove', { event: e, points, polygon })}
49
+ on:mouseleave
50
+ on:click={(e) => dispatch('click', { points, polygon })}
51
+ />
52
+ {/if}
53
+ </g>
@@ -0,0 +1,36 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ import { type ComponentProps } from 'svelte';
3
+ import { Delaunay } from 'd3-delaunay';
4
+ import Spline from './Spline.svelte';
5
+ declare const __propDef: {
6
+ props: {
7
+ [x: string]: any;
8
+ data?: any;
9
+ curve?: ComponentProps<Spline>['curve'];
10
+ classes?: {
11
+ root?: string | undefined;
12
+ path?: string | undefined;
13
+ } | undefined;
14
+ };
15
+ events: {
16
+ mouseleave: MouseEvent;
17
+ click: CustomEvent<{
18
+ points: [number, number][];
19
+ polygon: Delaunay.Polygon;
20
+ }>;
21
+ mousemove: CustomEvent<{
22
+ event: MouseEvent;
23
+ points: [number, number][];
24
+ polygon: Delaunay.Polygon;
25
+ }>;
26
+ } & {
27
+ [evt: string]: CustomEvent<any>;
28
+ };
29
+ slots: {};
30
+ };
31
+ export type HullProps = typeof __propDef.props;
32
+ export type HullEvents = typeof __propDef.events;
33
+ export type HullSlots = typeof __propDef.slots;
34
+ export default class Hull extends SvelteComponentTyped<HullProps, HullEvents, HullSlots> {
35
+ }
36
+ export {};
@@ -14,7 +14,7 @@ export let ticks = width / 64;
14
14
  export let tickFormat = undefined;
15
15
  export let tickValues = undefined;
16
16
  export let tickFontSize = 10;
17
- export let tickSize = 4;
17
+ export let tickLength = 4;
18
18
  export let placement = undefined;
19
19
  export let classes = {};
20
20
  $: if (scale == null && rScale) {
@@ -96,7 +96,7 @@ else {
96
96
  tickValues = scale.domain();
97
97
  tickLabelOffset = xScale.bandwidth() / 2;
98
98
  tickLine = false;
99
- tickSize = 0;
99
+ tickLength = 0;
100
100
  }
101
101
  </script>
102
102
 
@@ -126,8 +126,8 @@ else {
126
126
  <slot values={tickValues} {scale}>
127
127
  <svg
128
128
  {width}
129
- height={height + tickSize + tickFontSize}
130
- viewBox="0 0 {width} {height + tickSize + tickFontSize}"
129
+ height={height + tickLength + tickFontSize}
130
+ viewBox="0 0 {width} {height + tickLength + tickFontSize}"
131
131
  class="overflow-visible"
132
132
  >
133
133
  <g>
@@ -145,7 +145,7 @@ else {
145
145
  <text
146
146
  text-anchor="middle"
147
147
  x={xScale(tick) + tickLabelOffset}
148
- y={height + tickSize + tickFontSize}
148
+ y={height + tickLength + tickFontSize}
149
149
  style:font-size={tickFontSize}
150
150
  class={cls('fill-surface-content', classes.label)}
151
151
  >
@@ -157,7 +157,7 @@ else {
157
157
  x1={xScale(tick)}
158
158
  y1={0}
159
159
  x2={xScale(tick)}
160
- y2={height + tickSize}
160
+ y2={height + tickLength}
161
161
  class={cls('stroke-surface-content', classes.tick)}
162
162
  />
163
163
  {/if}
@@ -11,7 +11,7 @@ declare const __propDef: {
11
11
  tickFormat?: FormatType | undefined;
12
12
  tickValues?: any[] | undefined;
13
13
  tickFontSize?: number | undefined;
14
- tickSize?: number | undefined;
14
+ tickLength?: number | undefined;
15
15
  placement?: ("center" | "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right") | undefined;
16
16
  classes?: {
17
17
  root?: string | undefined;
@@ -6,7 +6,9 @@ import Link from './Link.svelte';
6
6
  import { isScaleBand } from '../utils/scales.js';
7
7
  import { pointRadial } from 'd3-shape';
8
8
  const context = getContext('LayerCake');
9
- const { data, xGet, y, yGet, xScale, yScale, rGet, config } = context;
9
+ const { data: contextData, xGet, y, yGet, xScale, yScale, rGet, config } = context;
10
+ /** Override data instead of using context */
11
+ export let data = undefined;
10
12
  export let r = 5;
11
13
  export let offsetX = undefined;
12
14
  export let offsetY = undefined;
@@ -28,7 +30,8 @@ function getOffset(value, offset, scale) {
28
30
  return 0;
29
31
  }
30
32
  }
31
- $: points = $data.flatMap((d) => {
33
+ $: pointsData = data ?? $contextData;
34
+ $: points = pointsData.flatMap((d) => {
32
35
  if (Array.isArray($config.x)) {
33
36
  /*
34
37
  x={["prop1" ,"prop2"]}
@@ -71,7 +74,7 @@ $: points = $data.flatMap((d) => {
71
74
  };
72
75
  }
73
76
  });
74
- $: _links = $data.flatMap((d) => {
77
+ $: _links = pointsData.flatMap((d) => {
75
78
  if (Array.isArray($config.x)) {
76
79
  /*
77
80
  x={["prop1" ,"prop2"]}
@@ -2,6 +2,7 @@ import { SvelteComponentTyped } from "svelte";
2
2
  declare const __propDef: {
3
3
  props: {
4
4
  [x: string]: any;
5
+ data?: any;
5
6
  r?: number | undefined;
6
7
  offsetX?: number | ((value: number, context: any) => number) | undefined;
7
8
  offsetY?: number | ((value: number, context: any) => number) | undefined;
@@ -1,5 +1,4 @@
1
1
  <script>import { createEventDispatcher, getContext } from 'svelte';
2
- import { draw as _drawTransition } from 'svelte/transition';
3
2
  import { cls } from 'svelte-ux';
4
3
  import { min } from 'd3-array';
5
4
  import { Delaunay } from 'd3-delaunay';
@@ -2,6 +2,7 @@ export { default as Arc } from './Arc.svelte';
2
2
  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
+ export { default as Bar } from './Bar.svelte';
5
6
  export { default as Bars } from './Bars.svelte';
6
7
  export { default as Blur } from './Blur.svelte';
7
8
  export { default as Bounds } from './Bounds.svelte';
@@ -13,6 +14,7 @@ export { default as CircleClipPath } from './CircleClipPath.svelte';
13
14
  export { default as ClipPath } from './ClipPath.svelte';
14
15
  export { default as ColorRamp } from './ColorRamp.svelte';
15
16
  export { default as Frame } from './Frame.svelte';
17
+ export { default as ForceSimulation } from './ForceSimulation.svelte';
16
18
  export { default as GeoCircle } from './GeoCircle.svelte';
17
19
  export { default as GeoContext, geoContext } from './GeoContext.svelte';
18
20
  export { default as GeoEdgeFade } from './GeoEdgeFade.svelte';
@@ -20,9 +22,11 @@ export { default as GeoPath } from './GeoPath.svelte';
20
22
  export { default as GeoPoint } from './GeoPoint.svelte';
21
23
  export { default as GeoSpline } from './GeoSpline.svelte';
22
24
  export { default as GeoTile } from './GeoTile.svelte';
25
+ export { default as GeoVisible } from './GeoVisible.svelte';
23
26
  export { default as Graticule } from './Graticule.svelte';
24
27
  export { default as Group } from './Group.svelte';
25
28
  export { default as Highlight } from './Highlight.svelte';
29
+ export { default as Hull } from './Hull.svelte';
26
30
  export { default as Labels } from './Labels.svelte';
27
31
  export { default as Legend } from './Legend.svelte';
28
32
  export { default as Line } from './Line.svelte';
@@ -2,6 +2,7 @@ export { default as Arc } from './Arc.svelte';
2
2
  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
+ export { default as Bar } from './Bar.svelte';
5
6
  export { default as Bars } from './Bars.svelte';
6
7
  export { default as Blur } from './Blur.svelte';
7
8
  export { default as Bounds } from './Bounds.svelte';
@@ -13,6 +14,7 @@ export { default as CircleClipPath } from './CircleClipPath.svelte';
13
14
  export { default as ClipPath } from './ClipPath.svelte';
14
15
  export { default as ColorRamp } from './ColorRamp.svelte';
15
16
  export { default as Frame } from './Frame.svelte';
17
+ export { default as ForceSimulation } from './ForceSimulation.svelte';
16
18
  export { default as GeoCircle } from './GeoCircle.svelte';
17
19
  export { default as GeoContext, geoContext } from './GeoContext.svelte';
18
20
  export { default as GeoEdgeFade } from './GeoEdgeFade.svelte';
@@ -20,9 +22,11 @@ export { default as GeoPath } from './GeoPath.svelte';
20
22
  export { default as GeoPoint } from './GeoPoint.svelte';
21
23
  export { default as GeoSpline } from './GeoSpline.svelte';
22
24
  export { default as GeoTile } from './GeoTile.svelte';
25
+ export { default as GeoVisible } from './GeoVisible.svelte';
23
26
  export { default as Graticule } from './Graticule.svelte';
24
27
  export { default as Group } from './Group.svelte';
25
28
  export { default as Highlight } from './Highlight.svelte';
29
+ export { default as Hull } from './Hull.svelte';
26
30
  export { default as Labels } from './Labels.svelte';
27
31
  export { default as Legend } from './Legend.svelte';
28
32
  export { default as Line } from './Line.svelte';
@@ -1,20 +1,20 @@
1
- <script>import { onMount } from 'svelte';
2
- import * as d3shapes from 'd3-shape';
3
- import { MenuField } from 'svelte-ux';
4
- export let value = undefined;
5
- const options = Object.keys(d3shapes)
6
- .filter((key) => key.startsWith('curve'))
7
- .filter((key) => !key.endsWith('Open') && !key.endsWith('Closed'))
8
- .filter((key) => !key.includes('Bundle')) // Not compatibile with area
9
- .map((key) => {
1
+ <script>import * as d3shapes from 'd3-shape';
2
+ import { MenuField, entries } from 'svelte-ux';
3
+ export let value = d3shapes['curveLinear'];
4
+ export let showOpenClosed = false;
5
+ const options = entries(d3shapes)
6
+ .filter(([key]) => {
7
+ return (key.startsWith('curve') &&
8
+ (showOpenClosed ? true : !key.endsWith('Open') && !key.endsWith('Closed')) &&
9
+ !key.includes('Bundle') // Not compatibile with area
10
+ );
11
+ })
12
+ .map(([key, value]) => {
10
13
  return {
11
14
  label: key.replace('curve', ''),
12
- value: d3shapes[key]
15
+ value: value,
13
16
  };
14
17
  });
15
- onMount(() => {
16
- value = d3shapes['curveLinear'];
17
- });
18
18
  </script>
19
19
 
20
20
  <MenuField label="Curve" {options} bind:value stepper classes={{ menuIcon: 'hidden' }} />
@@ -2,6 +2,7 @@ import { SvelteComponentTyped } from "svelte";
2
2
  declare const __propDef: {
3
3
  props: {
4
4
  value?: any | undefined;
5
+ showOpenClosed?: boolean | undefined;
5
6
  };
6
7
  events: {
7
8
  [evt: string]: CustomEvent<any>;
@@ -1,5 +1,18 @@
1
+ import { type GeoPermissibleObjects, type GeoProjection, type GeoStreamWrapper } from 'd3-geo';
2
+ import { type Path } from 'd3-path';
3
+ import { type CurveFactory, type CurveFactoryLineOnly } from 'd3-shape';
4
+ /**
5
+ * Render a geoPath() using curve factory
6
+ * @see {@link https://observablehq.com/@d3/context-to-curve}
7
+ */
8
+ export declare function geoCurvePath(projection: GeoProjection | GeoStreamWrapper | null, curve: CurveFactory | CurveFactoryLineOnly, context?: CanvasRenderingContext2D | Path): (object: GeoPermissibleObjects) => string | undefined;
1
9
  /**
2
10
  * Return the point on Earth's surface that is diametrically opposite to another point
3
11
  * @see: https://en.wikipedia.org/wiki/Antipodes
4
12
  */
5
13
  export declare function antipode([longitude, latitude]: [number, number]): [number, number];
14
+ /**
15
+ * Check if point ([x, y]) is visible on projection
16
+ * @see: https://observablehq.com/@d3/testing-projection-visibility
17
+ */
18
+ export declare function isVisible(projection: GeoProjection | GeoStreamWrapper): ([x, y]: [any, any]) => boolean;
package/dist/utils/geo.js CHANGED
@@ -1,3 +1,44 @@
1
+ import { geoPath as d3geoPath, } from 'd3-geo';
2
+ import { path } from 'd3-path';
3
+ import {} from 'd3-shape';
4
+ /**
5
+ * Render a geoPath() using curve factory
6
+ * @see {@link https://observablehq.com/@d3/context-to-curve}
7
+ */
8
+ export function geoCurvePath(projection, curve, context) {
9
+ const pathContext = context === undefined ? path() : context;
10
+ const geoPath = d3geoPath(projection, curveContext(curve(pathContext)));
11
+ const fn = (object) => {
12
+ geoPath(object);
13
+ return context === undefined ? pathContext + '' : undefined;
14
+ };
15
+ // Expose geoPath properties such as `.centroid()`
16
+ Object.setPrototypeOf(fn, geoPath);
17
+ return fn;
18
+ }
19
+ /**
20
+ * Translate Curve to GeoContext interface
21
+ */
22
+ function curveContext(curve) {
23
+ return {
24
+ beginPath() {
25
+ // nothing?
26
+ },
27
+ moveTo(x, y) {
28
+ curve.lineStart();
29
+ curve.point(x, y);
30
+ },
31
+ arc(x, y, radius, startAngle, endAngle, anticlockwise) {
32
+ // nothing?
33
+ },
34
+ lineTo(x, y) {
35
+ curve.point(x, y);
36
+ },
37
+ closePath() {
38
+ curve.lineEnd();
39
+ },
40
+ };
41
+ }
1
42
  /**
2
43
  * Return the point on Earth's surface that is diametrically opposite to another point
3
44
  * @see: https://en.wikipedia.org/wiki/Antipodes
@@ -5,3 +46,16 @@
5
46
  export function antipode([longitude, latitude]) {
6
47
  return [longitude + 180, -latitude];
7
48
  }
49
+ /**
50
+ * Check if point ([x, y]) is visible on projection
51
+ * @see: https://observablehq.com/@d3/testing-projection-visibility
52
+ */
53
+ export function isVisible(projection) {
54
+ let visible;
55
+ const stream = projection.stream({
56
+ point() {
57
+ visible = true;
58
+ },
59
+ });
60
+ return ([x, y]) => ((visible = false), stream.point(x, y), visible);
61
+ }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "author": "Sean Lynch <techniq35@gmail.com>",
5
5
  "license": "MIT",
6
6
  "repository": "techniq/layerchart",
7
- "version": "0.33.0",
7
+ "version": "0.35.0",
8
8
  "devDependencies": {
9
9
  "@changesets/cli": "^2.27.1",
10
10
  "@mdi/js": "^7.4.47",
@@ -17,6 +17,7 @@
17
17
  "@types/d3-array": "^3.2.1",
18
18
  "@types/d3-delaunay": "^6.0.4",
19
19
  "@types/d3-dsv": "^3.0.7",
20
+ "@types/d3-force": "^3.0.9",
20
21
  "@types/d3-geo": "^3.1.0",
21
22
  "@types/d3-hierarchy": "^3.1.6",
22
23
  "@types/d3-interpolate": "^3.0.4",
@@ -32,6 +33,7 @@
32
33
  "@types/prismjs": "^1.26.3",
33
34
  "@types/shapefile": "^0.6.4",
34
35
  "@types/topojson-client": "^3.1.4",
36
+ "@types/topojson-simplify": "^3.0.3",
35
37
  "autoprefixer": "^10.4.18",
36
38
  "execa": "^8.0.1",
37
39
  "marked": "^12.0.1",
@@ -52,6 +54,7 @@
52
54
  "svelte2tsx": "^0.7.4",
53
55
  "tailwindcss": "^3.4.1",
54
56
  "topojson-client": "^3.1.0",
57
+ "topojson-simplify": "^3.0.3",
55
58
  "tslib": "^2.6.2",
56
59
  "typescript": "^5.4.2",
57
60
  "unist-util-visit": "^5.0.0",
@@ -65,11 +68,13 @@
65
68
  "d3-color": "^3.1.0",
66
69
  "d3-delaunay": "^6.0.4",
67
70
  "d3-dsv": "^3.0.1",
71
+ "d3-force": "^3.0.0",
68
72
  "d3-geo": "^3.1.1",
69
73
  "d3-geo-voronoi": "^2.0.1",
70
74
  "d3-hierarchy": "^3.1.2",
71
75
  "d3-interpolate": "^3.0.1",
72
76
  "d3-interpolate-path": "^2.3.0",
77
+ "d3-path": "^3.1.0",
73
78
  "d3-quadtree": "^3.0.1",
74
79
  "d3-random": "^3.0.1",
75
80
  "d3-sankey": "^0.12.3",
@@ -83,7 +88,7 @@
83
88
  "lodash-es": "^4.17.21",
84
89
  "posthog-js": "^1.116.0",
85
90
  "shapefile": "^0.6.6",
86
- "svelte-ux": "^0.61.10",
91
+ "svelte-ux": "^0.62.0",
87
92
  "topojson-client": "^3.1.0"
88
93
  },
89
94
  "peerDependencies": {