@rokkit/chart 1.0.0-next.121 → 1.0.0-next.123

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 (36) hide show
  1. package/README.md +43 -35
  2. package/package.json +3 -3
  3. package/src/Plot/Axis.svelte +87 -95
  4. package/src/Plot/Bar.svelte +86 -86
  5. package/src/Plot/Grid.svelte +57 -57
  6. package/src/Plot/Legend.svelte +120 -122
  7. package/src/Plot/Root.svelte +107 -105
  8. package/src/elements/ColorRamp.svelte +19 -19
  9. package/src/elements/ContinuousLegend.svelte +1 -1
  10. package/src/elements/DefinePatterns.svelte +1 -1
  11. package/src/elements/DiscreteLegend.svelte +1 -1
  12. package/src/elements/SymbolGrid.svelte +1 -1
  13. package/src/examples/BarChartExample.svelte +42 -42
  14. package/src/index.js +13 -13
  15. package/src/lib/brewing/axes.svelte.js +120 -122
  16. package/src/lib/brewing/bars.svelte.js +70 -70
  17. package/src/lib/brewing/dimensions.svelte.js +25 -23
  18. package/src/lib/brewing/index.svelte.js +192 -204
  19. package/src/lib/brewing/legends.svelte.js +51 -52
  20. package/src/lib/brewing/scales.svelte.js +59 -68
  21. package/src/lib/brewing/types.js +2 -2
  22. package/src/lib/context.js +117 -107
  23. package/src/lib/scales.svelte.js +80 -87
  24. package/src/lib/utils.js +70 -72
  25. package/src/old_lib/chart.js +4 -4
  26. package/src/patterns/Brick.svelte +1 -1
  27. package/src/patterns/Circles.svelte +1 -1
  28. package/src/patterns/CrossHatch.svelte +1 -1
  29. package/src/patterns/Dots.svelte +1 -1
  30. package/src/patterns/OutlineCircles.svelte +1 -1
  31. package/src/patterns/Tile.svelte +1 -1
  32. package/src/patterns/Triangles.svelte +1 -1
  33. package/src/symbols/RoundedSquare.svelte +0 -1
  34. package/src/template/shapes/Circles.svelte +1 -1
  35. package/src/template/shapes/Lines.svelte +1 -1
  36. package/src/template/shapes/Polygons.svelte +1 -1
@@ -1,53 +1,53 @@
1
1
  <script>
2
- import { Plot } from '../index.js';
3
- import { dataset } from '@rokkit/data';
2
+ import { Plot } from '../index.js'
3
+ import { dataset } from '@rokkit/data'
4
4
 
5
- // Sample data
6
- const sampleData = [
7
- { model: 'Model A', name: 'Product 1', category: 'Electronics', count: 45 },
8
- { model: 'Model B', name: 'Product 2', category: 'Clothing', count: 32 },
9
- { model: 'Model C', name: 'Product 3', category: 'Electronics', count: 62 },
10
- { model: 'Model D', name: 'Product 4', category: 'Home', count: 28 },
11
- { model: 'Model E', name: 'Product 5', category: 'Electronics', count: 53 },
12
- { model: 'Model F', name: 'Product 6', category: 'Clothing', count: 24 },
13
- { model: 'Model G', name: 'Product 7', category: 'Home', count: 35 },
14
- ];
5
+ // Sample data
6
+ const sampleData = [
7
+ { model: 'Model A', name: 'Product 1', category: 'Electronics', count: 45 },
8
+ { model: 'Model B', name: 'Product 2', category: 'Clothing', count: 32 },
9
+ { model: 'Model C', name: 'Product 3', category: 'Electronics', count: 62 },
10
+ { model: 'Model D', name: 'Product 4', category: 'Home', count: 28 },
11
+ { model: 'Model E', name: 'Product 5', category: 'Electronics', count: 53 },
12
+ { model: 'Model F', name: 'Product 6', category: 'Clothing', count: 24 },
13
+ { model: 'Model G', name: 'Product 7', category: 'Home', count: 35 }
14
+ ]
15
15
 
16
- // Use the dataset class to process the data
17
- const data = dataset(sampleData)
18
- .groupBy('category')
19
- .summarize('name', { count: values => values.length })
20
- .rollup();
16
+ // Use the dataset class to process the data
17
+ const data = dataset(sampleData)
18
+ .groupBy('category')
19
+ .summarize('name', { count: (values) => values.length })
20
+ .rollup()
21
21
 
22
- // Chart dimensions
23
- const width = 600;
24
- const height = 400;
25
- const margin = { top: 20, right: 100, bottom: 60, left: 60 };
22
+ // Chart dimensions
23
+ const width = 600
24
+ const height = 400
25
+ const margin = { top: 20, right: 100, bottom: 60, left: 60 }
26
26
 
27
- // Click handler for bars
28
- function handleBarClick(item) {
29
- console.log('Bar clicked:', item);
30
- alert(`Clicked on ${item.category} with count ${item.count}`);
31
- }
27
+ // Click handler for bars
28
+ function handleBarClick(item) {
29
+ console.log('Bar clicked:', item)
30
+ alert(`Clicked on ${item.category} with count ${item.count}`)
31
+ }
32
32
  </script>
33
33
 
34
34
  <div class="example">
35
- <h2>Bar Chart Example</h2>
35
+ <h2>Bar Chart Example</h2>
36
36
 
37
- <div class="chart-wrapper">
38
- <Plot.Root {data} {width} {height} {margin} fill="category">
39
- <Plot.Grid direction="y" lineStyle="dashed" />
40
- <Plot.Axis type="x" field="category" label="Product Category" />
41
- <Plot.Axis type="y" field="count" label="Number of Products" />
42
- <Plot.Bar x="category" y="count" fill="category" onClick={handleBarClick} />
43
- <Plot.Legend title="Categories" />
44
- </Plot.Root>
45
- </div>
37
+ <div class="chart-wrapper">
38
+ <Plot.Root {data} {width} {height} {margin} fill="category">
39
+ <Plot.Grid direction="y" lineStyle="dashed" />
40
+ <Plot.Axis type="x" field="category" label="Product Category" />
41
+ <Plot.Axis type="y" field="count" label="Number of Products" />
42
+ <Plot.Bar x="category" y="count" fill="category" onClick={handleBarClick} />
43
+ <Plot.Legend title="Categories" />
44
+ </Plot.Root>
45
+ </div>
46
46
 
47
- <div class="code-example">
48
- <h3>Example Code:</h3>
49
- <pre>
50
- &lt;script&gt;
47
+ <div class="code-example">
48
+ <h3>Example Code:</h3>
49
+ <pre>
50
+ <!-- &lt;script&gt;
51
51
  import { Plot } from '@rokkit/chart';
52
52
  import { dataset } from '@rokkit/data';
53
53
 
@@ -75,7 +75,7 @@
75
75
  &lt;Plot.Axis type="y" field="count" label="Number of Products" /&gt;
76
76
  &lt;Plot.Bar x="category" y="count" fill="category" onClick={handleBarClick} /&gt;
77
77
  &lt;Plot.Legend title="Categories" /&gt;
78
- &lt;/Plot.Root&gt;
78
+ &lt;/Plot.Root&gt; -->
79
79
  </pre>
80
- </div>
80
+ </div>
81
81
  </div>
package/src/index.js CHANGED
@@ -1,18 +1,18 @@
1
- import Root from './Plot/Root.svelte';
2
- import Axis from './Plot/Axis.svelte';
3
- import Bar from './Plot/Bar.svelte';
4
- import Grid from './Plot/Grid.svelte';
5
- import Legend from './Plot/Legend.svelte';
1
+ import Root from './Plot/Root.svelte'
2
+ import Axis from './Plot/Axis.svelte'
3
+ import Bar from './Plot/Bar.svelte'
4
+ import Grid from './Plot/Grid.svelte'
5
+ import Legend from './Plot/Legend.svelte'
6
6
 
7
7
  // Export components
8
8
  export const Plot = {
9
- Root,
10
- Axis,
11
- Bar,
12
- Grid,
13
- Legend
14
- };
9
+ Root,
10
+ Axis,
11
+ Bar,
12
+ Grid,
13
+ Legend
14
+ }
15
15
 
16
16
  // Export utilities
17
- export { ChartBrewer } from './lib/brewing/index.svelte.js';
18
- export * from './lib/brewing/index.svelte.js';
17
+ export { ChartBrewer } from './lib/brewing/index.svelte.js'
18
+ export * from './lib/brewing/index.svelte.js'
@@ -1,6 +1,6 @@
1
- import { scaleBand } from 'd3-scale';
1
+ // import { scaleBand } from 'd3-scale'
2
2
 
3
- import { } from './types.js';
3
+ import {} from './types.js'
4
4
 
5
5
  /**
6
6
  * @typedef {import('./types').TickData} TickData
@@ -11,7 +11,7 @@ import { } from './types.js';
11
11
 
12
12
  /**
13
13
  * Creates x-axis tick data for rendering
14
- *
14
+ *
15
15
  * @param {Object} scales - Chart scales
16
16
  * @param {Function} scales.x - X-axis scale
17
17
  * @param {Object} dimensions - Chart dimensions
@@ -22,52 +22,50 @@ import { } from './types.js';
22
22
  * @returns {AxisData} Axis rendering data
23
23
  */
24
24
  export function createXAxis(scales, dimensions, options = {}) {
25
- if (!scales.x) return { ticks: [] };
26
-
27
- const { tickCount = null, tickFormat = null, label = '' } = options;
28
- const xScale = scales.x;
29
-
30
- // Determine tick values
31
- let tickValues;
32
- if (xScale.ticks) {
33
- // For continuous scales (linear, time)
34
- tickValues = tickCount !== null ? xScale.ticks(tickCount) : xScale.ticks();
35
- } else {
36
- // For band scales
37
- tickValues = xScale.domain();
38
- if (tickCount !== null && tickCount < tickValues.length) {
39
- const step = Math.max(1, Math.floor(tickValues.length / tickCount));
40
- tickValues = tickValues.filter((_, i) => i % step === 0);
41
- }
42
- }
43
-
44
- // Format ticks
45
- const formatter = tickFormat || (v => v);
46
-
47
- // Generate tick data
48
- const ticks = tickValues.map(value => {
49
- const position = xScale.bandwidth
50
- ? xScale(value) + xScale.bandwidth() / 2
51
- : xScale(value);
52
-
53
- return {
54
- value,
55
- position,
56
- formattedValue: formatter(value)
57
- };
58
- });
59
-
60
- return {
61
- ticks,
62
- label,
63
- transform: `translate(0, ${dimensions.innerHeight})`,
64
- labelTransform: `translate(${dimensions.innerWidth / 2}, 35)`
65
- };
25
+ if (!scales.x) return { ticks: [] }
26
+
27
+ const { tickCount = null, tickFormat = null, label = '' } = options
28
+ const xScale = scales.x
29
+
30
+ // Determine tick values
31
+ let tickValues
32
+ if (xScale.ticks) {
33
+ // For continuous scales (linear, time)
34
+ tickValues = tickCount !== null ? xScale.ticks(tickCount) : xScale.ticks()
35
+ } else {
36
+ // For band scales
37
+ tickValues = xScale.domain()
38
+ if (tickCount !== null && tickCount < tickValues.length) {
39
+ const step = Math.max(1, Math.floor(tickValues.length / tickCount))
40
+ tickValues = tickValues.filter((_, i) => i % step === 0)
41
+ }
42
+ }
43
+
44
+ // Format ticks
45
+ const formatter = tickFormat || ((v) => v)
46
+
47
+ // Generate tick data
48
+ const ticks = tickValues.map((value) => {
49
+ const position = xScale.bandwidth ? xScale(value) + xScale.bandwidth() / 2 : xScale(value)
50
+
51
+ return {
52
+ value,
53
+ position,
54
+ formattedValue: formatter(value)
55
+ }
56
+ })
57
+
58
+ return {
59
+ ticks,
60
+ label,
61
+ transform: `translate(0, ${dimensions.innerHeight})`,
62
+ labelTransform: `translate(${dimensions.innerWidth / 2}, 35)`
63
+ }
66
64
  }
67
65
 
68
66
  /**
69
67
  * Creates y-axis tick data for rendering
70
- *
68
+ *
71
69
  * @param {Object} scales - Chart scales
72
70
  * @param {Function} scales.y - Y-axis scale
73
71
  * @param {Object} dimensions - Chart dimensions
@@ -78,45 +76,45 @@ export function createXAxis(scales, dimensions, options = {}) {
78
76
  * @returns {AxisData} Axis rendering data
79
77
  */
80
78
  export function createYAxis(scales, dimensions, options = {}) {
81
- if (!scales.y) return { ticks: [] };
82
-
83
- const { tickCount = null, tickFormat = null, label = '' } = options;
84
- const yScale = scales.y;
85
-
86
- // Determine tick values
87
- let tickValues = [];
88
-
89
- if (yScale.ticks) {
90
- tickValues = tickCount !== null ? yScale.ticks(tickCount) : yScale.ticks();
91
- } else if (yScale.domain) {
92
- tickValues = yScale.domain();
93
- if (tickCount !== null && tickValues.length > tickCount) {
94
- const step = Math.max(1, Math.floor(tickValues.length / tickCount));
95
- tickValues = tickValues.filter((_, i) => i % step === 0);
96
- }
97
- }
98
-
99
- // Format ticks
100
- const formatter = tickFormat || (v => v);
101
-
102
- // Generate tick data
103
- const ticks = tickValues.map(value => ({
104
- value,
105
- position: yScale(value),
106
- formattedValue: formatter(value)
107
- }));
108
-
109
- return {
110
- ticks,
111
- label,
112
- transform: 'translate(0, 0)',
113
- labelTransform: `translate(-40, ${dimensions.innerHeight / 2}) rotate(-90)`
114
- };
79
+ if (!scales.y) return { ticks: [] }
80
+
81
+ const { tickCount = null, tickFormat = null, label = '' } = options
82
+ const yScale = scales.y
83
+
84
+ // Determine tick values
85
+ let tickValues = []
86
+
87
+ if (yScale.ticks) {
88
+ tickValues = tickCount !== null ? yScale.ticks(tickCount) : yScale.ticks()
89
+ } else if (yScale.domain) {
90
+ tickValues = yScale.domain()
91
+ if (tickCount !== null && tickValues.length > tickCount) {
92
+ const step = Math.max(1, Math.floor(tickValues.length / tickCount))
93
+ tickValues = tickValues.filter((_, i) => i % step === 0)
94
+ }
95
+ }
96
+
97
+ // Format ticks
98
+ const formatter = tickFormat || ((v) => v)
99
+
100
+ // Generate tick data
101
+ const ticks = tickValues.map((value) => ({
102
+ value,
103
+ position: yScale(value),
104
+ formattedValue: formatter(value)
105
+ }))
106
+
107
+ return {
108
+ ticks,
109
+ label,
110
+ transform: 'translate(0, 0)',
111
+ labelTransform: `translate(-40, ${dimensions.innerHeight / 2}) rotate(-90)`
112
+ }
115
113
  }
116
114
 
117
115
  /**
118
116
  * Creates grid line data for rendering
119
- *
117
+ *
120
118
  * @param {Object} scales - Chart scales
121
119
  * @param {Object} dimensions - Chart dimensions
122
120
  * @param {Object} options - Grid options
@@ -126,54 +124,54 @@ export function createYAxis(scales, dimensions, options = {}) {
126
124
  * @returns {Object} Grid rendering data
127
125
  */
128
126
  export function createGrid(scales, dimensions, options = {}) {
129
- const { direction = 'both', xTickCount = null, yTickCount = null } = options;
130
- const result = { xLines: [], yLines: [] };
131
-
132
- // Generate X grid lines (vertical)
133
- if ((direction === 'x' || direction === 'both') && scales.x) {
134
- const xAxis = createXAxis(scales, dimensions, { tickCount: xTickCount });
135
- result.xLines = xAxis.ticks.map(tick => ({
136
- x1: tick.position,
137
- y1: 0,
138
- x2: tick.position,
139
- y2: dimensions.innerHeight
140
- }));
141
- }
142
-
143
- // Generate Y grid lines (horizontal)
144
- if ((direction === 'y' || direction === 'both') && scales.y) {
145
- const yAxis = createYAxis(scales, dimensions, { tickCount: yTickCount });
146
- result.yLines = yAxis.ticks.map(tick => ({
147
- x1: 0,
148
- y1: tick.position,
149
- x2: dimensions.innerWidth,
150
- y2: tick.position
151
- }));
152
- }
153
-
154
- return result;
127
+ const { direction = 'both', xTickCount = null, yTickCount = null } = options
128
+ const result = { xLines: [], yLines: [] }
129
+
130
+ // Generate X grid lines (vertical)
131
+ if ((direction === 'x' || direction === 'both') && scales.x) {
132
+ const xAxis = createXAxis(scales, dimensions, { tickCount: xTickCount })
133
+ result.xLines = xAxis.ticks.map((tick) => ({
134
+ x1: tick.position,
135
+ y1: 0,
136
+ x2: tick.position,
137
+ y2: dimensions.innerHeight
138
+ }))
139
+ }
140
+
141
+ // Generate Y grid lines (horizontal)
142
+ if ((direction === 'y' || direction === 'both') && scales.y) {
143
+ const yAxis = createYAxis(scales, dimensions, { tickCount: yTickCount })
144
+ result.yLines = yAxis.ticks.map((tick) => ({
145
+ x1: 0,
146
+ y1: tick.position,
147
+ x2: dimensions.innerWidth,
148
+ y2: tick.position
149
+ }))
150
+ }
151
+
152
+ return result
155
153
  }
156
154
 
157
155
  /**
158
156
  * Creates DOM attributes for a tick element
159
- *
157
+ *
160
158
  * @param {TickData} tick - Tick data
161
159
  * @param {string} axis - Axis type ('x' or 'y')
162
160
  * @returns {Object} Attributes for the tick
163
161
  */
164
162
  export function createTickAttributes(tick, axis) {
165
- if (axis === 'x') {
166
- return {
167
- 'data-plot-tick': 'major',
168
- 'transform': `translate(${tick.position}, 0)`,
169
- 'text-anchor': 'middle'
170
- };
171
- } else {
172
- return {
173
- 'data-plot-tick': 'major',
174
- 'transform': `translate(0, ${tick.position})`,
175
- 'text-anchor': 'end',
176
- 'dominant-baseline': 'middle'
177
- };
178
- }
179
- }
163
+ if (axis === 'x') {
164
+ return {
165
+ 'data-plot-tick': 'major',
166
+ transform: `translate(${tick.position}, 0)`,
167
+ 'text-anchor': 'middle'
168
+ }
169
+ } else {
170
+ return {
171
+ 'data-plot-tick': 'major',
172
+ transform: `translate(0, ${tick.position})`,
173
+ 'text-anchor': 'end',
174
+ 'dominant-baseline': 'middle'
175
+ }
176
+ }
177
+ }
@@ -1,4 +1,4 @@
1
- import { } from './types.js';
1
+ import {} from './types.js'
2
2
 
3
3
  /**
4
4
  * @typedef {import('./types').BarData} BarData
@@ -9,7 +9,7 @@ import { } from './types.js';
9
9
 
10
10
  /**
11
11
  * Creates bar data for rendering
12
- *
12
+ *
13
13
  * @param {Array} data - Chart data
14
14
  * @param {Object} fields - Field mappings
15
15
  * @param {string} fields.x - X-axis field
@@ -24,47 +24,47 @@ import { } from './types.js';
24
24
  * @returns {BarData[]} Bar data for rendering
25
25
  */
26
26
  export function createBars(data, fields, scales, dimensions, defaultColor = '#4682b4') {
27
- if (!data || data.length === 0 || !scales.x || !scales.y) return [];
28
-
29
- const { x: xField, y: yField, color: colorField } = fields;
30
-
31
- return data.map(d => {
32
- const barWidth = scales.x.bandwidth ? scales.x.bandwidth() : 10;
33
- const barX = scales.x.bandwidth ? scales.x(d[xField]) : scales.x(d[xField]) - barWidth / 2;
34
-
35
- return {
36
- data: d,
37
- x: barX,
38
- y: scales.y(d[yField]),
39
- width: barWidth,
40
- height: dimensions.innerHeight - scales.y(d[yField]),
41
- color: colorField && scales.color ? scales.color(d[colorField]) : defaultColor
42
- };
43
- });
27
+ if (!data || data.length === 0 || !scales.x || !scales.y) return []
28
+
29
+ const { x: xField, y: yField, color: colorField } = fields
30
+
31
+ return data.map((d) => {
32
+ const barWidth = scales.x.bandwidth ? scales.x.bandwidth() : 10
33
+ const barX = scales.x.bandwidth ? scales.x(d[xField]) : scales.x(d[xField]) - barWidth / 2
34
+
35
+ return {
36
+ data: d,
37
+ x: barX,
38
+ y: scales.y(d[yField]),
39
+ width: barWidth,
40
+ height: dimensions.innerHeight - scales.y(d[yField]),
41
+ color: colorField && scales.color ? scales.color(d[colorField]) : defaultColor
42
+ }
43
+ })
44
44
  }
45
45
 
46
46
  /**
47
47
  * Filter bars based on a selection criteria
48
- *
48
+ *
49
49
  * @param {BarData[]} bars - Bar data array
50
50
  * @param {Object} selection - Selection criteria
51
51
  * @returns {BarData[]} Filtered bars
52
52
  */
53
53
  export function filterBars(bars, selection) {
54
- if (!selection) return bars;
55
-
56
- return bars.filter(bar => {
57
- for (const [key, value] of Object.entries(selection)) {
58
- if (bar.data[key] !== value) return false;
59
- }
60
- return true;
61
- });
54
+ if (!selection) return bars
55
+
56
+ return bars.filter((bar) => {
57
+ for (const [key, value] of Object.entries(selection)) {
58
+ if (bar.data[key] !== value) return false
59
+ }
60
+ return true
61
+ })
62
62
  }
63
63
 
64
64
  /**
65
65
  * Creates a grouped bars layout
66
- *
67
- * @param {Array} data - Chart data
66
+ *
67
+ * @param {Array} data - Chart data
68
68
  * @param {Object} fields - Field mappings
69
69
  * @param {Object} scales - Chart scales
70
70
  * @param {Object} dimensions - Chart dimensions
@@ -72,43 +72,43 @@ export function filterBars(bars, selection) {
72
72
  * @returns {Object} Grouped bar data
73
73
  */
74
74
  export function createGroupedBars(data, fields, scales, dimensions, options = {}) {
75
- if (!data || data.length === 0 || !fields.group) return { groups: [], bars: [] };
76
-
77
- const { x: xField, y: yField, group: groupField, color: colorField = groupField } = fields;
78
- const { padding = 0.1 } = options;
79
-
80
- // Get unique groups and x values
81
- const groups = [...new Set(data.map(d => d[groupField]))];
82
- const xValues = [...new Set(data.map(d => d[xField]))];
83
-
84
- // Calculate group width and individual bar width
85
- const xScale = scales.x;
86
- const groupWidth = xScale.bandwidth ? xScale.bandwidth() : 20;
87
- const barWidth = (groupWidth - padding * (groups.length - 1)) / groups.length;
88
-
89
- // Create bars for each group
90
- const bars = [];
91
-
92
- xValues.forEach(xValue => {
93
- const groupItems = data.filter(d => d[xField] === xValue);
94
- const xPos = xScale(xValue);
95
-
96
- groups.forEach((group, i) => {
97
- const item = groupItems.find(d => d[groupField] === group);
98
- if (!item) return;
99
-
100
- const barX = xPos + i * (barWidth + padding);
101
- bars.push({
102
- data: item,
103
- group,
104
- x: barX,
105
- y: scales.y(item[yField]),
106
- width: barWidth,
107
- height: dimensions.innerHeight - scales.y(item[yField]),
108
- color: scales.color ? scales.color(item[colorField]) : '#4682b4'
109
- });
110
- });
111
- });
112
-
113
- return { groups, bars };
114
- }
75
+ if (!data || data.length === 0 || !fields.group) return { groups: [], bars: [] }
76
+
77
+ const { x: xField, y: yField, group: groupField, color: colorField = groupField } = fields
78
+ const { padding = 0.1 } = options
79
+
80
+ // Get unique groups and x values
81
+ const groups = [...new Set(data.map((d) => d[groupField]))]
82
+ const xValues = [...new Set(data.map((d) => d[xField]))]
83
+
84
+ // Calculate group width and individual bar width
85
+ const xScale = scales.x
86
+ const groupWidth = xScale.bandwidth ? xScale.bandwidth() : 20
87
+ const barWidth = (groupWidth - padding * (groups.length - 1)) / groups.length
88
+
89
+ // Create bars for each group
90
+ const bars = []
91
+
92
+ xValues.forEach((xValue) => {
93
+ const groupItems = data.filter((d) => d[xField] === xValue)
94
+ const xPos = xScale(xValue)
95
+
96
+ groups.forEach((group, i) => {
97
+ const item = groupItems.find((d) => d[groupField] === group)
98
+ if (!item) return
99
+
100
+ const barX = xPos + i * (barWidth + padding)
101
+ bars.push({
102
+ data: item,
103
+ group,
104
+ x: barX,
105
+ y: scales.y(item[yField]),
106
+ width: barWidth,
107
+ height: dimensions.innerHeight - scales.y(item[yField]),
108
+ color: scales.color ? scales.color(item[colorField]) : '#4682b4'
109
+ })
110
+ })
111
+ })
112
+
113
+ return { groups, bars }
114
+ }