@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.
- package/README.md +140 -46
- package/dist/Plot/index.d.ts +5 -0
- package/dist/elements/index.d.ts +6 -0
- package/dist/index.d.ts +14 -0
- package/dist/lib/brewing/axes.svelte.d.ts +72 -0
- package/dist/lib/brewing/bars.svelte.d.ts +54 -0
- package/dist/lib/brewing/dimensions.svelte.d.ts +35 -0
- package/dist/lib/brewing/index.svelte.d.ts +118 -0
- package/dist/lib/brewing/legends.svelte.d.ts +54 -0
- package/dist/lib/brewing/scales.svelte.d.ts +29 -0
- package/dist/lib/brewing/types.d.ts +162 -0
- package/dist/lib/context.d.ts +13 -0
- package/dist/lib/scales.svelte.d.ts +35 -0
- package/dist/lib/utils.d.ts +58 -0
- package/dist/old_lib/brewer.d.ts +9 -0
- package/dist/old_lib/chart.d.ts +40 -0
- package/dist/old_lib/grid.d.ts +72 -0
- package/dist/old_lib/index.d.ts +4 -0
- package/dist/old_lib/plots.d.ts +3 -0
- package/dist/old_lib/swatch.d.ts +285 -0
- package/dist/old_lib/ticks.d.ts +36 -0
- package/dist/old_lib/utils.d.ts +1 -0
- package/dist/patterns/index.d.ts +9 -0
- package/dist/patterns/paths/constants.d.ts +1 -0
- package/dist/symbols/constants/index.d.ts +1 -0
- package/dist/symbols/index.d.ts +5 -0
- package/dist/template/constants.d.ts +43 -0
- package/dist/template/shapes/index.d.ts +4 -0
- package/package.json +28 -44
- package/src/Plot/Axis.svelte +95 -0
- package/src/Plot/Bar.svelte +96 -0
- package/src/Plot/Grid.svelte +68 -0
- package/src/Plot/Legend.svelte +127 -0
- package/src/Plot/Root.svelte +107 -0
- package/src/Plot/index.js +5 -0
- package/src/Symbol.svelte +21 -0
- package/src/Texture.svelte +10 -0
- package/src/elements/Bar.svelte +22 -24
- package/src/elements/ColorRamp.svelte +20 -22
- package/src/elements/ContinuousLegend.svelte +20 -17
- package/src/elements/DefinePatterns.svelte +24 -0
- package/src/elements/DiscreteLegend.svelte +15 -15
- package/src/elements/Label.svelte +11 -8
- package/src/elements/SymbolGrid.svelte +27 -0
- package/src/elements/index.js +6 -0
- package/src/examples/BarChartExample.svelte +81 -0
- package/src/index.js +18 -16
- package/src/lib/brewing/axes.svelte.js +177 -0
- package/src/lib/brewing/bars.svelte.js +114 -0
- package/src/lib/brewing/dimensions.svelte.js +56 -0
- package/src/lib/brewing/index.svelte.js +202 -0
- package/src/lib/brewing/legends.svelte.js +94 -0
- package/src/lib/brewing/scales.svelte.js +85 -0
- package/src/lib/brewing/types.js +73 -0
- package/src/lib/context.js +132 -0
- package/src/lib/scales.svelte.js +122 -0
- package/src/lib/utils.js +96 -120
- package/src/old_lib/brewer.js +25 -0
- package/src/old_lib/chart.js +213 -0
- package/src/old_lib/grid.js +85 -0
- package/src/old_lib/index.js +4 -0
- package/src/old_lib/plots.js +27 -0
- package/src/old_lib/swatch.js +16 -0
- package/src/old_lib/ticks.js +46 -0
- package/src/old_lib/utils.js +8 -0
- package/src/patterns/Brick.svelte +15 -0
- package/src/patterns/Circles.svelte +18 -0
- package/src/patterns/CrossHatch.svelte +12 -0
- package/src/patterns/CurvedWave.svelte +7 -0
- package/src/patterns/Dots.svelte +20 -0
- package/src/patterns/OutlineCircles.svelte +13 -0
- package/src/patterns/Tile.svelte +16 -0
- package/src/patterns/Triangles.svelte +13 -0
- package/src/patterns/Waves.svelte +9 -0
- package/src/patterns/index.js +14 -0
- package/src/patterns/paths/NamedPattern.svelte +9 -0
- package/src/patterns/paths/constants.js +4 -0
- package/src/symbols/RoundedSquare.svelte +22 -0
- package/src/symbols/Shape.svelte +24 -0
- package/src/symbols/constants/index.js +4 -0
- package/src/symbols/index.js +9 -0
- package/src/symbols/outline.svelte +60 -0
- package/src/symbols/solid.svelte +60 -0
- package/src/template/Texture.svelte +13 -0
- package/src/template/constants.js +43 -0
- package/src/template/shapes/Circles.svelte +13 -0
- package/src/template/shapes/Lines.svelte +14 -0
- package/src/template/shapes/Path.svelte +9 -0
- package/src/template/shapes/Polygons.svelte +9 -0
- package/src/template/shapes/index.js +4 -0
- package/LICENSE +0 -21
- package/src/chart/FacetGrid.svelte +0 -51
- package/src/chart/Grid.svelte +0 -34
- package/src/chart/Legend.svelte +0 -16
- package/src/chart/PatternDefs.svelte +0 -13
- package/src/chart/Swatch.svelte +0 -93
- package/src/chart/SwatchButton.svelte +0 -29
- package/src/chart/SwatchGrid.svelte +0 -55
- package/src/chart/Symbol.svelte +0 -37
- package/src/chart/Texture.svelte +0 -16
- package/src/chart/TexturedShape.svelte +0 -27
- package/src/chart/TimelapseChart.svelte +0 -97
- package/src/chart/Timer.svelte +0 -27
- package/src/chart.js +0 -9
- package/src/components/charts/Axis.svelte +0 -66
- package/src/components/charts/Chart.svelte +0 -35
- package/src/components/index.js +0 -23
- package/src/components/lib/axis.js +0 -0
- package/src/components/lib/chart.js +0 -187
- package/src/components/lib/color.js +0 -327
- package/src/components/lib/funnel.js +0 -204
- package/src/components/lib/index.js +0 -19
- package/src/components/lib/pattern.js +0 -190
- package/src/components/lib/rollup.js +0 -55
- package/src/components/lib/shape.js +0 -199
- package/src/components/lib/summary.js +0 -145
- package/src/components/lib/theme.js +0 -23
- package/src/components/lib/timer.js +0 -41
- package/src/components/lib/utils.js +0 -165
- package/src/components/plots/BarPlot.svelte +0 -36
- package/src/components/plots/BoxPlot.svelte +0 -54
- package/src/components/plots/ScatterPlot.svelte +0 -30
- package/src/components/store.js +0 -70
- package/src/constants.js +0 -66
- package/src/elements/PatternDefs.svelte +0 -13
- package/src/elements/PatternMask.svelte +0 -20
- package/src/elements/Symbol.svelte +0 -38
- package/src/elements/Tooltip.svelte +0 -23
- package/src/funnel.svelte +0 -35
- package/src/geom.js +0 -105
- package/src/lib/axis.js +0 -75
- package/src/lib/colors.js +0 -32
- package/src/lib/geom.js +0 -4
- package/src/lib/shapes.js +0 -144
- package/src/lib/timer.js +0 -44
- package/src/lookup.js +0 -29
- package/src/plots/BarPlot.svelte +0 -55
- package/src/plots/BoxPlot.svelte +0 -0
- package/src/plots/FunnelPlot.svelte +0 -33
- package/src/plots/HeatMap.svelte +0 -5
- package/src/plots/HeatMapCalendar.svelte +0 -129
- package/src/plots/LinePlot.svelte +0 -55
- package/src/plots/Plot.svelte +0 -25
- package/src/plots/RankBarPlot.svelte +0 -38
- package/src/plots/ScatterPlot.svelte +0 -20
- package/src/plots/ViolinPlot.svelte +0 -11
- package/src/plots/heatmap.js +0 -70
- package/src/plots/index.js +0 -10
- package/src/swatch.js +0 -11
|
@@ -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>
|
package/src/elements/Bar.svelte
CHANGED
|
@@ -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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
17
|
-
|
|
19
|
+
let y = $derived(rank * (height + spaceBetween))
|
|
20
|
+
let width = $derived(get(scales).x(value))
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
26
|
+
let formattedValue = $derived(format(formatString)(value))
|
|
27
|
+
let xOrigin = $derived(get(scales).x(0))
|
|
24
28
|
</script>
|
|
25
29
|
|
|
26
|
-
<rect x={
|
|
27
|
-
<rect x={
|
|
28
|
-
<Label x={width} y={y + textHeight + 8} anchor={textAnchor}
|
|
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 '
|
|
3
|
+
import { id as uniqueId } from '@rokkit/core'
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
let {
|
|
3
|
+
x,
|
|
4
|
+
y,
|
|
5
|
+
text,
|
|
6
|
+
angle = 0,
|
|
7
|
+
small = false,
|
|
8
|
+
anchor = 'middle'
|
|
9
|
+
} = $props()
|
|
8
10
|
|
|
9
|
-
|
|
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={
|
|
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
|
+
<!-- <script>
|
|
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
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<Plot.Root {data} width={600} height={400} margin={{ top: 20, right: 100, bottom: 60, left: 60 }} fill="category">
|
|
73
|
+
<Plot.Grid direction="y" lineStyle="dashed" />
|
|
74
|
+
<Plot.Axis type="x" field="category" label="Product Category" />
|
|
75
|
+
<Plot.Axis type="y" field="count" label="Number of Products" />
|
|
76
|
+
<Plot.Bar x="category" y="count" fill="category" onClick={handleBarClick} />
|
|
77
|
+
<Plot.Legend title="Categories" />
|
|
78
|
+
</Plot.Root> -->
|
|
79
|
+
</pre>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
package/src/index.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
+
}
|