@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.
Files changed (148) hide show
  1. package/README.md +132 -46
  2. package/dist/Plot/index.d.ts +5 -0
  3. package/dist/elements/index.d.ts +6 -0
  4. package/dist/index.d.ts +14 -0
  5. package/dist/lib/brewing/axes.svelte.d.ts +72 -0
  6. package/dist/lib/brewing/bars.svelte.d.ts +54 -0
  7. package/dist/lib/brewing/dimensions.svelte.d.ts +35 -0
  8. package/dist/lib/brewing/index.svelte.d.ts +118 -0
  9. package/dist/lib/brewing/legends.svelte.d.ts +54 -0
  10. package/dist/lib/brewing/scales.svelte.d.ts +29 -0
  11. package/dist/lib/brewing/types.d.ts +162 -0
  12. package/dist/lib/context.d.ts +13 -0
  13. package/dist/lib/scales.svelte.d.ts +35 -0
  14. package/dist/lib/utils.d.ts +58 -0
  15. package/dist/old_lib/brewer.d.ts +9 -0
  16. package/dist/old_lib/chart.d.ts +40 -0
  17. package/dist/old_lib/grid.d.ts +72 -0
  18. package/dist/old_lib/index.d.ts +4 -0
  19. package/dist/old_lib/plots.d.ts +3 -0
  20. package/dist/old_lib/swatch.d.ts +285 -0
  21. package/dist/old_lib/ticks.d.ts +36 -0
  22. package/dist/old_lib/utils.d.ts +1 -0
  23. package/dist/patterns/index.d.ts +9 -0
  24. package/dist/patterns/paths/constants.d.ts +1 -0
  25. package/dist/symbols/constants/index.d.ts +1 -0
  26. package/dist/symbols/index.d.ts +5 -0
  27. package/dist/template/constants.d.ts +43 -0
  28. package/dist/template/shapes/index.d.ts +4 -0
  29. package/package.json +28 -44
  30. package/src/Plot/Axis.svelte +103 -0
  31. package/src/Plot/Bar.svelte +95 -0
  32. package/src/Plot/Grid.svelte +68 -0
  33. package/src/Plot/Legend.svelte +129 -0
  34. package/src/Plot/Root.svelte +112 -0
  35. package/src/Plot/index.js +5 -0
  36. package/src/Symbol.svelte +21 -0
  37. package/src/{chart/Texture.svelte → Texture.svelte} +3 -3
  38. package/src/elements/Bar.svelte +2 -8
  39. package/src/elements/ColorRamp.svelte +3 -5
  40. package/src/elements/ContinuousLegend.svelte +4 -5
  41. package/src/elements/DefinePatterns.svelte +22 -0
  42. package/src/elements/DiscreteLegend.svelte +3 -5
  43. package/src/elements/Label.svelte +6 -5
  44. package/src/elements/SymbolGrid.svelte +23 -0
  45. package/src/elements/index.js +6 -0
  46. package/src/examples/BarChartExample.svelte +81 -0
  47. package/src/index.js +18 -16
  48. package/src/lib/brewing/axes.svelte.js +179 -0
  49. package/src/lib/brewing/bars.svelte.js +114 -0
  50. package/src/lib/brewing/dimensions.svelte.js +54 -0
  51. package/src/lib/brewing/index.svelte.js +214 -0
  52. package/src/lib/brewing/legends.svelte.js +95 -0
  53. package/src/lib/brewing/scales.svelte.js +94 -0
  54. package/src/lib/brewing/types.js +73 -0
  55. package/src/lib/context.js +122 -0
  56. package/src/lib/scales.svelte.js +129 -0
  57. package/src/lib/utils.js +110 -132
  58. package/src/old_lib/brewer.js +25 -0
  59. package/src/old_lib/chart.js +213 -0
  60. package/src/old_lib/grid.js +85 -0
  61. package/src/old_lib/index.js +4 -0
  62. package/src/old_lib/plots.js +27 -0
  63. package/src/old_lib/swatch.js +16 -0
  64. package/src/old_lib/ticks.js +46 -0
  65. package/src/old_lib/utils.js +8 -0
  66. package/src/patterns/Brick.svelte +17 -0
  67. package/src/patterns/Circles.svelte +18 -0
  68. package/src/patterns/CrossHatch.svelte +14 -0
  69. package/src/patterns/CurvedWave.svelte +9 -0
  70. package/src/patterns/Dots.svelte +19 -0
  71. package/src/patterns/OutlineCircles.svelte +15 -0
  72. package/src/patterns/Tile.svelte +17 -0
  73. package/src/patterns/Triangles.svelte +15 -0
  74. package/src/patterns/Waves.svelte +13 -0
  75. package/src/patterns/index.js +14 -0
  76. package/src/patterns/paths/NamedPattern.svelte +12 -0
  77. package/src/patterns/paths/constants.js +4 -0
  78. package/src/symbols/RoundedSquare.svelte +27 -0
  79. package/src/symbols/Shape.svelte +31 -0
  80. package/src/symbols/constants/index.js +4 -0
  81. package/src/symbols/index.js +9 -0
  82. package/src/symbols/outline.svelte +60 -0
  83. package/src/symbols/solid.svelte +60 -0
  84. package/src/template/Texture.svelte +16 -0
  85. package/src/template/constants.js +43 -0
  86. package/src/template/shapes/Circles.svelte +16 -0
  87. package/src/template/shapes/Lines.svelte +17 -0
  88. package/src/template/shapes/Path.svelte +12 -0
  89. package/src/template/shapes/Polygons.svelte +18 -0
  90. package/src/template/shapes/index.js +4 -0
  91. package/LICENSE +0 -21
  92. package/src/chart/FacetGrid.svelte +0 -51
  93. package/src/chart/Grid.svelte +0 -34
  94. package/src/chart/Legend.svelte +0 -16
  95. package/src/chart/PatternDefs.svelte +0 -13
  96. package/src/chart/Swatch.svelte +0 -93
  97. package/src/chart/SwatchButton.svelte +0 -29
  98. package/src/chart/SwatchGrid.svelte +0 -55
  99. package/src/chart/Symbol.svelte +0 -37
  100. package/src/chart/TexturedShape.svelte +0 -27
  101. package/src/chart/TimelapseChart.svelte +0 -97
  102. package/src/chart/Timer.svelte +0 -27
  103. package/src/chart.js +0 -9
  104. package/src/components/charts/Axis.svelte +0 -66
  105. package/src/components/charts/Chart.svelte +0 -35
  106. package/src/components/index.js +0 -23
  107. package/src/components/lib/axis.js +0 -0
  108. package/src/components/lib/chart.js +0 -187
  109. package/src/components/lib/color.js +0 -327
  110. package/src/components/lib/funnel.js +0 -204
  111. package/src/components/lib/index.js +0 -19
  112. package/src/components/lib/pattern.js +0 -190
  113. package/src/components/lib/rollup.js +0 -55
  114. package/src/components/lib/shape.js +0 -199
  115. package/src/components/lib/summary.js +0 -145
  116. package/src/components/lib/theme.js +0 -23
  117. package/src/components/lib/timer.js +0 -41
  118. package/src/components/lib/utils.js +0 -165
  119. package/src/components/plots/BarPlot.svelte +0 -36
  120. package/src/components/plots/BoxPlot.svelte +0 -54
  121. package/src/components/plots/ScatterPlot.svelte +0 -30
  122. package/src/components/store.js +0 -70
  123. package/src/constants.js +0 -66
  124. package/src/elements/PatternDefs.svelte +0 -13
  125. package/src/elements/PatternMask.svelte +0 -20
  126. package/src/elements/Symbol.svelte +0 -38
  127. package/src/elements/Tooltip.svelte +0 -23
  128. package/src/funnel.svelte +0 -35
  129. package/src/geom.js +0 -105
  130. package/src/lib/axis.js +0 -75
  131. package/src/lib/colors.js +0 -32
  132. package/src/lib/geom.js +0 -4
  133. package/src/lib/shapes.js +0 -144
  134. package/src/lib/timer.js +0 -44
  135. package/src/lookup.js +0 -29
  136. package/src/plots/BarPlot.svelte +0 -55
  137. package/src/plots/BoxPlot.svelte +0 -0
  138. package/src/plots/FunnelPlot.svelte +0 -33
  139. package/src/plots/HeatMap.svelte +0 -5
  140. package/src/plots/HeatMapCalendar.svelte +0 -129
  141. package/src/plots/LinePlot.svelte +0 -55
  142. package/src/plots/Plot.svelte +0 -25
  143. package/src/plots/RankBarPlot.svelte +0 -38
  144. package/src/plots/ScatterPlot.svelte +0 -20
  145. package/src/plots/ViolinPlot.svelte +0 -11
  146. package/src/plots/heatmap.js +0 -70
  147. package/src/plots/index.js +0 -10
  148. 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 { min, max } from 'd3-array'
3
- import { ascending, quantile } from 'd3-array'
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
- * Calculates a grid of centres to fit a list of items of `size` within the number of `columns` and `rows`.
9
- *
10
- * - Attempts to find a best fit square if both columns and rows are not specified
11
- * - Value in columns is prioritized over rows for recalculating the grid
12
- * - Supports padding between the items
13
- *
14
- * @param {number} count
15
- * @param {number} size
16
- * @param {number} pad
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 swatch(count, size, pad = 0, columns, rows) {
22
- if (columns > 0) {
23
- rows = Math.ceil(count / columns)
24
- } else if (rows > 0) {
25
- columns = Math.ceil(count / rows)
26
- } else {
27
- columns = Math.ceil(Math.sqrt(count))
28
- rows = Math.ceil(count / columns)
29
- }
30
-
31
- const width = (size + pad) * columns + pad
32
- const height = (size + pad) * rows + pad
33
- const data = [...Array(count).keys()].map((index) => ({
34
- cx: (size + pad) / 2 + (index % columns) * (size + pad),
35
- cy: (size + pad) / 2 + Math.floor(index / columns) * (size + pad),
36
- r: size / 2
37
- }))
38
-
39
- return { width, height, data }
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
- * Get a scale function mapping the values between a range of lower and upper values
43
- *
44
- * @param {Array} values
45
- * @param {Array[2]} bounds
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 getScale(values, bounds, buffer = 0, ordinal = false) {
50
- if (ordinal || values.some(isNaN)) {
51
- return scaleBand().range(bounds).domain(values).padding(0.5)
52
- } else {
53
- values = values.map((x) => +x)
54
-
55
- let minValue = min([...values, 0])
56
- let maxValue = max(values)
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
- * Obtain the scale function for the `x` and `y` fields in the data set.
58
+ * Normalizes data for use with D3 charts
70
59
  *
71
- * @param {array<dict>} data
72
- * @param {string} x
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 getScales(data, x, y, width, height, margin, ordinal) {
79
- const xValues = [...new Set(data.map((item) => item[x]))]
80
- const yValues = [...new Set(data.map((item) => item[y]))]
81
-
82
- return {
83
- x: getScale(xValues, [0 + margin.left, width - margin.right], 0, ordinal.x),
84
- y: getScale(yValues, [height - margin.top, margin.bottom], 0.1, ordinal.y)
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
- * Summarize `data` by fields `x` and `y` and return a nested array with
90
- * key as unique `x` values and value as statistical summaries of `y` values
91
- *
92
- * @param {*} data
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 aggregate(data, x, y) {
98
- const summary = nest()
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
- * Generate a palette with same size as input data containing values from palette array.
116
- * After the palette array is exhausted the fallback value is used
117
- *
118
- * @param {Array} values
119
- * @param {Array} palette
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 getPaletteForValues(values, palette, fallback) {
124
- return values.map((_, index) =>
125
- index < palette.length ? palette[index] : fallback
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
- * Converts input object array into a nested key,value array.
131
- * 'key' contains unique values for the attribute specified by the key parameter
132
- * and value contains array of all remaining attributes in an array.
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 toNested(data, key, label) {
140
- return nest()
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
- * Repeats array items of b using array items of a ask keys
147
- *
148
- * @param {Array} b
149
- * @param {Array} a
150
- * @returns {Object} with keys as items in a and values as items in b
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 repeatAcross(b, a) {
153
- return a.reduce(
154
- (acc, item, index) => ({ ...acc, [item]: b[index % b.length] }),
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() {}