@rokkit/chart 1.0.0-next.13 → 1.0.0-next.130

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 (149) 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 +96 -0
  32. package/src/Plot/Grid.svelte +68 -0
  33. package/src/Plot/Legend.svelte +127 -0
  34. package/src/Plot/Root.svelte +107 -0
  35. package/src/Plot/index.js +5 -0
  36. package/src/Symbol.svelte +21 -0
  37. package/src/Texture.svelte +10 -0
  38. package/src/elements/Bar.svelte +22 -24
  39. package/src/elements/ColorRamp.svelte +20 -22
  40. package/src/elements/ContinuousLegend.svelte +20 -17
  41. package/src/elements/DefinePatterns.svelte +24 -0
  42. package/src/elements/DiscreteLegend.svelte +15 -15
  43. package/src/elements/Label.svelte +11 -8
  44. package/src/elements/SymbolGrid.svelte +27 -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 +15 -0
  67. package/src/patterns/Circles.svelte +18 -0
  68. package/src/patterns/CrossHatch.svelte +12 -0
  69. package/src/patterns/CurvedWave.svelte +7 -0
  70. package/src/patterns/Dots.svelte +20 -0
  71. package/src/patterns/OutlineCircles.svelte +13 -0
  72. package/src/patterns/Tile.svelte +16 -0
  73. package/src/patterns/Triangles.svelte +13 -0
  74. package/src/patterns/Waves.svelte +9 -0
  75. package/src/patterns/index.js +14 -0
  76. package/src/patterns/paths/NamedPattern.svelte +9 -0
  77. package/src/patterns/paths/constants.js +4 -0
  78. package/src/symbols/RoundedSquare.svelte +22 -0
  79. package/src/symbols/Shape.svelte +24 -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 +13 -0
  85. package/src/template/constants.js +43 -0
  86. package/src/template/shapes/Circles.svelte +13 -0
  87. package/src/template/shapes/Lines.svelte +14 -0
  88. package/src/template/shapes/Path.svelte +9 -0
  89. package/src/template/shapes/Polygons.svelte +9 -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/Texture.svelte +0 -16
  101. package/src/chart/TexturedShape.svelte +0 -27
  102. package/src/chart/TimelapseChart.svelte +0 -97
  103. package/src/chart/Timer.svelte +0 -27
  104. package/src/chart.js +0 -9
  105. package/src/components/charts/Axis.svelte +0 -66
  106. package/src/components/charts/Chart.svelte +0 -35
  107. package/src/components/index.js +0 -23
  108. package/src/components/lib/axis.js +0 -0
  109. package/src/components/lib/chart.js +0 -187
  110. package/src/components/lib/color.js +0 -327
  111. package/src/components/lib/funnel.js +0 -204
  112. package/src/components/lib/index.js +0 -19
  113. package/src/components/lib/pattern.js +0 -190
  114. package/src/components/lib/rollup.js +0 -55
  115. package/src/components/lib/shape.js +0 -199
  116. package/src/components/lib/summary.js +0 -145
  117. package/src/components/lib/theme.js +0 -23
  118. package/src/components/lib/timer.js +0 -41
  119. package/src/components/lib/utils.js +0 -165
  120. package/src/components/plots/BarPlot.svelte +0 -36
  121. package/src/components/plots/BoxPlot.svelte +0 -54
  122. package/src/components/plots/ScatterPlot.svelte +0 -30
  123. package/src/components/store.js +0 -70
  124. package/src/constants.js +0 -66
  125. package/src/elements/PatternDefs.svelte +0 -13
  126. package/src/elements/PatternMask.svelte +0 -20
  127. package/src/elements/Symbol.svelte +0 -38
  128. package/src/elements/Tooltip.svelte +0 -23
  129. package/src/funnel.svelte +0 -35
  130. package/src/geom.js +0 -105
  131. package/src/lib/axis.js +0 -75
  132. package/src/lib/colors.js +0 -32
  133. package/src/lib/geom.js +0 -4
  134. package/src/lib/shapes.js +0 -144
  135. package/src/lib/timer.js +0 -44
  136. package/src/lookup.js +0 -29
  137. package/src/plots/BarPlot.svelte +0 -55
  138. package/src/plots/BoxPlot.svelte +0 -0
  139. package/src/plots/FunnelPlot.svelte +0 -33
  140. package/src/plots/HeatMap.svelte +0 -5
  141. package/src/plots/HeatMapCalendar.svelte +0 -129
  142. package/src/plots/LinePlot.svelte +0 -55
  143. package/src/plots/Plot.svelte +0 -25
  144. package/src/plots/RankBarPlot.svelte +0 -38
  145. package/src/plots/ScatterPlot.svelte +0 -20
  146. package/src/plots/ViolinPlot.svelte +0 -11
  147. package/src/plots/heatmap.js +0 -70
  148. package/src/plots/index.js +0 -10
  149. package/src/swatch.js +0 -11
@@ -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} />
@@ -0,0 +1,10 @@
1
+ <script>
2
+ let { id, path, fill = 'currentColor', stroke = 'currentColor', thickness = 0.5, patternUnits = 'userSpaceOnUse', size = 10 } = $props()
3
+ </script>
4
+
5
+ <pattern {id} {patternUnits} width={size} height={size}>
6
+ <rect width={size} height={size} {fill} />
7
+ {#if path}
8
+ <path d={path} fill="none" {stroke} stroke-width={thickness} />
9
+ {/if}
10
+ </pattern>
@@ -1,35 +1,33 @@
1
1
  <script>
2
2
  import { format } from 'd3-format'
3
+ import { get } from 'svelte/store'
3
4
  import Label from './Label.svelte'
4
5
 
5
- export let rank
6
- export let value
7
- export let name
8
- export let formatString = '.1%'
9
- export let scales
10
- export let height = 60
11
- export let fill
12
- export let spaceBetween = 5
6
+ let {
7
+ rank,
8
+ value,
9
+ name,
10
+ formatString = '.1%',
11
+ scales,
12
+ height = 60,
13
+ fill,
14
+ spaceBetween = 5
15
+ } = $props()
13
16
 
14
17
  const textHeight = 16
15
18
  const charWidth = 12
16
- $: y = rank * (height + spaceBetween)
17
- $: width = $scales.x(value)
19
+ let y = $derived(rank * (height + spaceBetween))
20
+ let width = $derived(get(scales).x(value))
18
21
 
19
- $: textWidth = name.length * charWidth
20
- $: textOffset = width <= textWidth ? width + charWidth : width
21
- $: textAnchor = textOffset > width ? 'start' : 'end'
22
+ let textWidth = $derived(name.length * charWidth)
23
+ let textOffset = $derived(width <= textWidth ? width + charWidth : width)
24
+ let textAnchor = $derived(textOffset > width ? 'start' : 'end')
22
25
 
23
- $: formattedValue = format(formatString)(value)
26
+ let formattedValue = $derived(format(formatString)(value))
27
+ let xOrigin = $derived(get(scales).x(0))
24
28
  </script>
25
29
 
26
- <rect x={$scales.x(0)} {y} {width} {height} {fill} opacity={0.5} />
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
- />
30
+ <rect x={xOrigin} {y} {width} {height} {fill} opacity={0.5} />
31
+ <rect x={xOrigin} {y} width={5} {height} {fill} />
32
+ <Label x={width} y={y + textHeight + 8} anchor={textAnchor} text={name} />
33
+ <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,24 +1,27 @@
1
1
  <script>
2
2
  import { scaleLinear } from 'd3-scale'
3
- import { uniqueId } from '../components/lib/utils'
4
3
 
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
4
+ let {
5
+ x = 0,
6
+ y = 0,
7
+ textSize = 5,
8
+ height = 10,
9
+ width = 100,
10
+ tickCount = 5,
11
+ scale,
12
+ id = 'legend'
13
+ } = $props()
12
14
 
13
- $: scaleTicks = scaleLinear()
14
- .range([x, x + 100])
15
- .domain(scale.domain())
16
- $: ticks = scale.ticks
17
- .apply(scale, [tickCount])
18
- .map((d) => ({ x: scaleTicks(d), label: d }))
15
+ let scaleTicks = $derived(
16
+ scaleLinear()
17
+ .range([x, x + 100])
18
+ .domain(scale.domain())
19
+ )
20
+ let ticks = $derived(
21
+ scale.ticks.apply(scale, [tickCount]).map((d) => ({ x: scaleTicks(d), label: d }))
22
+ )
19
23
 
20
- $: colors = scale.range()
21
- $: id = uniqueId('legend-')
24
+ let colors = $derived(scale.range())
22
25
  </script>
23
26
 
24
27
  <defs>
@@ -28,7 +31,7 @@
28
31
  </linearGradient>
29
32
  </defs>
30
33
  <rect {x} y={y + height} {width} {height} fill="url(#{id})" />
31
- {#each ticks as { x, label }}
34
+ {#each ticks as { x, label }, index (index)}
32
35
  <line x1={x} y1={y + (2 * height) / 3} x2={x} y2={y + height * 2} />
33
36
  <text {x} y={y + height / 2} font-size={textSize}>{label}</text>
34
37
  {/each}
@@ -0,0 +1,24 @@
1
+ <script>
2
+ import { uniq } from 'ramda'
3
+
4
+ let {
5
+ size = 10,
6
+ patternUnits = 'userSpaceOnUse',
7
+ /** @type {Array<import('./types').Pattern>} */
8
+ patterns = []
9
+ } = $props()
10
+
11
+ let names = $derived(uniq(patterns.map(({ id }) => id)))
12
+ </script>
13
+
14
+ {#if names.length < patterns.length}
15
+ <error> Patterns should be an array and should have unique names for each pattern </error>
16
+ {:else if patterns.length > 0}
17
+ <defs>
18
+ {#each patterns as { id, component: Component, fill, stroke }, index (index)}
19
+ <pattern {id} {patternUnits} width={size} height={size}>
20
+ <Component {size} {fill} {stroke} />
21
+ </pattern>
22
+ {/each}
23
+ </defs>
24
+ {/if}
@@ -1,22 +1,22 @@
1
1
  <script>
2
- export let x = 0
3
- export let y = 0
4
- export let textSize = 5
5
- export let size = 10
6
- export let space = 2
7
- export let padding = 5
8
- export let scale
9
- export let tickCount
2
+ let {
3
+ x = 0,
4
+ y = 0,
5
+ textSize = 5,
6
+ size = 10,
7
+ space = 2,
8
+ padding = 5,
9
+ scale,
10
+ tickCount = 10
11
+ } = $props()
10
12
 
11
- $: sizeWithSpace = size + space
12
- $: ticks = scale.ticks.apply(scale, [tickCount])
13
+ let sizeWithSpace = $derived(size + space)
14
+ let ticks = $derived(scale.ticks.apply(scale, [tickCount]))
13
15
  </script>
14
16
 
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
17
+ {#each ticks as tick, i (i)}
18
+ <text x={x + padding + i * sizeWithSpace + size / 2} y={y + size / 2} font-size={textSize}
19
+ >{tick}</text
20
20
  >
21
21
  <rect
22
22
  x={x + padding + i * sizeWithSpace}
@@ -1,12 +1,15 @@
1
1
  <script>
2
- export let small = false
3
- export let label
4
- export let angle = 0
5
- export let anchor = 'middle'
6
- export let x
7
- export let y
2
+ let {
3
+ x,
4
+ y,
5
+ text,
6
+ angle = 0,
7
+ small = false,
8
+ anchor = 'middle'
9
+ } = $props()
8
10
 
9
- $: transform = `translate(${x},${y}) rotate(${angle})`
11
+ let transform = $derived(`translate(${x},${y}) rotate(${angle})`)
12
+ let validAnchor = $derived(['start', 'middle', 'end'].includes(anchor) ? anchor : 'middle')
10
13
  </script>
11
14
 
12
- <text class="label" class:small text-anchor={anchor} {transform}>{label}</text>
15
+ <text class="label" class:small text-anchor={validAnchor} {transform}>{text}</text>
@@ -0,0 +1,27 @@
1
+ <script>
2
+ import { get } from 'svelte/store'
3
+ import { swatch, swatchGrid } from '../old_lib'
4
+ import Symbol from '../Symbol.svelte'
5
+
6
+ let {
7
+ base = 'teal',
8
+ size = 4,
9
+ shade = 600
10
+ } = $props()
11
+
12
+ let swatchValue = $derived(get(swatch))
13
+ let grid = $derived(swatchGrid(swatchValue.keys.symbol.length, size, 10))
14
+ </script>
15
+
16
+ <svg viewBox="0 0 {grid.width} {grid.height}">
17
+ {#each grid.data as { x, y, r }, index (index)}
18
+ <Symbol
19
+ {x}
20
+ {y}
21
+ size={r * 2}
22
+ name={swatchValue.keys.symbol[index]}
23
+ fill={swatchValue.palette[base][shade]}
24
+ stroke={swatchValue.palette[base][shade]}
25
+ />
26
+ {/each}
27
+ </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
+ }