@rokkit/chart 1.0.0-next.12 → 1.0.0-next.121
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 +132 -46
- package/dist/Plot/index.d.ts +5 -0
- package/dist/elements/index.d.ts +6 -0
- package/dist/index.d.ts +14 -0
- package/dist/lib/brewing/axes.svelte.d.ts +72 -0
- package/dist/lib/brewing/bars.svelte.d.ts +54 -0
- package/dist/lib/brewing/dimensions.svelte.d.ts +35 -0
- package/dist/lib/brewing/index.svelte.d.ts +118 -0
- package/dist/lib/brewing/legends.svelte.d.ts +54 -0
- package/dist/lib/brewing/scales.svelte.d.ts +29 -0
- package/dist/lib/brewing/types.d.ts +162 -0
- package/dist/lib/context.d.ts +13 -0
- package/dist/lib/scales.svelte.d.ts +35 -0
- package/dist/lib/utils.d.ts +58 -0
- package/dist/old_lib/brewer.d.ts +9 -0
- package/dist/old_lib/chart.d.ts +40 -0
- package/dist/old_lib/grid.d.ts +72 -0
- package/dist/old_lib/index.d.ts +4 -0
- package/dist/old_lib/plots.d.ts +3 -0
- package/dist/old_lib/swatch.d.ts +285 -0
- package/dist/old_lib/ticks.d.ts +36 -0
- package/dist/old_lib/utils.d.ts +1 -0
- package/dist/patterns/index.d.ts +9 -0
- package/dist/patterns/paths/constants.d.ts +1 -0
- package/dist/symbols/constants/index.d.ts +1 -0
- package/dist/symbols/index.d.ts +5 -0
- package/dist/template/constants.d.ts +43 -0
- package/dist/template/shapes/index.d.ts +4 -0
- package/package.json +28 -44
- package/src/Plot/Axis.svelte +103 -0
- package/src/Plot/Bar.svelte +95 -0
- package/src/Plot/Grid.svelte +68 -0
- package/src/Plot/Legend.svelte +129 -0
- package/src/Plot/Root.svelte +112 -0
- package/src/Plot/index.js +5 -0
- package/src/Symbol.svelte +21 -0
- package/src/{chart/Texture.svelte → Texture.svelte} +3 -3
- package/src/elements/Bar.svelte +2 -8
- package/src/elements/ColorRamp.svelte +3 -5
- package/src/elements/ContinuousLegend.svelte +4 -5
- package/src/elements/DefinePatterns.svelte +22 -0
- package/src/elements/DiscreteLegend.svelte +3 -5
- package/src/elements/Label.svelte +6 -5
- package/src/elements/SymbolGrid.svelte +23 -0
- package/src/elements/index.js +6 -0
- package/src/examples/BarChartExample.svelte +81 -0
- package/src/index.js +18 -16
- package/src/lib/brewing/axes.svelte.js +179 -0
- package/src/lib/brewing/bars.svelte.js +114 -0
- package/src/lib/brewing/dimensions.svelte.js +54 -0
- package/src/lib/brewing/index.svelte.js +214 -0
- package/src/lib/brewing/legends.svelte.js +95 -0
- package/src/lib/brewing/scales.svelte.js +94 -0
- package/src/lib/brewing/types.js +73 -0
- package/src/lib/context.js +122 -0
- package/src/lib/scales.svelte.js +129 -0
- package/src/lib/utils.js +110 -132
- package/src/old_lib/brewer.js +25 -0
- package/src/old_lib/chart.js +213 -0
- package/src/old_lib/grid.js +85 -0
- package/src/old_lib/index.js +4 -0
- package/src/old_lib/plots.js +27 -0
- package/src/old_lib/swatch.js +16 -0
- package/src/old_lib/ticks.js +46 -0
- package/src/old_lib/utils.js +8 -0
- package/src/patterns/Brick.svelte +17 -0
- package/src/patterns/Circles.svelte +18 -0
- package/src/patterns/CrossHatch.svelte +14 -0
- package/src/patterns/CurvedWave.svelte +9 -0
- package/src/patterns/Dots.svelte +19 -0
- package/src/patterns/OutlineCircles.svelte +15 -0
- package/src/patterns/Tile.svelte +17 -0
- package/src/patterns/Triangles.svelte +15 -0
- package/src/patterns/Waves.svelte +13 -0
- package/src/patterns/index.js +14 -0
- package/src/patterns/paths/NamedPattern.svelte +12 -0
- package/src/patterns/paths/constants.js +4 -0
- package/src/symbols/RoundedSquare.svelte +27 -0
- package/src/symbols/Shape.svelte +31 -0
- package/src/symbols/constants/index.js +4 -0
- package/src/symbols/index.js +9 -0
- package/src/symbols/outline.svelte +60 -0
- package/src/symbols/solid.svelte +60 -0
- package/src/template/Texture.svelte +16 -0
- package/src/template/constants.js +43 -0
- package/src/template/shapes/Circles.svelte +16 -0
- package/src/template/shapes/Lines.svelte +17 -0
- package/src/template/shapes/Path.svelte +12 -0
- package/src/template/shapes/Polygons.svelte +18 -0
- package/src/template/shapes/index.js +4 -0
- package/LICENSE +0 -21
- package/src/chart/FacetGrid.svelte +0 -51
- package/src/chart/Grid.svelte +0 -34
- package/src/chart/Legend.svelte +0 -16
- package/src/chart/PatternDefs.svelte +0 -13
- package/src/chart/Swatch.svelte +0 -93
- package/src/chart/SwatchButton.svelte +0 -29
- package/src/chart/SwatchGrid.svelte +0 -55
- package/src/chart/Symbol.svelte +0 -37
- package/src/chart/TexturedShape.svelte +0 -27
- package/src/chart/TimelapseChart.svelte +0 -97
- package/src/chart/Timer.svelte +0 -27
- package/src/chart.js +0 -9
- package/src/components/charts/Axis.svelte +0 -66
- package/src/components/charts/Chart.svelte +0 -35
- package/src/components/index.js +0 -23
- package/src/components/lib/axis.js +0 -0
- package/src/components/lib/chart.js +0 -187
- package/src/components/lib/color.js +0 -327
- package/src/components/lib/funnel.js +0 -204
- package/src/components/lib/index.js +0 -19
- package/src/components/lib/pattern.js +0 -190
- package/src/components/lib/rollup.js +0 -55
- package/src/components/lib/shape.js +0 -199
- package/src/components/lib/summary.js +0 -145
- package/src/components/lib/theme.js +0 -23
- package/src/components/lib/timer.js +0 -41
- package/src/components/lib/utils.js +0 -165
- package/src/components/plots/BarPlot.svelte +0 -36
- package/src/components/plots/BoxPlot.svelte +0 -54
- package/src/components/plots/ScatterPlot.svelte +0 -30
- package/src/components/store.js +0 -70
- package/src/constants.js +0 -66
- package/src/elements/PatternDefs.svelte +0 -13
- package/src/elements/PatternMask.svelte +0 -20
- package/src/elements/Symbol.svelte +0 -38
- package/src/elements/Tooltip.svelte +0 -23
- package/src/funnel.svelte +0 -35
- package/src/geom.js +0 -105
- package/src/lib/axis.js +0 -75
- package/src/lib/colors.js +0 -32
- package/src/lib/geom.js +0 -4
- package/src/lib/shapes.js +0 -144
- package/src/lib/timer.js +0 -44
- package/src/lookup.js +0 -29
- package/src/plots/BarPlot.svelte +0 -55
- package/src/plots/BoxPlot.svelte +0 -0
- package/src/plots/FunnelPlot.svelte +0 -33
- package/src/plots/HeatMap.svelte +0 -5
- package/src/plots/HeatMapCalendar.svelte +0 -129
- package/src/plots/LinePlot.svelte +0 -55
- package/src/plots/Plot.svelte +0 -25
- package/src/plots/RankBarPlot.svelte +0 -38
- package/src/plots/ScatterPlot.svelte +0 -20
- package/src/plots/ViolinPlot.svelte +0 -11
- package/src/plots/heatmap.js +0 -70
- package/src/plots/index.js +0 -10
- package/src/swatch.js +0 -11
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { writable, derived } from 'svelte/store';
|
|
3
|
+
import * as d3 from 'd3';
|
|
4
|
+
|
|
5
|
+
const CHART_CONTEXT = 'chart-context';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates chart context and provides it to child components
|
|
9
|
+
*
|
|
10
|
+
* @param {Object} options Initial chart options
|
|
11
|
+
* @returns {Object} Chart context with all stores and methods
|
|
12
|
+
*/
|
|
13
|
+
export function createChartContext(options = {}) {
|
|
14
|
+
// Default config values
|
|
15
|
+
const defaultOptions = {
|
|
16
|
+
width: 600,
|
|
17
|
+
height: 400,
|
|
18
|
+
margin: { top: 20, right: 30, bottom: 40, left: 50 },
|
|
19
|
+
padding: { top: 0, right: 0, bottom: 0, left: 0 },
|
|
20
|
+
responsive: true,
|
|
21
|
+
animationDuration: 300,
|
|
22
|
+
data: []
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Merge options with defaults
|
|
26
|
+
const config = { ...defaultOptions, ...options };
|
|
27
|
+
|
|
28
|
+
// Create stores for reactive properties
|
|
29
|
+
const dimensions = writable({
|
|
30
|
+
width: config.width,
|
|
31
|
+
height: config.height,
|
|
32
|
+
margin: { ...config.margin },
|
|
33
|
+
padding: { ...config.padding }
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const data = writable(config.data);
|
|
37
|
+
const scales = writable({});
|
|
38
|
+
|
|
39
|
+
// Compute inner dimensions (subtracting margins)
|
|
40
|
+
const innerDimensions = derived(dimensions, $dimensions => {
|
|
41
|
+
return {
|
|
42
|
+
width: $dimensions.width - $dimensions.margin.left - $dimensions.margin.right - $dimensions.padding.left - $dimensions.padding.right,
|
|
43
|
+
height: $dimensions.height - $dimensions.margin.top - $dimensions.margin.bottom - $dimensions.padding.top - $dimensions.padding.bottom
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Store for plot elements (bars, lines, etc.)
|
|
48
|
+
const plots = writable([]);
|
|
49
|
+
|
|
50
|
+
// Store for axes
|
|
51
|
+
const axes = writable({
|
|
52
|
+
x: null,
|
|
53
|
+
y: null
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const legend = writable({
|
|
57
|
+
enabled: false,
|
|
58
|
+
items: []
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Helper to add a new plot
|
|
62
|
+
function addPlot(plot) {
|
|
63
|
+
plots.update(currentPlots => [...currentPlots, plot]);
|
|
64
|
+
return () => {
|
|
65
|
+
plots.update(currentPlots => currentPlots.filter(p => p !== plot));
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Helper to update scales based on data and dimensions
|
|
70
|
+
function updateScales(xKey, yKey, colorKey = null) {
|
|
71
|
+
return derived([data, innerDimensions], ([$data, $innerDimensions]) => {
|
|
72
|
+
if (!$data || $data.length === 0) return null;
|
|
73
|
+
|
|
74
|
+
const xScale = d3.scaleBand()
|
|
75
|
+
.domain($data.map(d => d[xKey]))
|
|
76
|
+
.range([0, $innerDimensions.width])
|
|
77
|
+
.padding(0.2);
|
|
78
|
+
|
|
79
|
+
const yScale = d3.scaleLinear()
|
|
80
|
+
.domain([0, d3.max($data, d => d[yKey])])
|
|
81
|
+
.nice()
|
|
82
|
+
.range([$innerDimensions.height, 0]);
|
|
83
|
+
|
|
84
|
+
let colorScale = null;
|
|
85
|
+
|
|
86
|
+
if (colorKey) {
|
|
87
|
+
const uniqueCategories = [...new Set($data.map(d => d[colorKey]))];
|
|
88
|
+
colorScale = d3.scaleOrdinal()
|
|
89
|
+
.domain(uniqueCategories)
|
|
90
|
+
.range(d3.schemeCategory10);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { xScale, yScale, colorScale };
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Create and set context
|
|
98
|
+
const chartContext = {
|
|
99
|
+
dimensions,
|
|
100
|
+
innerDimensions,
|
|
101
|
+
data,
|
|
102
|
+
scales,
|
|
103
|
+
plots,
|
|
104
|
+
axes,
|
|
105
|
+
legend,
|
|
106
|
+
addPlot,
|
|
107
|
+
updateScales
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
setContext(CHART_CONTEXT, chartContext);
|
|
111
|
+
|
|
112
|
+
return chartContext;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Gets chart context provided by parent component
|
|
117
|
+
*
|
|
118
|
+
* @returns {Object} Chart context
|
|
119
|
+
*/
|
|
120
|
+
export function getChartContext() {
|
|
121
|
+
return getContext(CHART_CONTEXT);
|
|
122
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { scaleBand, scaleLinear, scaleTime, scaleOrdinal } from 'd3-scale';
|
|
2
|
+
import { schemeCategory10 } from 'd3-scale-chromatic';
|
|
3
|
+
import { min, max } from 'd3-array';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates appropriate scales based on data and dimensions
|
|
7
|
+
*
|
|
8
|
+
* @param {Array} data The dataset
|
|
9
|
+
* @param {string} xKey Field to use for x-axis
|
|
10
|
+
* @param {string} yKey Field to use for y-axis
|
|
11
|
+
* @param {Object} dimensions Chart dimensions
|
|
12
|
+
* @param {Object} options Additional options
|
|
13
|
+
* @returns {Object} Object containing xScale, yScale, and colorScale
|
|
14
|
+
*/
|
|
15
|
+
export function createScales(data, xKey, yKey, dimensions, options = {}) {
|
|
16
|
+
if (!data || data.length === 0) return {};
|
|
17
|
+
|
|
18
|
+
const { colorKey = null, padding = 0.2 } = options;
|
|
19
|
+
|
|
20
|
+
// Determine if x values are numeric, dates, or categorical
|
|
21
|
+
const xValues = data.map(d => d[xKey]);
|
|
22
|
+
const xIsDate = xValues.some(v => v instanceof Date);
|
|
23
|
+
const xIsNumeric = !xIsDate && xValues.every(v => !isNaN(parseFloat(v)));
|
|
24
|
+
|
|
25
|
+
// Create x-scale based on data type
|
|
26
|
+
let xScale;
|
|
27
|
+
if (xIsDate) {
|
|
28
|
+
xScale = scaleTime()
|
|
29
|
+
.domain([min(xValues), max(xValues)])
|
|
30
|
+
.range([0, dimensions.innerWidth])
|
|
31
|
+
.nice();
|
|
32
|
+
} else if (xIsNumeric) {
|
|
33
|
+
xScale = scaleLinear()
|
|
34
|
+
.domain([min([0, ...xValues]), max(xValues)])
|
|
35
|
+
.range([0, dimensions.innerWidth])
|
|
36
|
+
.nice();
|
|
37
|
+
} else {
|
|
38
|
+
xScale = scaleBand()
|
|
39
|
+
.domain(xValues)
|
|
40
|
+
.range([0, dimensions.innerWidth])
|
|
41
|
+
.padding(padding);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Create y-scale
|
|
45
|
+
const yValues = data.map(d => d[yKey]);
|
|
46
|
+
const yScale = scaleLinear()
|
|
47
|
+
.domain([0, max(yValues) * 1.1]) // Add 10% padding on top
|
|
48
|
+
.nice()
|
|
49
|
+
.range([dimensions.innerHeight, 0]);
|
|
50
|
+
|
|
51
|
+
// Create color scale if colorKey is provided
|
|
52
|
+
let colorScale = null;
|
|
53
|
+
if (colorKey) {
|
|
54
|
+
const uniqueCategories = [...new Set(data.map(d => d[colorKey]))];
|
|
55
|
+
colorScale = scaleOrdinal()
|
|
56
|
+
.domain(uniqueCategories)
|
|
57
|
+
.range(schemeCategory10);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { xScale, yScale, colorScale };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Calculates the actual chart dimensions after applying margins
|
|
65
|
+
*
|
|
66
|
+
* @param {Object} dimensions Original dimensions
|
|
67
|
+
* @returns {Object} Dimensions with calculated inner width and height
|
|
68
|
+
*/
|
|
69
|
+
export function calculateChartDimensions(width, height, margin) {
|
|
70
|
+
return {
|
|
71
|
+
width,
|
|
72
|
+
height,
|
|
73
|
+
margin,
|
|
74
|
+
innerWidth: width - margin.left - margin.right,
|
|
75
|
+
innerHeight: height - margin.top - margin.bottom
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Gets the axis origin value
|
|
81
|
+
*
|
|
82
|
+
* @param {Object} scale D3 scale
|
|
83
|
+
* @returns {number} Origin value
|
|
84
|
+
*/
|
|
85
|
+
export function getOriginValue(scale) {
|
|
86
|
+
return scale.ticks
|
|
87
|
+
? scale(Math.max(0, min(scale.domain())))
|
|
88
|
+
: scale.range()[0];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Creates axis ticks
|
|
93
|
+
*
|
|
94
|
+
* @param {Object} scale D3 scale
|
|
95
|
+
* @param {string} axis Axis type ('x' or 'y')
|
|
96
|
+
* @param {number} count Number of ticks
|
|
97
|
+
* @param {number} fontSize Font size for determining tick density
|
|
98
|
+
* @returns {Array} Array of tick objects
|
|
99
|
+
*/
|
|
100
|
+
export function createTicks(scale, axis, count = null, fontSize = 12) {
|
|
101
|
+
const [minRange, maxRange] = scale.range();
|
|
102
|
+
let ticks = [];
|
|
103
|
+
let offset = 0;
|
|
104
|
+
|
|
105
|
+
// Calculate default count based on available space
|
|
106
|
+
if (!count) {
|
|
107
|
+
count = Math.abs((maxRange - minRange) / (fontSize * (axis === 'y' ? 3 : 6)));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Get ticks based on scale type
|
|
111
|
+
if (scale.ticks) {
|
|
112
|
+
ticks = scale.ticks(Math.round(count));
|
|
113
|
+
} else {
|
|
114
|
+
offset = scale.bandwidth() / 2;
|
|
115
|
+
count = Math.min(Math.round(count), scale.domain().length);
|
|
116
|
+
|
|
117
|
+
ticks = scale.domain();
|
|
118
|
+
if (count < scale.domain().length) {
|
|
119
|
+
const step = Math.ceil(scale.domain().length / count);
|
|
120
|
+
ticks = ticks.filter((_, i) => i % step === 0);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Format ticks with positions
|
|
125
|
+
return ticks.map(t => ({
|
|
126
|
+
value: t,
|
|
127
|
+
position: scale(t) + (axis === 'x' ? offset : 0)
|
|
128
|
+
}));
|
|
129
|
+
}
|
package/src/lib/utils.js
CHANGED
|
@@ -1,157 +1,135 @@
|
|
|
1
|
-
import { scaleBand, scaleLinear } from 'd3-scale'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { nest } from 'd3-collection'
|
|
5
|
-
import { omit } from 'ramda'
|
|
1
|
+
import { scaleBand, scaleLinear, scaleOrdinal } from 'd3-scale';
|
|
2
|
+
import { schemeCategory10 } from 'd3-scale-chromatic';
|
|
3
|
+
import { max } from 'd3-array';
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {
|
|
16
|
-
* @
|
|
17
|
-
* @param {number} columns
|
|
18
|
-
* @param {number} rows
|
|
19
|
-
* @returns
|
|
6
|
+
* Creates appropriate scales based on data and dimensions
|
|
7
|
+
*
|
|
8
|
+
* @param {Array} data The dataset
|
|
9
|
+
* @param {string} xKey Field to use for x-axis
|
|
10
|
+
* @param {string} yKey Field to use for y-axis
|
|
11
|
+
* @param {Object} dimensions Chart dimensions
|
|
12
|
+
* @param {Object} [options] Additional options
|
|
13
|
+
* @param {string} [options.colorKey] Field to use for color mapping
|
|
14
|
+
* @returns {Object} Object containing xScale, yScale, and colorScale
|
|
20
15
|
*/
|
|
21
|
-
export function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
16
|
+
export function createScales(data, xKey, yKey, dimensions, options = {}) {
|
|
17
|
+
if (!data || data.length === 0) return {};
|
|
18
|
+
|
|
19
|
+
const xScale = scaleBand()
|
|
20
|
+
.domain(data.map(d => d[xKey]))
|
|
21
|
+
.range([0, dimensions.width])
|
|
22
|
+
.padding(0.2);
|
|
23
|
+
|
|
24
|
+
const yScale = scaleLinear()
|
|
25
|
+
.domain([0, max(data, d => d[yKey]) * 1.1]) // Add 10% padding on top
|
|
26
|
+
.nice()
|
|
27
|
+
.range([dimensions.height, 0]);
|
|
28
|
+
|
|
29
|
+
let colorScale = null;
|
|
30
|
+
|
|
31
|
+
if (options.colorKey) {
|
|
32
|
+
const uniqueCategories = [...new Set(data.map(d => d[options.colorKey]))];
|
|
33
|
+
colorScale = scaleOrdinal()
|
|
34
|
+
.domain(uniqueCategories)
|
|
35
|
+
.range(schemeCategory10);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { xScale, yScale, colorScale };
|
|
40
39
|
}
|
|
40
|
+
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @param {
|
|
45
|
-
* @
|
|
46
|
-
* @param {number} buffer
|
|
47
|
-
* @returns
|
|
42
|
+
* Calculates the actual chart dimensions after applying margins
|
|
43
|
+
*
|
|
44
|
+
* @param {Object} dimensions Original dimensions
|
|
45
|
+
* @returns {Object} Dimensions with calculated inner width and height
|
|
48
46
|
*/
|
|
49
|
-
export function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (minValue < 0 && maxValue > 0) {
|
|
59
|
-
maxValue = max([-1 * minValue, maxValue])
|
|
60
|
-
minValue = -1 * maxValue
|
|
61
|
-
}
|
|
62
|
-
const margin = (maxValue - minValue) * buffer
|
|
63
|
-
return scaleLinear()
|
|
64
|
-
.domain([minValue - margin, maxValue + margin])
|
|
65
|
-
.range(bounds)
|
|
66
|
-
}
|
|
47
|
+
export function calculateChartDimensions(dimensions) {
|
|
48
|
+
const { width, height, margin } = dimensions;
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
...dimensions,
|
|
52
|
+
innerWidth: width - margin.left - margin.right,
|
|
53
|
+
innerHeight: height - margin.top - margin.bottom
|
|
54
|
+
};
|
|
67
55
|
}
|
|
56
|
+
|
|
68
57
|
/**
|
|
69
|
-
*
|
|
58
|
+
* Normalizes data for use with D3 charts
|
|
70
59
|
*
|
|
71
|
-
* @param {
|
|
72
|
-
* @
|
|
73
|
-
* @param {string} y
|
|
74
|
-
* @param {number} width
|
|
75
|
-
* @param {number} height
|
|
76
|
-
* @returns
|
|
60
|
+
* @param {Array|Object} inputData Raw data or dataset object
|
|
61
|
+
* @returns {Array} Normalized data array
|
|
77
62
|
*/
|
|
78
|
-
export function
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
63
|
+
export function normalizeData(inputData) {
|
|
64
|
+
if (!inputData) return [];
|
|
65
|
+
|
|
66
|
+
// If it's a dataset class instance, call select() to get the data
|
|
67
|
+
if (inputData.select && typeof inputData.select === 'function') {
|
|
68
|
+
return inputData.select();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// If it's already an array, return as is
|
|
72
|
+
if (Array.isArray(inputData)) {
|
|
73
|
+
return inputData;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return [];
|
|
86
77
|
}
|
|
87
78
|
|
|
88
79
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* @
|
|
93
|
-
* @param {*} x
|
|
94
|
-
* @param {*} y
|
|
95
|
-
* @returns
|
|
80
|
+
* Generates a unique ID for SVG elements
|
|
81
|
+
*
|
|
82
|
+
* @param {string} prefix Prefix for the ID
|
|
83
|
+
* @returns {string} A unique ID
|
|
96
84
|
*/
|
|
97
|
-
export function
|
|
98
|
-
|
|
99
|
-
.key((d) => d[x])
|
|
100
|
-
.rollup((d) => {
|
|
101
|
-
let values = d.map((g) => g[y]).sort(ascending)
|
|
102
|
-
let q1 = quantile(values, 0.25)
|
|
103
|
-
let q3 = quantile(values, 0.75)
|
|
104
|
-
let median = quantile(values, 0.5)
|
|
105
|
-
let interQuantileRange = q3 - q1
|
|
106
|
-
let min = q1 - 1.5 * interQuantileRange
|
|
107
|
-
let max = q3 + 1.5 * interQuantileRange
|
|
108
|
-
return { q1, q3, median, interQuantileRange, min, max }
|
|
109
|
-
})
|
|
110
|
-
.entries(data)
|
|
111
|
-
return summary
|
|
85
|
+
export function uniqueId(prefix = 'chart') {
|
|
86
|
+
return `${prefix}-${Math.random().toString(36).substring(2, 10)}`;
|
|
112
87
|
}
|
|
113
88
|
|
|
114
89
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* @param {
|
|
119
|
-
* @
|
|
120
|
-
* @param {*} fallback
|
|
121
|
-
* @returns
|
|
90
|
+
* Formats tooltip content for a data point
|
|
91
|
+
*
|
|
92
|
+
* @param {Object} d Data point
|
|
93
|
+
* @param {Object} options Tooltip format options
|
|
94
|
+
* @returns {string} Formatted tooltip HTML content
|
|
122
95
|
*/
|
|
123
|
-
export function
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
96
|
+
export function formatTooltipContent(d, options = {}) {
|
|
97
|
+
if (!d) return '';
|
|
98
|
+
|
|
99
|
+
const { xKey, yKey, xFormat, yFormat } = options;
|
|
100
|
+
|
|
101
|
+
if (xKey && yKey) {
|
|
102
|
+
const xValue = d[xKey];
|
|
103
|
+
const yValue = d[yKey];
|
|
104
|
+
|
|
105
|
+
const xFormatted = xFormat ? xFormat(xValue) : xValue;
|
|
106
|
+
const yFormatted = yFormat ? yFormat(yValue) : yValue;
|
|
107
|
+
|
|
108
|
+
return `${xKey}: ${xFormatted}<br>${yKey}: ${yFormatted}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return Object.entries(d)
|
|
112
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
113
|
+
.join('<br>');
|
|
127
114
|
}
|
|
128
115
|
|
|
129
116
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* @param {Array<Object>} data
|
|
135
|
-
* @param {string} key
|
|
136
|
-
* @param {string} label
|
|
137
|
-
* @returns
|
|
117
|
+
* Generates a tooltip formatter function
|
|
118
|
+
*
|
|
119
|
+
* @param {Object} options Tooltip format options
|
|
120
|
+
* @returns {Function} A function that formats tooltip content
|
|
138
121
|
*/
|
|
139
|
-
export function
|
|
140
|
-
|
|
141
|
-
.key((d) => d[key])
|
|
142
|
-
.rollup((values) => values.map((value) => omit([key], value)))
|
|
143
|
-
.entries(data.sort((a, b) => ascending(a[label], b[label])))
|
|
122
|
+
export function createTooltipFormatter(options = {}) {
|
|
123
|
+
return (d) => formatTooltipContent(d, options);
|
|
144
124
|
}
|
|
125
|
+
|
|
145
126
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* @param {
|
|
149
|
-
* @param {
|
|
150
|
-
* @returns {
|
|
127
|
+
* Calculates the transform attribute for SVG elements
|
|
128
|
+
*
|
|
129
|
+
* @param {number} x X position
|
|
130
|
+
* @param {number} y Y position
|
|
131
|
+
* @returns {string} Transform attribute value
|
|
151
132
|
*/
|
|
152
|
-
export function
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
{}
|
|
156
|
-
)
|
|
157
|
-
}
|
|
133
|
+
export function transform(x, y) {
|
|
134
|
+
return `translate(${x}, ${y})`;
|
|
135
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get fill patterns for a set of values
|
|
3
|
+
*
|
|
4
|
+
* @param {Array} values - Array of values
|
|
5
|
+
* @param {Object} swatch - Object with keys for color, gray, and pattern
|
|
6
|
+
* @param {Boolean} gray - Boolean to determine if gray or color
|
|
7
|
+
* @returns {Object} - Object with keys for pattern and color
|
|
8
|
+
*/
|
|
9
|
+
export function getFillPatterns(values, swatch, gray = false) {
|
|
10
|
+
const colors = gray ? swatch.keys.gray : swatch.keys.color
|
|
11
|
+
const max_colors = colors.length
|
|
12
|
+
const max_patterns = swatch.keys.pattern.length
|
|
13
|
+
|
|
14
|
+
const mix = values
|
|
15
|
+
.map((value, index) => ({
|
|
16
|
+
[value]: {
|
|
17
|
+
pattern: swatch.keys.pattern[index % max_patterns],
|
|
18
|
+
color: colors[index % max_colors]
|
|
19
|
+
}
|
|
20
|
+
}))
|
|
21
|
+
.reduce((acc, current) => ({ ...acc, ...current }), {})
|
|
22
|
+
return mix
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// export function getStrokePatterns() {}
|