@rokkit/chart 1.0.0-next.14 → 1.0.0-next.140

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 (150) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +150 -46
  3. package/dist/Plot/index.d.ts +5 -0
  4. package/dist/elements/index.d.ts +6 -0
  5. package/dist/index.d.ts +14 -0
  6. package/dist/lib/brewing/axes.svelte.d.ts +66 -0
  7. package/dist/lib/brewing/bars.svelte.d.ts +56 -0
  8. package/dist/lib/brewing/dimensions.svelte.d.ts +35 -0
  9. package/dist/lib/brewing/index.svelte.d.ts +118 -0
  10. package/dist/lib/brewing/legends.svelte.d.ts +48 -0
  11. package/dist/lib/brewing/scales.svelte.d.ts +24 -0
  12. package/dist/lib/brewing/types.d.ts +162 -0
  13. package/dist/lib/context.d.ts +13 -0
  14. package/dist/lib/scales.svelte.d.ts +35 -0
  15. package/dist/lib/utils.d.ts +60 -0
  16. package/dist/old_lib/brewer.d.ts +9 -0
  17. package/dist/old_lib/chart.d.ts +40 -0
  18. package/dist/old_lib/grid.d.ts +72 -0
  19. package/dist/old_lib/index.d.ts +4 -0
  20. package/dist/old_lib/plots.d.ts +3 -0
  21. package/dist/old_lib/swatch.d.ts +285 -0
  22. package/dist/old_lib/ticks.d.ts +36 -0
  23. package/dist/old_lib/utils.d.ts +1 -0
  24. package/dist/patterns/index.d.ts +9 -0
  25. package/dist/patterns/paths/constants.d.ts +1 -0
  26. package/dist/symbols/constants/index.d.ts +1 -0
  27. package/dist/symbols/index.d.ts +5 -0
  28. package/dist/template/constants.d.ts +43 -0
  29. package/dist/template/shapes/index.d.ts +4 -0
  30. package/package.json +34 -44
  31. package/src/Plot/Axis.svelte +95 -0
  32. package/src/Plot/Bar.svelte +96 -0
  33. package/src/Plot/Grid.svelte +68 -0
  34. package/src/Plot/Legend.svelte +127 -0
  35. package/src/Plot/Root.svelte +107 -0
  36. package/src/Plot/index.js +5 -0
  37. package/src/Symbol.svelte +21 -0
  38. package/src/Texture.svelte +18 -0
  39. package/src/elements/Bar.svelte +22 -24
  40. package/src/elements/ColorRamp.svelte +20 -22
  41. package/src/elements/ContinuousLegend.svelte +20 -17
  42. package/src/elements/DefinePatterns.svelte +24 -0
  43. package/src/elements/DiscreteLegend.svelte +15 -15
  44. package/src/elements/Label.svelte +4 -8
  45. package/src/elements/SymbolGrid.svelte +23 -0
  46. package/src/elements/index.js +6 -0
  47. package/src/examples/BarChartExample.svelte +81 -0
  48. package/src/index.js +18 -16
  49. package/src/lib/brewing/axes.svelte.js +265 -0
  50. package/src/lib/brewing/bars.svelte.js +177 -0
  51. package/src/lib/brewing/dimensions.svelte.js +56 -0
  52. package/src/lib/brewing/index.svelte.js +205 -0
  53. package/src/lib/brewing/legends.svelte.js +137 -0
  54. package/src/lib/brewing/scales.svelte.js +106 -0
  55. package/src/lib/brewing/types.js +73 -0
  56. package/src/lib/context.js +133 -0
  57. package/src/lib/scales.svelte.js +172 -0
  58. package/src/lib/utils.js +107 -120
  59. package/src/old_lib/brewer.js +25 -0
  60. package/src/old_lib/chart.js +213 -0
  61. package/src/old_lib/grid.js +85 -0
  62. package/src/old_lib/index.js +4 -0
  63. package/src/old_lib/plots.js +27 -0
  64. package/src/old_lib/swatch.js +16 -0
  65. package/src/old_lib/ticks.js +46 -0
  66. package/src/old_lib/utils.js +8 -0
  67. package/src/patterns/Brick.svelte +15 -0
  68. package/src/patterns/Circles.svelte +18 -0
  69. package/src/patterns/CrossHatch.svelte +12 -0
  70. package/src/patterns/CurvedWave.svelte +7 -0
  71. package/src/patterns/Dots.svelte +20 -0
  72. package/src/patterns/OutlineCircles.svelte +13 -0
  73. package/src/patterns/README.md +3 -0
  74. package/src/patterns/Tile.svelte +16 -0
  75. package/src/patterns/Triangles.svelte +13 -0
  76. package/src/patterns/Waves.svelte +9 -0
  77. package/src/patterns/index.js +14 -0
  78. package/src/patterns/paths/NamedPattern.svelte +9 -0
  79. package/src/patterns/paths/constants.js +4 -0
  80. package/src/symbols/RoundedSquare.svelte +33 -0
  81. package/src/symbols/Shape.svelte +37 -0
  82. package/src/symbols/constants/index.js +4 -0
  83. package/src/symbols/index.js +9 -0
  84. package/src/symbols/outline.svelte +60 -0
  85. package/src/symbols/solid.svelte +60 -0
  86. package/src/template/Texture.svelte +13 -0
  87. package/src/template/constants.js +43 -0
  88. package/src/template/shapes/Circles.svelte +15 -0
  89. package/src/template/shapes/Lines.svelte +16 -0
  90. package/src/template/shapes/Path.svelte +9 -0
  91. package/src/template/shapes/Polygons.svelte +15 -0
  92. package/src/template/shapes/index.js +4 -0
  93. package/src/chart/FacetGrid.svelte +0 -51
  94. package/src/chart/Grid.svelte +0 -34
  95. package/src/chart/Legend.svelte +0 -16
  96. package/src/chart/PatternDefs.svelte +0 -13
  97. package/src/chart/Swatch.svelte +0 -93
  98. package/src/chart/SwatchButton.svelte +0 -29
  99. package/src/chart/SwatchGrid.svelte +0 -55
  100. package/src/chart/Symbol.svelte +0 -37
  101. package/src/chart/Texture.svelte +0 -16
  102. package/src/chart/TexturedShape.svelte +0 -27
  103. package/src/chart/TimelapseChart.svelte +0 -97
  104. package/src/chart/Timer.svelte +0 -27
  105. package/src/chart.js +0 -9
  106. package/src/components/charts/Axis.svelte +0 -66
  107. package/src/components/charts/Chart.svelte +0 -35
  108. package/src/components/index.js +0 -23
  109. package/src/components/lib/axis.js +0 -0
  110. package/src/components/lib/chart.js +0 -187
  111. package/src/components/lib/color.js +0 -327
  112. package/src/components/lib/funnel.js +0 -204
  113. package/src/components/lib/index.js +0 -19
  114. package/src/components/lib/pattern.js +0 -190
  115. package/src/components/lib/rollup.js +0 -55
  116. package/src/components/lib/shape.js +0 -199
  117. package/src/components/lib/summary.js +0 -145
  118. package/src/components/lib/theme.js +0 -23
  119. package/src/components/lib/timer.js +0 -41
  120. package/src/components/lib/utils.js +0 -165
  121. package/src/components/plots/BarPlot.svelte +0 -36
  122. package/src/components/plots/BoxPlot.svelte +0 -54
  123. package/src/components/plots/ScatterPlot.svelte +0 -30
  124. package/src/components/store.js +0 -70
  125. package/src/constants.js +0 -66
  126. package/src/elements/PatternDefs.svelte +0 -13
  127. package/src/elements/PatternMask.svelte +0 -20
  128. package/src/elements/Symbol.svelte +0 -38
  129. package/src/elements/Tooltip.svelte +0 -23
  130. package/src/funnel.svelte +0 -35
  131. package/src/geom.js +0 -105
  132. package/src/lib/axis.js +0 -75
  133. package/src/lib/colors.js +0 -32
  134. package/src/lib/geom.js +0 -4
  135. package/src/lib/shapes.js +0 -144
  136. package/src/lib/timer.js +0 -44
  137. package/src/lookup.js +0 -29
  138. package/src/plots/BarPlot.svelte +0 -55
  139. package/src/plots/BoxPlot.svelte +0 -0
  140. package/src/plots/FunnelPlot.svelte +0 -33
  141. package/src/plots/HeatMap.svelte +0 -5
  142. package/src/plots/HeatMapCalendar.svelte +0 -129
  143. package/src/plots/LinePlot.svelte +0 -55
  144. package/src/plots/Plot.svelte +0 -25
  145. package/src/plots/RankBarPlot.svelte +0 -38
  146. package/src/plots/ScatterPlot.svelte +0 -20
  147. package/src/plots/ViolinPlot.svelte +0 -11
  148. package/src/plots/heatmap.js +0 -70
  149. package/src/plots/index.js +0 -10
  150. package/src/swatch.js +0 -11
@@ -1,187 +0,0 @@
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
- }
@@ -1,327 +0,0 @@
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
- }
@@ -1,204 +0,0 @@
1
- import { sum, median, max, mean, min, quantile, cumsum } from 'd3-array'
2
- import { nest } from 'd3-collection'
3
- import { pick, flatten } from 'ramda'
4
- import { area, curveBasis, curveBumpX, curveBumpY } from 'd3-shape'
5
- import { scaleLinear } from 'd3-scale'
6
-
7
- const aggregate = {
8
- count: (values) => values.length,
9
- sum: (values) => sum(values),
10
- min: (values) => min(values),
11
- max: (values) => max(values),
12
- mean: (values) => mean(values),
13
- median: (values) => median(values),
14
- q1: (values) => quantile(values, 0.25),
15
- q3: (values) => quantile(values, 0.75)
16
- }
17
-
18
- export function summarize(data, by, attr, stat = 'count') {
19
- const stats = Array.isArray(stat) ? stat : [stat]
20
- const grouped = nest()
21
- .key((d) => by.map((f) => d[f]).join('|'))
22
- .rollup((rows) => {
23
- let agg = pick(by, rows[0])
24
- stats.map(
25
- (stat) => (agg[stat] = aggregate[stat](rows.map((d) => d[attr])))
26
- )
27
- return [agg]
28
- })
29
- .entries(data)
30
- return flatten(grouped.map((group) => group.value))
31
- }
32
-
33
- export function getUniques(input, aes) {
34
- const attrs = ['x', 'y', 'fill']
35
- let values = {}
36
-
37
- attrs.map((attr) => {
38
- if (attr in aes) {
39
- values[attr] = [...new Set(input.map((d) => d[aes[attr]]))]
40
- }
41
- })
42
- return values
43
- }
44
-
45
- export function fillMissing(fill, rows, key, aes) {
46
- const filled = fill.map((f) => {
47
- let matched = rows.filter((r) => r[aes.fill] === f)
48
- if (matched.length == 0) {
49
- let row = {}
50
- row[key] = rows[0][key]
51
- row[aes.fill] = f
52
- row[aes.stat] = 0
53
- return row
54
- } else {
55
- return matched[0]
56
- }
57
- })
58
- return filled
59
- }
60
-
61
- export function convertToPhases(input, aes) {
62
- const uniques = getUniques(input, aes)
63
- let vertical = 'y' in uniques && uniques.y.some(isNaN)
64
- const horizontal = 'x' in uniques && uniques.x.some(isNaN)
65
-
66
- let summary = []
67
-
68
- if (horizontal && vertical) {
69
- if ((aes.stat || 'count') === 'count') {
70
- vertical = false
71
- console.warn('Assuming horizontal layout becuse stat is count')
72
- } else {
73
- console.error(
74
- 'cannot plot without at least one axis having numeric values'
75
- )
76
- return { uniques, vertical }
77
- }
78
- }
79
-
80
- const key = vertical ? aes.y : aes.x
81
- const value = vertical ? aes.x : aes.y
82
-
83
- let by = [key]
84
- if ('fill' in aes) {
85
- by.push(aes.fill)
86
- }
87
- summary = summarize(input, by, value, aes.stat)
88
- const phases = nest()
89
- .key((d) => d[key])
90
- .rollup((rows) => {
91
- return 'fill' in aes ? fillMissing(uniques.fill, rows, key, aes) : rows
92
- })
93
- .entries(summary)
94
-
95
- return { phases, uniques, vertical }
96
- }
97
-
98
- export function mirror(input, aes) {
99
- let domain = 0
100
-
101
- const stats = input.phases.map((phase) => {
102
- const stat = cumsum(phase.value.map((row) => row[aes.stat]))
103
- const midpoint = max(stat) / 2
104
- domain = Math.max(domain, midpoint)
105
-
106
- const rows = phase.value.map((row, index) => {
107
- if (input.vertical) {
108
- return {
109
- ...row,
110
- y: input.uniques.y.indexOf(row[aes.y]),
111
- x1: stat[index] - midpoint,
112
- x0: stat[index] - midpoint - row[aes.stat]
113
- }
114
- } else {
115
- return {
116
- ...row,
117
- x: input.uniques.x.indexOf(row[aes.x]),
118
- y1: stat[index] - midpoint,
119
- y0: stat[index] - midpoint - row[aes.stat]
120
- }
121
- }
122
- })
123
-
124
- phase.value = rows
125
- return phase
126
- })
127
-
128
- return { ...input, stats, domain }
129
- }
130
-
131
- export function getScales(input, width, height) {
132
- let scale
133
- if (input.vertical) {
134
- scale = {
135
- x: scaleLinear()
136
- .domain([-input.domain * 1.4, input.domain * 1.4])
137
- .range([0, width]),
138
- y: scaleLinear().domain([0, input.uniques.y.length]).range([0, height])
139
- }
140
- } else {
141
- scale = {
142
- x: scaleLinear().domain([0, input.uniques.x.length]).range([0, width]),
143
- y: scaleLinear()
144
- .domain([-input.domain, input.domain * 1.4])
145
- .range([height - 20, 0])
146
- }
147
- }
148
- return scale
149
- }
150
-
151
- function getLabels(data) {
152
- let key = data.vertical ? 'y' : 'x'
153
- let opp = key === 'x' ? 'y' : 'x'
154
-
155
- let labels = data.uniques[key].map((label, index) => {
156
- let row = { label }
157
- let domain = data.scale[opp].domain()
158
- row[`${key}1`] = row[`${key}2`] = data.scale[key](index + 1)
159
- row[`${opp}1`] = data.scale[opp](domain[0])
160
- row[`${opp}2`] = data.scale[opp](domain[1])
161
- row[opp] = 20
162
- row[key] = data.scale[key](index) + 20
163
- return row
164
- })
165
- return labels
166
- }
167
-
168
- export function getPaths(vertical, scale, curve) {
169
- return vertical
170
- ? area()
171
- .x0((d) => scale.x(d.x0))
172
- .x1((d) => scale.x(d.x1))
173
- .y((d) => scale.y(d.y))
174
- .curve(curve)
175
- : area()
176
- .x((d) => scale.x(d.x))
177
- .y0((d) => scale.y(d.y0))
178
- .y1((d) => scale.y(d.y1))
179
- .curve(curve)
180
- }
181
- export function funnel(input, aes, width, height) {
182
- let data = convertToPhases(input, aes)
183
- data = mirror(data, aes)
184
- const curve =
185
- aes.curve === 'basis' ? curveBasis : data.vertical ? curveBumpY : curveBumpX
186
- // console.log(data)
187
-
188
- if ('fill' in aes) {
189
- let stats = flatten(data.stats.map((phase) => phase.value))
190
- // console.log(stats)
191
-
192
- data.stats = nest()
193
- .key((d) => d[aes.fill])
194
- .rollup((rows) => {
195
- let last = data.vertical ? { y: rows.length } : { x: rows.length }
196
- return [...rows, { ...rows[rows.length - 1], ...last }]
197
- })
198
- .entries(stats)
199
- }
200
- data.scale = getScales(data, width, height)
201
- data.path = getPaths(data.vertical, data.scale, curve)
202
- data.labels = getLabels(data)
203
- return data
204
- }