layerchart 0.0.1 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -37
- package/components/Arc.svelte +77 -0
- package/components/Arc.svelte.d.ts +34 -0
- package/components/Area.svelte +47 -0
- package/components/Area.svelte.d.ts +31 -0
- package/components/AreaStack.svelte +40 -0
- package/components/AreaStack.svelte.d.ts +20 -0
- package/components/AxisX.svelte +52 -0
- package/components/AxisX.svelte.d.ts +23 -0
- package/components/AxisY.svelte +66 -0
- package/components/AxisY.svelte.d.ts +23 -0
- package/components/Bars.svelte +102 -0
- package/components/Bars.svelte.d.ts +35 -0
- package/components/Baseline.svelte +21 -0
- package/components/Baseline.svelte.d.ts +17 -0
- package/components/Chart.svelte +50 -0
- package/components/Chart.svelte.d.ts +24 -0
- package/components/Circle.svelte +15 -0
- package/components/Circle.svelte.d.ts +22 -0
- package/components/ConnectedPoints.svelte +68 -0
- package/components/ConnectedPoints.svelte.d.ts +18 -0
- package/components/Group.svelte +26 -0
- package/components/Group.svelte.d.ts +21 -0
- package/components/HighlightLine.svelte +52 -0
- package/components/HighlightLine.svelte.d.ts +17 -0
- package/components/HighlightRect.svelte +27 -0
- package/components/HighlightRect.svelte.d.ts +18 -0
- package/components/Labels.svelte +96 -0
- package/components/Labels.svelte.d.ts +22 -0
- package/components/Line.svelte +18 -0
- package/components/Line.svelte.d.ts +23 -0
- package/components/LinearGradient.svelte +27 -0
- package/components/LinearGradient.svelte.d.ts +27 -0
- package/components/Path.svelte +40 -0
- package/components/Path.svelte.d.ts +27 -0
- package/components/Points.svelte +58 -0
- package/components/Points.svelte.d.ts +19 -0
- package/components/Rect.svelte +25 -0
- package/components/Rect.svelte.d.ts +25 -0
- package/components/Text.svelte +129 -0
- package/components/Text.svelte.d.ts +28 -0
- package/components/Threshold.svelte +86 -0
- package/components/Threshold.svelte.d.ts +35 -0
- package/components/Tooltip.svelte +120 -0
- package/components/Tooltip.svelte.d.ts +33 -0
- package/components/index.d.ts +19 -0
- package/components/index.js +19 -0
- package/docs/Blockquote.svelte +7 -0
- package/docs/Blockquote.svelte.d.ts +23 -0
- package/docs/Code.svelte +6 -0
- package/docs/Code.svelte.d.ts +23 -0
- package/docs/Layout.svelte +20 -0
- package/docs/Layout.svelte.d.ts +29 -0
- package/docs/Link.svelte +7 -0
- package/docs/Link.svelte.d.ts +27 -0
- package/docs/Preview.svelte +23 -0
- package/docs/Preview.svelte.d.ts +21 -0
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/package.json +84 -26
- package/stores/motionStore.d.ts +8 -0
- package/stores/motionStore.js +16 -0
- package/utils/event.d.ts +4 -0
- package/utils/event.js +42 -0
- package/utils/genData.d.ts +32 -0
- package/utils/genData.js +59 -0
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/math.d.ts +4 -0
- package/utils/math.js +6 -0
- package/utils/path.d.ts +5 -0
- package/utils/path.js +14 -0
- package/utils/pivot.d.ts +14 -0
- package/utils/pivot.js +36 -0
- package/utils/scales.d.ts +10 -0
- package/utils/scales.js +21 -0
- package/utils/stack.d.ts +14 -0
- package/utils/stack.js +69 -0
- package/utils/string.d.ts +4 -0
- package/utils/string.js +27 -0
- package/utils/ticks.d.ts +3 -0
- package/utils/ticks.js +157 -0
- package/.prettierrc +0 -6
- package/src/app.html +0 -12
- package/src/global.d.ts +0 -1
- package/src/routes/index.svelte +0 -2
- package/static/favicon.png +0 -0
- package/svelte.config.js +0 -15
- package/tsconfig.json +0 -31
package/README.md
CHANGED
|
@@ -1,38 +1,3 @@
|
|
|
1
|
-
#
|
|
1
|
+
# layerchart
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Creating a project
|
|
6
|
-
|
|
7
|
-
If you're seeing this, you've probably already done this step. Congrats!
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
# create a new project in the current directory
|
|
11
|
-
npm init svelte@next
|
|
12
|
-
|
|
13
|
-
# create a new project in my-app
|
|
14
|
-
npm init svelte@next my-app
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
> Note: the `@next` is temporary
|
|
18
|
-
|
|
19
|
-
## Developing
|
|
20
|
-
|
|
21
|
-
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm run dev
|
|
25
|
-
|
|
26
|
-
# or start the server and open the app in a new browser tab
|
|
27
|
-
npm run dev -- --open
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Building
|
|
31
|
-
|
|
32
|
-
Before creating a production version of your app, install an [adapter](https://kit.svelte.dev/docs#adapters) for your target environment. Then:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
npm run build
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
> You can preview the built app with `npm run preview`, regardless of whether you installed an adapter. This should _not_ be used to serve your app in production.
|
|
3
|
+
WIP
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script >/*
|
|
2
|
+
TODO:
|
|
3
|
+
- [ ] Chart usage
|
|
4
|
+
- [x] Track on/off and pass props
|
|
5
|
+
- [x] Text configuration / slot?
|
|
6
|
+
- [ ] Pie usage (second dimension?)
|
|
7
|
+
- [x] style / class (gradient, etc)
|
|
8
|
+
- [ ] Allow spring/tweened to be reactive (but ignore value)
|
|
9
|
+
*/
|
|
10
|
+
// https://caniuse.com/#feat=css-conic-gradients
|
|
11
|
+
// https://css-tricks.com/snippets/css/css-conic-gradient/
|
|
12
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/conic-gradient
|
|
13
|
+
import { arc as d3arc } from 'd3-shape';
|
|
14
|
+
import { scaleLinear } from 'd3-scale';
|
|
15
|
+
import { getMotionStore } from '../stores/motionStore';
|
|
16
|
+
import { degreesToRadians } from '../utils/math';
|
|
17
|
+
export let spring = undefined;
|
|
18
|
+
export let tweened = undefined;
|
|
19
|
+
export let value = 0;
|
|
20
|
+
let tweened_value = getMotionStore(value, { spring, tweened });
|
|
21
|
+
$: tweened_value.set(value);
|
|
22
|
+
export let domain = [0, 100];
|
|
23
|
+
export let range = [0, 360]; // degrees
|
|
24
|
+
export let innerRadius = 50;
|
|
25
|
+
export let outerRadius = 60;
|
|
26
|
+
export let cornerRadius = 10;
|
|
27
|
+
export let padAngle = 0;
|
|
28
|
+
export let padRadius = 0;
|
|
29
|
+
export let track = false;
|
|
30
|
+
$: scale = scaleLinear().domain(domain).range(range);
|
|
31
|
+
$: startAngle = degreesToRadians(range[0]);
|
|
32
|
+
$: endAngle = degreesToRadians(range[1]);
|
|
33
|
+
$: valueAngle = degreesToRadians(scale($tweened_value));
|
|
34
|
+
$: arc = d3arc()
|
|
35
|
+
.innerRadius(innerRadius)
|
|
36
|
+
.outerRadius(outerRadius)
|
|
37
|
+
.startAngle(startAngle)
|
|
38
|
+
.endAngle(valueAngle)
|
|
39
|
+
.cornerRadius(cornerRadius)
|
|
40
|
+
.padAngle(padAngle);
|
|
41
|
+
// .padRadius(padRadius);
|
|
42
|
+
$: trackArc = d3arc()
|
|
43
|
+
.innerRadius(innerRadius)
|
|
44
|
+
.outerRadius(outerRadius)
|
|
45
|
+
.startAngle(startAngle)
|
|
46
|
+
.endAngle(endAngle)
|
|
47
|
+
.cornerRadius(cornerRadius)
|
|
48
|
+
.padAngle(padAngle);
|
|
49
|
+
// .padRadius(padRadius);
|
|
50
|
+
$: trackArcCentroid = trackArc.centroid();
|
|
51
|
+
// $: console.log(trackArcCentroid)
|
|
52
|
+
let trackArcEl;
|
|
53
|
+
$: boundingBox = trackArc && trackArcEl ? trackArcEl.getBBox() : {};
|
|
54
|
+
// $: console.log(boundingBox)
|
|
55
|
+
$: labelArcCenterOffset = {
|
|
56
|
+
x: outerRadius - boundingBox.width / 2,
|
|
57
|
+
// x: 0,
|
|
58
|
+
y: (outerRadius - boundingBox.height / 2) * -1
|
|
59
|
+
};
|
|
60
|
+
// $: console.log(labelArcCenterOffset)
|
|
61
|
+
$: labelArcBottomOffset = {
|
|
62
|
+
// x: outerRadius - boundingBox.width / 2,
|
|
63
|
+
x: outerRadius - boundingBox.width / 2,
|
|
64
|
+
// x: 0,
|
|
65
|
+
// y: (outerRadius - boundingBox.height) * -1
|
|
66
|
+
y: (outerRadius - boundingBox.height) * -1
|
|
67
|
+
};
|
|
68
|
+
// $: console.log(labelArcBottomOffset)
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
{#if track}
|
|
72
|
+
<path d={trackArc()} class="track" bind:this={trackArcEl} {...track} />
|
|
73
|
+
{/if}
|
|
74
|
+
|
|
75
|
+
<path d={arc()} {...$$restProps} />
|
|
76
|
+
|
|
77
|
+
<slot value={$tweened_value} centroid={trackArcCentroid} {boundingBox} />
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { spring as springStore, tweened as tweenedStore } from 'svelte/motion';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
[x: string]: any;
|
|
6
|
+
spring?: boolean | Parameters<typeof springStore>[1];
|
|
7
|
+
tweened?: boolean | Parameters<typeof tweenedStore>[1];
|
|
8
|
+
value?: number;
|
|
9
|
+
domain?: number[];
|
|
10
|
+
range?: number[];
|
|
11
|
+
innerRadius?: number;
|
|
12
|
+
outerRadius?: number;
|
|
13
|
+
cornerRadius?: number;
|
|
14
|
+
padAngle?: number;
|
|
15
|
+
padRadius?: number;
|
|
16
|
+
track?: boolean | svelte.JSX.SVGProps<SVGPathElement>;
|
|
17
|
+
};
|
|
18
|
+
events: {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {
|
|
22
|
+
default: {
|
|
23
|
+
value: any;
|
|
24
|
+
centroid: [number, number];
|
|
25
|
+
boundingBox: any;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export declare type ArcProps = typeof __propDef.props;
|
|
30
|
+
export declare type ArcEvents = typeof __propDef.events;
|
|
31
|
+
export declare type ArcSlots = typeof __propDef.slots;
|
|
32
|
+
export default class Arc extends SvelteComponentTyped<ArcProps, ArcEvents, ArcSlots> {
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script >import { getContext } from 'svelte';
|
|
2
|
+
import { area as d3Area } from 'd3-shape';
|
|
3
|
+
import { interpolatePath } from 'd3-interpolate-path';
|
|
4
|
+
import { getMotionStore } from '../stores/motionStore';
|
|
5
|
+
import Path from './Path.svelte';
|
|
6
|
+
const { data: contextData, xGet, yGet, yRange } = getContext('LayerCake');
|
|
7
|
+
// Properties to override what is used from context
|
|
8
|
+
export let data = undefined; // TODO: Update Type
|
|
9
|
+
export let x = undefined; // TODO: Update Type
|
|
10
|
+
export let y0 = undefined; // TODO: Update Type
|
|
11
|
+
export let y1 = undefined; // TODO: Update Type
|
|
12
|
+
export let pathData = undefined;
|
|
13
|
+
export let clipPath = undefined;
|
|
14
|
+
export let tweened = undefined;
|
|
15
|
+
export let curve = undefined;
|
|
16
|
+
export let defined = undefined;
|
|
17
|
+
export let color = 'var(--color-blue-500)';
|
|
18
|
+
export let opacity = 0.3;
|
|
19
|
+
export let line = false;
|
|
20
|
+
$: tweenedOptions = tweened ? { interpolate: interpolatePath, ...tweened } : false;
|
|
21
|
+
$: tweened_d = getMotionStore('', { tweened: tweenedOptions });
|
|
22
|
+
$: {
|
|
23
|
+
const path = d3Area()
|
|
24
|
+
.x(x ?? $xGet)
|
|
25
|
+
.y0(y0 ?? $yRange[0])
|
|
26
|
+
.y1(y1 ?? $yGet);
|
|
27
|
+
if (curve)
|
|
28
|
+
path.curve(curve);
|
|
29
|
+
if (defined)
|
|
30
|
+
path.defined(defined);
|
|
31
|
+
const d = pathData ?? path(data ?? $contextData);
|
|
32
|
+
tweened_d.set(d);
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
{#if line}
|
|
37
|
+
<Path {curve} {defined} {color} {tweened} {...line} />
|
|
38
|
+
{/if}
|
|
39
|
+
|
|
40
|
+
<path
|
|
41
|
+
class="path-area"
|
|
42
|
+
d={$tweened_d}
|
|
43
|
+
clip-path={clipPath}
|
|
44
|
+
fill={color}
|
|
45
|
+
fill-opacity={opacity}
|
|
46
|
+
{...$$restProps}
|
|
47
|
+
/>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { tweened as tweenedStore } from 'svelte/motion';
|
|
3
|
+
import { Area } from 'd3-shape';
|
|
4
|
+
import type { CurveFactory } from 'd3-shape';
|
|
5
|
+
declare const __propDef: {
|
|
6
|
+
props: {
|
|
7
|
+
[x: string]: any;
|
|
8
|
+
data?: any;
|
|
9
|
+
x?: any;
|
|
10
|
+
y0?: any;
|
|
11
|
+
y1?: any;
|
|
12
|
+
pathData?: string;
|
|
13
|
+
clipPath?: string;
|
|
14
|
+
tweened?: boolean | Parameters<typeof tweenedStore>[1];
|
|
15
|
+
curve?: CurveFactory;
|
|
16
|
+
defined?: Parameters<Area<any>['defined']>[0];
|
|
17
|
+
color?: string;
|
|
18
|
+
opacity?: number;
|
|
19
|
+
line?: boolean | any;
|
|
20
|
+
};
|
|
21
|
+
events: {
|
|
22
|
+
[evt: string]: CustomEvent<any>;
|
|
23
|
+
};
|
|
24
|
+
slots: {};
|
|
25
|
+
};
|
|
26
|
+
export declare type AreaProps = typeof __propDef.props;
|
|
27
|
+
export declare type AreaEvents = typeof __propDef.events;
|
|
28
|
+
export declare type AreaSlots = typeof __propDef.slots;
|
|
29
|
+
export default class Area extends SvelteComponentTyped<AreaProps, AreaEvents, AreaSlots> {
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script >import { getContext } from 'svelte';
|
|
2
|
+
import Area from './Area.svelte';
|
|
3
|
+
import Path from './Path.svelte';
|
|
4
|
+
const { data, yScale, zGet } = getContext('LayerCake');
|
|
5
|
+
export let curve = undefined;
|
|
6
|
+
export let defined = undefined;
|
|
7
|
+
export let opacity = 0.3;
|
|
8
|
+
export let line = false;
|
|
9
|
+
// Render in reverse order so bottom stacks are rendered last (and stack above the upper stacks). Fixes when upper stack has 0 value
|
|
10
|
+
$: lineData = [...$data].reverse();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
{#if line}
|
|
14
|
+
<g class="line-group">
|
|
15
|
+
{#each lineData as seriesData}
|
|
16
|
+
<Path
|
|
17
|
+
data={seriesData}
|
|
18
|
+
y={(d) => $yScale(d[1])}
|
|
19
|
+
color={$zGet(seriesData)}
|
|
20
|
+
{curve}
|
|
21
|
+
{defined}
|
|
22
|
+
{...line}
|
|
23
|
+
/>
|
|
24
|
+
{/each}
|
|
25
|
+
</g>
|
|
26
|
+
{/if}
|
|
27
|
+
|
|
28
|
+
<g class="area-group">
|
|
29
|
+
{#each $data as seriesData}
|
|
30
|
+
<Area
|
|
31
|
+
data={seriesData}
|
|
32
|
+
y0={(d) => $yScale(d[0])}
|
|
33
|
+
y1={(d) => $yScale(d[1])}
|
|
34
|
+
color={$zGet(seriesData)}
|
|
35
|
+
{curve}
|
|
36
|
+
{defined}
|
|
37
|
+
{opacity}
|
|
38
|
+
/>
|
|
39
|
+
{/each}
|
|
40
|
+
</g>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { CurveFactory } from 'd3-shape';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
curve?: CurveFactory;
|
|
6
|
+
defined?: (d: any, index: number, data: any[]) => boolean;
|
|
7
|
+
opacity?: number;
|
|
8
|
+
line?: boolean | any;
|
|
9
|
+
};
|
|
10
|
+
events: {
|
|
11
|
+
[evt: string]: CustomEvent<any>;
|
|
12
|
+
};
|
|
13
|
+
slots: {};
|
|
14
|
+
};
|
|
15
|
+
export declare type AreaStackProps = typeof __propDef.props;
|
|
16
|
+
export declare type AreaStackEvents = typeof __propDef.events;
|
|
17
|
+
export declare type AreaStackSlots = typeof __propDef.slots;
|
|
18
|
+
export default class AreaStack extends SvelteComponentTyped<AreaStackProps, AreaStackEvents, AreaStackSlots> {
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script >import { getContext } from 'svelte';
|
|
2
|
+
import { format } from 'svelte-ux/utils/format';
|
|
3
|
+
import Text from './Text.svelte';
|
|
4
|
+
import { isScaleBand } from '../utils/scales';
|
|
5
|
+
const { height, xScale, yRange } = getContext('LayerCake');
|
|
6
|
+
export let gridlines = false;
|
|
7
|
+
export let formatTick = undefined;
|
|
8
|
+
export let ticks = undefined;
|
|
9
|
+
export let xTick = undefined;
|
|
10
|
+
export let yTick = 8;
|
|
11
|
+
export let dxTick = 0;
|
|
12
|
+
export let dyTick = 0;
|
|
13
|
+
$: isBand = isScaleBand($xScale);
|
|
14
|
+
$: tickVals = Array.isArray(ticks)
|
|
15
|
+
? ticks
|
|
16
|
+
: isBand
|
|
17
|
+
? $xScale.domain()
|
|
18
|
+
: $xScale.ticks(typeof ticks === 'function' ? ticks($xScale) : ticks);
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<g class="axis x-axis">
|
|
22
|
+
{#each tickVals as tick, i}
|
|
23
|
+
<g class="tick tick-{tick}" transform="translate({$xScale(tick)},{$yRange[0]})">
|
|
24
|
+
{#if gridlines !== false}
|
|
25
|
+
<line y1={$height * -1} y2="0" x1="0" x2="0" {...gridlines} />
|
|
26
|
+
{/if}
|
|
27
|
+
<Text
|
|
28
|
+
x={xTick || isBand ? $xScale.bandwidth() / 2 : 0}
|
|
29
|
+
y={yTick}
|
|
30
|
+
dx={dxTick}
|
|
31
|
+
dy={dyTick}
|
|
32
|
+
rotate={315}
|
|
33
|
+
textAnchor="end"
|
|
34
|
+
verticalAnchor="middle"
|
|
35
|
+
style="font-size: 10px;"
|
|
36
|
+
value={format(tick, formatTick ?? $xScale.tickFormat?.())}
|
|
37
|
+
/>
|
|
38
|
+
</g>
|
|
39
|
+
{/each}
|
|
40
|
+
</g>
|
|
41
|
+
|
|
42
|
+
<style >
|
|
43
|
+
.tick {
|
|
44
|
+
font-size: 0.725em;
|
|
45
|
+
font-weight: 200;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
line,
|
|
49
|
+
.tick line {
|
|
50
|
+
stroke: #e0e0e0;
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { FormatType } from 'svelte-ux/utils/format';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
gridlines?: boolean;
|
|
6
|
+
formatTick?: FormatType;
|
|
7
|
+
ticks?: any;
|
|
8
|
+
xTick?: any;
|
|
9
|
+
yTick?: number;
|
|
10
|
+
dxTick?: number;
|
|
11
|
+
dyTick?: number;
|
|
12
|
+
};
|
|
13
|
+
events: {
|
|
14
|
+
[evt: string]: CustomEvent<any>;
|
|
15
|
+
};
|
|
16
|
+
slots: {};
|
|
17
|
+
};
|
|
18
|
+
export declare type AxisXProps = typeof __propDef.props;
|
|
19
|
+
export declare type AxisXEvents = typeof __propDef.events;
|
|
20
|
+
export declare type AxisXSlots = typeof __propDef.slots;
|
|
21
|
+
export default class AxisX extends SvelteComponentTyped<AxisXProps, AxisXEvents, AxisXSlots> {
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script >import { getContext } from 'svelte';
|
|
2
|
+
import { format } from 'svelte-ux/utils/format';
|
|
3
|
+
import Text from './Text.svelte';
|
|
4
|
+
import { isScaleBand } from '../utils/scales';
|
|
5
|
+
const { padding, xRange, yScale, width } = getContext('LayerCake');
|
|
6
|
+
export let gridlines = false;
|
|
7
|
+
export let ticks = 4;
|
|
8
|
+
export let formatTick = undefined;
|
|
9
|
+
export let xTick = 0;
|
|
10
|
+
export let yTick = 0;
|
|
11
|
+
export let dxTick = 0;
|
|
12
|
+
export let dyTick = -3; // TODO: Maualliy tweak based on font-size until <Text /> handles custom styles
|
|
13
|
+
$: isBand = isScaleBand($yScale);
|
|
14
|
+
$: tickVals = Array.isArray(ticks)
|
|
15
|
+
? ticks
|
|
16
|
+
: isBand
|
|
17
|
+
? $yScale.domain()
|
|
18
|
+
: $yScale.ticks(typeof ticks === 'function' ? ticks($yScale) : ticks);
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<g class="axis y-axis" transform="translate({-$padding.left}, 0)">
|
|
22
|
+
{#each tickVals as tick, i}
|
|
23
|
+
<g
|
|
24
|
+
class="tick tick-{tick}"
|
|
25
|
+
transform="translate({$xRange[0] + (isBand ? $padding.left : 0)}, {$yScale(tick)})"
|
|
26
|
+
>
|
|
27
|
+
{#if gridlines !== false}
|
|
28
|
+
<line
|
|
29
|
+
x1={$padding.left}
|
|
30
|
+
x2={$width + $padding.left}
|
|
31
|
+
y1={yTick + (isBand ? $yScale.bandwidth() / 2 : 0)}
|
|
32
|
+
y2={yTick + (isBand ? $yScale.bandwidth() / 2 : 0)}
|
|
33
|
+
{...gridlines}
|
|
34
|
+
/>
|
|
35
|
+
{/if}
|
|
36
|
+
<!-- <circle
|
|
37
|
+
cx={$padding.left - 4}
|
|
38
|
+
cy={yTick + (isBand ? $yScale.bandwidth() / 2 : 0)}
|
|
39
|
+
r="2"
|
|
40
|
+
fill="red"
|
|
41
|
+
/> -->
|
|
42
|
+
<Text
|
|
43
|
+
x={$padding.left - 4}
|
|
44
|
+
y={yTick + (isBand ? $yScale.bandwidth() / 2 : 0)}
|
|
45
|
+
dx={dxTick}
|
|
46
|
+
dy={dyTick}
|
|
47
|
+
textAnchor="end"
|
|
48
|
+
verticalAnchor="middle"
|
|
49
|
+
style="font-size: 10px;"
|
|
50
|
+
value={format(tick, formatTick ?? $yScale.tickFormat?.())}
|
|
51
|
+
/>
|
|
52
|
+
</g>
|
|
53
|
+
{/each}
|
|
54
|
+
</g>
|
|
55
|
+
|
|
56
|
+
<style >
|
|
57
|
+
.tick {
|
|
58
|
+
font-size: 0.725em;
|
|
59
|
+
font-weight: 200;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.tick line {
|
|
63
|
+
stroke: #e0e0e0;
|
|
64
|
+
/* stroke-dasharray: 2; */
|
|
65
|
+
}
|
|
66
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { FormatType } from 'svelte-ux/utils/format';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
gridlines?: boolean;
|
|
6
|
+
ticks?: number | Function;
|
|
7
|
+
formatTick?: FormatType;
|
|
8
|
+
xTick?: number;
|
|
9
|
+
yTick?: number;
|
|
10
|
+
dxTick?: number;
|
|
11
|
+
dyTick?: number;
|
|
12
|
+
};
|
|
13
|
+
events: {
|
|
14
|
+
[evt: string]: CustomEvent<any>;
|
|
15
|
+
};
|
|
16
|
+
slots: {};
|
|
17
|
+
};
|
|
18
|
+
export declare type AxisYProps = typeof __propDef.props;
|
|
19
|
+
export declare type AxisYEvents = typeof __propDef.events;
|
|
20
|
+
export declare type AxisYSlots = typeof __propDef.slots;
|
|
21
|
+
export default class AxisY extends SvelteComponentTyped<AxisYProps, AxisYEvents, AxisYSlots> {
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script >import { getContext } from 'svelte';
|
|
2
|
+
import { scaleBand } from 'd3-scale';
|
|
3
|
+
import { max, min } from 'd3-array';
|
|
4
|
+
import { unique } from 'svelte-ux/utils/array';
|
|
5
|
+
import Rect from './Rect.svelte';
|
|
6
|
+
const { data, flatData, xGet, yRange, xScale, yScale, x: xContext, y: yContext, rGet, config } = getContext('LayerCake');
|
|
7
|
+
/**
|
|
8
|
+
* Override `x` from context. Useful for multiple Bar instances
|
|
9
|
+
*/
|
|
10
|
+
export let x = $xContext;
|
|
11
|
+
// Convert x to function
|
|
12
|
+
$: _x = x ? (typeof x === 'string' ? (d) => d[x] : x) : $xContext;
|
|
13
|
+
/**
|
|
14
|
+
* Override `y` from context. Useful for multiple Bar instances
|
|
15
|
+
*/
|
|
16
|
+
export let y = $yContext;
|
|
17
|
+
$: _y = y ? (typeof y === 'string' ? (d) => d[y] : y) : $yContext;
|
|
18
|
+
/*
|
|
19
|
+
TODO:
|
|
20
|
+
- [ ] Support vertical/horizontal layout (Bar/Column)
|
|
21
|
+
*/
|
|
22
|
+
export let color = 'var(--color-blue-500)';
|
|
23
|
+
export let opacity = 1;
|
|
24
|
+
export let stroke = 'black';
|
|
25
|
+
export let strokeWidth = 0;
|
|
26
|
+
export let radius = 0;
|
|
27
|
+
export let getKey = (item) => _x(item);
|
|
28
|
+
export let getProps = undefined;
|
|
29
|
+
export let widthOffset = 0;
|
|
30
|
+
// See: https://svelte.dev/repl/7000c5ce05b84cd98ccbfb2768b4be3d?version=3.38.3
|
|
31
|
+
export let groupBy = undefined;
|
|
32
|
+
// export let delay = 300;
|
|
33
|
+
// $: console.log({ $data, $flatData, groupBy, stackBy })
|
|
34
|
+
$: groupKeys = unique($flatData.map((d) => d[groupBy]));
|
|
35
|
+
$: x1Scale = scaleBand().domain(groupKeys).range([0, $xScale.bandwidth()]).paddingInner(0.2);
|
|
36
|
+
$: getDimensions = (item) => {
|
|
37
|
+
// console.log({ item, y: $y(item) });
|
|
38
|
+
const x = $xGet(item) + (groupBy ? x1Scale(item[groupBy]) : 0) - widthOffset / 2;
|
|
39
|
+
// TODO: Do we need to support the non-bandwidth scale?
|
|
40
|
+
// const width = $xScale.bandwidth
|
|
41
|
+
// ? $xScale.bandwidth()
|
|
42
|
+
// : Math.max(0, $xGet(d)[1] - $xGet(d)[0]);
|
|
43
|
+
const width = (groupBy ? x1Scale.bandwidth() : $xScale.bandwidth()) + widthOffset;
|
|
44
|
+
const yValue = _y(item);
|
|
45
|
+
let yTop = 0;
|
|
46
|
+
let yBottom = 0;
|
|
47
|
+
if (Array.isArray(yValue)) {
|
|
48
|
+
// Array contains both top and bottom values (stack, etc);
|
|
49
|
+
yTop = max(yValue);
|
|
50
|
+
yBottom = min(yValue);
|
|
51
|
+
}
|
|
52
|
+
else if (yValue == null) {
|
|
53
|
+
// null/undefined value
|
|
54
|
+
yTop = 0;
|
|
55
|
+
yBottom = 0;
|
|
56
|
+
}
|
|
57
|
+
else if (yValue > 0) {
|
|
58
|
+
// Positive value
|
|
59
|
+
yTop = yValue;
|
|
60
|
+
yBottom = $yRange[1]; // or `0`?
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// Negative value
|
|
64
|
+
yTop = $yRange[1]; // or `0`?
|
|
65
|
+
yBottom = yValue;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
x,
|
|
69
|
+
y: $yScale(yTop),
|
|
70
|
+
width,
|
|
71
|
+
height: $yScale(yBottom) - $yScale(yTop)
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
function getColor(item, index) {
|
|
75
|
+
if (typeof color === 'function') {
|
|
76
|
+
return color({ value: _y(item), item, index });
|
|
77
|
+
}
|
|
78
|
+
else if ($config.r) {
|
|
79
|
+
return $rGet(item);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
return color;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<g class="column-group">
|
|
88
|
+
{#each $data as item, index (getKey(item, index))}
|
|
89
|
+
<Rect
|
|
90
|
+
class="group-rect"
|
|
91
|
+
data-id={index}
|
|
92
|
+
fill={getColor(item, index)}
|
|
93
|
+
fill-opacity={opacity}
|
|
94
|
+
{stroke}
|
|
95
|
+
stroke-width={strokeWidth}
|
|
96
|
+
rx={radius}
|
|
97
|
+
{...getDimensions(item)}
|
|
98
|
+
{...getProps?.({ value: _y(item), item, index })}
|
|
99
|
+
{...$$restProps}
|
|
100
|
+
/>
|
|
101
|
+
{/each}
|
|
102
|
+
</g>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
[x: string]: any;
|
|
5
|
+
x?: any;
|
|
6
|
+
y?: any;
|
|
7
|
+
color?: string | ((obj: {
|
|
8
|
+
value: any;
|
|
9
|
+
item: any;
|
|
10
|
+
index: number;
|
|
11
|
+
}) => string);
|
|
12
|
+
opacity?: number;
|
|
13
|
+
stroke?: string;
|
|
14
|
+
strokeWidth?: number;
|
|
15
|
+
radius?: number;
|
|
16
|
+
getKey?: (item: any, index: number) => any;
|
|
17
|
+
getProps?: (obj: {
|
|
18
|
+
value: any;
|
|
19
|
+
item: any;
|
|
20
|
+
index: number;
|
|
21
|
+
}) => any;
|
|
22
|
+
widthOffset?: number;
|
|
23
|
+
groupBy?: string;
|
|
24
|
+
};
|
|
25
|
+
events: {
|
|
26
|
+
[evt: string]: CustomEvent<any>;
|
|
27
|
+
};
|
|
28
|
+
slots: {};
|
|
29
|
+
};
|
|
30
|
+
export declare type BarsProps = typeof __propDef.props;
|
|
31
|
+
export declare type BarsEvents = typeof __propDef.events;
|
|
32
|
+
export declare type BarsSlots = typeof __propDef.slots;
|
|
33
|
+
export default class Bars extends SvelteComponentTyped<BarsProps, BarsEvents, BarsSlots> {
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script >import { getContext } from 'svelte';
|
|
2
|
+
const { xRange, yScale, yRange } = getContext('LayerCake');
|
|
3
|
+
export let x = false;
|
|
4
|
+
export let y = false;
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<g class="baseline">
|
|
8
|
+
{#if x}
|
|
9
|
+
<line x1={0} x2={$xRange[1] || 0} y1={$yScale(0) || 0} y2={$yScale(0) || 0} class="baseline" />
|
|
10
|
+
{/if}
|
|
11
|
+
|
|
12
|
+
{#if y}
|
|
13
|
+
<line x1={0} x2={0} y1={$yRange[0] || 0} y2={$yRange[1] || 0} class="baseline" />
|
|
14
|
+
{/if}
|
|
15
|
+
</g>
|
|
16
|
+
|
|
17
|
+
<style >
|
|
18
|
+
.baseline {
|
|
19
|
+
stroke: #777;
|
|
20
|
+
}
|
|
21
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
x?: boolean;
|
|
5
|
+
y?: boolean;
|
|
6
|
+
};
|
|
7
|
+
events: {
|
|
8
|
+
[evt: string]: CustomEvent<any>;
|
|
9
|
+
};
|
|
10
|
+
slots: {};
|
|
11
|
+
};
|
|
12
|
+
export declare type BaselineProps = typeof __propDef.props;
|
|
13
|
+
export declare type BaselineEvents = typeof __propDef.events;
|
|
14
|
+
export declare type BaselineSlots = typeof __propDef.slots;
|
|
15
|
+
export default class Baseline extends SvelteComponentTyped<BaselineProps, BaselineEvents, BaselineSlots> {
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script context="module" >import { LayerCake, Svg, Html } from 'layercake';
|
|
2
|
+
export { Svg, Html };
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script >import { max, min } from 'd3-array';
|
|
6
|
+
import { get } from 'lodash-es';
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a value from data based on the accessor type
|
|
9
|
+
*/
|
|
10
|
+
function getValue(accessor, d) {
|
|
11
|
+
console.log({ accessor });
|
|
12
|
+
if (Array.isArray(accessor)) {
|
|
13
|
+
return accessor.map((a) => getValue(a, d));
|
|
14
|
+
}
|
|
15
|
+
else if (typeof accessor === 'function') {
|
|
16
|
+
return accessor(d) || 0;
|
|
17
|
+
}
|
|
18
|
+
else if (typeof accessor === 'string') {
|
|
19
|
+
return get(d, accessor);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
throw new Error('Unexpected accessor: ' + accessor);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export let data = [];
|
|
26
|
+
export let x;
|
|
27
|
+
export let y;
|
|
28
|
+
/**
|
|
29
|
+
* xBaseline guaranteed to be visible in xDomain
|
|
30
|
+
*/
|
|
31
|
+
export let xBaseline = null;
|
|
32
|
+
let xDomain = undefined;
|
|
33
|
+
$: if (xBaseline != null) {
|
|
34
|
+
const xValues = data.flatMap((d) => getValue(x, d));
|
|
35
|
+
xDomain = [min([xBaseline, ...xValues]), max([xBaseline, ...xValues])];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* yBaseline guaranteed to be visible in yDomain
|
|
39
|
+
*/
|
|
40
|
+
export let yBaseline = null;
|
|
41
|
+
let yDomain = undefined;
|
|
42
|
+
$: if (yBaseline != null) {
|
|
43
|
+
const yValues = data.flatMap((d) => getValue(y, d));
|
|
44
|
+
yDomain = [min([yBaseline, ...yValues]), max([yBaseline, ...yValues])];
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<LayerCake {data} {y} {yDomain} {x} {xDomain} {...$$restProps}>
|
|
49
|
+
<slot />
|
|
50
|
+
</LayerCake>
|