@rokkit/chart 1.0.0-next.11 → 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,112 @@
1
+ <script>
2
+ import { setContext } from 'svelte';
3
+ import { ChartBrewer } from '../lib/brewing/index.svelte.js';
4
+
5
+ let {
6
+ data = [],
7
+ width = 600,
8
+ height = 400,
9
+ margin = { top: 20, right: 30, bottom: 40, left: 50 },
10
+ fill = null,
11
+ responsive = true,
12
+ animationDuration = 300
13
+ } = $props();
14
+
15
+ // Create chart brewer instance
16
+ let brewer = $state(new ChartBrewer({
17
+ width,
18
+ height,
19
+ margin,
20
+ animationDuration
21
+ }));
22
+
23
+ // Chart dimensions derived from brewer
24
+ let dimensions = $derived(brewer.getDimensions());
25
+
26
+ // Process data
27
+ $effect(() => {
28
+ // If data has a select method (dataset object), call it to get actual data
29
+ const chartData = data.select && typeof data.select === 'function' ? data.select() : data;
30
+
31
+ // Update brewer with data and fields
32
+ brewer.setData(chartData);
33
+ brewer.setFields({ color: fill });
34
+
35
+ // Create scales after setting data
36
+ brewer.createScales();
37
+ });
38
+
39
+ // Update chart dimensions when props change
40
+ $effect(() => {
41
+ brewer.setDimensions({ width, height, margin });
42
+ });
43
+
44
+ // Provide chart context to child components
45
+ setContext('chart-brewer', brewer);
46
+
47
+ // Handle responsive behavior
48
+ let container;
49
+
50
+ $effect(() => {
51
+ if (!responsive || !container || !document) return;
52
+
53
+ const resizeObserver = new ResizeObserver(entries => {
54
+ const entry = entries[0];
55
+ if (!entry) return;
56
+
57
+ const containerWidth = entry.contentRect.width;
58
+ const aspectRatio = height / width;
59
+
60
+ // Update chart dimensions while maintaining aspect ratio
61
+ brewer.setDimensions({
62
+ width: containerWidth,
63
+ height: containerWidth * aspectRatio
64
+ });
65
+
66
+ // Update scales after dimensions change
67
+ brewer.createScales();
68
+ });
69
+
70
+ // Start observing container size
71
+ resizeObserver.observe(container);
72
+
73
+ return () => {
74
+ resizeObserver.disconnect();
75
+ };
76
+ });
77
+ </script>
78
+
79
+ <div class="chart-container" bind:this={container} data-plot-root>
80
+ <svg
81
+ width={dimensions.width}
82
+ height={dimensions.height}
83
+ viewBox="0 0 {dimensions.width} {dimensions.height}"
84
+ role="img"
85
+ aria-label="Chart visualization"
86
+ >
87
+ <g
88
+ class="chart-area"
89
+ transform="translate({dimensions.margin.left}, {dimensions.margin.top})"
90
+ data-plot-canvas
91
+ >
92
+ <slot />
93
+ </g>
94
+ </svg>
95
+ </div>
96
+
97
+ <style>
98
+ .chart-container {
99
+ position: relative;
100
+ width: 100%;
101
+ height: auto;
102
+ }
103
+
104
+ svg {
105
+ display: block;
106
+ overflow: visible;
107
+ }
108
+
109
+ .chart-area {
110
+ pointer-events: all;
111
+ }
112
+ </style>
@@ -0,0 +1,5 @@
1
+ export { default as Root } from './Root.svelte'
2
+ export { default as Axis } from './Axis.svelte'
3
+ export { default as Bar } from './Bar.svelte'
4
+ export { default as Legend } from './Legend.svelte'
5
+ export { default as Grid } from './Grid.svelte'
@@ -0,0 +1,21 @@
1
+ <script>
2
+ import { components } from './symbols'
3
+
4
+ let {
5
+ x = 0,
6
+ y = 0,
7
+ size = 10,
8
+ fill = 'currentColor',
9
+ stroke = 'currentColor',
10
+ name = 'circle',
11
+ ...restProps
12
+ } = $props()
13
+
14
+ let RenderShape = $derived(components[name] ?? components.default)
15
+ let props = $derived({ ...restProps, x, y, size, fill, stroke })
16
+ </script>
17
+
18
+ <!-- {#snippet defaultSymbol(props)}
19
+ <circle cx={x} cy={y} r={size / 2} {fill} {stroke} />
20
+ {/snippet} -->
21
+ <RenderShape {...props} />
@@ -1,8 +1,8 @@
1
1
  <script>
2
2
  export let id
3
- export let fill
4
3
  export let path
5
- export let contrast
4
+ export let fill = 'currentColor'
5
+ export let stroke = 'currentColor'
6
6
  export let thickness = 0.5
7
7
  export let patternUnits = 'userSpaceOnUse'
8
8
  export let size = 10
@@ -11,6 +11,6 @@
11
11
  <pattern {id} {patternUnits} width={size} height={size}>
12
12
  <rect width={size} height={size} {fill} />
13
13
  {#if path}
14
- <path d={path} fill="none" stroke={contrast} stroke-width={thickness} />
14
+ <path d={path} fill="none" {stroke} stroke-width={thickness} />
15
15
  {/if}
16
16
  </pattern>
@@ -25,11 +25,5 @@
25
25
 
26
26
  <rect x={$scales.x(0)} {y} {width} {height} {fill} opacity={0.5} />
27
27
  <rect x={$scales.x(0)} {y} width={5} {height} {fill} />
28
- <Label x={width} y={y + textHeight + 8} anchor={textAnchor} label={name} />
29
- <Label
30
- x={width}
31
- y={y + height - 14}
32
- anchor={textAnchor}
33
- label={formattedValue}
34
- small
35
- />
28
+ <Label x={width} y={y + textHeight + 8} anchor={textAnchor} text={name} />
29
+ <Label x={width} y={y + height - 14} anchor={textAnchor} text={formattedValue} small />
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import { scaleLinear } from 'd3-scale'
3
- import { uniqueId } from '../lib/utils'
3
+ import { id as uniqueId } from '@rokkit/core'
4
4
 
5
5
  export let x = 0
6
6
  export let y = 0
@@ -14,13 +14,11 @@
14
14
  .range([x, x + width])
15
15
  .domain(scale.domain())
16
16
  $: scalePercent = scaleLinear().range([0, 100]).domain(scale.domain())
17
- $: ticks = scale.ticks
18
- .apply(scale, [tickCount])
19
- .map((d) => ({ x: scaleTicks(d), value: d }))
17
+ $: ticks = scale.ticks.apply(scale, [tickCount]).map((d) => ({ x: scaleTicks(d), value: d }))
20
18
 
21
19
  $: colors = ticks.map(({ value }) => ({
22
20
  color: scale(value),
23
- offset: `${scalePercent(value)}%`,
21
+ offset: `${scalePercent(value)}%`
24
22
  }))
25
23
  $: id = uniqueId('legend-')
26
24
  </script>
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import { scaleLinear } from 'd3-scale'
3
- import { uniqueId } from '../components/lib/utils'
3
+ // import { id as uniqueId } from '@rokkit/core'
4
4
 
5
5
  export let x = 0
6
6
  export let y = 0
@@ -9,16 +9,15 @@
9
9
  export let width = 100
10
10
  export let tickCount = 5
11
11
  export let scale
12
+ export let id = 'legend'
12
13
 
13
14
  $: scaleTicks = scaleLinear()
14
15
  .range([x, x + 100])
15
16
  .domain(scale.domain())
16
- $: ticks = scale.ticks
17
- .apply(scale, [tickCount])
18
- .map((d) => ({ x: scaleTicks(d), label: d }))
17
+ $: ticks = scale.ticks.apply(scale, [tickCount]).map((d) => ({ x: scaleTicks(d), label: d }))
19
18
 
20
19
  $: colors = scale.range()
21
- $: id = uniqueId('legend-')
20
+ // $: id = uniqueId('legend-')
22
21
  </script>
23
22
 
24
23
  <defs>
@@ -0,0 +1,22 @@
1
+ <script>
2
+ import { uniq } from 'ramda'
3
+
4
+ export let size = 10
5
+ export let patternUnits = 'userSpaceOnUse'
6
+ /** @type {Array<import('./types').Pattern>} */
7
+ export let patterns = []
8
+
9
+ $: names = uniq(patterns.map(({ id }) => id))
10
+ </script>
11
+
12
+ {#if names.length < patterns.length}
13
+ <error> Patterns should be an array and should have unique names for each pattern </error>
14
+ {:else if patterns.length > 0}
15
+ <defs>
16
+ {#each patterns as { id, component, fill, stroke }}
17
+ <pattern {id} {patternUnits} width={size} height={size}>
18
+ <svelte:component this={component} {size} {fill} {stroke} />
19
+ </pattern>
20
+ {/each}
21
+ </defs>
22
+ {/if}
@@ -6,17 +6,15 @@
6
6
  export let space = 2
7
7
  export let padding = 5
8
8
  export let scale
9
- export let tickCount
9
+ export let tickCount = 10
10
10
 
11
11
  $: sizeWithSpace = size + space
12
12
  $: ticks = scale.ticks.apply(scale, [tickCount])
13
13
  </script>
14
14
 
15
15
  {#each ticks as tick, i}
16
- <text
17
- x={x + padding + i * sizeWithSpace + size / 2}
18
- y={y + size / 2}
19
- font-size={textSize}>{tick}</text
16
+ <text x={x + padding + i * sizeWithSpace + size / 2} y={y + size / 2} font-size={textSize}
17
+ >{tick}</text
20
18
  >
21
19
  <rect
22
20
  x={x + padding + i * sizeWithSpace}
@@ -1,12 +1,13 @@
1
1
  <script>
2
- export let small = false
3
- export let label
4
- export let angle = 0
5
- export let anchor = 'middle'
6
2
  export let x
7
3
  export let y
4
+ export let text
5
+ export let angle = 0
6
+ export let small = false
7
+ export let anchor = 'middle'
8
8
 
9
9
  $: transform = `translate(${x},${y}) rotate(${angle})`
10
+ $: anchor = ['start', 'middle', 'end'].includes(anchor) ? anchor : 'middle'
10
11
  </script>
11
12
 
12
- <text class="label" class:small text-anchor={anchor} {transform}>{label}</text>
13
+ <text class="label" class:small text-anchor={anchor} {transform}>{text}</text>
@@ -0,0 +1,23 @@
1
+ <script>
2
+ import { swatch, swatchGrid } from '../old_lib'
3
+ import Symbol from '../Symbol.svelte'
4
+
5
+ export let base = 'teal'
6
+ export let size = 4
7
+ export let shade = 600
8
+
9
+ $: grid = swatchGrid($swatch.keys.symbol.length, size, 10)
10
+ </script>
11
+
12
+ <svg viewBox="0 0 {grid.width} {grid.height}">
13
+ {#each grid.data as { x, y, r }, index}
14
+ <Symbol
15
+ {x}
16
+ {y}
17
+ size={r * 2}
18
+ name={$swatch.keys.symbol[index]}
19
+ fill={$swatch.palette[base][shade]}
20
+ stroke={$swatch.palette[base][shade]}
21
+ />
22
+ {/each}
23
+ </svg>
@@ -0,0 +1,6 @@
1
+ export { default as Bar } from './Bar.svelte'
2
+ export { default as ColorRamp } from './ColorRamp.svelte'
3
+ export { default as ContinuousLegend } from './ContinuousLegend.svelte'
4
+ export { default as Label } from './Label.svelte'
5
+ export { default as DefinePatterns } from './DefinePatterns.svelte'
6
+ export { default as SymbolGrid } from './SymbolGrid.svelte'
@@ -0,0 +1,81 @@
1
+ <script>
2
+ import { Plot } from '../index.js';
3
+ import { dataset } from '@rokkit/data';
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
+ ];
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();
21
+
22
+ // Chart dimensions
23
+ const width = 600;
24
+ const height = 400;
25
+ const margin = { top: 20, right: 100, bottom: 60, left: 60 };
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
+ }
32
+ </script>
33
+
34
+ <div class="example">
35
+ <h2>Bar Chart Example</h2>
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>
46
+
47
+ <div class="code-example">
48
+ <h3>Example Code:</h3>
49
+ <pre>
50
+ &lt;script&gt;
51
+ import { Plot } from '@rokkit/chart';
52
+ import { dataset } from '@rokkit/data';
53
+
54
+ // Sample data
55
+ const sampleData = [
56
+ { model: 'Model A', name: 'Product 1', category: 'Electronics', count: 45 },
57
+ { model: 'Model B', name: 'Product 2', category: 'Clothing', count: 32 },
58
+ { model: 'Model C', name: 'Product 3', category: 'Electronics', count: 62 },
59
+ { model: 'Model D', name: 'Product 4', category: 'Home', count: 28 },
60
+ { model: 'Model E', name: 'Product 5', category: 'Electronics', count: 53 },
61
+ { model: 'Model F', name: 'Product 6', category: 'Clothing', count: 24 },
62
+ { model: 'Model G', name: 'Product 7', category: 'Home', count: 35 },
63
+ ];
64
+
65
+ // Use the dataset class to process the data
66
+ const data = dataset(sampleData)
67
+ .groupBy('category')
68
+ .summarize('name', { count: values => values.length })
69
+ .rollup();
70
+ &lt;/script&gt;
71
+
72
+ &lt;Plot.Root {data} width={600} height={400} margin={{ top: 20, right: 100, bottom: 60, left: 60 }} fill="category"&gt;
73
+ &lt;Plot.Grid direction="y" lineStyle="dashed" /&gt;
74
+ &lt;Plot.Axis type="x" field="category" label="Product Category" /&gt;
75
+ &lt;Plot.Axis type="y" field="count" label="Number of Products" /&gt;
76
+ &lt;Plot.Bar x="category" y="count" fill="category" onClick={handleBarClick} /&gt;
77
+ &lt;Plot.Legend title="Categories" /&gt;
78
+ &lt;/Plot.Root&gt;
79
+ </pre>
80
+ </div>
81
+ </div>
package/src/index.js CHANGED
@@ -1,16 +1,18 @@
1
- // export { aes } from './lib/aes'
2
- // export { timelapse } from './lib/timelapse'
3
- // export { axisTicks } from './lib/axis'
4
- export { timer, elapsed } from './lib/timer'
5
- // export { default as Chart } from './chart/Chart.svelte'
6
- // export { default as Axis } from './chart/Axis.svelte'
7
- export { default as Swatch } from './chart/Swatch.svelte'
8
- // export { default as AxisTicks } from './chart/AxisTicks.svelte'
9
- // export { default as AxisGrid } from './chart/AxisGrid.svelte'
10
- // export { default as AxisLabels } from './chart/AxisLabels.svelte'
11
- export { default as BarPlot } from './plots/BarPlot.svelte'
12
- export { default as LinePlot } from './plots/LinePlot.svelte'
13
- export { default as BoxPlot } from './plots/BoxPlot.svelte'
14
- export { default as ViolinPlot } from './plots/ViolinPlot.svelte'
15
- export { default as ScatterPlot } from './plots/ScatterPlot.svelte'
16
- export * from './components/lib'
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
+
7
+ // Export components
8
+ export const Plot = {
9
+ Root,
10
+ Axis,
11
+ Bar,
12
+ Grid,
13
+ Legend
14
+ };
15
+
16
+ // Export utilities
17
+ export { ChartBrewer } from './lib/brewing/index.svelte.js';
18
+ export * from './lib/brewing/index.svelte.js';
@@ -0,0 +1,179 @@
1
+ import { scaleBand } from 'd3-scale';
2
+
3
+ import { } from './types.js';
4
+
5
+ /**
6
+ * @typedef {import('./types').TickData} TickData
7
+ * @typedef {import('./types').AxisData} AxisData
8
+ * @typedef {import('./types').ChartScales} ChartScales
9
+ * @typedef {import('./types').ChartDimensions} ChartDimensions
10
+ */
11
+
12
+ /**
13
+ * Creates x-axis tick data for rendering
14
+ *
15
+ * @param {Object} scales - Chart scales
16
+ * @param {Function} scales.x - X-axis scale
17
+ * @param {Object} dimensions - Chart dimensions
18
+ * @param {Object} options - Axis options
19
+ * @param {number} [options.tickCount] - Number of ticks to show
20
+ * @param {Function} [options.tickFormat] - Tick formatting function
21
+ * @param {string} [options.label] - Axis label
22
+ * @returns {AxisData} Axis rendering data
23
+ */
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
+ };
66
+ }
67
+
68
+ /**
69
+ * Creates y-axis tick data for rendering
70
+ *
71
+ * @param {Object} scales - Chart scales
72
+ * @param {Function} scales.y - Y-axis scale
73
+ * @param {Object} dimensions - Chart dimensions
74
+ * @param {Object} options - Axis options
75
+ * @param {number} [options.tickCount] - Number of ticks to show
76
+ * @param {Function} [options.tickFormat] - Tick formatting function
77
+ * @param {string} [options.label] - Axis label
78
+ * @returns {AxisData} Axis rendering data
79
+ */
80
+ 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
+ };
115
+ }
116
+
117
+ /**
118
+ * Creates grid line data for rendering
119
+ *
120
+ * @param {Object} scales - Chart scales
121
+ * @param {Object} dimensions - Chart dimensions
122
+ * @param {Object} options - Grid options
123
+ * @param {string} [options.direction='both'] - Grid direction ('x', 'y', or 'both')
124
+ * @param {number} [options.xTickCount] - Number of x-axis ticks
125
+ * @param {number} [options.yTickCount] - Number of y-axis ticks
126
+ * @returns {Object} Grid rendering data
127
+ */
128
+ 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;
155
+ }
156
+
157
+ /**
158
+ * Creates DOM attributes for a tick element
159
+ *
160
+ * @param {TickData} tick - Tick data
161
+ * @param {string} axis - Axis type ('x' or 'y')
162
+ * @returns {Object} Attributes for the tick
163
+ */
164
+ 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
+ }