@rokkit/chart 1.0.0-next.11

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 (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -0
  3. package/package.json +63 -0
  4. package/src/chart/FacetGrid.svelte +51 -0
  5. package/src/chart/Grid.svelte +34 -0
  6. package/src/chart/Legend.svelte +16 -0
  7. package/src/chart/PatternDefs.svelte +13 -0
  8. package/src/chart/Swatch.svelte +93 -0
  9. package/src/chart/SwatchButton.svelte +29 -0
  10. package/src/chart/SwatchGrid.svelte +55 -0
  11. package/src/chart/Symbol.svelte +37 -0
  12. package/src/chart/Texture.svelte +16 -0
  13. package/src/chart/TexturedShape.svelte +27 -0
  14. package/src/chart/TimelapseChart.svelte +97 -0
  15. package/src/chart/Timer.svelte +27 -0
  16. package/src/chart.js +9 -0
  17. package/src/components/charts/Axis.svelte +66 -0
  18. package/src/components/charts/Chart.svelte +35 -0
  19. package/src/components/index.js +23 -0
  20. package/src/components/lib/axis.js +0 -0
  21. package/src/components/lib/chart.js +187 -0
  22. package/src/components/lib/color.js +327 -0
  23. package/src/components/lib/funnel.js +204 -0
  24. package/src/components/lib/index.js +19 -0
  25. package/src/components/lib/pattern.js +190 -0
  26. package/src/components/lib/rollup.js +55 -0
  27. package/src/components/lib/shape.js +199 -0
  28. package/src/components/lib/summary.js +145 -0
  29. package/src/components/lib/theme.js +23 -0
  30. package/src/components/lib/timer.js +41 -0
  31. package/src/components/lib/utils.js +165 -0
  32. package/src/components/plots/BarPlot.svelte +36 -0
  33. package/src/components/plots/BoxPlot.svelte +54 -0
  34. package/src/components/plots/ScatterPlot.svelte +30 -0
  35. package/src/components/store.js +70 -0
  36. package/src/constants.js +66 -0
  37. package/src/elements/Bar.svelte +35 -0
  38. package/src/elements/ColorRamp.svelte +51 -0
  39. package/src/elements/ContinuousLegend.svelte +46 -0
  40. package/src/elements/DiscreteLegend.svelte +41 -0
  41. package/src/elements/Label.svelte +12 -0
  42. package/src/elements/PatternDefs.svelte +13 -0
  43. package/src/elements/PatternMask.svelte +20 -0
  44. package/src/elements/Symbol.svelte +38 -0
  45. package/src/elements/Tooltip.svelte +23 -0
  46. package/src/funnel.svelte +35 -0
  47. package/src/geom.js +105 -0
  48. package/src/index.js +16 -0
  49. package/src/lib/axis.js +75 -0
  50. package/src/lib/colors.js +32 -0
  51. package/src/lib/geom.js +4 -0
  52. package/src/lib/shapes.js +144 -0
  53. package/src/lib/timer.js +44 -0
  54. package/src/lib/utils.js +157 -0
  55. package/src/lookup.js +29 -0
  56. package/src/plots/BarPlot.svelte +55 -0
  57. package/src/plots/BoxPlot.svelte +0 -0
  58. package/src/plots/FunnelPlot.svelte +33 -0
  59. package/src/plots/HeatMap.svelte +5 -0
  60. package/src/plots/HeatMapCalendar.svelte +129 -0
  61. package/src/plots/LinePlot.svelte +55 -0
  62. package/src/plots/Plot.svelte +25 -0
  63. package/src/plots/RankBarPlot.svelte +38 -0
  64. package/src/plots/ScatterPlot.svelte +20 -0
  65. package/src/plots/ViolinPlot.svelte +11 -0
  66. package/src/plots/heatmap.js +70 -0
  67. package/src/plots/index.js +10 -0
  68. package/src/swatch.js +11 -0
@@ -0,0 +1,51 @@
1
+ <script>
2
+ import { scaleLinear } from 'd3-scale'
3
+ import { uniqueId } from '../lib/utils'
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
12
+
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 }))
20
+
21
+ $: colors = ticks.map(({ value }) => ({
22
+ color: scale(value),
23
+ offset: `${scalePercent(value)}%`,
24
+ }))
25
+ $: id = uniqueId('legend-')
26
+ </script>
27
+
28
+ <defs>
29
+ <linearGradient {id}>
30
+ {#each colors as { color, offset }}
31
+ <stop stop-color={color} {offset} />
32
+ {/each}
33
+ </linearGradient>
34
+ </defs>
35
+ <rect {x} y={y + height} {width} {height} fill="url(#{id})" />
36
+ {#each ticks as { x, value }}
37
+ <line x1={x} y1={y + (2 * height) / 3} x2={x} y2={y + height * 2} />
38
+ <text {x} y={y + height / 2} font-size={textSize}>{value}</text>
39
+ {/each}
40
+ <line x1={x} y1={y + 2 * height} x2={x + 100} y2={y + 2 * height} />
41
+
42
+ <style>
43
+ line {
44
+ stroke: currentColor;
45
+ stroke-width: 0.2;
46
+ }
47
+ text {
48
+ fill: currentColor;
49
+ text-anchor: middle;
50
+ }
51
+ </style>
@@ -0,0 +1,46 @@
1
+ <script>
2
+ import { scaleLinear } from 'd3-scale'
3
+ import { uniqueId } from '../components/lib/utils'
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
12
+
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 }))
19
+
20
+ $: colors = scale.range()
21
+ $: id = uniqueId('legend-')
22
+ </script>
23
+
24
+ <defs>
25
+ <linearGradient {id}>
26
+ <stop stop-color={colors[0]} offset="0%" />
27
+ <stop stop-color={colors[1]} offset="100%" />
28
+ </linearGradient>
29
+ </defs>
30
+ <rect {x} y={y + height} {width} {height} fill="url(#{id})" />
31
+ {#each ticks as { x, label }}
32
+ <line x1={x} y1={y + (2 * height) / 3} x2={x} y2={y + height * 2} />
33
+ <text {x} y={y + height / 2} font-size={textSize}>{label}</text>
34
+ {/each}
35
+ <line x1={x} y1={y + 2 * height} x2={x + 100} y2={y + 2 * height} />
36
+
37
+ <style>
38
+ line {
39
+ stroke: currentColor;
40
+ stroke-width: 0.2;
41
+ }
42
+ text {
43
+ fill: currentColor;
44
+ text-anchor: middle;
45
+ }
46
+ </style>
@@ -0,0 +1,41 @@
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
10
+
11
+ $: sizeWithSpace = size + space
12
+ $: ticks = scale.ticks.apply(scale, [tickCount])
13
+ </script>
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
20
+ >
21
+ <rect
22
+ x={x + padding + i * sizeWithSpace}
23
+ y={y + padding + textSize}
24
+ width={size}
25
+ height={size}
26
+ fill={scale(tick)}
27
+ rx="1"
28
+ ry="1"
29
+ />
30
+ {/each}
31
+
32
+ <style>
33
+ rect {
34
+ stroke: currentColor;
35
+ stroke-width: 0.2;
36
+ }
37
+ text {
38
+ fill: currentColor;
39
+ text-anchor: middle;
40
+ }
41
+ </style>
@@ -0,0 +1,12 @@
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
8
+
9
+ $: transform = `translate(${x},${y}) rotate(${angle})`
10
+ </script>
11
+
12
+ <text class="label" class:small text-anchor={anchor} {transform}>{label}</text>
@@ -0,0 +1,13 @@
1
+ <script>
2
+ import PatternMask from './PatternMask.svelte'
3
+ const size = 10
4
+
5
+ export let thickness = 0.5
6
+ export let patterns
7
+ </script>
8
+
9
+ <defs>
10
+ {#each patterns as pattern}
11
+ <PatternMask {...pattern} {thickness} {size} />
12
+ {/each}
13
+ </defs>
@@ -0,0 +1,20 @@
1
+ <script>
2
+ export let id
3
+ // export let fill
4
+ export let path
5
+ // export let contrast
6
+ export let thickness = 0.5
7
+ export let patternUnits = 'userSpaceOnUse'
8
+ export let size = 10
9
+ </script>
10
+
11
+ <pattern id="p-{id}" {patternUnits} width={size} height={size}>
12
+ {#if path}
13
+ <path d={path} fill="none" stroke="white" stroke-width={thickness} />
14
+ <!-- {:else}
15
+ <rect width={size} height={size} {fill} /> -->
16
+ {/if}
17
+ </pattern>
18
+ <mask {id}>
19
+ <rect x="0" y="0" width="100%" height="100%" fill="url(#p-{id})" />
20
+ </mask>
@@ -0,0 +1,38 @@
1
+ <script>
2
+ // import { namedShapes } from '../lib/shape'
3
+ import { swatchStore } from '../swatch'
4
+
5
+ export let x = 0
6
+ export let y = 0
7
+ export let size = 10
8
+ export let fill = 'none'
9
+ export let stroke = 'currentColor'
10
+ export let thickness = 0.5
11
+
12
+ export let name = 'circle'
13
+ // export let shape = null
14
+
15
+ $: x = x - size / 2
16
+ $: y = y - size / 2
17
+
18
+ $: d = $swatchStore[shapes][name](size)
19
+ // typeof shape === 'function'
20
+ // ? shape(size)
21
+ // : (shape || name) in namedShapes
22
+ // ? namedShapes[shape || name](size)
23
+ // : namedShapes.circle(size)
24
+ </script>
25
+
26
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
27
+ <path
28
+ {d}
29
+ {fill}
30
+ {stroke}
31
+ transform="translate({x},{y})"
32
+ stroke-width={thickness}
33
+ fill-rule="evenodd"
34
+ on:click
35
+ on:mouseover
36
+ on:mouseleave
37
+ on:focus
38
+ />
@@ -0,0 +1,23 @@
1
+ <script>
2
+ export let left
3
+ export let top
4
+ export let hidden = true
5
+ </script>
6
+
7
+ <div
8
+ class="tooltip {$$props.class}"
9
+ {hidden}
10
+ style="--top: {top};--left: {left}"
11
+ >
12
+ <slot />
13
+ </div>
14
+
15
+ <style lang="postcss">
16
+ .tooltip {
17
+ padding: 1em 0.5em;
18
+ left: var(--left);
19
+ top: var(--top);
20
+ position: absolute;
21
+ z-index: 10;
22
+ }
23
+ </style>
@@ -0,0 +1,35 @@
1
+ <script context="module">
2
+ /**
3
+ * @type {import('@sveltejs/kit').Load}
4
+ */
5
+ export async function load({ page, fetch, session, stuff }) {
6
+ const url = '/api/data/funnel'
7
+ const response = await fetch(url)
8
+
9
+ if (response.ok) {
10
+ let result = await response.json()
11
+
12
+ return {
13
+ props: { data: result }
14
+ }
15
+ }
16
+
17
+ return {
18
+ status: response.status,
19
+ error: new Error(`Could not load ${url}`)
20
+ }
21
+ }
22
+ </script>
23
+
24
+ <script>
25
+ import { FunnelPlot, Chart } from '@rokkit/chart'
26
+ export let data
27
+
28
+ // let names = ['one', 'two', 'three'] // each one is a separate segment. max of Combined value at each stage is overall height/width
29
+ // let groups = ['a', 'b', 'c'] // each group should have a value. individual values are used for each band height
30
+ </script>
31
+
32
+ <h1>Funnel</h1>
33
+ <Chart {data} width={1200}>
34
+ <FunnelPlot x="stage" y="count" fill="client" stat="sum" />
35
+ </Chart>
package/src/geom.js ADDED
@@ -0,0 +1,105 @@
1
+ import {
2
+ sum,
3
+ min,
4
+ max,
5
+ mean,
6
+ mode,
7
+ median,
8
+ deviation,
9
+ variance,
10
+ flatRollup
11
+ } from 'd3-array'
12
+
13
+ const summaries = {
14
+ identity: (value) => value,
15
+ count: (values) => values.length,
16
+ sum: (values) => sum(values),
17
+ min: (values) => min(values),
18
+ max: (values) => max(values),
19
+ mean: (values) => mean(values),
20
+ median: (values) => median(values),
21
+ mode: (values) => mode(values),
22
+ variance: (values) => variance(values),
23
+ deviation: (values) => deviation(values)
24
+ }
25
+
26
+ /**
27
+ * Returns an aggregator function for an input string or function.
28
+ *
29
+ * @param {string|function} stat
30
+ * @returns
31
+ */
32
+ export function rollup(stat) {
33
+ if (typeof stat === 'function') return stat
34
+ if (typeof stat !== 'string')
35
+ throw new TypeError('stat must be a string or function')
36
+ if (!(stat in summaries)) throw new TypeError('Unknown stat: ' + stat)
37
+
38
+ return summaries[stat]
39
+ }
40
+
41
+ /**
42
+ * Aesthetics for a chart.
43
+ *
44
+ * @typedef Aesthetics
45
+ * @property {string} x
46
+ * @property {string} y
47
+ * @property {string} [fill]
48
+ * @property {string} [size]
49
+ * @property {string} [color]
50
+ * @property {string} [shape]
51
+ * @property {string} [pattern]
52
+ */
53
+
54
+ /**
55
+ *
56
+ * @param {Array<any>} data
57
+ * @param {Aesthetics} aes
58
+ * @param {function|string} stat
59
+ * @returns
60
+ */
61
+ export function aggregate(data, aes, stat = 'identity') {
62
+ const agg = rollup(stat)
63
+ const keys = ['color', 'fill', 'pattern', 'shape', 'size'].filter((k) =>
64
+ Object.keys(aes).includes(k)
65
+ )
66
+
67
+ let groups = keys.map((k) => (d) => d[aes[k]])
68
+
69
+ return flatRollup(
70
+ data,
71
+ (v) => agg(v.map((d) => d[aes.y])),
72
+ (d) => d[aes.x],
73
+ ...groups
74
+ )
75
+ }
76
+
77
+ // export function geomBars(chart, aes) {
78
+ // const { x, y, fill, color, pattern } = { ...aes, ...chart.aes }
79
+ // return aggregate(chart.data, { x, y, fill, color, pattern })
80
+ // }
81
+
82
+ // export function geomLines(chart, aes) {
83
+ // const { x, y, color } = { ...aes, ...chart.aes }
84
+ // return aggregate(chart.data, { x, y, color })
85
+ // }
86
+
87
+ // export function geomViolin(chart, aes) {
88
+ // const { x, y, fill, color, pattern } = { ...aes, ...chart.aes }
89
+ // return { x, y, fill, color, pattern, ...opts }
90
+ // }
91
+
92
+ // export function geomArea(chart, aes) {
93
+ // const { x, y, fill, color, pattern } = { ...aes, ...chart.aes }
94
+ // return { x, y, fill, color, pattern, ...opts }
95
+ // }
96
+
97
+ // export function geomTrend(chart, aes) {
98
+ // const { x, y, fill, color, pattern } = { ...aes, ...chart.aes }
99
+ // return { x, y, fill, color, pattern, ...opts }
100
+ // }
101
+
102
+ // export function geomPoints(chart, aes) {
103
+ // const { x, y, fill, color, shape, size } = { ...aes, ...chart.aes }
104
+ // return { x, y, fill, color, shape, size, ...opts }
105
+ // }
package/src/index.js ADDED
@@ -0,0 +1,16 @@
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'
@@ -0,0 +1,75 @@
1
+ export function axis(scale) {
2
+ const origin = {
3
+ x: scale.x.ticks
4
+ ? scale.x(Math.max(0, Math.min(...scale.x.domain())))
5
+ : scale.x.range()[0],
6
+ y: scale.y.ticks
7
+ ? scale.y(Math.max(0, Math.min(...scale.y.domain())))
8
+ : scale.y.range()[0]
9
+ }
10
+ const ticks = {
11
+ x: axisTicks(scale.x, { axis: 'x', origin }),
12
+ y: axisTicks(scale.y, { axis: 'y', origin })
13
+ }
14
+ return { origin, ticks }
15
+ }
16
+
17
+ export function axisTicks(scale, opts) {
18
+ let [minRange, maxRange] = scale.range()
19
+ let count = Math.abs((maxRange - minRange) / 40)
20
+ let ticks = scale.domain()
21
+ let offset = 0
22
+ let { axis, format, origin } = {
23
+ axis: 'x',
24
+ format: (x) => x,
25
+ origin: { x: 0, y: 0 },
26
+ ...opts
27
+ }
28
+ if (scale.ticks) {
29
+ ticks = scale.ticks(count)
30
+ } else {
31
+ offset = Math.sign(maxRange - minRange) * (scale.bandwidth() / 2)
32
+ count = Math.min(Math.round(count), scale.domain().length)
33
+ if (count < scale.domain().length) {
34
+ let diff = scale.domain().length - count
35
+ ticks = ticks.filter((d, i) => i % diff == 0)
36
+ }
37
+ // let diff = scale.domain().length - count
38
+ }
39
+ ticks = ticks
40
+ .map((t) => ({
41
+ label: format(t),
42
+ pos: scale(t)
43
+ }))
44
+ .map(({ label, pos }) => ({
45
+ label,
46
+ offset: { x: axis === 'x' ? offset : 0, y: axis === 'y' ? offset : 0 },
47
+ x: axis === 'x' ? pos : origin.x,
48
+ y: axis === 'y' ? pos : origin.y
49
+ }))
50
+
51
+ return ticks
52
+ }
53
+
54
+ export class Axis {
55
+ constructor(name, chart, offset) {
56
+ this.name = ['x', 'y'].includes(name) ? name : 'x'
57
+ this.chart = chart
58
+ this.offset = offset
59
+ }
60
+
61
+ set offset(value) {
62
+ const [min, max] = this.chart.scale[this.name].range()
63
+ const otherAxis = this.name === 'x' ? 'y' : 'x'
64
+ const origin = this.chart.origin[otherAxis]
65
+
66
+ this.offset = value * (origin == min ? 1 : origin == max ? -1 : 0)
67
+ }
68
+
69
+ // get domain() {
70
+ // let coords =
71
+ // (coords[axis + '1'] =
72
+ // coords[axis + '2'] =
73
+ // origin[axis] - offset[axis])
74
+ // }
75
+ }
@@ -0,0 +1,32 @@
1
+ // import { writable } from 'svelte/store'
2
+ import { repeatAcross } from '../lib/utils'
3
+
4
+ const palette = [
5
+ '#FFDE6B',
6
+ '#EF89EE',
7
+ '#F79F1E',
8
+ '#02B8FF',
9
+ '#9F84EC',
10
+ '#15CBC4',
11
+ '#0092FD',
12
+ '#F63A57',
13
+ '#A2CB39',
14
+ '#FF6E2F',
15
+ '#FEB8B9',
16
+ '#af7aa1',
17
+ '#7EFFF5'
18
+ ]
19
+
20
+ export class Palette {
21
+ constructor(colors = palette) {
22
+ this.colors = colors
23
+ }
24
+
25
+ set colors(value) {
26
+ if (value && Array.isArray(value)) this.colors = value
27
+ }
28
+ }
29
+
30
+ export function colorBrewer(values) {
31
+ return repeatAcross(palette, [...new Set(values)])
32
+ }
@@ -0,0 +1,4 @@
1
+ // export function violin(data, mapping) {}
2
+ // export function bar(data, mapping) {}
3
+ // export function scatter(data, mapping) {}
4
+ // export function line(data, mapping) {}
@@ -0,0 +1,144 @@
1
+ const names = [
2
+ 'circle',
3
+ 'square',
4
+ 'triangle',
5
+ 'diamond',
6
+ 'star',
7
+ 'rhombus',
8
+ 'heart'
9
+ ]
10
+ const data = {
11
+ square: ['M', 1, 1, 'L', 9, 1, 'L', 9, 9, 'L', 1, 9, 'Z'],
12
+ circle: [
13
+ ['M', 0, 5],
14
+ ['A', 5, 5, 0, 0, 0, 10, 5],
15
+ ['A', 5, 5, 0, 0, 0, 0, 5]
16
+ ],
17
+ triangle: ['M', 5, 0, 'L', 10, 10, 'L', 0, 10, 'Z'],
18
+ diamond: [
19
+ ['M', 5, 0],
20
+ ['A', 7, 7, 0, 0, 0, 10, 5],
21
+ ['A', 7, 7, 0, 0, 0, 5, 10],
22
+ ['A', 7, 7, 0, 0, 0, 0, 5],
23
+ ['A', 7, 7, 0, 0, 0, 5, 0]
24
+ ],
25
+ rhombus: ['M', 0, 5, 'L', 5, 0, 'L', 10, 5, 'L', 5, 10, 'Z'],
26
+ heart: [
27
+ ['M', 9, 5],
28
+ ['A', 0.8, 0.8, 0, 0, 0, 5, 2],
29
+ ['A', 0.8, 0.8, 0, 0, 0, 1, 5],
30
+ ['L', 5, 9],
31
+ ['L', 9, 5]
32
+ ],
33
+ star: [
34
+ ['M', 4.80001, 0],
35
+ ['L', 5.92258, 3.45491],
36
+ ['H', 9.55529],
37
+ ['L', 6.61637, 5.59017],
38
+ ['L', 7.73894, 9.04509],
39
+ ['L', 4.80001, 6.90983],
40
+ ['L', 1.86108, 9.04509],
41
+ ['L', 2.98365, 5.59017],
42
+ ['L', 0.0447266, 3.45491],
43
+ ['H', 3.67744],
44
+ ['L', 4.80001, 0],
45
+ ['Z']
46
+ ]
47
+ }
48
+
49
+ function scaledPath(size, x) {
50
+ if (Array.isArray(x)) return x.map((x) => scaledPath(size, x)).join(' ')
51
+ return typeof size === 'number' ? x * size : x
52
+ }
53
+
54
+ export const shapes = names.map((name) => ({
55
+ name,
56
+ path: (s) => scaledPath(s, data[name])
57
+ }))
58
+
59
+ export const namedShapes = {
60
+ square: (s) =>
61
+ `M${0.1 * s} 0` +
62
+ `A${0.1 * s} ${0.1 * s} 0 0 0 0 ${0.1 * s}V${0.9 * s}` +
63
+ `A${0.1 * s} ${0.1 * s} 0 0 0 ${0.1 * s} ${s}H${0.9 * s}` +
64
+ `A${0.1 * s} ${0.1 * s} 0 0 0 ${s} ${0.9 * s}V${0.1 * s}` +
65
+ `A${0.1 * s} ${0.1 * s} 0 0 0 ${0.9 * s} 0Z`,
66
+ circle: (s) =>
67
+ `M0 ${0.5 * s}` +
68
+ `A${0.5 * s} ${0.5 * s} 0 0 0 ${s} ${0.5 * s}` +
69
+ `A${0.5 * s} ${0.5 * s} 0 0 0 0 ${0.5 * s}`,
70
+ diamond: (s) =>
71
+ `M${0.5 * s} 0` +
72
+ `A${0.6 * s} ${0.6 * s} 0 0 0 ${s} ${0.5 * s}` +
73
+ `A${0.6 * s} ${0.6 * s} 0 0 0 ${0.5 * s} ${s}` +
74
+ `A${0.6 * s} ${0.6 * s} 0 0 0 0 ${0.5 * s}` +
75
+ `A${0.6 * s} ${0.6 * s} 0 0 0 ${0.5 * s} 0`,
76
+ triangle: (s) =>
77
+ `M${0.5 * s} ${0.0866 * s}L0 ${0.9234 * s}L${s} ${0.9234 * s}Z`,
78
+ rhombus: (s) =>
79
+ `M${0.5 * s} 0` +
80
+ `L${s} ${0.5 * s}` +
81
+ `L${0.5 * s} ${s}` +
82
+ `L0 ${0.5 * s}Z`,
83
+ star: (s) =>
84
+ `M${0.5 * s} ${0.05 * s}` +
85
+ `L${0.606 * s} ${0.36 * s}` +
86
+ `L${s} ${0.36 * s}` +
87
+ `L${0.685 * s} ${0.59 * s}` +
88
+ `L${0.81 * s} ${0.95 * s}` +
89
+ `L${0.5 * s} ${0.725 * s}` +
90
+ `L${0.19 * s} ${0.95 * s}` +
91
+ `L${0.315 * s} ${0.59 * s}` +
92
+ `L0 ${0.36 * s}` +
93
+ `L${0.394 * s} ${0.36 * s}Z`,
94
+ heart: (s) =>
95
+ `M${0.9 * s} ${0.5 * s}` +
96
+ `A${0.08 * s} ${0.08 * s} 0 0 0 ${0.5 * s} ${0.2 * s}` +
97
+ `A${0.08 * s} ${0.08 * s} 0 0 0 ${0.1 * s} ${0.5 * s}` +
98
+ `L${0.5 * s} ${0.9 * s}` +
99
+ `L${0.9 * s} ${0.5 * s}`,
100
+ shurikan: (s) =>
101
+ `M${0.3 * s} ${0.1 * s}L${0.5 * s} 0L${0.7 * s} ${0.1 * s}` +
102
+ `A ${0.05 * s} ${0.05 * s} 0 0 0 ${0.9 * s} ${0.35 * s}` +
103
+ `L${s} ${0.5 * s}L${0.9 * s} ${0.7 * s}` +
104
+ `A ${0.05 * s} ${0.05 * s} 0 0 0 ${0.7 * s} ${0.9 * s}` +
105
+ `L${0.5 * s} ${s}L${0.3 * s} ${0.9 * s}` +
106
+ `A${0.05 * s} ${0.05 * s} 0 0 0 ${0.1 * s} ${0.7 * s}` +
107
+ `L0 ${0.5 * s}L${0.1 * s} ${0.3 * s}` +
108
+ `A${0.05 * s} ${0.05 * s} 0 0 0 ${0.3 * s} ${0.1 * s}` +
109
+ `M${0.4 * s} ${0.5 * s}` +
110
+ `A${0.1 * s} ${0.1 * s} 0 0 0 ${0.6 * s} ${0.5 * s}` +
111
+ `A${0.1 * s} ${0.1 * s} 0 0 0 ${0.4 * s} ${0.5 * s}`,
112
+ crosshair: (s) =>
113
+ `M${0.2 * s} ${0.5 * s}` +
114
+ `A${0.3 * s} ${0.3 * s} 0 0 0 ${0.8 * s} ${0.5 * s}` +
115
+ `A${0.3 * s} ${0.3 * s} 0 0 0 ${0.2 * s} ${0.5 * s}` +
116
+ `M0 ${0.5 * s}` +
117
+ `L${s} ${0.5 * s}` +
118
+ `M${0.5 * s} 0` +
119
+ `L${0.5 * s} ${s}`,
120
+ crossboats: (s) =>
121
+ `M0 ${0.5 * s}` +
122
+ `A${0.6 * s} ${0.4 * s} 0 0 0 ${s} ${0.5 * s}` +
123
+ `A${0.6 * s} ${0.4 * s} 0 0 0 0 ${0.5 * s}` +
124
+ `M${0.5 * s} 0` +
125
+ `A${0.4 * s} ${0.6 * s} 0 0 0 ${0.5 * s} ${s}` +
126
+ `A${0.4 * s} ${0.6 * s} 0 0 0 ${0.5 * s} 0`,
127
+ curvedrhombus: (s) =>
128
+ `M${0.1 * s} ${0.1 * s}` +
129
+ `A${0.5 * s} ${0.5 * s} 0 0 0 ${0.9 * s} ${0.1 * s}` +
130
+ `A${0.5 * s} ${0.5 * s} 0 0 0 ${0.9 * s} ${0.9 * s}` +
131
+ `A${0.5 * s} ${0.5 * s} 0 0 0 ${0.1 * s} ${0.9 * s}` +
132
+ `A${0.5 * s} ${0.5 * s} 0 0 0 ${0.1 * s} ${0.1 * s}`,
133
+ fourflags: (s) =>
134
+ `M${0.5 * s} ${0.3 * s}` +
135
+ `A${0.2 * s} ${0.1 * s} 0 0 0 ${0.5 * s} ${0.1 * s}` +
136
+ `L${0.5 * s} ${0.9 * s}` +
137
+ `M${0.5 * s} ${0.7 * s}` +
138
+ `A${0.2 * s} ${0.1 * s} 0 0 0 ${0.5 * s} ${0.9 * s}` +
139
+ `M${0.3 * s} ${0.5 * s}` +
140
+ `A${0.1 * s} ${0.2 * s} 0 0 0 ${0.1 * s} ${0.5 * s}` +
141
+ `L${0.9 * s} ${0.5 * s}` +
142
+ `M${0.7 * s} ${0.5 * s}` +
143
+ `A${0.1 * s} ${0.2 * s} 0 0 0 ${0.9 * s} ${0.5 * s}`
144
+ }