@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,66 @@
1
+ <script>
2
+ import { getContext } from 'svelte'
3
+ export let orient = 'bottom'
4
+
5
+ let chart = getContext('chart')
6
+
7
+ let top =
8
+ orient === 'bottom'
9
+ ? $chart.height - $chart.margin.bottom
10
+ : $chart.margin.top
11
+ let left =
12
+ orient === 'right' ? $chart.width - $chart.margin.right : $chart.margin.left
13
+ let tickSizeInner = $chart.theme.tick.size.inner || 6
14
+ let tickSizeOuter = $chart.theme.tick.size.outer || 6
15
+ let tickPadding = $chart.theme.tick.size.padding || 3
16
+
17
+ function axisPath(vertical, scale) {
18
+ const range = scale.range()
19
+ return vertical
20
+ ? `M${k * tickSizeOuter},${range[0]}H0V${range[1]}H${k * tickSizeOuter}`
21
+ : `M${range[0]},${k * tickSizeOuter}V0H${range[1]}V${k * tickSizeOuter}`
22
+ }
23
+
24
+ $: anchor =
25
+ orient === 'right' ? 'start' : orient === 'left' ? 'end' : 'middle'
26
+ $: k = orient === 'top' || orient === 'left' ? -1 : 1
27
+ $: dy = orient === 'top' ? '0em' : orient === 'bottom' ? '0.71em' : '0.32em'
28
+ $: vertical = orient === 'left' || orient === 'right'
29
+ // $: range = axis.scale.range()
30
+ $: axis = vertical ? $chart.axis.y : $chart.axis.x
31
+ </script>
32
+
33
+ <g
34
+ transform="translate({vertical ? left : 0},{vertical ? 0 : top})"
35
+ fill="none"
36
+ font-size="10"
37
+ font-family="sans-serif"
38
+ text-anchor={anchor}
39
+ class="axis"
40
+ >
41
+ <path
42
+ class="domain"
43
+ stroke="currentColor"
44
+ d="{axisPath(vertical, axis.scale)}}"
45
+ />
46
+ {#each axis.ticks as tick}
47
+ <g
48
+ class="tick"
49
+ transform="translate({vertical ? 0 : tick.position},{vertical
50
+ ? tick.position
51
+ : 0})"
52
+ >
53
+ <line
54
+ stroke="currentColor"
55
+ y2={vertical ? 0 : k * tickSizeInner}
56
+ x2={vertical ? k * tickSizeInner : 0}
57
+ />
58
+ <text
59
+ fill="currentColor"
60
+ y={vertical ? 0 : k * (tickSizeInner + tickPadding)}
61
+ x={vertical ? k * (tickSizeInner + tickPadding) : 0}
62
+ {dy}>{tick.label}</text
63
+ >
64
+ </g>
65
+ {/each}
66
+ </g>
@@ -0,0 +1,35 @@
1
+ <script>
2
+ import { setContext } from 'svelte'
3
+ import { writable } from 'svelte/store'
4
+ import { compact } from '../lib/utils'
5
+ import { builtIn } from '../lib/theme'
6
+
7
+ let chart = writable({})
8
+
9
+ setContext('chart', chart)
10
+
11
+ export let width = 800
12
+ export let height = 450
13
+ export let data
14
+ export let theme = builtIn
15
+ export let x
16
+ export let y
17
+ export let fill
18
+ export let color
19
+ export let padding = 20
20
+ export let curve = 'basis'
21
+ export let stat = 'identity'
22
+
23
+ $: aes = compact({ x, y, fill, color, stat, curve, padding })
24
+ $: chart.set({
25
+ width,
26
+ height,
27
+ data,
28
+ theme,
29
+ aes,
30
+ })
31
+ </script>
32
+
33
+ <svg viewBox="0 0 {width} {height}" class="chart" width="100%">
34
+ <slot />
35
+ </svg>
@@ -0,0 +1,23 @@
1
+ export { default as ColorRamp } from './elements/ColorRamp.svelte'
2
+
3
+ export { default as Symbol } from './chart/Symbol.svelte'
4
+ export { default as PatternDefs } from './chart/PatternDefs.svelte'
5
+ export { default as Swatch } from './chart/Swatch.svelte'
6
+ export { default as SwatchButton } from './chart/SwatchButton.svelte'
7
+ export { default as SwatchGrid } from './chart/SwatchGrid.svelte'
8
+
9
+ export { default as Axis } from './chart/Axis.svelte'
10
+ export { default as Grid } from './chart/Grid.svelte'
11
+
12
+ export { default as BoxPlot } from './plots/BoxPlot.svelte'
13
+ export { default as ViolinPlot } from '../plots/ViolinPlot.svelte'
14
+ export { default as ScatterPlot } from './plots/ScatterPlot.svelte'
15
+ export { default as FunnelPlot } from '../plots/FunnelPlot.svelte'
16
+
17
+ export { default as Chart } from './chart/Chart.svelte'
18
+ export { default as TimelapseChart } from './chart/TimelapseChart.svelte'
19
+ export { default as Timer } from './chart/Timer.svelte'
20
+ export { default as BarPlot } from './plots/BarPlot.svelte'
21
+ export { default as HeatMapCalendar } from '../plots/HeatMapCalendar.svelte'
22
+ export { toHexString, initCap, uniqueId, toNested } from './lib/utils'
23
+ export { brewer, uniques, slidingWindow, colors } from './lib/index'
File without changes
@@ -0,0 +1,187 @@
1
+ import { nest } from 'd3-collection'
2
+ import { max, quantile, ascending, histogram } from 'd3-array'
3
+ import { scaleLinear } from 'd3-scale'
4
+ import { area, curveCatmullRom } from 'd3-shape'
5
+ import { getScale } from './utils'
6
+
7
+ /**
8
+ * axis, theme, params, fields
9
+ */
10
+ export class ChartBrewer {
11
+ constructor(data, x, y) {
12
+ this.data = data
13
+ this.x = x
14
+ this.y = y
15
+ this.fill = x
16
+ this.axis = null
17
+ this.stats = {}
18
+ // this.yOffset = 20
19
+ this.padding = 10
20
+ this.margin = {
21
+ left: 10,
22
+ top: 10,
23
+ right: 10,
24
+ bottom: 10
25
+ }
26
+ this.params = {
27
+ ticks: {}
28
+ }
29
+ this.labels = []
30
+ this.width = 800
31
+ this.height = (this.width * 7) / 16
32
+ this.scaleValues = null
33
+ this.theme = {}
34
+ }
35
+
36
+ computeMargin(xAxisOrientation, yAxisOrientation) {
37
+ this.scaleValues = {
38
+ x: [...new Set(this.data.map((item) => item[this.x]))],
39
+ y: [...new Set(this.data.map((item) => item[this.y]))],
40
+ fill: [...new Set(this.data.map((item) => item[this.fill]))]
41
+ }
42
+
43
+ let xOffset =
44
+ max(this.scaleValues.y.map((value) => value.toString().length)) * 10
45
+ let yOffset = 20
46
+
47
+ this.margin = {
48
+ left: this.padding + (yAxisOrientation === 'left' ? xOffset : 0),
49
+ right: this.padding + (yAxisOrientation === 'left' ? 0 : xOffset),
50
+ top: this.padding + (xAxisOrientation === 'bottom' ? 0 : yOffset),
51
+ bottom: this.padding + (xAxisOrientation === 'bottom' ? yOffset : 0)
52
+ }
53
+ }
54
+
55
+ computeAxis(buffer = 0, inverse = false) {
56
+ let x = {}
57
+ let y = {}
58
+ let fill = {}
59
+
60
+ if (!this.scaleValues) {
61
+ this.computeMargin('bottom', 'left')
62
+ }
63
+
64
+ x.scale = getScale(
65
+ this.scaleValues.x,
66
+ [this.margin.left, this.width - this.margin.right],
67
+ buffer
68
+ )
69
+ const domainY = inverse
70
+ ? [this.margin.top, this.height - this.margin.bottom]
71
+ : [this.height - this.margin.bottom, this.margin.top]
72
+ y.scale = getScale(this.scaleValues.y, domainY, buffer)
73
+
74
+ x.ticks = tickValues(x.scale, 'x', this.params)
75
+ y.ticks = tickValues(y.scale, 'y', this.params)
76
+
77
+ this.axis = { x, y, fill }
78
+ return this
79
+ }
80
+ use(theme) {
81
+ this.theme = theme
82
+ return this
83
+ }
84
+
85
+ params(margin, ticks) {
86
+ this.margin = margin
87
+ this.ticks = ticks
88
+ return this
89
+ }
90
+
91
+ fillWith(fill) {
92
+ this.fill = fill
93
+ return this
94
+ }
95
+
96
+ highlight(values) {
97
+ this.highlight = values
98
+ return this
99
+ }
100
+
101
+ animate() {
102
+ return this
103
+ }
104
+
105
+ summary() {
106
+ const result = nest()
107
+ .key((d) => d[this.x])
108
+ .rollup((d) => {
109
+ let values = d.map((g) => g[this.y]).sort(ascending)
110
+ let q1 = quantile(values, 0.25)
111
+ let q3 = quantile(values, 0.75)
112
+ let median = quantile(values, 0.5)
113
+ let interQuantileRange = q3 - q1
114
+ let min = q1 - 1.5 * interQuantileRange
115
+ let max = q3 + 1.5 * interQuantileRange
116
+ return { q1, q3, median, interQuantileRange, min, max }
117
+ })
118
+ .entries(this.data)
119
+ return result
120
+ }
121
+
122
+ // assumes axis has been computes
123
+ violin() {
124
+ if (!this.axis) this.computeAxis()
125
+ // Features of the histogram
126
+ var histogramBins = bin()
127
+ .domain(this.axis.y.scale.domain())
128
+ .thresholds(this.axis.y.scale.ticks(20)) // Important: how many bins approx are going to be made? It is the 'resolution' of the violin plot
129
+ .value((d) => d)
130
+
131
+ // Compute the binning for each group of the dataset
132
+ var sumstat = nest()
133
+ .key((d) => d[this.x])
134
+ .rollup((d) => histogramBins(d.map((g) => +g[this.y])))
135
+ .entries(this.data)
136
+
137
+ // console.log(sumstat)
138
+ // What is the biggest number of value in a bin? We need it cause this value will have a width of 100% of the bandwidth.
139
+ var maxNum = 0
140
+ for (let i in sumstat) {
141
+ let allBins = sumstat[i].value
142
+ let lengths = allBins.map((a) => a.length)
143
+ let longest = max(lengths)
144
+ if (longest > maxNum) {
145
+ maxNum = longest
146
+ }
147
+ }
148
+ // console.log(
149
+ // maxNum,
150
+ // this.axis.x.scale.bandwidth(),
151
+ // this.axis.x.scale('setosa')
152
+ // )
153
+
154
+ // The maximum width of a violin must be x.bandwidth = the width dedicated to a group
155
+ var xNum = scaleLinear()
156
+ .range([0, this.axis.x.scale.bandwidth()])
157
+ .domain([0, maxNum])
158
+
159
+ let result = area()
160
+ .x0(xNum(0))
161
+ .x1(function (d) {
162
+ return xNum(d.length)
163
+ })
164
+ .y((d) => this.axis.y.scale(d.x0))
165
+ .curve(curveCatmullRom)
166
+
167
+ let areas = sumstat.map((d) => ({
168
+ curve: result(d.value),
169
+ x: this.axis.x.scale(d.key)
170
+ }))
171
+ return areas
172
+ }
173
+ }
174
+
175
+ function tickValues(scale, whichAxis, params) {
176
+ let { values, count } =
177
+ whichAxis in params.ticks ? params.ticks[whichAxis] : {}
178
+ values =
179
+ Array.isArray(values) && values.length > 2
180
+ ? values
181
+ : scale.ticks
182
+ ? scale.ticks.apply(scale, [count])
183
+ : scale.domain()
184
+ const ticks = values.map((label) => ({ label, position: scale(label) }))
185
+
186
+ return ticks
187
+ }
@@ -0,0 +1,327 @@
1
+ export const colors = [
2
+ '#FFDE6B',
3
+ '#EF89EE',
4
+ '#F79F1E',
5
+ '#02B8FF',
6
+ '#9F84EC',
7
+ '#15CBC4',
8
+ '#0092FD',
9
+ '#F63A57',
10
+ '#A2CB39',
11
+ '#FF6E2F',
12
+ '#FEB8B9',
13
+ '#af7aa1',
14
+ '#7EFFF5'
15
+ ]
16
+ export const palette = {
17
+ indigo: {
18
+ 50: '#eef2ff',
19
+ 100: '#e0e7ff',
20
+ 200: '#c7d2fe',
21
+ 300: '#a5b4fc',
22
+ 400: '#818cf8',
23
+ 500: '#6366f1',
24
+ 600: '#4f46e5',
25
+ 700: '#4338ca',
26
+ 800: '#3730a3',
27
+ 900: '#312e81'
28
+ },
29
+ blue: {
30
+ 50: '#eff6ff',
31
+ 100: '#dbeafe',
32
+ 200: '#bfdbfe',
33
+ 300: '#93c5fd',
34
+ 400: '#60a5fa',
35
+ 500: '#3b82f6',
36
+ 600: '#2563eb',
37
+ 700: '#1d4ed8',
38
+ 800: '#1e40af',
39
+ 900: '#1e3a8a'
40
+ },
41
+ sky: {
42
+ 50: '#f0f9ff',
43
+ 100: '#e0f2fe',
44
+ 200: '#bae6fd',
45
+ 300: '#7dd3fc',
46
+ 400: '#38bdf8',
47
+ 500: '#0ea5e9',
48
+ 600: '#0284c7',
49
+ 700: '#0369a1',
50
+ 800: '#075985',
51
+ 900: '#0c4a6e'
52
+ },
53
+ cyan: {
54
+ 50: '#ecfeff',
55
+ 100: '#cffafe',
56
+ 200: '#a5f3fc',
57
+ 300: '#67e8f9',
58
+ 400: '#22d3ee',
59
+ 500: '#06b6d4',
60
+ 600: '#0891b2',
61
+ 700: '#0e7490',
62
+ 800: '#155e75',
63
+ 900: '#164e63'
64
+ },
65
+ teal: {
66
+ 50: '#f0fdfa',
67
+ 100: '#ccfbf1',
68
+ 200: '#99f6e4',
69
+ 300: '#5eead4',
70
+ 400: '#2dd4bf',
71
+ 500: '#14b8a6',
72
+ 600: '#0d9488',
73
+ 700: '#0f766e',
74
+ 800: '#115e59',
75
+ 900: '#134e4a'
76
+ },
77
+ emerald: {
78
+ 50: '#ecfdf5',
79
+ 100: '#d1fae5',
80
+ 200: '#a7f3d0',
81
+ 300: '#6ee7b7',
82
+ 400: '#34d399',
83
+ 500: '#10b981',
84
+ 600: '#059669',
85
+ 700: '#047857',
86
+ 800: '#065f46',
87
+ 900: '#064e3b'
88
+ },
89
+ green: {
90
+ 50: '#f0fdf4',
91
+ 100: '#dcfce7',
92
+ 200: '#bbf7d0',
93
+ 300: '#86efac',
94
+ 400: '#4ade80',
95
+ 500: '#22c55e',
96
+ 600: '#16a34a',
97
+ 700: '#15803d',
98
+ 800: '#166534',
99
+ 900: '#14532d'
100
+ },
101
+ lime: {
102
+ 50: '#f7fee7',
103
+ 100: '#ecfccb',
104
+ 200: '#d9f99d',
105
+ 300: '#bef264',
106
+ 400: '#a3e635',
107
+ 500: '#84cc16',
108
+ 600: '#65a30d',
109
+ 700: '#4d7c0f',
110
+ 800: '#3f6212',
111
+ 900: '#365314'
112
+ },
113
+ yellow: {
114
+ 50: '#fefce8',
115
+ 100: '#fef9c3',
116
+ 200: '#fef08a',
117
+ 300: '#fde047',
118
+ 400: '#facc15',
119
+ 500: '#eab308',
120
+ 600: '#ca8a04',
121
+ 700: '#a16207',
122
+ 800: '#854d0e',
123
+ 900: '#713f12'
124
+ },
125
+ amber: {
126
+ 50: '#fffbeb',
127
+ 100: '#fef3c7',
128
+ 200: '#fde68a',
129
+ 300: '#fcd34d',
130
+ 400: '#fbbf24',
131
+ 500: '#f59e0b',
132
+ 600: '#d97706',
133
+ 700: '#b45309',
134
+ 800: '#92400e',
135
+ 900: '#78350f'
136
+ },
137
+ orange: {
138
+ 50: '#fff7ed',
139
+ 100: '#ffedd5',
140
+ 200: '#fed7aa',
141
+ 300: '#fdba74',
142
+ 400: '#fb923c',
143
+ 500: '#f97316',
144
+ 600: '#ea580c',
145
+ 700: '#c2410c',
146
+ 800: '#9a3412',
147
+ 900: '#7c2d12'
148
+ },
149
+ red: {
150
+ 50: '#fef2f2',
151
+ 100: '#fee2e2',
152
+ 200: '#fecaca',
153
+ 300: '#fca5a5',
154
+ 400: '#f87171',
155
+ 500: '#ef4444',
156
+ 600: '#dc2626',
157
+ 700: '#b91c1c',
158
+ 800: '#991b1b',
159
+ 900: '#7f1d1d'
160
+ },
161
+ rose: {
162
+ 50: '#fff1f2',
163
+ 100: '#ffe4e6',
164
+ 200: '#fecdd3',
165
+ 300: '#fda4af',
166
+ 400: '#fb7185',
167
+ 500: '#f43f5e',
168
+ 600: '#e11d48',
169
+ 700: '#be123c',
170
+ 800: '#9f1239',
171
+ 900: '#881337'
172
+ },
173
+ pink: {
174
+ 50: '#fdf2f8',
175
+ 100: '#fce7f3',
176
+ 200: '#fbcfe8',
177
+ 300: '#f9a8d4',
178
+ 400: '#f472b6',
179
+ 500: '#ec4899',
180
+ 600: '#db2777',
181
+ 700: '#be185d',
182
+ 800: '#9d174d',
183
+ 900: '#831843'
184
+ },
185
+ fuchsia: {
186
+ 50: '#fdf4ff',
187
+ 100: '#fae8ff',
188
+ 200: '#f5d0fe',
189
+ 300: '#f0abfc',
190
+ 400: '#e879f9',
191
+ 500: '#d946ef',
192
+ 600: '#c026d3',
193
+ 700: '#a21caf',
194
+ 800: '#86198f',
195
+ 900: '#701a75'
196
+ },
197
+ purple: {
198
+ 50: '#faf5ff',
199
+ 100: '#f3e8ff',
200
+ 200: '#e9d5ff',
201
+ 300: '#d8b4fe',
202
+ 400: '#c084fc',
203
+ 500: '#a855f7',
204
+ 600: '#9333ea',
205
+ 700: '#7e22ce',
206
+ 800: '#6b21a8',
207
+ 900: '#581c87'
208
+ },
209
+ violet: {
210
+ 50: '#f5f3ff',
211
+ 100: '#ede9fe',
212
+ 200: '#ddd6fe',
213
+ 300: '#c4b5fd',
214
+ 400: '#a78bfa',
215
+ 500: '#8b5cf6',
216
+ 600: '#7c3aed',
217
+ 700: '#6d28d9',
218
+ 800: '#5b21b6',
219
+ 900: '#4c1d95'
220
+ },
221
+ warmGray: {
222
+ 50: '#fafaf9',
223
+ 100: '#f5f5f4',
224
+ 200: '#e7e5e4',
225
+ 300: '#d6d3d1',
226
+ 400: '#a8a29e',
227
+ 500: '#78716c',
228
+ 600: '#57534e',
229
+ 700: '#44403c',
230
+ 800: '#292524',
231
+ 900: '#1c1917'
232
+ },
233
+ trueGray: {
234
+ 50: '#fafafa',
235
+ 100: '#f5f5f5',
236
+ 200: '#e5e5e5',
237
+ 300: '#d4d4d4',
238
+ 400: '#a3a3a3',
239
+ 500: '#737373',
240
+ 600: '#525252',
241
+ 700: '#404040',
242
+ 800: '#262626',
243
+ 900: '#171717'
244
+ },
245
+ gray: {
246
+ 50: '#fafafa',
247
+ 100: '#f4f4f5',
248
+ 200: '#e4e4e7',
249
+ 300: '#d4d4d8',
250
+ 400: '#a1a1aa',
251
+ 500: '#71717a',
252
+ 600: '#52525b',
253
+ 700: '#3f3f46',
254
+ 800: '#27272a',
255
+ 900: '#18181b'
256
+ },
257
+ blueGray: {
258
+ 50: '#f8fafc',
259
+ 100: '#f1f5f9',
260
+ 200: '#e2e8f0',
261
+ 300: '#cbd5e1',
262
+ 400: '#94a3b8',
263
+ 500: '#64748b',
264
+ 600: '#475569',
265
+ 700: '#334155',
266
+ 800: '#1e293b',
267
+ 900: '#0f172a'
268
+ }
269
+ }
270
+
271
+ export class ColorBrewer {
272
+ constructor() {
273
+ this.colors = ['blue', 'pink', 'teal', 'indigo', 'purple', 'amber', 'rose']
274
+ this.palette = palette
275
+ this.grayscale = this.palette['trueGray']
276
+ this.fill = 100
277
+ this.stroke = 600
278
+ this.contrast = 600
279
+ }
280
+
281
+ dark() {
282
+ this.fill = 500
283
+ this.stroke = 700
284
+ this.contrast = 100
285
+ return this
286
+ }
287
+
288
+ mix(fill, stroke, contrast) {
289
+ this.fill = Object.keys(this.grayscale).includes(fill) ? fill : this.fill
290
+ this.stroke = Object.keys(this.grayscale).includes(stroke)
291
+ ? stroke
292
+ : this.stroke
293
+ this.contrast = Object.keys(this.grayscale).includes(contrast)
294
+ ? contrast
295
+ : this.contrast
296
+
297
+ return this
298
+ }
299
+
300
+ swatch(colors) {
301
+ this.palette = colors
302
+ return this
303
+ }
304
+
305
+ filter(colors) {
306
+ this.colors = colors
307
+ return this
308
+ }
309
+
310
+ gray() {
311
+ return {
312
+ fill: this.grayscale[this.fill],
313
+ stroke: this.grayscale[this.stroke],
314
+ contrast: this.grayscale[this.contrast]
315
+ }
316
+ }
317
+
318
+ brew() {
319
+ const palette = this.colors.map((color) => ({
320
+ fill: this.palette[color][this.fill],
321
+ stroke: this.palette[color][this.stroke],
322
+ contrast: this.palette[color][this.contrast]
323
+ }))
324
+
325
+ return palette
326
+ }
327
+ }