svelteplot 0.0.1-alpha.2 → 0.0.1-alpha.20
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/dist/Plot.svelte +47 -41
- package/dist/Plot.svelte.d.ts +3 -3
- package/dist/classes/Mark.svelte.js +4 -0
- package/dist/classes/Plot.svelte.js +50 -24
- package/dist/classes/Scale.svelte.js +94 -0
- package/dist/contants.d.ts +3 -3
- package/dist/contants.js +18 -16
- package/dist/helpers/GroupMultiple.svelte.d.ts +3 -3
- package/dist/helpers/autoTimeFormat.d.ts +2 -2
- package/dist/helpers/autoTimeFormat.js +1 -1
- package/dist/helpers/callWithProps.d.ts +4 -0
- package/dist/helpers/callWithProps.js +9 -0
- package/dist/helpers/colors.d.ts +1 -1
- package/dist/helpers/createScale.d.ts +2 -1
- package/dist/helpers/createScale.js +37 -16
- package/dist/helpers/curves.d.ts +3 -0
- package/dist/helpers/curves.js +42 -0
- package/dist/helpers/getBaseStyles.d.ts +1 -1
- package/dist/helpers/getBaseStyles.js +2 -3
- package/dist/helpers/getLogTicks.js +5 -5
- package/dist/helpers/isDataRecord.d.ts +1 -1
- package/dist/helpers/isRawValue.d.ts +2 -0
- package/dist/helpers/isRawValue.js +5 -0
- package/dist/helpers/resolveChannel.d.ts +6 -2
- package/dist/helpers/resolveChannel.js +16 -6
- package/dist/helpers/typeChecks.d.ts +1 -1
- package/dist/helpers/typeChecks.js +1 -1
- package/dist/helpers/wrapArray.d.ts +2 -2
- package/dist/helpers/wrapValueArray.d.ts +6 -0
- package/dist/helpers/wrapValueArray.js +5 -0
- package/dist/index.d.ts +15 -1
- package/dist/index.js +17 -1
- package/dist/marks/Area.svelte +95 -0
- package/dist/marks/Area.svelte.d.ts +28 -0
- package/dist/marks/AreaX.svelte +11 -0
- package/dist/marks/AreaX.svelte.d.ts +30 -0
- package/dist/marks/AreaY.svelte +12 -0
- package/dist/marks/AreaY.svelte.d.ts +30 -0
- package/dist/marks/AxisX.svelte +17 -17
- package/dist/marks/AxisX.svelte.d.ts +3 -3
- package/dist/marks/AxisY.svelte +25 -11
- package/dist/marks/AxisY.svelte.d.ts +3 -3
- package/dist/marks/BarX.svelte +52 -0
- package/dist/marks/BarX.svelte.d.ts +25 -0
- package/dist/marks/BarY.svelte +52 -0
- package/dist/marks/BarY.svelte.d.ts +25 -0
- package/dist/marks/BaseMark.svelte +10 -3
- package/dist/marks/BaseMark.svelte.d.ts +5 -4
- package/dist/marks/ColorLegend.svelte +26 -24
- package/dist/marks/ColorLegend.svelte.d.ts +2 -2
- package/dist/marks/Dot.svelte +28 -43
- package/dist/marks/Dot.svelte.d.ts +11 -3
- package/dist/marks/DotX.svelte.d.ts +3 -3
- package/dist/marks/DotY.svelte.d.ts +3 -3
- package/dist/marks/Frame.svelte +1 -1
- package/dist/marks/Frame.svelte.d.ts +4 -4
- package/dist/marks/GridX.svelte +29 -18
- package/dist/marks/GridX.svelte.d.ts +6 -6
- package/dist/marks/GridY.svelte +17 -7
- package/dist/marks/GridY.svelte.d.ts +3 -3
- package/dist/marks/Line.svelte +28 -29
- package/dist/marks/Line.svelte.d.ts +15 -3
- package/dist/marks/LineX.svelte +5 -7
- package/dist/marks/LineX.svelte.d.ts +13 -6
- package/dist/marks/LineY.svelte +4 -6
- package/dist/marks/LineY.svelte.d.ts +14 -6
- package/dist/marks/RuleX.svelte +17 -9
- package/dist/marks/RuleX.svelte.d.ts +3 -3
- package/dist/marks/RuleY.svelte +17 -10
- package/dist/marks/RuleY.svelte.d.ts +3 -3
- package/dist/marks/SymbolLegend.svelte +17 -17
- package/dist/marks/SymbolLegend.svelte.d.ts +2 -2
- package/dist/marks/TickX.svelte +30 -0
- package/dist/marks/TickX.svelte.d.ts +15 -0
- package/dist/marks/TickY.svelte +30 -0
- package/dist/marks/TickY.svelte.d.ts +15 -0
- package/dist/transforms/normalize.d.ts +18 -0
- package/dist/transforms/normalize.js +25 -0
- package/dist/transforms/recordize.d.ts +3 -0
- package/dist/transforms/recordize.js +36 -0
- package/dist/transforms/rename.d.ts +4 -0
- package/dist/transforms/rename.js +10 -0
- package/dist/transforms/stack.d.ts +11 -0
- package/dist/transforms/stack.js +80 -0
- package/dist/types.d.ts +60 -23
- package/package.json +28 -23
- package/dist/classes/Channel.svelte.js +0 -72
package/dist/Plot.svelte
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
<script>import { setContext } from "svelte";
|
|
2
|
-
import { Frame, GridX, GridY } from "./";
|
|
3
|
-
import { DEFAULT_PLOT_OPTIONS, Plot } from "./classes/Plot.svelte";
|
|
4
|
-
import mergeDeep from "./helpers/mergeDeep";
|
|
5
|
-
import AxisX from "./marks/AxisX.svelte";
|
|
6
|
-
import AxisY from "./marks/AxisY.svelte";
|
|
7
|
-
import ColorLegend from "./marks/ColorLegend.svelte";
|
|
8
|
-
import SymbolLegend from "./marks/SymbolLegend.svelte";
|
|
2
|
+
import { Frame, GridX, GridY, AxisX, AxisY, ColorLegend, SymbolLegend } from "./index.js";
|
|
3
|
+
import { DEFAULT_PLOT_OPTIONS, Plot } from "./classes/Plot.svelte.js";
|
|
4
|
+
import mergeDeep from "./helpers/mergeDeep.js";
|
|
9
5
|
let {
|
|
10
6
|
// snippets
|
|
11
7
|
header,
|
|
@@ -25,6 +21,7 @@ let {
|
|
|
25
21
|
title = "",
|
|
26
22
|
subtitle = "",
|
|
27
23
|
caption = "",
|
|
24
|
+
testid,
|
|
28
25
|
// scales
|
|
29
26
|
radius = null,
|
|
30
27
|
color = null,
|
|
@@ -77,39 +74,44 @@ function onMouseMove(evt) {
|
|
|
77
74
|
let hasLegend = $derived(color?.legend || symbol?.legend);
|
|
78
75
|
</script>
|
|
79
76
|
|
|
80
|
-
<figure class="svelteplot" bind:clientWidth={width} style:max-width={maxWidth}>
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
77
|
+
<figure data-testid={testid} class="svelteplot" bind:clientWidth={width} style:max-width={maxWidth}>
|
|
78
|
+
<div class="plot-body">
|
|
79
|
+
<svg
|
|
80
|
+
role="document"
|
|
81
|
+
{width}
|
|
82
|
+
height={plot.height}
|
|
83
|
+
onmousemove={onmousemove ? onMouseMove : null}
|
|
84
|
+
>
|
|
85
|
+
<!-- automatic grids -->
|
|
86
|
+
{#if (grid && plot.hasScaleX) || x?.grid}<GridX automatic />{/if}
|
|
87
|
+
{#if (grid && plot.hasScaleY) || y?.grid}<GridY automatic />{/if}
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
{#if !plot.hasAxisXMark && (plot.hasScaleX || x?.grid)}
|
|
90
|
+
<!-- automatic x axis -->
|
|
91
|
+
{#if plot.options.x.axis === 'bottom' || plot.options.x.axis === 'both'}
|
|
92
|
+
<AxisX anchor="bottom" automatic />
|
|
93
|
+
{/if}
|
|
94
|
+
{#if plot.options.x.axis === 'top' || plot.options.x.axis === 'both'}
|
|
95
|
+
<AxisX anchor="top" automatic />
|
|
96
|
+
{/if}
|
|
95
97
|
{/if}
|
|
96
|
-
{#if plot.
|
|
97
|
-
|
|
98
|
+
{#if !plot.hasAxisYMark && (plot.hasScaleY || y?.grid)}
|
|
99
|
+
<!-- automatic y axis -->
|
|
100
|
+
{#if plot.options.y.axis === 'left' || plot.options.y.axis === 'both'}
|
|
101
|
+
<AxisY anchor="left" automatic />
|
|
102
|
+
{/if}
|
|
103
|
+
{#if plot.options.y.axis === 'right' || plot.options.y.axis === 'both'}
|
|
104
|
+
<AxisY anchor="right" automatic />
|
|
105
|
+
{/if}
|
|
98
106
|
{/if}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
{/if}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
{/if}
|
|
108
|
-
{/if}
|
|
109
|
-
<!-- automatic frame -->
|
|
110
|
-
{#if frame}<Frame />{/if}
|
|
111
|
-
{#if children}{@render children(plot)}{/if}
|
|
112
|
-
</svg>
|
|
107
|
+
<!-- automatic frame -->
|
|
108
|
+
{#if frame}<Frame />{/if}
|
|
109
|
+
{#if children}{@render children(plot)}{/if}
|
|
110
|
+
</svg>
|
|
111
|
+
<div class="overlay">
|
|
112
|
+
{#if overlay}{@render overlay(plot)}{/if}
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
113
115
|
|
|
114
116
|
{#if plot.options.title || plot.options.subtitle || header || hasLegend}
|
|
115
117
|
<div class="plot-header">
|
|
@@ -137,10 +139,6 @@ let hasLegend = $derived(color?.legend || symbol?.legend);
|
|
|
137
139
|
{#if footer}{@render footer(plot)}{/if}
|
|
138
140
|
</div>
|
|
139
141
|
{/if}
|
|
140
|
-
|
|
141
|
-
<div class="overlay">
|
|
142
|
-
{#if overlay}{@render overlay(plot)}{/if}
|
|
143
|
-
</div>
|
|
144
142
|
</figure>
|
|
145
143
|
|
|
146
144
|
<style>
|
|
@@ -150,9 +148,17 @@ let hasLegend = $derived(color?.legend || symbol?.legend);
|
|
|
150
148
|
display: flex;
|
|
151
149
|
flex-direction: column;
|
|
152
150
|
}
|
|
151
|
+
|
|
152
|
+
.plot-body {
|
|
153
|
+
position: relative;
|
|
154
|
+
}
|
|
153
155
|
figure .plot-header {
|
|
154
156
|
order: 1;
|
|
155
157
|
}
|
|
158
|
+
h2,
|
|
159
|
+
h3 {
|
|
160
|
+
margin: 0;
|
|
161
|
+
}
|
|
156
162
|
svg {
|
|
157
163
|
order: 2;
|
|
158
164
|
overflow: visible;
|
package/dist/Plot.svelte.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { PlotProps } from './types';
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { PlotProps } from './types.js';
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: PlotProps;
|
|
5
5
|
events: {
|
|
@@ -11,5 +11,5 @@ type PlotProps_ = typeof __propDef.props;
|
|
|
11
11
|
export { PlotProps_ as PlotProps };
|
|
12
12
|
export type PlotEvents = typeof __propDef.events;
|
|
13
13
|
export type PlotSlots = typeof __propDef.slots;
|
|
14
|
-
export default class Plot extends
|
|
14
|
+
export default class Plot extends SvelteComponentTyped<PlotProps, PlotEvents, PlotSlots> {
|
|
15
15
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { CHANNEL_SCALE } from '../contants.js';
|
|
1
2
|
export class Mark {
|
|
2
3
|
id;
|
|
3
4
|
type;
|
|
4
5
|
automatic;
|
|
5
6
|
channels = $state(new Set());
|
|
6
7
|
props = $state();
|
|
8
|
+
scales = $derived(new Set(Array.from(this.channels.values())
|
|
9
|
+
.filter((channel) => this.props[channel] != null && !(typeof this.props[channel] === 'number'))
|
|
10
|
+
.map((channel) => CHANNEL_SCALE[channel])));
|
|
7
11
|
constructor(type, channels, automatic, props) {
|
|
8
12
|
this.id = Symbol();
|
|
9
13
|
this.type = type;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createScale, createColorScale } from '../helpers/createScale';
|
|
2
|
-
import mergeDeep from '../helpers/mergeDeep';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
1
|
+
import { createScale, createColorScale } from '../helpers/createScale.js';
|
|
2
|
+
import mergeDeep from '../helpers/mergeDeep.js';
|
|
3
|
+
import { Scale } from './Scale.svelte.js';
|
|
4
|
+
import pick from 'underscore/modules/pick.js';
|
|
5
5
|
export const DEFAULT_PLOT_OPTIONS = {
|
|
6
6
|
title: '',
|
|
7
7
|
subtitle: '',
|
|
@@ -37,16 +37,24 @@ export class Plot {
|
|
|
37
37
|
_height = $state(400);
|
|
38
38
|
options = $state(DEFAULT_PLOT_OPTIONS);
|
|
39
39
|
marks = $state([]);
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
hasScaleX = $derived(!!this.marks.find((mark) => !mark.automatic && mark.scales.has('x')));
|
|
41
|
+
hasScaleY = $derived(!!this.marks.find((mark) => !mark.automatic && mark.scales.has('y')));
|
|
42
42
|
hasFilledDotMarks = $derived(!!this.marks.find((d) => d.type === 'dot' && d.props?.fill));
|
|
43
43
|
manualMarks = $derived(this.marks.filter((mark) => !mark.automatic));
|
|
44
|
-
|
|
44
|
+
singlePosScaleMark = $derived(this.manualMarks.length === 1 &&
|
|
45
45
|
(!this.manualMarks[0].channels.has('x') || !this.manualMarks[0].channels.has('y')));
|
|
46
|
-
height = $derived(this._height === 'auto'
|
|
46
|
+
height = $derived(this._height === 'auto'
|
|
47
|
+
? this.hasScaleY
|
|
48
|
+
? this.y.scaleType === 'band'
|
|
49
|
+
? this.y.domain.length * 30
|
|
50
|
+
: this.y.scaleType === 'point'
|
|
51
|
+
? this.y.domain.length * 18
|
|
52
|
+
: 400
|
|
53
|
+
: 90
|
|
54
|
+
: this._height);
|
|
47
55
|
inset = $derived(typeof this.options.inset === 'number'
|
|
48
56
|
? this.options.inset
|
|
49
|
-
: this.
|
|
57
|
+
: this.singlePosScaleMark
|
|
50
58
|
? 10
|
|
51
59
|
: 0);
|
|
52
60
|
// derived props
|
|
@@ -59,25 +67,29 @@ export class Plot {
|
|
|
59
67
|
// margins = $state<Margins>({ left: 0, right: 0, top: 0, bottom: 0 });
|
|
60
68
|
plotWidth = $derived(this.width - this.margins.left - this.margins.right);
|
|
61
69
|
plotHeight = $derived(this.height - this.margins.top - this.margins.bottom);
|
|
62
|
-
x = new
|
|
63
|
-
y = new
|
|
64
|
-
radius = new
|
|
65
|
-
color = new
|
|
66
|
-
symbol = new
|
|
70
|
+
x = new Scale('x', this);
|
|
71
|
+
y = new Scale('y', this);
|
|
72
|
+
radius = new Scale('radius', this);
|
|
73
|
+
color = new Scale('color', this);
|
|
74
|
+
symbol = new Scale('symbol', this);
|
|
67
75
|
colorSymbolRedundant = $derived(this.color.uniqueMarkProps.length === 1 &&
|
|
68
76
|
this.symbol.uniqueMarkProps.length === 1 &&
|
|
69
77
|
this.color.uniqueMarkProps[0] === this.symbol.uniqueMarkProps[0]);
|
|
70
|
-
xScale = $derived(createScale(this.x.scaleType
|
|
78
|
+
xScale = $derived(createScale(this.x.scaleType, this.options?.x?.domain || this.x.domain, this.options?.x?.reverse
|
|
71
79
|
? [this.margins.left + this.plotWidth - this.inset, this.margins.left + this.inset]
|
|
72
|
-
: [this.margins.left + this.inset, this.margins.left + this.plotWidth - this.inset],
|
|
73
|
-
|
|
80
|
+
: [this.margins.left + this.inset, this.margins.left + this.plotWidth - this.inset],
|
|
81
|
+
// options
|
|
82
|
+
getScaleOptions(this.x.scaleType, this.options.x)));
|
|
83
|
+
yScale = $derived(createScale(this.y.scaleType, this.options.y?.domain || this.y.domain, this.options.y?.reverse
|
|
74
84
|
? [this.margins.top + this.inset, this.height - this.margins.bottom - this.inset]
|
|
75
|
-
: [this.height - this.margins.bottom - this.inset, this.margins.top + this.inset],
|
|
85
|
+
: [this.height - this.margins.bottom - this.inset, this.margins.top + this.inset],
|
|
86
|
+
// options
|
|
87
|
+
getScaleOptions(this.y.scaleType, this.options.y)));
|
|
76
88
|
radiusScale = $derived(createScale(this.radius.scaleType, [0, Math.max(this.radius.domain[0], this.radius.domain[1])], this.options.radius.range));
|
|
77
89
|
symbolScale = $derived(createScale('ordinal', this.symbol.domain, this.options.symbol?.range || this.hasFilledDotMarks
|
|
78
90
|
? ['circle', 'cross', 'diamond', 'square', 'star', 'triangle', 'wye']
|
|
79
|
-
: ['circle', 'plus', 'times', 'triangle2', 'asterisk', 'square2', 'diamond2']));
|
|
80
|
-
colorScale = $derived(createColorScale(this.color.scaleType, this.color.domain, this.options.color.scheme));
|
|
91
|
+
: ['circle', 'plus', 'times', 'triangle2', 'asterisk', 'square2', 'diamond2'], getScaleOptions(this.symbol.scaleType, this.options.symbol || {})));
|
|
92
|
+
colorScale = $derived(createColorScale(this.color.scaleType, this.color.domain, this.options.color?.range || null, this.options.color?.scheme));
|
|
81
93
|
hasAxisXMark = $derived(!!this.marks.find((mark) => mark.type === 'axis-x' && !mark.automatic));
|
|
82
94
|
hasAxisYMark = $derived(!!this.marks.find((mark) => mark.type === 'axis-y' && !mark.automatic));
|
|
83
95
|
constructor(width, height, options) {
|
|
@@ -87,13 +99,27 @@ export class Plot {
|
|
|
87
99
|
this.options = opts;
|
|
88
100
|
}
|
|
89
101
|
addMark(mark) {
|
|
90
|
-
// console.log('addMark: ' + mark);
|
|
91
102
|
this.marks = [...this.marks, mark];
|
|
92
|
-
// add mark to respective channels
|
|
93
|
-
if (mark.channels.has('color'))
|
|
94
|
-
console.log(this.color.uniqueMarkProps);
|
|
95
103
|
}
|
|
96
104
|
removeMark(removeMark) {
|
|
97
105
|
this.marks = this.marks.filter((mark) => mark.id !== removeMark.id);
|
|
98
106
|
}
|
|
99
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* users can pass options to the D3 scale function
|
|
110
|
+
*/
|
|
111
|
+
function getScaleOptions(scaleType, options = {}) {
|
|
112
|
+
return scaleType === 'linear'
|
|
113
|
+
? pick(options, ['clamp', 'unknown'])
|
|
114
|
+
: scaleType === 'pow'
|
|
115
|
+
? pick(options, ['exponent'])
|
|
116
|
+
: scaleType === 'log'
|
|
117
|
+
? { base: 10, ...pick(options, ['base']) }
|
|
118
|
+
: scaleType === 'symlog'
|
|
119
|
+
? pick(options, ['constant'])
|
|
120
|
+
: scaleType === 'point'
|
|
121
|
+
? pick(options, ['padding', 'align', 'round'])
|
|
122
|
+
: scaleType === 'band'
|
|
123
|
+
? pick(options, ['padding', 'paddingInner', 'paddingOuter', 'align', 'round'])
|
|
124
|
+
: {};
|
|
125
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import resolveChannel from '../helpers/resolveChannel.js';
|
|
2
|
+
import { extent } from 'd3-array';
|
|
3
|
+
import { CHANNEL_SCALE } from '../contants.js';
|
|
4
|
+
import { isDateOrNull, isNumberOrNull, isStringOrNull } from '../helpers/typeChecks.js';
|
|
5
|
+
import uniq from 'underscore/modules/uniq.js';
|
|
6
|
+
const FUNCTION = '(function)';
|
|
7
|
+
export class Scale {
|
|
8
|
+
name = undefined;
|
|
9
|
+
plot = $state(undefined);
|
|
10
|
+
constructor(name, plot) {
|
|
11
|
+
this.name = name;
|
|
12
|
+
this.plot = plot;
|
|
13
|
+
}
|
|
14
|
+
// readonly type: ScaleType = SCALE_TYPES.position;
|
|
15
|
+
// all marks that have this channel
|
|
16
|
+
marks = $derived(this.plot?.marks ?? []);
|
|
17
|
+
scaleOptions = $derived(this.plot && this.name !== undefined ? this.plot.options[this.name] || {} : {});
|
|
18
|
+
forceDomain = $derived(this.plot && (this.name === 'x' || this.name === 'y')
|
|
19
|
+
? this.scaleOptions?.domain || null
|
|
20
|
+
: null);
|
|
21
|
+
possibleChannels = $derived(Object.entries(CHANNEL_SCALE)
|
|
22
|
+
.filter(([, channel]) => channel === this.name)
|
|
23
|
+
.map(([prop]) => prop));
|
|
24
|
+
activeMarks = $derived(this.marks.filter((mark) => this.possibleChannels.find((channel) => mark.channels.has(channel) && mark.props[channel] !== undefined)));
|
|
25
|
+
manualActiveMarks = $derived(this.activeMarks.filter((mark) => !mark.automatic));
|
|
26
|
+
propNames = $derived(uniq(this.manualActiveMarks
|
|
27
|
+
.map((mark) => this.possibleChannels
|
|
28
|
+
.filter((channel) => mark.channels.has(channel) &&
|
|
29
|
+
(typeof mark.props[channel] === 'string' ||
|
|
30
|
+
typeof mark.props[channel] === 'function') &&
|
|
31
|
+
!String(mark.props[channel]).startsWith('__'))
|
|
32
|
+
.map((channel) => typeof mark.props[channel] === 'string' ? mark.props[channel] : FUNCTION))
|
|
33
|
+
.flat(2)));
|
|
34
|
+
autoTitle = $derived(this.propNames.length === 1 && this.propNames[0] !== FUNCTION ? this.propNames[0] : null);
|
|
35
|
+
uniqueMarkProps = $derived(uniq(this.manualActiveMarks
|
|
36
|
+
.map((mark) => this.possibleChannels
|
|
37
|
+
.filter((prop) => mark.props[prop] !== undefined)
|
|
38
|
+
.map((prop) => mark.props[prop]))
|
|
39
|
+
.flat(2)));
|
|
40
|
+
dataValues = $derived([
|
|
41
|
+
...this.activeMarks
|
|
42
|
+
// only check marks with data
|
|
43
|
+
.filter((mark) => mark.props.data.length)
|
|
44
|
+
.map((mark) => this.possibleChannels.map((prop) => mark.props.data.map((row) => resolveChannel(prop, row, mark.props))))
|
|
45
|
+
.flat(3)
|
|
46
|
+
.filter((d) => d != null),
|
|
47
|
+
...(this.forceDomain || [])
|
|
48
|
+
]);
|
|
49
|
+
isPosition = $derived(this.name === 'x' || this.name === 'y');
|
|
50
|
+
isColor = $derived(this.name === 'color');
|
|
51
|
+
scaleType = $derived(this.scaleOptions.type ||
|
|
52
|
+
inferScaleType(this.dataValues, { isPosition: this.isPosition, isColor: this.isColor }));
|
|
53
|
+
// readonly valueType = $derived(
|
|
54
|
+
// this.dataValues.every((v) => v == null)
|
|
55
|
+
// ? 'null'
|
|
56
|
+
// : this.dataValues.every(isColorOrNull)
|
|
57
|
+
// ? 'color'
|
|
58
|
+
// : this.dataValues.every(isBooleanOrNull)
|
|
59
|
+
// ? 'boolean'
|
|
60
|
+
// : this.dataValues.every(isStringOrNull)
|
|
61
|
+
// ? 'text'
|
|
62
|
+
// : this.dataValues.every(isNumberOrNull)
|
|
63
|
+
// ? 'number'
|
|
64
|
+
// : this.dataValues.every(isDateOrNull)
|
|
65
|
+
// ? 'date'
|
|
66
|
+
// : 'mixed'
|
|
67
|
+
// );
|
|
68
|
+
domain = $derived(this.scaleOptions.domain || inferScaleDomain(this.dataValues, this.scaleType));
|
|
69
|
+
}
|
|
70
|
+
// opacity: typeof === 'number' && between [0,1]
|
|
71
|
+
function inferScaleType(dataValues, { isPosition, isColor }) {
|
|
72
|
+
if (!dataValues.length)
|
|
73
|
+
return 'linear';
|
|
74
|
+
if (dataValues.every(isNumberOrNull))
|
|
75
|
+
return 'linear';
|
|
76
|
+
if (dataValues.every(isDateOrNull))
|
|
77
|
+
return 'time';
|
|
78
|
+
if (dataValues.every(isStringOrNull))
|
|
79
|
+
return 'band';
|
|
80
|
+
return 'linear';
|
|
81
|
+
}
|
|
82
|
+
function inferScaleDomain(dataValues, scaleType) {
|
|
83
|
+
if (scaleType === 'point' || scaleType === 'band') {
|
|
84
|
+
return uniq(dataValues);
|
|
85
|
+
}
|
|
86
|
+
if (scaleType === 'linear' ||
|
|
87
|
+
scaleType === 'pow' ||
|
|
88
|
+
scaleType === 'log' ||
|
|
89
|
+
scaleType === 'sqrt' ||
|
|
90
|
+
scaleType === 'sequential' ||
|
|
91
|
+
scaleType === 'time') {
|
|
92
|
+
return extent(dataValues);
|
|
93
|
+
}
|
|
94
|
+
}
|
package/dist/contants.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
1
|
+
import type { ScaleName, ChannelName } from './types.js';
|
|
2
|
+
export declare const SCALE_TYPES: Record<ScaleName, symbol>;
|
|
3
|
+
export declare const CHANNEL_SCALE: Record<ChannelName, ScaleName>;
|
package/dist/contants.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const SCALE_TYPES = {
|
|
2
2
|
opacity: Symbol('opacity'),
|
|
3
3
|
color: Symbol('color'),
|
|
4
4
|
x: Symbol('position'),
|
|
@@ -6,9 +6,10 @@ export const CHANNEL_TYPES = {
|
|
|
6
6
|
angle: Symbol('angle'),
|
|
7
7
|
symbol: Symbol('symbol'),
|
|
8
8
|
radius: Symbol('radius'),
|
|
9
|
-
width: Symbol('width')
|
|
9
|
+
width: Symbol('width'),
|
|
10
|
+
fontSize: Symbol('width')
|
|
10
11
|
};
|
|
11
|
-
export const
|
|
12
|
+
export const CHANNEL_SCALE = {
|
|
12
13
|
x: 'x',
|
|
13
14
|
x1: 'x',
|
|
14
15
|
x2: 'x',
|
|
@@ -23,18 +24,19 @@ export const MARK_PROP_CHANNEL = {
|
|
|
23
24
|
opacity: 'opacity',
|
|
24
25
|
fillOpacity: 'opacity',
|
|
25
26
|
strokeOpacity: 'opacity',
|
|
26
|
-
strokeWidth: 'width'
|
|
27
|
+
strokeWidth: 'width',
|
|
28
|
+
fontSize: 'fontSize'
|
|
27
29
|
};
|
|
28
|
-
// export const CHANNEL_MAP: Record<
|
|
29
|
-
// x:
|
|
30
|
-
// y:
|
|
31
|
-
// opacity:
|
|
32
|
-
// strokeOpacity:
|
|
33
|
-
// strokeWidth:
|
|
34
|
-
// fillOpacity:
|
|
35
|
-
// stroke:
|
|
36
|
-
// fill:
|
|
37
|
-
// r:
|
|
38
|
-
// rotate:
|
|
39
|
-
// symbol:
|
|
30
|
+
// export const CHANNEL_MAP: Record<ScaleName, ValueOf<typeof SCALE_TYPES>> = {
|
|
31
|
+
// x: SCALE_TYPES.x,
|
|
32
|
+
// y: SCALE_TYPES.y,
|
|
33
|
+
// opacity: SCALE_TYPES.opacity,
|
|
34
|
+
// strokeOpacity: SCALE_TYPES.opacity,
|
|
35
|
+
// strokeWidth: SCALE_TYPES.width,
|
|
36
|
+
// fillOpacity: SCALE_TYPES.opacity,
|
|
37
|
+
// stroke: SCALE_TYPES.color,
|
|
38
|
+
// fill: SCALE_TYPES.color,
|
|
39
|
+
// r: SCALE_TYPES.radius,
|
|
40
|
+
// rotate: SCALE_TYPES.angle,
|
|
41
|
+
// symbol: SCALE_TYPES.symbol
|
|
40
42
|
// };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { DataRow } from '../types';
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { DataRow } from '../types.js';
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
5
|
data: DataRow[];
|
|
@@ -14,6 +14,6 @@ declare const __propDef: {
|
|
|
14
14
|
export type GroupMultipleProps = typeof __propDef.props;
|
|
15
15
|
export type GroupMultipleEvents = typeof __propDef.events;
|
|
16
16
|
export type GroupMultipleSlots = typeof __propDef.slots;
|
|
17
|
-
export default class GroupMultiple extends
|
|
17
|
+
export default class GroupMultiple extends SvelteComponentTyped<GroupMultipleProps, GroupMultipleEvents, GroupMultipleSlots> {
|
|
18
18
|
}
|
|
19
19
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export default function autoTimeFormat(x:
|
|
1
|
+
import type { Scale } from '../classes/Scale.svelte.js';
|
|
2
|
+
export default function autoTimeFormat(x: Scale, plotWidth: number): (date: Date) => string[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
|
-
import
|
|
2
|
+
import isDate from 'underscore/modules/isDate.js';
|
|
3
3
|
export default function autoTimeFormat(x, plotWidth) {
|
|
4
4
|
const daysPer100Px = ((toNumber(x.domain[1]) - toNumber(x.domain[0])) / plotWidth / 864e5) * 100;
|
|
5
5
|
const format = daysPer100Px < 1 ? 'HH:mm\nMMM DD' : daysPer100Px < 30 ? 'DD\nMMM' : 'MMM\nYYYY';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default function (d3func, args, props = {}) {
|
|
2
|
+
const res = d3func(...args);
|
|
3
|
+
for (const [key, val] of Object.entries(props)) {
|
|
4
|
+
if (typeof res[key] !== 'function')
|
|
5
|
+
throw new Error(`function ${key} does not exist`);
|
|
6
|
+
res[key](val);
|
|
7
|
+
}
|
|
8
|
+
return res;
|
|
9
|
+
}
|
package/dist/helpers/colors.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { interpolateBrBG } from 'd3-scale-chromatic';
|
|
2
|
-
import type { ColorScheme } from '../types';
|
|
2
|
+
import type { ColorScheme } from '../types.js';
|
|
3
3
|
export declare const categoricalSchemes: Map<string, readonly string[]>;
|
|
4
4
|
export declare function isCategoricalScheme(scheme: string): boolean;
|
|
5
5
|
type SchemeGetter = (n: number) => readonly string[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
+
import type { ColorScheme, RawValue } from '../types.js';
|
|
1
2
|
declare const Scales: Record<string, (domain: number[], range: [number, number]) => (val: any) => any>;
|
|
2
3
|
export declare function createScale(type: keyof typeof Scales, domain: any, range: any, options?: {}): (val: any) => any;
|
|
3
|
-
export declare function createColorScale(type: any, domain: string[] | [number, number] | [Date, Date] | [boolean | boolean], scheme:
|
|
4
|
+
export declare function createColorScale(type: any, domain: string[] | [number, number] | [Date, Date] | [boolean | boolean], range: RawValue[] | null, scheme: ColorScheme | null): ((d: any) => any) | (unknown[] & string[] & import("d3-scale").ScaleOrdinal<string, unknown, never>) | import("d3-scale").ScaleSequential<string, never>;
|
|
4
5
|
export {};
|
|
@@ -1,47 +1,68 @@
|
|
|
1
|
-
import { scaleBand, scaleLinear, scaleTime, scaleSqrt, scaleLog, scaleOrdinal } from 'd3-scale';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { scaleBand, scaleLinear, scaleTime, scaleSqrt, scaleLog, scaleOrdinal, scalePoint, scaleSymlog, scalePow } from 'd3-scale';
|
|
2
|
+
import { scaleSequential, scaleDiverging } from 'd3-scale';
|
|
3
|
+
import { getLogTicks } from './getLogTicks.js';
|
|
4
|
+
import { categoricalSchemes, isCategoricalScheme, isQuantitativeScheme, ordinalScheme, quantitativeScheme } from './colors.js';
|
|
5
|
+
import { isColorOrNull } from './typeChecks.js';
|
|
5
6
|
const Scales = {
|
|
7
|
+
point: scalePoint,
|
|
6
8
|
band: scaleBand,
|
|
7
9
|
linear: scaleLinear,
|
|
8
10
|
time: scaleTime,
|
|
9
11
|
sqrt: scaleSqrt,
|
|
12
|
+
pow: scalePow,
|
|
10
13
|
log: scaleLog,
|
|
11
|
-
|
|
14
|
+
symlog: scaleSymlog,
|
|
15
|
+
ordinal: scaleOrdinal,
|
|
16
|
+
sequential: scaleSequential,
|
|
17
|
+
diverging: scaleDiverging
|
|
12
18
|
};
|
|
13
19
|
export function createScale(type, domain, range, options = {}) {
|
|
14
|
-
const scale = Scales[type](
|
|
20
|
+
const scale = Scales[type]();
|
|
21
|
+
// scale defaults
|
|
22
|
+
if (type === 'band' &&
|
|
23
|
+
options.padding === undefined &&
|
|
24
|
+
options.paddingInner === undefined &&
|
|
25
|
+
options.paddingOuter === undefined) {
|
|
26
|
+
options.padding = 0.2;
|
|
27
|
+
}
|
|
15
28
|
// allow setting arbiraty scale options
|
|
16
|
-
|
|
29
|
+
// callWithProps(scale, { domain,})
|
|
30
|
+
for (const [key, val] of Object.entries({ domain, range, ...options })) {
|
|
17
31
|
if (typeof scale[key] === 'function')
|
|
18
32
|
scale[key](val);
|
|
19
33
|
else
|
|
20
34
|
console.warn('unknown scale setter ' + key);
|
|
21
35
|
}
|
|
36
|
+
if (type === 'band' || type === 'point') {
|
|
37
|
+
scale.ticks = () => domain;
|
|
38
|
+
}
|
|
22
39
|
if (type === 'log') {
|
|
23
|
-
// overwrite scaleLog's internal ticks() method
|
|
24
40
|
scale.ticks = (count) => getLogTicks(domain, count);
|
|
25
|
-
// console.log({domain})
|
|
26
|
-
// console.log(getLogTicks(domain, 5))
|
|
27
41
|
}
|
|
28
42
|
return scale;
|
|
29
43
|
}
|
|
30
44
|
const identity = (d) => d;
|
|
31
|
-
export function createColorScale(type, domain, scheme) {
|
|
45
|
+
export function createColorScale(type, domain, range, scheme) {
|
|
46
|
+
if (type === 'identity')
|
|
47
|
+
return identity;
|
|
32
48
|
if (type === 'band') {
|
|
33
49
|
if (domain.every(isColorOrNull)) {
|
|
34
|
-
console.log('domain is colors', domain);
|
|
35
50
|
return identity;
|
|
36
51
|
}
|
|
37
|
-
const colorRange =
|
|
38
|
-
?
|
|
39
|
-
:
|
|
40
|
-
?
|
|
52
|
+
const colorRange = Array.isArray(range)
|
|
53
|
+
? range
|
|
54
|
+
: !scheme
|
|
55
|
+
? categoricalSchemes.get('tableau10')
|
|
41
56
|
: isCategoricalScheme(scheme)
|
|
42
57
|
? categoricalSchemes.get(scheme)
|
|
43
58
|
: ordinalScheme(scheme)(domain.length);
|
|
44
59
|
return scaleOrdinal().domain(domain).range(colorRange);
|
|
45
60
|
}
|
|
61
|
+
else if (type === 'linear') {
|
|
62
|
+
const colorInterpolator = isQuantitativeScheme(scheme)
|
|
63
|
+
? quantitativeScheme(scheme)
|
|
64
|
+
: quantitativeScheme('blues');
|
|
65
|
+
return scaleSequential(domain, colorInterpolator);
|
|
66
|
+
}
|
|
46
67
|
return (d) => d;
|
|
47
68
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { curveBasis, curveBasisClosed, curveBasisOpen, curveBundle, curveBumpX, curveBumpY, curveCardinal, curveCardinalClosed, curveCardinalOpen, curveCatmullRom, curveCatmullRomClosed, curveCatmullRomOpen, curveLinear, curveLinearClosed, curveMonotoneX, curveMonotoneY, curveNatural, curveStep, curveStepAfter, curveStepBefore } from 'd3-shape';
|
|
2
|
+
const curves = new Map([
|
|
3
|
+
['basis', curveBasis],
|
|
4
|
+
['basis-closed', curveBasisClosed],
|
|
5
|
+
['basis-open', curveBasisOpen],
|
|
6
|
+
['bundle', curveBundle],
|
|
7
|
+
['bump-x', curveBumpX],
|
|
8
|
+
['bump-y', curveBumpY],
|
|
9
|
+
['cardinal', curveCardinal],
|
|
10
|
+
['cardinal-closed', curveCardinalClosed],
|
|
11
|
+
['cardinal-open', curveCardinalOpen],
|
|
12
|
+
['catmull-rom', curveCatmullRom],
|
|
13
|
+
['catmull-rom-closed', curveCatmullRomClosed],
|
|
14
|
+
['catmull-rom-open', curveCatmullRomOpen],
|
|
15
|
+
['linear', curveLinear],
|
|
16
|
+
['linear-closed', curveLinearClosed],
|
|
17
|
+
['monotone-x', curveMonotoneX],
|
|
18
|
+
['monotone-y', curveMonotoneY],
|
|
19
|
+
['natural', curveNatural],
|
|
20
|
+
['step', curveStep],
|
|
21
|
+
['step-after', curveStepAfter],
|
|
22
|
+
['step-before', curveStepBefore]
|
|
23
|
+
]);
|
|
24
|
+
export function maybeCurve(curve = curveLinear, tension) {
|
|
25
|
+
if (typeof curve === 'function')
|
|
26
|
+
return curve; // custom curve
|
|
27
|
+
const c = curves.get(`${curve}`.toLowerCase());
|
|
28
|
+
if (!c)
|
|
29
|
+
throw new Error(`unknown curve: ${curve}`);
|
|
30
|
+
if (tension !== undefined) {
|
|
31
|
+
if ('beta' in c) {
|
|
32
|
+
return c.beta(tension);
|
|
33
|
+
}
|
|
34
|
+
else if ('tension' in c) {
|
|
35
|
+
return c.tension(tension);
|
|
36
|
+
}
|
|
37
|
+
else if ('alpha' in c) {
|
|
38
|
+
return c.alpha(tension);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return c;
|
|
42
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { ChannelAccessor, MarkStyleProps, DataRow } from '../types';
|
|
1
|
+
import type { ChannelAccessor, MarkStyleProps, DataRow } from '../types.js';
|
|
2
2
|
export default function (datum: DataRow, props: Partial<Record<MarkStyleProps, ChannelAccessor>>): string;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import resolveChannel from './resolveChannel';
|
|
1
|
+
import resolveChannel from './resolveChannel.js';
|
|
3
2
|
const styleProps = {
|
|
4
3
|
fill: 'fill',
|
|
5
4
|
stroke: 'stroke',
|
|
@@ -13,6 +12,6 @@ const styleProps = {
|
|
|
13
12
|
export default function (datum, props) {
|
|
14
13
|
return Object.entries(styleProps)
|
|
15
14
|
.filter(([key, cssKey]) => cssKey && props[key] != null)
|
|
16
|
-
.map(([key, cssKey]) => `${cssKey}: ${resolveChannel(
|
|
15
|
+
.map(([key, cssKey]) => `${cssKey}: ${resolveChannel(key, datum, props)}`)
|
|
17
16
|
.join(';');
|
|
18
17
|
}
|