@rokkit/chart 1.0.0-next.86 → 1.0.0-next.88
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/package.json +11 -6
- package/src/Chart.svelte +67 -0
- package/src/PatternDefs.svelte +14 -0
- package/src/Symbol.svelte +17 -0
- package/src/{chart/Texture.svelte → Texture.svelte} +3 -3
- package/src/elements/Bar.svelte +2 -2
- package/src/elements/ContinuousLegend.svelte +3 -2
- package/src/elements/DefinePatterns.svelte +22 -0
- package/src/elements/DiscreteLegend.svelte +1 -1
- package/src/elements/Label.svelte +7 -5
- package/src/elements/SymbolGrid.svelte +23 -0
- package/src/elements/index.js +6 -0
- package/src/index.js +5 -15
- package/src/lib/brewer.js +17 -0
- package/src/lib/chart.js +179 -160
- package/src/lib/grid.js +68 -0
- package/src/lib/index.js +4 -0
- package/src/lib/palette.js +279 -28
- package/src/lib/plots.js +23 -0
- package/src/lib/swatch.js +24 -8
- package/src/lib/ticks.js +19 -0
- package/src/patterns/Brick.svelte +17 -0
- package/src/patterns/Circles.svelte +18 -0
- package/src/patterns/CrossHatch.svelte +14 -0
- package/src/patterns/CurvedWave.svelte +9 -0
- package/src/patterns/Dots.svelte +19 -0
- package/src/patterns/OutlineCircles.svelte +15 -0
- package/src/patterns/Texture.svelte +20 -0
- package/src/patterns/Tile.svelte +17 -0
- package/src/patterns/Triangles.svelte +15 -0
- package/src/patterns/Waves.svelte +13 -0
- package/src/patterns/constants.js +43 -0
- package/src/patterns/index.js +13 -0
- package/src/patterns/paths/NamedPattern.svelte +12 -0
- package/src/patterns/paths/constants.js +7 -0
- package/src/patterns/templates/Circles.svelte +18 -0
- package/src/patterns/templates/Lines.svelte +17 -0
- package/src/patterns/templates/Path.svelte +17 -0
- package/src/patterns/templates/index.js +3 -0
- package/src/plots/Plot.svelte +36 -21
- package/src/plots/index.js +1 -10
- package/src/symbols/Circle.svelte +22 -0
- package/src/symbols/Shape.svelte +31 -0
- package/src/symbols/Square.svelte +27 -0
- package/src/symbols/Triangle.svelte +24 -0
- package/src/symbols/constants/index.js +7 -0
- package/src/symbols/index.js +13 -0
- package/src/chart/Axis.svelte +0 -81
- package/src/chart/AxisGrid.svelte +0 -22
- package/src/chart/Chart.svelte +0 -40
- package/src/chart/FacetGrid.svelte +0 -49
- package/src/chart/Legend.svelte +0 -16
- package/src/chart/Swatch.svelte +0 -84
- package/src/chart/SwatchButton.svelte +0 -29
- package/src/chart/SwatchGrid.svelte +0 -53
- package/src/chart/TexturedShape.svelte +0 -20
- package/src/chart/TimelapseChart.svelte +0 -90
- package/src/chart/Timer.svelte +0 -27
- package/src/elements/Tooltip.svelte +0 -19
- package/src/lib/axis.js +0 -77
- package/src/lib/color.js +0 -55
- package/src/lib/constants.js +0 -41
- package/src/lib/funnel.js +0 -230
- package/src/lib/geom.js +0 -99
- package/src/lib/heatmap.js +0 -68
- package/src/lib/lookup.js +0 -29
- package/src/lib/pattern.js +0 -182
- package/src/lib/rollup.js +0 -49
- package/src/lib/shape.js +0 -46
- package/src/lib/store.js +0 -63
- package/src/lib/summary.js +0 -28
- package/src/lib/theme.js +0 -31
- package/src/lib/utils.js +0 -158
- package/src/plots/BarPlot.svelte +0 -51
- package/src/plots/BarPlot2.svelte +0 -34
- package/src/plots/BoxPlot.svelte +0 -54
- package/src/plots/FunnelPlot.svelte +0 -26
- package/src/plots/HeatMapCalendar.svelte +0 -121
- package/src/plots/LinePlot.svelte +0 -51
- package/src/plots/RankBarPlot.svelte +0 -38
- package/src/plots/ScatterPlot.svelte +0 -28
- package/src/plots/ViolinPlot.svelte +0 -10
package/src/lib/chart.js
CHANGED
|
@@ -1,189 +1,208 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
import { min, max } from 'd3-array'
|
|
2
|
+
import { scaleBand, scaleLinear, scaleTime } from 'd3-scale'
|
|
3
|
+
|
|
4
|
+
function getScale(domain, range, padding = 0) {
|
|
5
|
+
if (domain.some(isNaN)) {
|
|
6
|
+
return scaleBand().domain(domain).range(range).padding(padding)
|
|
7
|
+
} else if (domain[0] instanceof Date) {
|
|
8
|
+
return scaleTime()
|
|
9
|
+
.domain([min(domain), max(domain)])
|
|
10
|
+
.range(range)
|
|
11
|
+
.nice()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return scaleLinear()
|
|
15
|
+
.domain([min([0, ...domain]), max([0, ...domain])])
|
|
16
|
+
.range(range)
|
|
17
|
+
.nice()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class Chart {
|
|
21
|
+
// data = []
|
|
22
|
+
// width = 512
|
|
23
|
+
// height = 512
|
|
24
|
+
// origin = { x: 0, y: 0 }
|
|
25
|
+
// range = {
|
|
26
|
+
// x: [0, this.width],
|
|
27
|
+
// y: [this.height, 0]
|
|
28
|
+
// }
|
|
29
|
+
// x
|
|
30
|
+
// y
|
|
31
|
+
// stat = 'identity'
|
|
32
|
+
// scale
|
|
33
|
+
// fill
|
|
34
|
+
// color
|
|
35
|
+
// value
|
|
36
|
+
// shape
|
|
37
|
+
// valueFormat
|
|
38
|
+
// valueLabel
|
|
39
|
+
// domain
|
|
40
|
+
// margin
|
|
41
|
+
// spacing
|
|
42
|
+
// padding
|
|
43
|
+
// flipCoords = false
|
|
44
|
+
|
|
45
|
+
constructor(data, opts) {
|
|
46
|
+
this.width = +opts.width || 2048
|
|
47
|
+
this.height = +opts.height || 2048
|
|
48
|
+
this.flipCoords = opts.flipCoords || false
|
|
49
|
+
this.x = opts.x
|
|
50
|
+
this.y = opts.y
|
|
51
|
+
this.value = opts.value || opts.y
|
|
52
|
+
this.valueLabel = opts.valueLabel || this.value
|
|
53
|
+
this.valueFormat = opts.valueFormat || ((d) => d)
|
|
54
|
+
this.fill = opts.fill || opts.x
|
|
55
|
+
this.color = opts.color || opts.fill
|
|
56
|
+
this.shape = opts.shape || opts.fill
|
|
57
|
+
|
|
58
|
+
this.padding = opts.padding !== undefined ? +opts.padding : 32
|
|
59
|
+
|
|
60
|
+
this.spacing = +opts.spacing >= 0 && +opts.spacing <= 0.5 ? +opts.spacing : 0
|
|
32
61
|
this.margin = {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
right:
|
|
36
|
-
bottom:
|
|
62
|
+
top: +opts.margin?.top || 0,
|
|
63
|
+
left: +opts.margin?.left || 0,
|
|
64
|
+
right: +opts.margin?.right || 0,
|
|
65
|
+
bottom: +opts.margin?.bottom || 0
|
|
37
66
|
}
|
|
38
|
-
this.
|
|
39
|
-
|
|
67
|
+
this.domain = {
|
|
68
|
+
x: [...new Set(data.map((d) => d[this.x]))],
|
|
69
|
+
y: [...new Set(data.map((d) => d[this.y]))]
|
|
40
70
|
}
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
-
this.height = (this.width * 7) / 16
|
|
44
|
-
this.scaleValues = null
|
|
45
|
-
this.theme = {}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
computeMargin(xAxisOrientation, yAxisOrientation) {
|
|
49
|
-
this.scaleValues = {
|
|
50
|
-
x: [...new Set(this.data.map((item) => item[this.x]))],
|
|
51
|
-
y: [...new Set(this.data.map((item) => item[this.y]))],
|
|
52
|
-
fill: [...new Set(this.data.map((item) => item[this.fill]))]
|
|
71
|
+
if (this.flipCoords) {
|
|
72
|
+
this.domain = { y: this.domain.x, x: this.domain.y }
|
|
53
73
|
}
|
|
74
|
+
this.stat = opts.stat || 'identity'
|
|
75
|
+
|
|
76
|
+
this.data = data.map((d) => ({
|
|
77
|
+
x: this.flipCoords ? d[this.y] : d[this.x],
|
|
78
|
+
y: this.flipCoords ? d[this.x] : d[this.y],
|
|
79
|
+
fill: d[this.fill],
|
|
80
|
+
color: d[this.color],
|
|
81
|
+
shape: d[this.shape]
|
|
82
|
+
}))
|
|
54
83
|
|
|
55
|
-
|
|
56
|
-
|
|
84
|
+
this.refresh()
|
|
85
|
+
}
|
|
57
86
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
top: this.padding + (xAxisOrientation === 'bottom' ? 0 : yOffset),
|
|
62
|
-
bottom: this.padding + (xAxisOrientation === 'bottom' ? yOffset : 0)
|
|
63
|
-
}
|
|
87
|
+
padding(value) {
|
|
88
|
+
this.padding = value
|
|
89
|
+
return this.refresh()
|
|
64
90
|
}
|
|
65
91
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
92
|
+
margin(value) {
|
|
93
|
+
this.margin = value
|
|
94
|
+
return this.refresh()
|
|
95
|
+
}
|
|
70
96
|
|
|
71
|
-
|
|
72
|
-
|
|
97
|
+
refresh() {
|
|
98
|
+
this.range = {
|
|
99
|
+
x: [this.margin.left + this.padding, this.width - this.margin.right - this.padding],
|
|
100
|
+
y: [this.height - this.padding - this.margin.bottom, this.margin.top + this.padding]
|
|
73
101
|
}
|
|
74
102
|
|
|
75
|
-
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
)
|
|
80
|
-
const domainY = inverse
|
|
81
|
-
? [this.margin.top, this.height - this.margin.bottom]
|
|
82
|
-
: [this.height - this.margin.bottom, this.margin.top]
|
|
83
|
-
y.scale = getScale(this.scaleValues.y, domainY, buffer)
|
|
103
|
+
let scale = {
|
|
104
|
+
x: getScale(this.domain.x, this.range.x, this.spacing),
|
|
105
|
+
y: getScale(this.domain.y, this.range.y, this.spacing)
|
|
106
|
+
}
|
|
84
107
|
|
|
85
|
-
|
|
86
|
-
y.ticks = tickValues(y.scale, 'y', this.params)
|
|
108
|
+
// scale['value'] = this.value === this.x ? scale.x : scale.y
|
|
87
109
|
|
|
88
|
-
this.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
this.theme = theme
|
|
93
|
-
return this
|
|
94
|
-
}
|
|
110
|
+
this.origin = {
|
|
111
|
+
x: scale.x.ticks ? scale.x(Math.max(0, Math.min(...scale.x.domain()))) : scale.x.range()[0],
|
|
112
|
+
y: scale.y.ticks ? scale.y(Math.max(0, Math.min(...scale.y.domain()))) : scale.y.range()[0]
|
|
113
|
+
}
|
|
95
114
|
|
|
96
|
-
|
|
97
|
-
this.margin = margin
|
|
98
|
-
this.ticks = ticks
|
|
99
|
-
return this
|
|
100
|
-
}
|
|
115
|
+
this.scale = scale
|
|
101
116
|
|
|
102
|
-
fillWith(fill) {
|
|
103
|
-
this.fill = fill
|
|
104
117
|
return this
|
|
105
118
|
}
|
|
106
119
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
// get scale() {
|
|
121
|
+
// return this.scale
|
|
122
|
+
// }
|
|
123
|
+
// get origin() {
|
|
124
|
+
// return this.origin
|
|
125
|
+
// }
|
|
126
|
+
// get margin() {
|
|
127
|
+
// return this.margin
|
|
128
|
+
// }
|
|
129
|
+
// get range() {
|
|
130
|
+
// const [x1, x2] = this.scale.x.range()
|
|
131
|
+
// const [y1, y2] = this.scale.y.range()
|
|
132
|
+
|
|
133
|
+
// return { x1, y1, x2, y2 }
|
|
134
|
+
// }
|
|
135
|
+
// get data() {
|
|
136
|
+
// // aggregate data group by x,y,fill,shape, color
|
|
137
|
+
// // stat = [min, max, avg, std, q1, q3, median, sum, count, box, all]
|
|
138
|
+
|
|
139
|
+
// return this.data
|
|
140
|
+
// }
|
|
141
|
+
// get width() {
|
|
142
|
+
// return this.width
|
|
143
|
+
// }
|
|
144
|
+
// get height() {
|
|
145
|
+
// return this.height
|
|
146
|
+
// }
|
|
147
|
+
// set width(value) {
|
|
148
|
+
// this.width = value
|
|
149
|
+
// }
|
|
150
|
+
// set height(value) {
|
|
151
|
+
// this.height = value
|
|
152
|
+
// }
|
|
153
|
+
// get domain() {
|
|
154
|
+
// return this.domain
|
|
155
|
+
// }
|
|
156
|
+
// get flipCoords() {
|
|
157
|
+
// return this.flipCoords
|
|
158
|
+
// }
|
|
159
|
+
aggregate(value, stat) {
|
|
160
|
+
this.value = value
|
|
161
|
+
this.stat = stat
|
|
162
|
+
|
|
163
|
+
// this.data = nest(this.data)
|
|
110
164
|
}
|
|
111
165
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
166
|
+
ticks(axis, count, fontSize = 8) {
|
|
167
|
+
const scale = this.scale[axis]
|
|
168
|
+
const [minRange, maxRange] = scale.range()
|
|
169
|
+
let ticks = []
|
|
170
|
+
let offset = 0
|
|
115
171
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
let median = quantile(values, 0.5)
|
|
124
|
-
let interQuantileRange = q3 - q1
|
|
125
|
-
let min = q1 - 1.5 * interQuantileRange
|
|
126
|
-
let max = q3 + 1.5 * interQuantileRange
|
|
127
|
-
return { q1, q3, median, interQuantileRange, min, max }
|
|
128
|
-
})
|
|
129
|
-
.entries(this.data)
|
|
130
|
-
return result
|
|
131
|
-
}
|
|
172
|
+
count = count || Math.abs((maxRange - minRange) / (fontSize * (axis === 'y' ? 8 : 8)))
|
|
173
|
+
|
|
174
|
+
if (scale.ticks) {
|
|
175
|
+
ticks = scale.ticks(Math.round(count))
|
|
176
|
+
} else {
|
|
177
|
+
offset = scale.bandwidth() / 2
|
|
178
|
+
count = Math.min(Math.round(count), scale.domain().length)
|
|
132
179
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
var histogramBins = bin()
|
|
138
|
-
.domain(this.axis.y.scale.domain())
|
|
139
|
-
.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
|
|
140
|
-
.value((d) => d)
|
|
141
|
-
|
|
142
|
-
// Compute the binning for each group of the dataset
|
|
143
|
-
var sumstat = nest()
|
|
144
|
-
.key((d) => d[this.x])
|
|
145
|
-
.rollup((d) => histogramBins(d.map((g) => +g[this.y])))
|
|
146
|
-
.entries(this.data)
|
|
147
|
-
|
|
148
|
-
// 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.
|
|
149
|
-
var maxNum = 0
|
|
150
|
-
for (let i in sumstat) {
|
|
151
|
-
let allBins = sumstat[i].value
|
|
152
|
-
let lengths = allBins.map((a) => a.length)
|
|
153
|
-
let longest = max(lengths)
|
|
154
|
-
if (longest > maxNum) {
|
|
155
|
-
maxNum = longest
|
|
180
|
+
ticks = scale.domain()
|
|
181
|
+
if (count < scale.domain().length) {
|
|
182
|
+
let diff = scale.domain().length - count
|
|
183
|
+
ticks = ticks.filter((d, i) => i % diff == 0)
|
|
156
184
|
}
|
|
157
185
|
}
|
|
158
186
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return
|
|
187
|
+
ticks = ticks
|
|
188
|
+
.map((t) => ({
|
|
189
|
+
label: t,
|
|
190
|
+
pos: scale(t)
|
|
191
|
+
}))
|
|
192
|
+
.map(({ label, pos }) => ({
|
|
193
|
+
label,
|
|
194
|
+
offset: {
|
|
195
|
+
x: axis === 'x' ? offset : 0,
|
|
196
|
+
y: axis === 'y' ? offset : 0
|
|
197
|
+
},
|
|
198
|
+
x: axis === 'x' ? pos : this.origin.x,
|
|
199
|
+
y: axis === 'y' ? pos : this.origin.y
|
|
200
|
+
}))
|
|
201
|
+
|
|
202
|
+
return ticks
|
|
175
203
|
}
|
|
176
204
|
}
|
|
177
205
|
|
|
178
|
-
function
|
|
179
|
-
|
|
180
|
-
values =
|
|
181
|
-
Array.isArray(values) && values.length > 2
|
|
182
|
-
? values
|
|
183
|
-
: scale.ticks
|
|
184
|
-
? scale.ticks.apply(scale, [count])
|
|
185
|
-
: scale.domain()
|
|
186
|
-
const ticks = values.map((label) => ({ label, position: scale(label) }))
|
|
187
|
-
|
|
188
|
-
return ticks
|
|
206
|
+
export function chart(data, aes) {
|
|
207
|
+
return new Chart(data, aes)
|
|
189
208
|
}
|
package/src/lib/grid.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef GridPoint
|
|
3
|
+
* @property {number} x
|
|
4
|
+
* @property {number} y
|
|
5
|
+
* @property {number} r
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef SwatchGrid
|
|
10
|
+
* @property {number} width
|
|
11
|
+
* @property {number} height
|
|
12
|
+
* @property {GridPoint[]} data
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Calculates a grid of centres to fit a list of items of `size` within the number of `columns` and `rows`.
|
|
16
|
+
*
|
|
17
|
+
* - Attempts to find a best fit square if both columns and rows are not specified
|
|
18
|
+
* - Value in columns is prioritized over rows for recalculating the grid
|
|
19
|
+
* - Supports padding between the items
|
|
20
|
+
*
|
|
21
|
+
* @param {number} count
|
|
22
|
+
* @param {number} size
|
|
23
|
+
* @param {number} pad
|
|
24
|
+
* @param {number} columns
|
|
25
|
+
* @param {number} rows
|
|
26
|
+
* @returns {SwatchGrid}
|
|
27
|
+
*/
|
|
28
|
+
export function swatchGrid(count, size, pad = 0, columns = 0, rows = 0) {
|
|
29
|
+
if (columns > 0) {
|
|
30
|
+
rows = Math.ceil(count / columns)
|
|
31
|
+
} else if (rows > 0) {
|
|
32
|
+
columns = Math.ceil(count / rows)
|
|
33
|
+
} else {
|
|
34
|
+
columns = Math.ceil(Math.sqrt(count))
|
|
35
|
+
rows = Math.ceil(count / columns)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const width = (size + pad) * columns + pad
|
|
39
|
+
const height = (size + pad) * rows + pad
|
|
40
|
+
const radius = size / 2
|
|
41
|
+
const data = [...Array(count).keys()].map((index) => ({
|
|
42
|
+
x: pad + radius + (index % columns) * (size + pad),
|
|
43
|
+
y: pad + radius + Math.floor(index / columns) * (size + pad),
|
|
44
|
+
r: radius
|
|
45
|
+
}))
|
|
46
|
+
|
|
47
|
+
return { width, height, data }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function spreadValuesAsPatterns(values, patterns, palette) {
|
|
51
|
+
values
|
|
52
|
+
.map((value, index) => ({
|
|
53
|
+
pattern: patterns[index % patterns.length],
|
|
54
|
+
color: palette[index % palette.length],
|
|
55
|
+
value
|
|
56
|
+
}))
|
|
57
|
+
.reduce(
|
|
58
|
+
(acc, { value, pattern, color }) => ({
|
|
59
|
+
...acc,
|
|
60
|
+
[value]: {
|
|
61
|
+
id: pattern + '_' + color,
|
|
62
|
+
pattern,
|
|
63
|
+
color
|
|
64
|
+
}
|
|
65
|
+
}),
|
|
66
|
+
{}
|
|
67
|
+
)
|
|
68
|
+
}
|
package/src/lib/index.js
CHANGED