@rokkit/chart 1.0.0-next.12 → 1.0.0-next.122

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 +140 -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 +95 -0
  31. package/src/Plot/Bar.svelte +95 -0
  32. package/src/Plot/Grid.svelte +68 -0
  33. package/src/Plot/Legend.svelte +127 -0
  34. package/src/Plot/Root.svelte +114 -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 +20 -22
  40. package/src/elements/ContinuousLegend.svelte +5 -6
  41. package/src/elements/DefinePatterns.svelte +22 -0
  42. package/src/elements/DiscreteLegend.svelte +4 -6
  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 +177 -0
  49. package/src/lib/brewing/bars.svelte.js +114 -0
  50. package/src/lib/brewing/dimensions.svelte.js +56 -0
  51. package/src/lib/brewing/index.svelte.js +202 -0
  52. package/src/lib/brewing/legends.svelte.js +94 -0
  53. package/src/lib/brewing/scales.svelte.js +85 -0
  54. package/src/lib/brewing/types.js +73 -0
  55. package/src/lib/context.js +132 -0
  56. package/src/lib/scales.svelte.js +122 -0
  57. package/src/lib/utils.js +96 -120
  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 +26 -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,114 @@
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(
17
+ new ChartBrewer({
18
+ width,
19
+ height,
20
+ margin,
21
+ animationDuration
22
+ })
23
+ )
24
+
25
+ // Chart dimensions derived from brewer
26
+ let dimensions = $derived(brewer.getDimensions())
27
+
28
+ // Process data
29
+ $effect(() => {
30
+ // If data has a select method (dataset object), call it to get actual data
31
+ const chartData = data.select && typeof data.select === 'function' ? data.select() : data
32
+
33
+ // Update brewer with data and fields
34
+ brewer.setData(chartData)
35
+ brewer.setFields({ color: fill })
36
+
37
+ // Create scales after setting data
38
+ brewer.createScales()
39
+ })
40
+
41
+ // Update chart dimensions when props change
42
+ $effect(() => {
43
+ brewer.setDimensions({ width, height, margin })
44
+ })
45
+
46
+ // Provide chart context to child components
47
+ setContext('chart-brewer', brewer)
48
+
49
+ // Handle responsive behavior
50
+ let container
51
+
52
+ $effect(() => {
53
+ if (!responsive || !container || !document) return
54
+
55
+ const resizeObserver = new ResizeObserver((entries) => {
56
+ const entry = entries[0]
57
+ if (!entry) return
58
+
59
+ const containerWidth = entry.contentRect.width
60
+ const aspectRatio = height / width
61
+
62
+ // Update chart dimensions while maintaining aspect ratio
63
+ brewer.setDimensions({
64
+ width: containerWidth,
65
+ height: containerWidth * aspectRatio
66
+ })
67
+
68
+ // Update scales after dimensions change
69
+ brewer.createScales()
70
+ })
71
+
72
+ // Start observing container size
73
+ resizeObserver.observe(container)
74
+
75
+ return () => {
76
+ resizeObserver.disconnect()
77
+ }
78
+ })
79
+ </script>
80
+
81
+ <div class="chart-container" bind:this={container} data-plot-root>
82
+ <svg
83
+ width={dimensions.width}
84
+ height={dimensions.height}
85
+ viewBox="0 0 {dimensions.width} {dimensions.height}"
86
+ role="img"
87
+ aria-label="Chart visualization"
88
+ >
89
+ <g
90
+ class="chart-area"
91
+ transform="translate({dimensions.margin.left}, {dimensions.margin.top})"
92
+ data-plot-canvas
93
+ >
94
+ <slot />
95
+ </g>
96
+ </svg>
97
+ </div>
98
+
99
+ <style>
100
+ .chart-container {
101
+ position: relative;
102
+ width: 100%;
103
+ height: auto;
104
+ }
105
+
106
+ svg {
107
+ display: block;
108
+ overflow: visible;
109
+ }
110
+
111
+ .chart-area {
112
+ pointer-events: all;
113
+ }
114
+ </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,39 +1,37 @@
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
- export let x = 0
6
- export let y = 0
7
- export let textSize = 5
8
- export let height = 10
9
- export let width = 100
10
- export let tickCount = 5
11
- export let scale
5
+ let { x = 0, y = 0, textSize = 5, height = 10, width = 100, tickCount = 5, scale } = $props()
12
6
 
13
- $: scaleTicks = scaleLinear()
14
- .range([x, x + width])
15
- .domain(scale.domain())
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 }))
7
+ let scaleTicks = $derived(
8
+ scaleLinear()
9
+ .range([x, x + width])
10
+ .domain(scale.domain())
11
+ )
12
+ let scalePercent = $derived(scaleLinear().range([0, 100]).domain(scale.domain()))
13
+ let ticks = $derived(
14
+ scale.ticks.apply(scale, [tickCount]).map((d) => ({ x: scaleTicks(d), value: d }))
15
+ )
20
16
 
21
- $: colors = ticks.map(({ value }) => ({
22
- color: scale(value),
23
- offset: `${scalePercent(value)}%`,
24
- }))
25
- $: id = uniqueId('legend-')
17
+ let colors = $derived(
18
+ ticks.map(({ value }) => ({
19
+ color: scale(value),
20
+ offset: `${scalePercent(value)}%`
21
+ }))
22
+ )
23
+ let id = $state(uniqueId('legend-'))
26
24
  </script>
27
25
 
28
26
  <defs>
29
27
  <linearGradient {id}>
30
- {#each colors as { color, offset }}
28
+ {#each colors as { color, offset }, index (index)}
31
29
  <stop stop-color={color} {offset} />
32
30
  {/each}
33
31
  </linearGradient>
34
32
  </defs>
35
33
  <rect {x} y={y + height} {width} {height} fill="url(#{id})" />
36
- {#each ticks as { x, value }}
34
+ {#each ticks as { x, value }, index (index)}
37
35
  <line x1={x} y1={y + (2 * height) / 3} x2={x} y2={y + height * 2} />
38
36
  <text {x} y={y + height / 2} font-size={textSize}>{value}</text>
39
37
  {/each}
@@ -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>
@@ -28,7 +27,7 @@
28
27
  </linearGradient>
29
28
  </defs>
30
29
  <rect {x} y={y + height} {width} {height} fill="url(#{id})" />
31
- {#each ticks as { x, label }}
30
+ {#each ticks as { x, label }, index (index)}
32
31
  <line x1={x} y1={y + (2 * height) / 3} x2={x} y2={y + height * 2} />
33
32
  <text {x} y={y + height / 2} font-size={textSize}>{label}</text>
34
33
  {/each}
@@ -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 }, index (index)}
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
- {#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
15
+ {#each ticks as tick, i (i)}
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 (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,177 @@
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 ? 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
+ }
64
+ }
65
+
66
+ /**
67
+ * Creates y-axis tick data for rendering
68
+ *
69
+ * @param {Object} scales - Chart scales
70
+ * @param {Function} scales.y - Y-axis scale
71
+ * @param {Object} dimensions - Chart dimensions
72
+ * @param {Object} options - Axis options
73
+ * @param {number} [options.tickCount] - Number of ticks to show
74
+ * @param {Function} [options.tickFormat] - Tick formatting function
75
+ * @param {string} [options.label] - Axis label
76
+ * @returns {AxisData} Axis rendering data
77
+ */
78
+ export function createYAxis(scales, dimensions, options = {}) {
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
+ }
113
+ }
114
+
115
+ /**
116
+ * Creates grid line data for rendering
117
+ *
118
+ * @param {Object} scales - Chart scales
119
+ * @param {Object} dimensions - Chart dimensions
120
+ * @param {Object} options - Grid options
121
+ * @param {string} [options.direction='both'] - Grid direction ('x', 'y', or 'both')
122
+ * @param {number} [options.xTickCount] - Number of x-axis ticks
123
+ * @param {number} [options.yTickCount] - Number of y-axis ticks
124
+ * @returns {Object} Grid rendering data
125
+ */
126
+ export function createGrid(scales, dimensions, options = {}) {
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
153
+ }
154
+
155
+ /**
156
+ * Creates DOM attributes for a tick element
157
+ *
158
+ * @param {TickData} tick - Tick data
159
+ * @param {string} axis - Axis type ('x' or 'y')
160
+ * @returns {Object} Attributes for the tick
161
+ */
162
+ export function createTickAttributes(tick, axis) {
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
+ }