@uwdata/vgplot 0.4.0 → 0.5.0

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 (65) hide show
  1. package/README.md +4 -2
  2. package/dist/vgplot.js +5643 -5842
  3. package/dist/vgplot.min.js +14 -35
  4. package/package.json +8 -10
  5. package/src/api.js +292 -0
  6. package/src/connect.js +14 -0
  7. package/src/context.js +20 -0
  8. package/src/index.js +14 -303
  9. package/src/inputs.js +24 -0
  10. package/src/{directives → plot}/attributes.js +14 -5
  11. package/src/{directives → plot}/interactors.js +8 -6
  12. package/src/{directives → plot}/legends.js +14 -6
  13. package/src/{directives → plot}/marks.js +16 -13
  14. package/src/plot/named-plots.js +49 -0
  15. package/src/plot/plot.js +9 -0
  16. package/src/directives/plot.js +0 -39
  17. package/src/interactors/Highlight.js +0 -101
  18. package/src/interactors/Interval1D.js +0 -90
  19. package/src/interactors/Interval2D.js +0 -102
  20. package/src/interactors/Nearest.js +0 -66
  21. package/src/interactors/PanZoom.js +0 -121
  22. package/src/interactors/Toggle.js +0 -111
  23. package/src/interactors/util/brush.js +0 -45
  24. package/src/interactors/util/close-to.js +0 -9
  25. package/src/interactors/util/get-field.js +0 -4
  26. package/src/interactors/util/invert.js +0 -3
  27. package/src/interactors/util/patchScreenCTM.js +0 -13
  28. package/src/interactors/util/sanitize-styles.js +0 -9
  29. package/src/interactors/util/to-kebab-case.js +0 -9
  30. package/src/layout/index.js +0 -2
  31. package/src/legend.js +0 -64
  32. package/src/marks/ConnectedMark.js +0 -63
  33. package/src/marks/ContourMark.js +0 -89
  34. package/src/marks/DenseLineMark.js +0 -146
  35. package/src/marks/Density1DMark.js +0 -104
  36. package/src/marks/Density2DMark.js +0 -69
  37. package/src/marks/Grid2DMark.js +0 -191
  38. package/src/marks/HexbinMark.js +0 -88
  39. package/src/marks/Mark.js +0 -195
  40. package/src/marks/RasterMark.js +0 -122
  41. package/src/marks/RasterTileMark.js +0 -332
  42. package/src/marks/RegressionMark.js +0 -117
  43. package/src/marks/util/bin-field.js +0 -17
  44. package/src/marks/util/density.js +0 -226
  45. package/src/marks/util/extent.js +0 -56
  46. package/src/marks/util/grid.js +0 -57
  47. package/src/marks/util/handle-param.js +0 -14
  48. package/src/marks/util/is-arrow-table.js +0 -3
  49. package/src/marks/util/is-color.js +0 -18
  50. package/src/marks/util/is-constant-option.js +0 -40
  51. package/src/marks/util/is-symbol.js +0 -20
  52. package/src/marks/util/raster.js +0 -44
  53. package/src/marks/util/stats.js +0 -133
  54. package/src/marks/util/to-data-array.js +0 -58
  55. package/src/plot-attributes.js +0 -211
  56. package/src/plot-renderer.js +0 -161
  57. package/src/plot.js +0 -136
  58. package/src/spec/parse-data.js +0 -69
  59. package/src/spec/parse-spec.js +0 -422
  60. package/src/spec/to-module.js +0 -465
  61. package/src/spec/util.js +0 -43
  62. package/src/symbols.js +0 -3
  63. package/src/transforms/bin.js +0 -81
  64. package/src/transforms/index.js +0 -3
  65. /package/src/{directives → plot}/data.js +0 -0
@@ -1,117 +0,0 @@
1
- import { range } from 'd3';
2
- import {
3
- Query, max, min, castDouble, isNotNull,
4
- regrIntercept, regrSlope, regrCount,
5
- regrSYY, regrSXX, regrAvgX
6
- } from '@uwdata/mosaic-sql';
7
- import { qt } from './util/stats.js';
8
- import { Mark, channelOption } from './Mark.js';
9
- import { handleParam } from './util/handle-param.js';
10
- import { toDataArray } from './util/to-data-array.js';
11
-
12
- export class RegressionMark extends Mark {
13
- constructor(source, options) {
14
- const { ci = 0.95, precision = 4, ...channels } = options;
15
- super('line', source, channels);
16
- const update = () => {
17
- return this.modelFit ? this.confidenceBand().update() : null
18
- };
19
- handleParam(this, 'ci', ci, update);
20
- handleParam(this, 'precision', precision, update);
21
- }
22
-
23
- query(filter = []) {
24
- const x = this.channelField('x').as;
25
- const y = this.channelField('y').as;
26
- const groupby = Array.from(new Set(
27
- ['stroke', 'z', 'fx', 'fy'].flatMap(c => this.channelField(c)?.as || [])
28
- ));
29
-
30
- return Query
31
- .from(super.query(filter))
32
- .select({
33
- intercept: regrIntercept(y, x),
34
- slope: regrSlope(y, x),
35
- n: regrCount(y, x),
36
- ssy: regrSYY(y, x),
37
- ssx: regrSXX(y, x),
38
- xm: regrAvgX(y, x),
39
- x0: castDouble(min(x).where(isNotNull(y))),
40
- x1: castDouble(max(x).where(isNotNull(y)))
41
- })
42
- .select(groupby)
43
- .groupby(groupby);
44
- }
45
-
46
- queryResult(data) {
47
- this.modelFit = toDataArray(data);
48
-
49
- // regression line
50
- this.lineData = this.modelFit.flatMap(m => linePoints(m));
51
-
52
- // prepare confidence band
53
- return this.confidenceBand();
54
- }
55
-
56
- confidenceBand() {
57
- // regression ci area
58
- const { ci, modelFit, precision, plot } = this;
59
- const w = plot.innerWidth();
60
- this.areaData = ci ? modelFit.flatMap(m => areaPoints(ci, precision, m, w)) : null;
61
- return this;
62
- }
63
-
64
- plotSpecs() {
65
- const { lineData, areaData, channels, ci } = this;
66
- const lopt = { x: 'x', y: 'y' };
67
- const aopt = { x: 'x', y1: 'y1', y2: 'y2', fillOpacity: 0.1 };
68
-
69
- for (const c of channels) {
70
- switch (c.channel) {
71
- case 'x':
72
- case 'y':
73
- case 'fill':
74
- break;
75
- case 'stroke':
76
- lopt.stroke = aopt.fill = channelOption(c);
77
- break;
78
- case 'strokeOpacity':
79
- lopt.strokeOpacity = channelOption(c);
80
- break;
81
- case 'fillOpacity':
82
- aopt.fillOpacity = channelOption(c);
83
- break;
84
- default:
85
- lopt[c.channel] = aopt[c.channel] = channelOption(c);
86
- break;
87
- }
88
- }
89
-
90
- return [
91
- ...(ci ? [{ type: 'areaY', data: areaData, options: aopt }] : []),
92
- { type: 'line', data: lineData, options: lopt }
93
- ];
94
- }
95
- }
96
-
97
- function linePoints(model) {
98
- // eslint-disable-next-line no-unused-vars
99
- const { x0, x1, xm, intercept, slope, n, ssx, ssy, ...rest } = model;
100
- return [
101
- { x: x0, y: intercept + x0 * slope, ...rest },
102
- { x: x1, y: intercept + x1 * slope, ...rest }
103
- ];
104
- }
105
-
106
- function areaPoints(ci, precision, model, width) {
107
- const { x0, x1, xm, intercept, slope, n, ssx, ssy, ...rest } = model;
108
- const pp = precision * (x1 - x0) / width;
109
- const t_sy = qt((1 - ci) / 2, n - 2) * Math.sqrt(ssy / (n - 2));
110
- return range(x0, x1 - pp / 2, pp)
111
- .concat(x1)
112
- .map(x => {
113
- const y = intercept + x * slope;
114
- const ye = t_sy * Math.sqrt(1 / n + (x - xm) ** 2 / ssx);
115
- return { x, y1: y - ye, y2: y + ye, ...rest };
116
- });
117
- }
@@ -1,17 +0,0 @@
1
- import { epoch_ms, sql } from '@uwdata/mosaic-sql';
2
-
3
- export function binField(mark, channel, expr) {
4
- if (!mark.stats) return field;
5
- const { field } = mark.channelField(channel);
6
- const { type } = mark.stats[field.column];
7
- expr = expr ?? field;
8
- return type === 'date' ? epoch_ms(expr) : expr;
9
- }
10
-
11
- export function bin1d(x, x0, x1, n, reverse = false, pad = 1) {
12
- const d = (n - pad) / (x1 - x0);
13
- const f = d !== 1 ? ` * ${d}::DOUBLE` : '';
14
- return reverse
15
- ? sql`(${+x1} - ${x}::DOUBLE)${f}`
16
- : sql`(${x}::DOUBLE - ${+x0})${f}`;
17
- }
@@ -1,226 +0,0 @@
1
- // Deriche's approximation of Gaussian smoothing
2
- // Adapted from Getreuer's C implementation (BSD license)
3
- // https://www.ipol.im/pub/art/2013/87/gaussian_20131215.tgz
4
- // http://dev.ipol.im/~getreuer/code/doc/gaussian_20131215_doc/gaussian__conv__deriche_8c.html
5
-
6
- export function dericheConfig(sigma, negative = false) {
7
- // compute causal filter coefficients
8
- const a = new Float64Array(5);
9
- const bc = new Float64Array(4);
10
- dericheCausalCoeff(a, bc, sigma);
11
-
12
- // numerator coefficients of the anticausal filter
13
- const ba = Float64Array.of(
14
- 0,
15
- bc[1] - a[1] * bc[0],
16
- bc[2] - a[2] * bc[0],
17
- bc[3] - a[3] * bc[0],
18
- -a[4] * bc[0]
19
- );
20
-
21
- // impulse response sums
22
- const accum_denom = 1.0 + a[1] + a[2] + a[3] + a[4];
23
- const sum_causal = (bc[0] + bc[1] + bc[2] + bc[3]) / accum_denom;
24
- const sum_anticausal = (ba[1] + ba[2] + ba[3] + ba[4]) / accum_denom;
25
-
26
- // coefficients object
27
- return {
28
- sigma,
29
- negative,
30
- a,
31
- b_causal: bc,
32
- b_anticausal: ba,
33
- sum_causal,
34
- sum_anticausal
35
- };
36
- }
37
-
38
- function dericheCausalCoeff(a_out, b_out, sigma) {
39
- const K = 4;
40
-
41
- const alpha = Float64Array.of(
42
- 0.84, 1.8675,
43
- 0.84, -1.8675,
44
- -0.34015, -0.1299,
45
- -0.34015, 0.1299
46
- );
47
-
48
- const x1 = Math.exp(-1.783 / sigma);
49
- const x2 = Math.exp(-1.723 / sigma);
50
- const y1 = 0.6318 / sigma;
51
- const y2 = 1.997 / sigma;
52
- const beta = Float64Array.of(
53
- -x1 * Math.cos( y1), x1 * Math.sin( y1),
54
- -x1 * Math.cos(-y1), x1 * Math.sin(-y1),
55
- -x2 * Math.cos( y2), x2 * Math.sin( y2),
56
- -x2 * Math.cos(-y2), x2 * Math.sin(-y2)
57
- );
58
-
59
- const denom = sigma * 2.5066282746310007;
60
-
61
- // initialize b/a = alpha[0] / (1 + beta[0] z^-1)
62
- const b = Float64Array.of(alpha[0], alpha[1], 0, 0, 0, 0, 0, 0);
63
- const a = Float64Array.of(1, 0, beta[0], beta[1], 0, 0, 0, 0, 0, 0);
64
-
65
- let j, k;
66
-
67
- for (k = 2; k < 8; k += 2) {
68
- // add kth term, b/a += alpha[k] / (1 + beta[k] z^-1)
69
- b[k] = beta[k] * b[k - 2] - beta[k + 1] * b[k - 1];
70
- b[k + 1] = beta[k] * b[k - 1] + beta[k + 1] * b[k - 2];
71
- for (j = k - 2; j > 0; j -= 2) {
72
- b[j] += beta[k] * b[j - 2] - beta[k + 1] * b[j - 1];
73
- b[j + 1] += beta[k] * b[j - 1] + beta[k + 1] * b[j - 2];
74
- }
75
- for (j = 0; j <= k; j += 2) {
76
- b[j] += alpha[k] * a[j] - alpha[k + 1] * a[j + 1];
77
- b[j + 1] += alpha[k] * a[j + 1] + alpha[k + 1] * a[j];
78
- }
79
-
80
- a[k + 2] = beta[k] * a[k] - beta[k + 1] * a[k + 1];
81
- a[k + 3] = beta[k] * a[k + 1] + beta[k + 1] * a[k];
82
- for (j = k; j > 0; j -= 2) {
83
- a[j] += beta[k] * a[j - 2] - beta[k + 1] * a[j - 1];
84
- a[j + 1] += beta[k] * a[j - 1] + beta[k + 1] * a[j - 2];
85
- }
86
- }
87
-
88
- for (k = 0; k < K; ++k) {
89
- j = k << 1;
90
- b_out[k] = b[j] / denom;
91
- a_out[k + 1] = a[j + 2];
92
- }
93
- }
94
-
95
- export function dericheConv2d(cx, cy, grid, [nx, ny]) {
96
- // allocate buffers
97
- const yc = new Float64Array(Math.max(nx, ny)); // causal
98
- const ya = new Float64Array(Math.max(nx, ny)); // anticausal
99
- const h = new Float64Array(5);
100
- const d = new Float64Array(grid.length);
101
-
102
- // convolve rows
103
- for (let row = 0, r0 = 0; row < ny; ++row, r0 += nx) {
104
- const dx = d.subarray(r0);
105
- dericheConv1d(cx, grid.subarray(r0), nx, 1, yc, ya, h, dx);
106
- }
107
-
108
- // convolve columns
109
- for (let c0 = 0; c0 < nx; ++c0) {
110
- const dy = d.subarray(c0);
111
- dericheConv1d(cy, dy, ny, nx, yc, ya, h, dy);
112
- }
113
-
114
- return d;
115
- }
116
-
117
- export function dericheConv1d(
118
- c, src, N,
119
- stride = 1,
120
- y_causal = new Float64Array(N),
121
- y_anticausal = new Float64Array(N),
122
- h = new Float64Array(5),
123
- d = y_causal,
124
- init = dericheInitZeroPad
125
- ) {
126
- const stride_2 = stride * 2;
127
- const stride_3 = stride * 3;
128
- const stride_4 = stride * 4;
129
- const stride_N = stride * N;
130
- let i, n;
131
-
132
- // initialize causal filter on the left boundary
133
- init(
134
- y_causal, src, N, stride,
135
- c.b_causal, 3, c.a, 4, c.sum_causal, h, c.sigma
136
- );
137
-
138
- // filter the interior samples using a 4th order filter. Implements:
139
- // for n = K, ..., N - 1,
140
- // y^+(n) = \sum_{k=0}^{K-1} b^+_k src(n - k)
141
- // - \sum_{k=1}^K a_k y^+(n - k)
142
- // variable i tracks the offset to the nth sample of src, it is
143
- // updated together with n such that i = stride * n.
144
- for (n = 4, i = stride_4; n < N; ++n, i += stride) {
145
- y_causal[n] = c.b_causal[0] * src[i]
146
- + c.b_causal[1] * src[i - stride]
147
- + c.b_causal[2] * src[i - stride_2]
148
- + c.b_causal[3] * src[i - stride_3]
149
- - c.a[1] * y_causal[n - 1]
150
- - c.a[2] * y_causal[n - 2]
151
- - c.a[3] * y_causal[n - 3]
152
- - c.a[4] * y_causal[n - 4];
153
- }
154
-
155
- // initialize the anticausal filter on the right boundary
156
- init(
157
- y_anticausal, src, N, -stride,
158
- c.b_anticausal, 4, c.a, 4, c.sum_anticausal, h, c.sigma
159
- );
160
-
161
- // similar to the causal filter above, the following implements:
162
- // for n = K, ..., N - 1,
163
- // y^-(n) = \sum_{k=1}^K b^-_k src(N - n - 1 - k)
164
- // - \sum_{k=1}^K a_k y^-(n - k)
165
- // variable i is updated such that i = stride * (N - n - 1).
166
- for (n = 4, i = stride_N - stride * 5; n < N; ++n, i -= stride) {
167
- y_anticausal[n] = c.b_anticausal[1] * src[i + stride]
168
- + c.b_anticausal[2] * src[i + stride_2]
169
- + c.b_anticausal[3] * src[i + stride_3]
170
- + c.b_anticausal[4] * src[i + stride_4]
171
- - c.a[1] * y_anticausal[n - 1]
172
- - c.a[2] * y_anticausal[n - 2]
173
- - c.a[3] * y_anticausal[n - 3]
174
- - c.a[4] * y_anticausal[n - 4];
175
- }
176
-
177
- // sum the causal and anticausal responses to obtain the final result
178
- if (c.negative) {
179
- // do not threshold if the input grid includes negatively weighted values
180
- for (n = 0, i = 0; n < N; ++n, i += stride) {
181
- d[i] = y_causal[n] + y_anticausal[N - n - 1];
182
- }
183
- } else {
184
- // threshold to prevent small negative values due to floating point error
185
- for (n = 0, i = 0; n < N; ++n, i += stride) {
186
- d[i] = Math.max(0, y_causal[n] + y_anticausal[N - n - 1]);
187
- }
188
- }
189
-
190
- return d;
191
- }
192
-
193
- export function dericheInitZeroPad(dest, src, N, stride, b, p, a, q, sum, h) {
194
- const stride_N = Math.abs(stride) * N;
195
- const off = stride < 0 ? stride_N + stride : 0;
196
- let i, n, m;
197
-
198
- // compute the first q taps of the impulse response, h_0, ..., h_{q-1}
199
- for (n = 0; n < q; ++n) {
200
- h[n] = (n <= p) ? b[n] : 0;
201
- for (m = 1; m <= q && m <= n; ++m) {
202
- h[n] -= a[m] * h[n - m];
203
- }
204
- }
205
-
206
- // compute dest_m = sum_{n=1}^m h_{m-n} src_n, m = 0, ..., q-1
207
- // note: q == 4
208
- for (m = 0; m < q; ++m) {
209
- for (dest[m] = 0, n = 1; n <= m; ++n) {
210
- i = off + stride * n;
211
- if (i >= 0 && i < stride_N) {
212
- dest[m] += h[m - n] * src[i];
213
- }
214
- }
215
- }
216
-
217
- // dest_m = dest_m + h_{n+m} src_{-n}
218
- const cur = src[off];
219
- if (cur > 0) {
220
- for (m = 0; m < q; ++m) {
221
- dest[m] += h[m] * cur;
222
- }
223
- }
224
-
225
- return;
226
- }
@@ -1,56 +0,0 @@
1
- import { scaleLinear } from 'd3';
2
- import { Fixed, Transient } from '../../symbols.js';
3
-
4
- export const xext = { x: ['min', 'max'] };
5
- export const yext = { y: ['min', 'max'] };
6
- export const xyext = { ...xext, ...yext };
7
-
8
- export function plotExtent(mark, filter, channel, domainAttr, niceAttr) {
9
- const { plot, stats } = mark;
10
- const domain = plot.getAttribute(domainAttr);
11
- const nice = plot.getAttribute(niceAttr);
12
-
13
- if (Array.isArray(domain) && !domain[Transient]) {
14
- return domain;
15
- } else {
16
- const { field } = mark.channelField(channel);
17
- const { column } = field;
18
- const { min, max } = stats[column];
19
- const dom = filteredExtent(filter, column) || (nice
20
- ? scaleLinear().domain([min, max]).nice().domain()
21
- : [min, max]);
22
- if (domain !== Fixed) dom[Transient] = true;
23
- plot.setAttribute(domainAttr, dom, { silent: true });
24
- return dom;
25
- }
26
- }
27
-
28
- export function extentX(mark, filter) {
29
- return plotExtent(mark, filter, 'x', 'xDomain', 'xNice');
30
- }
31
-
32
- export function extentY(mark, filter) {
33
- return plotExtent(mark, filter, 'y', 'yDomain', 'yNice');
34
- }
35
-
36
- export function filteredExtent(filter, column) {
37
- if (!filter) return;
38
-
39
- let lo;
40
- let hi;
41
- const visitor = (type, clause) => {
42
- if (type === 'BETWEEN' && clause.field.column === column) {
43
- const { range } = clause;
44
- if (range && (lo == null || range[0] < lo)) lo = range[0];
45
- if (range && (hi == null || range[1] > hi)) hi = range[1];
46
- }
47
- };
48
-
49
- if (Array.isArray(filter)) {
50
- filter.forEach(p => p.visit?.(visitor));
51
- } else if (filter.visit) {
52
- filter.visit(visitor);
53
- }
54
-
55
- return lo != null && hi != null && lo !== hi ? [lo, hi] : undefined;
56
- }
@@ -1,57 +0,0 @@
1
- import { isArrowTable } from './is-arrow-table.js';
2
-
3
- export function grid1d(n, values) {
4
- return valuesToGrid(new Float64Array(n), values);
5
- }
6
-
7
- export function grid2d(m, n, values, groupby = []) {
8
- return groupby.length
9
- ? Object.values(groupedValuesToGrids(m * n, values, groupby))
10
- : [{ grid: valuesToGrid(new Float64Array(m * n), values) }];
11
- }
12
-
13
- function valuesToGrid(grid, values) {
14
- if (isArrowTable(values)) {
15
- // optimize access for Arrow tables
16
- const numRows = values.numRows;
17
- if (numRows === 0) return grid;
18
- const index = values.getChild('index').toArray();
19
- const value = values.getChild('value').toArray();
20
- for (let row = 0; row < numRows; ++row) {
21
- grid[index[row]] = value[row];
22
- }
23
- } else {
24
- // fallback to iterable data
25
- for (const row of values) {
26
- grid[row.index] = row.value;
27
- }
28
- }
29
- return grid;
30
- }
31
-
32
- function groupedValuesToGrids(size, values, groupby) {
33
- const grids = {};
34
- const getGrid = key => {
35
- const cell = grids[key] || (grids[key] = { key, grid: new Float64Array(size) });
36
- return cell.grid;
37
- };
38
- if (isArrowTable(values)) {
39
- // optimize access for Arrow tables
40
- const numRows = values.numRows;
41
- if (numRows === 0) return grids;
42
- const index = values.getChild('index').toArray();
43
- const value = values.getChild('value').toArray();
44
- const groups = groupby.map(name => values.getChild(name));
45
- for (let row = 0; row < numRows; ++row) {
46
- const key = groups.map(vec => vec.get(row));
47
- getGrid(key)[index[row]] = value[row];
48
- }
49
- } else {
50
- // fallback to iterable data
51
- for (const row of values) {
52
- const key = groupby.map(col => row[col]);
53
- getGrid(key)[row.index] = row.value;
54
- }
55
- }
56
- return grids;
57
- }
@@ -1,14 +0,0 @@
1
- import { isParam } from '@uwdata/mosaic-core';
2
-
3
- export function handleParam(client, key, param, update) {
4
- if (isParam(param)) {
5
- update = update || (() => client.requestUpdate());
6
- param.addEventListener('value', value => {
7
- client[key] = value;
8
- return update();
9
- });
10
- client[key] = param.value;
11
- } else {
12
- client[key] = param;
13
- }
14
- }
@@ -1,3 +0,0 @@
1
- export function isArrowTable(values) {
2
- return typeof values?.getChild === 'function';
3
- }
@@ -1,18 +0,0 @@
1
- import { color } from 'd3';
2
-
3
- // Mostly relies on d3-color, with a few extra color keywords. Currently this
4
- // strictly requires that the value be a string; we might want to apply string
5
- // coercion here, though note that d3-color instances would need to support
6
- // valueOf to work correctly with InternMap.
7
- // https://www.w3.org/TR/SVG11/painting.html#SpecifyingPaint
8
- export function isColor(value) {
9
- if (typeof value !== "string") return false;
10
- value = value.toLowerCase().trim();
11
- return (
12
- value === "none" ||
13
- value === "currentcolor" ||
14
- (value.startsWith("url(") && value.endsWith(")")) || // <funciri>, e.g. pattern or gradient
15
- (value.startsWith("var(") && value.endsWith(")")) || // CSS variable
16
- color(value) !== null
17
- );
18
- }
@@ -1,40 +0,0 @@
1
- const constantOptions = new Set([
2
- 'order',
3
- 'sort',
4
- 'label',
5
- 'anchor',
6
- 'curve',
7
- 'tension',
8
- 'marker',
9
- 'markerStart',
10
- 'markerMid',
11
- 'markerEnd',
12
- 'textAnchor',
13
- 'lineAnchor',
14
- 'lineHeight',
15
- 'textOverflow',
16
- 'monospace',
17
- 'fontFamily',
18
- 'fontSize',
19
- 'fontStyle',
20
- 'fontVariant',
21
- 'fontWeight',
22
- 'frameAnchor',
23
- 'strokeLinejoin',
24
- 'strokeLinecap',
25
- 'strokeMiterlimit',
26
- 'strokeDasharray',
27
- 'strokeDashoffset',
28
- 'mixBlendMode',
29
- 'shapeRendering',
30
- 'imageRendering',
31
- 'preserveAspectRatio',
32
- 'interpolate',
33
- 'crossOrigin',
34
- 'paintOrder',
35
- 'pointerEvents'
36
- ]);
37
-
38
- export function isConstantOption(value) {
39
- return constantOptions.has(value);
40
- }
@@ -1,20 +0,0 @@
1
- const symbols = new Set([
2
- 'asterisk',
3
- 'circle',
4
- 'cross',
5
- 'diamond',
6
- 'diamond2',
7
- 'hexagon',
8
- 'plus',
9
- 'square',
10
- 'square2',
11
- 'star',
12
- 'times',
13
- 'triangle',
14
- 'triangle2',
15
- 'wye'
16
- ]);
17
-
18
- export function isSymbol(value) {
19
- return symbols.has(`${value}`.toLowerCase());
20
- }
@@ -1,44 +0,0 @@
1
- import { rgb } from 'd3';
2
-
3
- export function raster(grid, data, w, h, scale, scheme) {
4
- const n = (scheme.length >> 2) - 1;
5
- for (let j = 0, k = 0; j < h; ++j) {
6
- for (let i = 0, row = (h - j - 1) * w; i < w; ++i, k += 4) {
7
- const c = (n * scale(grid[i + row])) << 2;
8
- data[k + 0] = scheme[c + 0];
9
- data[k + 1] = scheme[c + 1];
10
- data[k + 2] = scheme[c + 2];
11
- data[k + 3] = scheme[c + 3];
12
- }
13
- }
14
- }
15
-
16
- export function palette(size, interp) {
17
- const p = new Uint8ClampedArray(4 * size);
18
- const n = size - 1;
19
- for (let i = 0; i <= n; ++i) {
20
- const v = interp(i / n);
21
- const { r, g, b, opacity = 1 } = typeof v === 'string' ? rgb(v) : v;
22
- const k = i << 2;
23
- p[k + 0] = r;
24
- p[k + 1] = g;
25
- p[k + 2] = b;
26
- p[k + 3] = (255 * opacity) | 0;
27
- }
28
- return p;
29
- }
30
-
31
- export function createCanvas(w, h) {
32
- if (typeof document !== 'undefined') {
33
- const c = document.createElement('canvas');
34
- c.setAttribute('width', w);
35
- c.setAttribute('height', h);
36
- return c;
37
- }
38
- throw new Error('Can not create a canvas instance.');
39
- }
40
-
41
- export function opacityMap(color = 'black') {
42
- const { r, g, b } = rgb(color);
43
- return opacity => ({ r, g, b, opacity });
44
- }