vega-functions 5.18.0 → 6.1.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.
- package/build/vega-functions.js +762 -1800
- package/build/vega-functions.js.map +1 -0
- package/index.js +20 -20
- package/package.json +29 -22
- package/rollup.config.js +1 -0
- package/src/codegen.js +22 -22
- package/src/functions/geo.js +1 -1
- package/src/functions/lasso.js +1 -1
- package/src/functions/scale-gradient.js +1 -1
- package/src/functions/scale.js +1 -1
- package/src/functions/shape.js +1 -1
- package/src/functions/tree.js +1 -1
- package/src/parser.js +2 -2
- package/src/scales.js +2 -2
- package/src/visitors.js +1 -1
- package/build/vega-functions.min.js +0 -2
- package/build/vega-functions.min.js.map +0 -1
- package/build/vega-functions.module.js +0 -790
- package/rollup.config.mjs +0 -1
package/build/vega-functions.js
CHANGED
|
@@ -1,1815 +1,777 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { truthy, hasOwnProperty, error, stringValue, isString, isFunction, extend, isArray, isObject, field, ascending, isRegExp, peek, identity, array as array$1, zoomSymlog, zoomPow, zoomLog, zoomLinear, panSymlog, panPow, panLog, panLinear, clampRange, utcquarter, quarter, truncate, inrange, span, pad, lerp, flush, toString, toNumber, toBoolean, isNumber, isDate, isBoolean, extent, toDate } from 'vega-util';
|
|
2
|
+
import { Literal, codegenExpression, constants, functions, parseExpression, CallExpression } from 'vega-expression';
|
|
3
|
+
import { isRegisteredScale, bandSpace, scale as scale$1, scaleFraction } from 'vega-scale';
|
|
4
|
+
import { geoBounds as geoBounds$1, geoCentroid as geoCentroid$1, geoArea as geoArea$1 } from 'd3-geo';
|
|
5
|
+
import { rgb, hsl, hcl, lab } from 'd3-color';
|
|
6
|
+
import { isTuple } from 'vega-dataflow';
|
|
7
|
+
import { Gradient, pathRender, pathParse, Bounds, intersect as intersect$1 } from 'vega-scenegraph';
|
|
8
|
+
import { selectionVisitor, selectionTest, selectionIdTest, selectionResolve, selectionTuples } from 'vega-selections';
|
|
9
|
+
import { sampleUniform, sampleLogNormal, sampleNormal, quantileUniform, quantileLogNormal, quantileNormal, densityUniform, densityLogNormal, densityNormal, cumulativeUniform, cumulativeLogNormal, cumulativeNormal, random } from 'vega-statistics';
|
|
10
|
+
import { utcdayofyear, dayofyear, utcweek, week, timeUnitSpecifier, timeSequence, timeOffset, utcSequence, utcOffset } from 'vega-time';
|
|
11
|
+
import { range as range$1 } from 'd3-array';
|
|
12
|
+
|
|
13
|
+
function data(name) {
|
|
14
|
+
const data = this.context.data[name];
|
|
15
|
+
return data ? data.values.value : [];
|
|
16
|
+
}
|
|
17
|
+
function indata(name, field, value) {
|
|
18
|
+
const index = this.context.data[name]['index:' + field],
|
|
19
|
+
entry = index ? index.value.get(value) : undefined;
|
|
20
|
+
return entry ? entry.count : entry;
|
|
21
|
+
}
|
|
22
|
+
function setdata(name, tuples) {
|
|
23
|
+
const df = this.context.dataflow,
|
|
24
|
+
data = this.context.data[name],
|
|
25
|
+
input = data.input;
|
|
26
|
+
df.pulse(input, df.changeset().remove(truthy).insert(tuples));
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function encode (item, name, retval) {
|
|
31
|
+
if (item) {
|
|
17
32
|
const df = this.context.dataflow,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const SignalPrefix = '$';
|
|
67
|
-
|
|
68
|
-
function dataVisitor(name, args, scope, params) {
|
|
69
|
-
if (args[0].type !== vegaExpression.Literal) {
|
|
70
|
-
vegaUtil.error('First argument to data functions must be a string literal.');
|
|
71
|
-
}
|
|
72
|
-
const data = args[0].value,
|
|
73
|
-
dataName = DataPrefix + data;
|
|
74
|
-
if (!vegaUtil.hasOwnProperty(dataName, params)) {
|
|
75
|
-
try {
|
|
76
|
-
params[dataName] = scope.getData(data).tuplesRef();
|
|
77
|
-
} catch (err) {
|
|
78
|
-
// if data set does not exist, there's nothing to track
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function indataVisitor(name, args, scope, params) {
|
|
83
|
-
if (args[0].type !== vegaExpression.Literal) vegaUtil.error('First argument to indata must be a string literal.');
|
|
84
|
-
if (args[1].type !== vegaExpression.Literal) vegaUtil.error('Second argument to indata must be a string literal.');
|
|
85
|
-
const data = args[0].value,
|
|
86
|
-
field = args[1].value,
|
|
87
|
-
indexName = IndexPrefix + field;
|
|
88
|
-
if (!vegaUtil.hasOwnProperty(indexName, params)) {
|
|
89
|
-
params[indexName] = scope.getData(data).indataRef(scope, field);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function scaleVisitor(name, args, scope, params) {
|
|
93
|
-
if (args[0].type === vegaExpression.Literal) {
|
|
94
|
-
// add scale dependency
|
|
95
|
-
addScaleDependency(scope, params, args[0].value);
|
|
96
|
-
} else {
|
|
97
|
-
// indirect scale lookup; add all scales as parameters
|
|
98
|
-
for (name in scope.scales) {
|
|
99
|
-
addScaleDependency(scope, params, name);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
function addScaleDependency(scope, params, name) {
|
|
104
|
-
const scaleName = ScalePrefix + name;
|
|
105
|
-
if (!vegaUtil.hasOwnProperty(params, scaleName)) {
|
|
106
|
-
try {
|
|
107
|
-
params[scaleName] = scope.scaleRef(name);
|
|
108
|
-
} catch (err) {
|
|
109
|
-
// TODO: error handling? warning?
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* nameOrFunction must be a string or function that was registered.
|
|
116
|
-
* Return undefined if scale is not recognized.
|
|
117
|
-
*/
|
|
118
|
-
function getScale(nameOrFunction, ctx) {
|
|
119
|
-
if (vegaUtil.isString(nameOrFunction)) {
|
|
120
|
-
const maybeScale = ctx.scales[nameOrFunction];
|
|
121
|
-
return maybeScale && vegaScale.isRegisteredScale(maybeScale.value) ? maybeScale.value : undefined;
|
|
122
|
-
} else if (vegaUtil.isFunction(nameOrFunction)) {
|
|
123
|
-
return vegaScale.isRegisteredScale(nameOrFunction) ? nameOrFunction : undefined;
|
|
124
|
-
}
|
|
125
|
-
return undefined;
|
|
126
|
-
}
|
|
127
|
-
function internalScaleFunctions(codegen, fnctx, visitors) {
|
|
128
|
-
// add helper method to the 'this' expression function context
|
|
129
|
-
fnctx.__bandwidth = s => s && s.bandwidth ? s.bandwidth() : 0;
|
|
130
|
-
|
|
131
|
-
// register AST visitors for internal scale functions
|
|
132
|
-
visitors._bandwidth = scaleVisitor;
|
|
133
|
-
visitors._range = scaleVisitor;
|
|
134
|
-
visitors._scale = scaleVisitor;
|
|
135
|
-
|
|
136
|
-
// resolve scale reference directly to the signal hash argument
|
|
137
|
-
const ref = arg => '_[' + (arg.type === vegaExpression.Literal ? vegaUtil.stringValue(ScalePrefix + arg.value) : vegaUtil.stringValue(ScalePrefix) + '+' + codegen(arg)) + ']';
|
|
138
|
-
|
|
139
|
-
// define and return internal scale function code generators
|
|
140
|
-
// these internal functions are called by mark encoders
|
|
141
|
-
return {
|
|
142
|
-
_bandwidth: args => `this.__bandwidth(${ref(args[0])})`,
|
|
143
|
-
_range: args => `${ref(args[0])}.range()`,
|
|
144
|
-
_scale: args => `${ref(args[0])}(${codegen(args[1])})`
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
|
|
149
|
-
class Adder {
|
|
150
|
-
constructor() {
|
|
151
|
-
this._partials = new Float64Array(32);
|
|
152
|
-
this._n = 0;
|
|
153
|
-
}
|
|
154
|
-
add(x) {
|
|
155
|
-
const p = this._partials;
|
|
156
|
-
let i = 0;
|
|
157
|
-
for (let j = 0; j < this._n && j < 32; j++) {
|
|
158
|
-
const y = p[j],
|
|
159
|
-
hi = x + y,
|
|
160
|
-
lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
|
|
161
|
-
if (lo) p[i++] = lo;
|
|
162
|
-
x = hi;
|
|
163
|
-
}
|
|
164
|
-
p[i] = x;
|
|
165
|
-
this._n = i + 1;
|
|
166
|
-
return this;
|
|
167
|
-
}
|
|
168
|
-
valueOf() {
|
|
169
|
-
const p = this._partials;
|
|
170
|
-
let n = this._n,
|
|
171
|
-
x,
|
|
172
|
-
y,
|
|
173
|
-
lo,
|
|
174
|
-
hi = 0;
|
|
175
|
-
if (n > 0) {
|
|
176
|
-
hi = p[--n];
|
|
177
|
-
while (n > 0) {
|
|
178
|
-
x = hi;
|
|
179
|
-
y = p[--n];
|
|
180
|
-
hi = x + y;
|
|
181
|
-
lo = y - (hi - x);
|
|
182
|
-
if (lo) break;
|
|
183
|
-
}
|
|
184
|
-
if (n > 0 && (lo < 0 && p[n - 1] < 0 || lo > 0 && p[n - 1] > 0)) {
|
|
185
|
-
y = lo * 2;
|
|
186
|
-
x = hi + y;
|
|
187
|
-
if (y == x - hi) hi = x;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return hi;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function range$2(start, stop, step) {
|
|
195
|
-
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
|
|
196
|
-
var i = -1,
|
|
197
|
-
n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
|
|
198
|
-
range = new Array(n);
|
|
199
|
-
while (++i < n) {
|
|
200
|
-
range[i] = start + i * step;
|
|
201
|
-
}
|
|
202
|
-
return range;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
var epsilon = 1e-6;
|
|
206
|
-
var epsilon2 = 1e-12;
|
|
207
|
-
var pi = Math.PI;
|
|
208
|
-
var halfPi = pi / 2;
|
|
209
|
-
var quarterPi = pi / 4;
|
|
210
|
-
var tau = pi * 2;
|
|
211
|
-
var degrees$1 = 180 / pi;
|
|
212
|
-
var radians$1 = pi / 180;
|
|
213
|
-
var abs = Math.abs;
|
|
214
|
-
var atan2 = Math.atan2;
|
|
215
|
-
var cos = Math.cos;
|
|
216
|
-
var hypot = Math.hypot;
|
|
217
|
-
var sin = Math.sin;
|
|
218
|
-
var sqrt = Math.sqrt;
|
|
219
|
-
function asin(x) {
|
|
220
|
-
return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function noop() {}
|
|
224
|
-
|
|
225
|
-
function streamGeometry(geometry, stream) {
|
|
226
|
-
if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
|
|
227
|
-
streamGeometryType[geometry.type](geometry, stream);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
var streamObjectType = {
|
|
231
|
-
Feature: function (object, stream) {
|
|
232
|
-
streamGeometry(object.geometry, stream);
|
|
233
|
-
},
|
|
234
|
-
FeatureCollection: function (object, stream) {
|
|
235
|
-
var features = object.features,
|
|
236
|
-
i = -1,
|
|
237
|
-
n = features.length;
|
|
238
|
-
while (++i < n) streamGeometry(features[i].geometry, stream);
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
var streamGeometryType = {
|
|
242
|
-
Sphere: function (object, stream) {
|
|
243
|
-
stream.sphere();
|
|
244
|
-
},
|
|
245
|
-
Point: function (object, stream) {
|
|
246
|
-
object = object.coordinates;
|
|
247
|
-
stream.point(object[0], object[1], object[2]);
|
|
248
|
-
},
|
|
249
|
-
MultiPoint: function (object, stream) {
|
|
250
|
-
var coordinates = object.coordinates,
|
|
251
|
-
i = -1,
|
|
252
|
-
n = coordinates.length;
|
|
253
|
-
while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
|
|
254
|
-
},
|
|
255
|
-
LineString: function (object, stream) {
|
|
256
|
-
streamLine(object.coordinates, stream, 0);
|
|
257
|
-
},
|
|
258
|
-
MultiLineString: function (object, stream) {
|
|
259
|
-
var coordinates = object.coordinates,
|
|
260
|
-
i = -1,
|
|
261
|
-
n = coordinates.length;
|
|
262
|
-
while (++i < n) streamLine(coordinates[i], stream, 0);
|
|
263
|
-
},
|
|
264
|
-
Polygon: function (object, stream) {
|
|
265
|
-
streamPolygon(object.coordinates, stream);
|
|
266
|
-
},
|
|
267
|
-
MultiPolygon: function (object, stream) {
|
|
268
|
-
var coordinates = object.coordinates,
|
|
269
|
-
i = -1,
|
|
270
|
-
n = coordinates.length;
|
|
271
|
-
while (++i < n) streamPolygon(coordinates[i], stream);
|
|
272
|
-
},
|
|
273
|
-
GeometryCollection: function (object, stream) {
|
|
274
|
-
var geometries = object.geometries,
|
|
275
|
-
i = -1,
|
|
276
|
-
n = geometries.length;
|
|
277
|
-
while (++i < n) streamGeometry(geometries[i], stream);
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
function streamLine(coordinates, stream, closed) {
|
|
281
|
-
var i = -1,
|
|
282
|
-
n = coordinates.length - closed,
|
|
283
|
-
coordinate;
|
|
284
|
-
stream.lineStart();
|
|
285
|
-
while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
|
|
286
|
-
stream.lineEnd();
|
|
287
|
-
}
|
|
288
|
-
function streamPolygon(coordinates, stream) {
|
|
289
|
-
var i = -1,
|
|
290
|
-
n = coordinates.length;
|
|
291
|
-
stream.polygonStart();
|
|
292
|
-
while (++i < n) streamLine(coordinates[i], stream, 1);
|
|
293
|
-
stream.polygonEnd();
|
|
294
|
-
}
|
|
295
|
-
function geoStream (object, stream) {
|
|
296
|
-
if (object && streamObjectType.hasOwnProperty(object.type)) {
|
|
297
|
-
streamObjectType[object.type](object, stream);
|
|
298
|
-
} else {
|
|
299
|
-
streamGeometry(object, stream);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
var areaRingSum = new Adder();
|
|
304
|
-
|
|
305
|
-
// hello?
|
|
306
|
-
|
|
307
|
-
var areaSum = new Adder(),
|
|
308
|
-
lambda00$2,
|
|
309
|
-
phi00$2,
|
|
310
|
-
lambda0$1,
|
|
311
|
-
cosPhi0,
|
|
312
|
-
sinPhi0;
|
|
313
|
-
var areaStream = {
|
|
314
|
-
point: noop,
|
|
315
|
-
lineStart: noop,
|
|
316
|
-
lineEnd: noop,
|
|
317
|
-
polygonStart: function () {
|
|
318
|
-
areaRingSum = new Adder();
|
|
319
|
-
areaStream.lineStart = areaRingStart;
|
|
320
|
-
areaStream.lineEnd = areaRingEnd;
|
|
321
|
-
},
|
|
322
|
-
polygonEnd: function () {
|
|
323
|
-
var areaRing = +areaRingSum;
|
|
324
|
-
areaSum.add(areaRing < 0 ? tau + areaRing : areaRing);
|
|
325
|
-
this.lineStart = this.lineEnd = this.point = noop;
|
|
326
|
-
},
|
|
327
|
-
sphere: function () {
|
|
328
|
-
areaSum.add(tau);
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
function areaRingStart() {
|
|
332
|
-
areaStream.point = areaPointFirst;
|
|
333
|
-
}
|
|
334
|
-
function areaRingEnd() {
|
|
335
|
-
areaPoint(lambda00$2, phi00$2);
|
|
336
|
-
}
|
|
337
|
-
function areaPointFirst(lambda, phi) {
|
|
338
|
-
areaStream.point = areaPoint;
|
|
339
|
-
lambda00$2 = lambda, phi00$2 = phi;
|
|
340
|
-
lambda *= radians$1, phi *= radians$1;
|
|
341
|
-
lambda0$1 = lambda, cosPhi0 = cos(phi = phi / 2 + quarterPi), sinPhi0 = sin(phi);
|
|
342
|
-
}
|
|
343
|
-
function areaPoint(lambda, phi) {
|
|
344
|
-
lambda *= radians$1, phi *= radians$1;
|
|
345
|
-
phi = phi / 2 + quarterPi; // half the angular distance from south pole
|
|
346
|
-
|
|
347
|
-
// Spherical excess E for a spherical triangle with vertices: south pole,
|
|
348
|
-
// previous point, current point. Uses a formula derived from Cagnoli’s
|
|
349
|
-
// theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
|
|
350
|
-
var dLambda = lambda - lambda0$1,
|
|
351
|
-
sdLambda = dLambda >= 0 ? 1 : -1,
|
|
352
|
-
adLambda = sdLambda * dLambda,
|
|
353
|
-
cosPhi = cos(phi),
|
|
354
|
-
sinPhi = sin(phi),
|
|
355
|
-
k = sinPhi0 * sinPhi,
|
|
356
|
-
u = cosPhi0 * cosPhi + k * cos(adLambda),
|
|
357
|
-
v = k * sdLambda * sin(adLambda);
|
|
358
|
-
areaRingSum.add(atan2(v, u));
|
|
359
|
-
|
|
360
|
-
// Advance the previous points.
|
|
361
|
-
lambda0$1 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
|
|
362
|
-
}
|
|
363
|
-
function area (object) {
|
|
364
|
-
areaSum = new Adder();
|
|
365
|
-
geoStream(object, areaStream);
|
|
366
|
-
return areaSum * 2;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function spherical(cartesian) {
|
|
370
|
-
return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
|
|
371
|
-
}
|
|
372
|
-
function cartesian(spherical) {
|
|
373
|
-
var lambda = spherical[0],
|
|
374
|
-
phi = spherical[1],
|
|
375
|
-
cosPhi = cos(phi);
|
|
376
|
-
return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
|
|
377
|
-
}
|
|
378
|
-
function cartesianCross(a, b) {
|
|
379
|
-
return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// TODO return d
|
|
383
|
-
function cartesianNormalizeInPlace(d) {
|
|
384
|
-
var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
|
|
385
|
-
d[0] /= l, d[1] /= l, d[2] /= l;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
var lambda0, phi0, lambda1, phi1,
|
|
389
|
-
// bounds
|
|
390
|
-
lambda2,
|
|
391
|
-
// previous lambda-coordinate
|
|
392
|
-
lambda00$1, phi00$1,
|
|
393
|
-
// first point
|
|
394
|
-
p0,
|
|
395
|
-
// previous 3D point
|
|
396
|
-
deltaSum, ranges, range$1;
|
|
397
|
-
var boundsStream = {
|
|
398
|
-
point: boundsPoint,
|
|
399
|
-
lineStart: boundsLineStart,
|
|
400
|
-
lineEnd: boundsLineEnd,
|
|
401
|
-
polygonStart: function () {
|
|
402
|
-
boundsStream.point = boundsRingPoint;
|
|
403
|
-
boundsStream.lineStart = boundsRingStart;
|
|
404
|
-
boundsStream.lineEnd = boundsRingEnd;
|
|
405
|
-
deltaSum = new Adder();
|
|
406
|
-
areaStream.polygonStart();
|
|
407
|
-
},
|
|
408
|
-
polygonEnd: function () {
|
|
409
|
-
areaStream.polygonEnd();
|
|
410
|
-
boundsStream.point = boundsPoint;
|
|
411
|
-
boundsStream.lineStart = boundsLineStart;
|
|
412
|
-
boundsStream.lineEnd = boundsLineEnd;
|
|
413
|
-
if (areaRingSum < 0) lambda0 = -(lambda1 = 180), phi0 = -(phi1 = 90);else if (deltaSum > epsilon) phi1 = 90;else if (deltaSum < -1e-6) phi0 = -90;
|
|
414
|
-
range$1[0] = lambda0, range$1[1] = lambda1;
|
|
415
|
-
},
|
|
416
|
-
sphere: function () {
|
|
417
|
-
lambda0 = -(lambda1 = 180), phi0 = -(phi1 = 90);
|
|
418
|
-
}
|
|
419
|
-
};
|
|
420
|
-
function boundsPoint(lambda, phi) {
|
|
421
|
-
ranges.push(range$1 = [lambda0 = lambda, lambda1 = lambda]);
|
|
422
|
-
if (phi < phi0) phi0 = phi;
|
|
423
|
-
if (phi > phi1) phi1 = phi;
|
|
424
|
-
}
|
|
425
|
-
function linePoint(lambda, phi) {
|
|
426
|
-
var p = cartesian([lambda * radians$1, phi * radians$1]);
|
|
427
|
-
if (p0) {
|
|
428
|
-
var normal = cartesianCross(p0, p),
|
|
429
|
-
equatorial = [normal[1], -normal[0], 0],
|
|
430
|
-
inflection = cartesianCross(equatorial, normal);
|
|
431
|
-
cartesianNormalizeInPlace(inflection);
|
|
432
|
-
inflection = spherical(inflection);
|
|
433
|
-
var delta = lambda - lambda2,
|
|
434
|
-
sign = delta > 0 ? 1 : -1,
|
|
435
|
-
lambdai = inflection[0] * degrees$1 * sign,
|
|
436
|
-
phii,
|
|
437
|
-
antimeridian = abs(delta) > 180;
|
|
438
|
-
if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
|
|
439
|
-
phii = inflection[1] * degrees$1;
|
|
440
|
-
if (phii > phi1) phi1 = phii;
|
|
441
|
-
} else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
|
|
442
|
-
phii = -inflection[1] * degrees$1;
|
|
443
|
-
if (phii < phi0) phi0 = phii;
|
|
444
|
-
} else {
|
|
445
|
-
if (phi < phi0) phi0 = phi;
|
|
446
|
-
if (phi > phi1) phi1 = phi;
|
|
447
|
-
}
|
|
448
|
-
if (antimeridian) {
|
|
449
|
-
if (lambda < lambda2) {
|
|
450
|
-
if (angle(lambda0, lambda) > angle(lambda0, lambda1)) lambda1 = lambda;
|
|
451
|
-
} else {
|
|
452
|
-
if (angle(lambda, lambda1) > angle(lambda0, lambda1)) lambda0 = lambda;
|
|
453
|
-
}
|
|
454
|
-
} else {
|
|
455
|
-
if (lambda1 >= lambda0) {
|
|
456
|
-
if (lambda < lambda0) lambda0 = lambda;
|
|
457
|
-
if (lambda > lambda1) lambda1 = lambda;
|
|
458
|
-
} else {
|
|
459
|
-
if (lambda > lambda2) {
|
|
460
|
-
if (angle(lambda0, lambda) > angle(lambda0, lambda1)) lambda1 = lambda;
|
|
461
|
-
} else {
|
|
462
|
-
if (angle(lambda, lambda1) > angle(lambda0, lambda1)) lambda0 = lambda;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
} else {
|
|
467
|
-
ranges.push(range$1 = [lambda0 = lambda, lambda1 = lambda]);
|
|
468
|
-
}
|
|
469
|
-
if (phi < phi0) phi0 = phi;
|
|
470
|
-
if (phi > phi1) phi1 = phi;
|
|
471
|
-
p0 = p, lambda2 = lambda;
|
|
472
|
-
}
|
|
473
|
-
function boundsLineStart() {
|
|
474
|
-
boundsStream.point = linePoint;
|
|
475
|
-
}
|
|
476
|
-
function boundsLineEnd() {
|
|
477
|
-
range$1[0] = lambda0, range$1[1] = lambda1;
|
|
478
|
-
boundsStream.point = boundsPoint;
|
|
479
|
-
p0 = null;
|
|
480
|
-
}
|
|
481
|
-
function boundsRingPoint(lambda, phi) {
|
|
482
|
-
if (p0) {
|
|
483
|
-
var delta = lambda - lambda2;
|
|
484
|
-
deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
|
|
485
|
-
} else {
|
|
486
|
-
lambda00$1 = lambda, phi00$1 = phi;
|
|
487
|
-
}
|
|
488
|
-
areaStream.point(lambda, phi);
|
|
489
|
-
linePoint(lambda, phi);
|
|
490
|
-
}
|
|
491
|
-
function boundsRingStart() {
|
|
492
|
-
areaStream.lineStart();
|
|
493
|
-
}
|
|
494
|
-
function boundsRingEnd() {
|
|
495
|
-
boundsRingPoint(lambda00$1, phi00$1);
|
|
496
|
-
areaStream.lineEnd();
|
|
497
|
-
if (abs(deltaSum) > epsilon) lambda0 = -(lambda1 = 180);
|
|
498
|
-
range$1[0] = lambda0, range$1[1] = lambda1;
|
|
499
|
-
p0 = null;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Finds the left-right distance between two longitudes.
|
|
503
|
-
// This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
|
|
504
|
-
// the distance between ±180° to be 360°.
|
|
505
|
-
function angle(lambda0, lambda1) {
|
|
506
|
-
return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
|
|
507
|
-
}
|
|
508
|
-
function rangeCompare(a, b) {
|
|
509
|
-
return a[0] - b[0];
|
|
510
|
-
}
|
|
511
|
-
function rangeContains(range, x) {
|
|
512
|
-
return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
|
|
513
|
-
}
|
|
514
|
-
function bounds (feature) {
|
|
515
|
-
var i, n, a, b, merged, deltaMax, delta;
|
|
516
|
-
phi1 = lambda1 = -(lambda0 = phi0 = Infinity);
|
|
517
|
-
ranges = [];
|
|
518
|
-
geoStream(feature, boundsStream);
|
|
519
|
-
|
|
520
|
-
// First, sort ranges by their minimum longitudes.
|
|
521
|
-
if (n = ranges.length) {
|
|
522
|
-
ranges.sort(rangeCompare);
|
|
523
|
-
|
|
524
|
-
// Then, merge any ranges that overlap.
|
|
525
|
-
for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
|
|
526
|
-
b = ranges[i];
|
|
527
|
-
if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
|
|
528
|
-
if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
|
|
529
|
-
if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
|
|
530
|
-
} else {
|
|
531
|
-
merged.push(a = b);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// Finally, find the largest gap between the merged ranges.
|
|
536
|
-
// The final bounding box will be the inverse of this gap.
|
|
537
|
-
for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
|
|
538
|
-
b = merged[i];
|
|
539
|
-
if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0 = b[0], lambda1 = a[1];
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
ranges = range$1 = null;
|
|
543
|
-
return lambda0 === Infinity || phi0 === Infinity ? [[NaN, NaN], [NaN, NaN]] : [[lambda0, phi0], [lambda1, phi1]];
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
var W0, W1, X0, Y0, Z0, X1, Y1, Z1, X2, Y2, Z2, lambda00, phi00,
|
|
547
|
-
// first point
|
|
548
|
-
x0, y0, z0; // previous point
|
|
549
|
-
|
|
550
|
-
var centroidStream = {
|
|
551
|
-
sphere: noop,
|
|
552
|
-
point: centroidPoint,
|
|
553
|
-
lineStart: centroidLineStart,
|
|
554
|
-
lineEnd: centroidLineEnd,
|
|
555
|
-
polygonStart: function () {
|
|
556
|
-
centroidStream.lineStart = centroidRingStart;
|
|
557
|
-
centroidStream.lineEnd = centroidRingEnd;
|
|
558
|
-
},
|
|
559
|
-
polygonEnd: function () {
|
|
560
|
-
centroidStream.lineStart = centroidLineStart;
|
|
561
|
-
centroidStream.lineEnd = centroidLineEnd;
|
|
562
|
-
}
|
|
563
|
-
};
|
|
564
|
-
|
|
565
|
-
// Arithmetic mean of Cartesian vectors.
|
|
566
|
-
function centroidPoint(lambda, phi) {
|
|
567
|
-
lambda *= radians$1, phi *= radians$1;
|
|
568
|
-
var cosPhi = cos(phi);
|
|
569
|
-
centroidPointCartesian(cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi));
|
|
570
|
-
}
|
|
571
|
-
function centroidPointCartesian(x, y, z) {
|
|
572
|
-
++W0;
|
|
573
|
-
X0 += (x - X0) / W0;
|
|
574
|
-
Y0 += (y - Y0) / W0;
|
|
575
|
-
Z0 += (z - Z0) / W0;
|
|
576
|
-
}
|
|
577
|
-
function centroidLineStart() {
|
|
578
|
-
centroidStream.point = centroidLinePointFirst;
|
|
579
|
-
}
|
|
580
|
-
function centroidLinePointFirst(lambda, phi) {
|
|
581
|
-
lambda *= radians$1, phi *= radians$1;
|
|
582
|
-
var cosPhi = cos(phi);
|
|
583
|
-
x0 = cosPhi * cos(lambda);
|
|
584
|
-
y0 = cosPhi * sin(lambda);
|
|
585
|
-
z0 = sin(phi);
|
|
586
|
-
centroidStream.point = centroidLinePoint;
|
|
587
|
-
centroidPointCartesian(x0, y0, z0);
|
|
588
|
-
}
|
|
589
|
-
function centroidLinePoint(lambda, phi) {
|
|
590
|
-
lambda *= radians$1, phi *= radians$1;
|
|
591
|
-
var cosPhi = cos(phi),
|
|
592
|
-
x = cosPhi * cos(lambda),
|
|
593
|
-
y = cosPhi * sin(lambda),
|
|
594
|
-
z = sin(phi),
|
|
595
|
-
w = atan2(sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
|
|
596
|
-
W1 += w;
|
|
597
|
-
X1 += w * (x0 + (x0 = x));
|
|
598
|
-
Y1 += w * (y0 + (y0 = y));
|
|
599
|
-
Z1 += w * (z0 + (z0 = z));
|
|
600
|
-
centroidPointCartesian(x0, y0, z0);
|
|
601
|
-
}
|
|
602
|
-
function centroidLineEnd() {
|
|
603
|
-
centroidStream.point = centroidPoint;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
|
|
607
|
-
// J. Applied Mechanics 42, 239 (1975).
|
|
608
|
-
function centroidRingStart() {
|
|
609
|
-
centroidStream.point = centroidRingPointFirst;
|
|
610
|
-
}
|
|
611
|
-
function centroidRingEnd() {
|
|
612
|
-
centroidRingPoint(lambda00, phi00);
|
|
613
|
-
centroidStream.point = centroidPoint;
|
|
614
|
-
}
|
|
615
|
-
function centroidRingPointFirst(lambda, phi) {
|
|
616
|
-
lambda00 = lambda, phi00 = phi;
|
|
617
|
-
lambda *= radians$1, phi *= radians$1;
|
|
618
|
-
centroidStream.point = centroidRingPoint;
|
|
619
|
-
var cosPhi = cos(phi);
|
|
620
|
-
x0 = cosPhi * cos(lambda);
|
|
621
|
-
y0 = cosPhi * sin(lambda);
|
|
622
|
-
z0 = sin(phi);
|
|
623
|
-
centroidPointCartesian(x0, y0, z0);
|
|
624
|
-
}
|
|
625
|
-
function centroidRingPoint(lambda, phi) {
|
|
626
|
-
lambda *= radians$1, phi *= radians$1;
|
|
627
|
-
var cosPhi = cos(phi),
|
|
628
|
-
x = cosPhi * cos(lambda),
|
|
629
|
-
y = cosPhi * sin(lambda),
|
|
630
|
-
z = sin(phi),
|
|
631
|
-
cx = y0 * z - z0 * y,
|
|
632
|
-
cy = z0 * x - x0 * z,
|
|
633
|
-
cz = x0 * y - y0 * x,
|
|
634
|
-
m = hypot(cx, cy, cz),
|
|
635
|
-
w = asin(m),
|
|
636
|
-
// line weight = angle
|
|
637
|
-
v = m && -w / m; // area weight multiplier
|
|
638
|
-
X2.add(v * cx);
|
|
639
|
-
Y2.add(v * cy);
|
|
640
|
-
Z2.add(v * cz);
|
|
641
|
-
W1 += w;
|
|
642
|
-
X1 += w * (x0 + (x0 = x));
|
|
643
|
-
Y1 += w * (y0 + (y0 = y));
|
|
644
|
-
Z1 += w * (z0 + (z0 = z));
|
|
645
|
-
centroidPointCartesian(x0, y0, z0);
|
|
646
|
-
}
|
|
647
|
-
function centroid (object) {
|
|
648
|
-
W0 = W1 = X0 = Y0 = Z0 = X1 = Y1 = Z1 = 0;
|
|
649
|
-
X2 = new Adder();
|
|
650
|
-
Y2 = new Adder();
|
|
651
|
-
Z2 = new Adder();
|
|
652
|
-
geoStream(object, centroidStream);
|
|
653
|
-
var x = +X2,
|
|
654
|
-
y = +Y2,
|
|
655
|
-
z = +Z2,
|
|
656
|
-
m = hypot(x, y, z);
|
|
657
|
-
|
|
658
|
-
// If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
|
|
659
|
-
if (m < epsilon2) {
|
|
660
|
-
x = X1, y = Y1, z = Z1;
|
|
661
|
-
// If the feature has zero length, fall back to arithmetic mean of point vectors.
|
|
662
|
-
if (W1 < epsilon) x = X0, y = Y0, z = Z0;
|
|
663
|
-
m = hypot(x, y, z);
|
|
664
|
-
// If the feature still has an undefined ccentroid, then return.
|
|
665
|
-
if (m < epsilon2) return [NaN, NaN];
|
|
666
|
-
}
|
|
667
|
-
return [atan2(y, x) * degrees$1, asin(z / m) * degrees$1];
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
function geoMethod(methodName, globalMethod) {
|
|
671
|
-
return function (projection, geojson, group) {
|
|
672
|
-
if (projection) {
|
|
673
|
-
// projection defined, use it
|
|
674
|
-
const p = getScale(projection, (group || this).context);
|
|
675
|
-
return p && p.path[methodName](geojson);
|
|
676
|
-
} else {
|
|
677
|
-
// projection undefined, use global method
|
|
678
|
-
return globalMethod(geojson);
|
|
679
|
-
}
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
const geoArea = geoMethod('area', area);
|
|
683
|
-
const geoBounds = geoMethod('bounds', bounds);
|
|
684
|
-
const geoCentroid = geoMethod('centroid', centroid);
|
|
685
|
-
function geoScale(projection, group) {
|
|
686
|
-
const p = getScale(projection, (group || this).context);
|
|
687
|
-
return p && p.scale();
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
function inScope (item) {
|
|
691
|
-
const group = this.context.group;
|
|
692
|
-
let value = false;
|
|
693
|
-
if (group) while (item) {
|
|
694
|
-
if (item === group) {
|
|
695
|
-
value = true;
|
|
696
|
-
break;
|
|
697
|
-
}
|
|
698
|
-
item = item.mark.group;
|
|
699
|
-
}
|
|
700
|
-
return value;
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
function log(df, method, args) {
|
|
33
|
+
target = item.mark.source;
|
|
34
|
+
df.pulse(target, df.changeset().encode(item, name));
|
|
35
|
+
}
|
|
36
|
+
return retval !== undefined ? retval : item;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const wrap = method => function (value, spec) {
|
|
40
|
+
const locale = this.context.dataflow.locale();
|
|
41
|
+
return value === null ? 'null' : locale[method](spec)(value);
|
|
42
|
+
};
|
|
43
|
+
const format = wrap('format');
|
|
44
|
+
const timeFormat = wrap('timeFormat');
|
|
45
|
+
const utcFormat = wrap('utcFormat');
|
|
46
|
+
const timeParse = wrap('timeParse');
|
|
47
|
+
const utcParse = wrap('utcParse');
|
|
48
|
+
const dateObj = new Date(2000, 0, 1);
|
|
49
|
+
function time(month, day, specifier) {
|
|
50
|
+
if (!Number.isInteger(month) || !Number.isInteger(day)) return '';
|
|
51
|
+
dateObj.setYear(2000);
|
|
52
|
+
dateObj.setMonth(month);
|
|
53
|
+
dateObj.setDate(day);
|
|
54
|
+
return timeFormat.call(this, dateObj, specifier);
|
|
55
|
+
}
|
|
56
|
+
function monthFormat(month) {
|
|
57
|
+
return time.call(this, month, 1, '%B');
|
|
58
|
+
}
|
|
59
|
+
function monthAbbrevFormat(month) {
|
|
60
|
+
return time.call(this, month, 1, '%b');
|
|
61
|
+
}
|
|
62
|
+
function dayFormat(day) {
|
|
63
|
+
return time.call(this, 0, 2 + day, '%A');
|
|
64
|
+
}
|
|
65
|
+
function dayAbbrevFormat(day) {
|
|
66
|
+
return time.call(this, 0, 2 + day, '%a');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const DataPrefix = ':';
|
|
70
|
+
const IndexPrefix = '@';
|
|
71
|
+
const ScalePrefix = '%';
|
|
72
|
+
const SignalPrefix = '$';
|
|
73
|
+
|
|
74
|
+
function dataVisitor(name, args, scope, params) {
|
|
75
|
+
if (args[0].type !== Literal) {
|
|
76
|
+
error('First argument to data functions must be a string literal.');
|
|
77
|
+
}
|
|
78
|
+
const data = args[0].value,
|
|
79
|
+
dataName = DataPrefix + data;
|
|
80
|
+
if (!hasOwnProperty(dataName, params)) {
|
|
704
81
|
try {
|
|
705
|
-
|
|
82
|
+
params[dataName] = scope.getData(data).tuplesRef();
|
|
706
83
|
} catch (err) {
|
|
707
|
-
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
for (
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
darkolivegreen: 0x556b2f,
|
|
775
|
-
darkorange: 0xff8c00,
|
|
776
|
-
darkorchid: 0x9932cc,
|
|
777
|
-
darkred: 0x8b0000,
|
|
778
|
-
darksalmon: 0xe9967a,
|
|
779
|
-
darkseagreen: 0x8fbc8f,
|
|
780
|
-
darkslateblue: 0x483d8b,
|
|
781
|
-
darkslategray: 0x2f4f4f,
|
|
782
|
-
darkslategrey: 0x2f4f4f,
|
|
783
|
-
darkturquoise: 0x00ced1,
|
|
784
|
-
darkviolet: 0x9400d3,
|
|
785
|
-
deeppink: 0xff1493,
|
|
786
|
-
deepskyblue: 0x00bfff,
|
|
787
|
-
dimgray: 0x696969,
|
|
788
|
-
dimgrey: 0x696969,
|
|
789
|
-
dodgerblue: 0x1e90ff,
|
|
790
|
-
firebrick: 0xb22222,
|
|
791
|
-
floralwhite: 0xfffaf0,
|
|
792
|
-
forestgreen: 0x228b22,
|
|
793
|
-
fuchsia: 0xff00ff,
|
|
794
|
-
gainsboro: 0xdcdcdc,
|
|
795
|
-
ghostwhite: 0xf8f8ff,
|
|
796
|
-
gold: 0xffd700,
|
|
797
|
-
goldenrod: 0xdaa520,
|
|
798
|
-
gray: 0x808080,
|
|
799
|
-
green: 0x008000,
|
|
800
|
-
greenyellow: 0xadff2f,
|
|
801
|
-
grey: 0x808080,
|
|
802
|
-
honeydew: 0xf0fff0,
|
|
803
|
-
hotpink: 0xff69b4,
|
|
804
|
-
indianred: 0xcd5c5c,
|
|
805
|
-
indigo: 0x4b0082,
|
|
806
|
-
ivory: 0xfffff0,
|
|
807
|
-
khaki: 0xf0e68c,
|
|
808
|
-
lavender: 0xe6e6fa,
|
|
809
|
-
lavenderblush: 0xfff0f5,
|
|
810
|
-
lawngreen: 0x7cfc00,
|
|
811
|
-
lemonchiffon: 0xfffacd,
|
|
812
|
-
lightblue: 0xadd8e6,
|
|
813
|
-
lightcoral: 0xf08080,
|
|
814
|
-
lightcyan: 0xe0ffff,
|
|
815
|
-
lightgoldenrodyellow: 0xfafad2,
|
|
816
|
-
lightgray: 0xd3d3d3,
|
|
817
|
-
lightgreen: 0x90ee90,
|
|
818
|
-
lightgrey: 0xd3d3d3,
|
|
819
|
-
lightpink: 0xffb6c1,
|
|
820
|
-
lightsalmon: 0xffa07a,
|
|
821
|
-
lightseagreen: 0x20b2aa,
|
|
822
|
-
lightskyblue: 0x87cefa,
|
|
823
|
-
lightslategray: 0x778899,
|
|
824
|
-
lightslategrey: 0x778899,
|
|
825
|
-
lightsteelblue: 0xb0c4de,
|
|
826
|
-
lightyellow: 0xffffe0,
|
|
827
|
-
lime: 0x00ff00,
|
|
828
|
-
limegreen: 0x32cd32,
|
|
829
|
-
linen: 0xfaf0e6,
|
|
830
|
-
magenta: 0xff00ff,
|
|
831
|
-
maroon: 0x800000,
|
|
832
|
-
mediumaquamarine: 0x66cdaa,
|
|
833
|
-
mediumblue: 0x0000cd,
|
|
834
|
-
mediumorchid: 0xba55d3,
|
|
835
|
-
mediumpurple: 0x9370db,
|
|
836
|
-
mediumseagreen: 0x3cb371,
|
|
837
|
-
mediumslateblue: 0x7b68ee,
|
|
838
|
-
mediumspringgreen: 0x00fa9a,
|
|
839
|
-
mediumturquoise: 0x48d1cc,
|
|
840
|
-
mediumvioletred: 0xc71585,
|
|
841
|
-
midnightblue: 0x191970,
|
|
842
|
-
mintcream: 0xf5fffa,
|
|
843
|
-
mistyrose: 0xffe4e1,
|
|
844
|
-
moccasin: 0xffe4b5,
|
|
845
|
-
navajowhite: 0xffdead,
|
|
846
|
-
navy: 0x000080,
|
|
847
|
-
oldlace: 0xfdf5e6,
|
|
848
|
-
olive: 0x808000,
|
|
849
|
-
olivedrab: 0x6b8e23,
|
|
850
|
-
orange: 0xffa500,
|
|
851
|
-
orangered: 0xff4500,
|
|
852
|
-
orchid: 0xda70d6,
|
|
853
|
-
palegoldenrod: 0xeee8aa,
|
|
854
|
-
palegreen: 0x98fb98,
|
|
855
|
-
paleturquoise: 0xafeeee,
|
|
856
|
-
palevioletred: 0xdb7093,
|
|
857
|
-
papayawhip: 0xffefd5,
|
|
858
|
-
peachpuff: 0xffdab9,
|
|
859
|
-
peru: 0xcd853f,
|
|
860
|
-
pink: 0xffc0cb,
|
|
861
|
-
plum: 0xdda0dd,
|
|
862
|
-
powderblue: 0xb0e0e6,
|
|
863
|
-
purple: 0x800080,
|
|
864
|
-
rebeccapurple: 0x663399,
|
|
865
|
-
red: 0xff0000,
|
|
866
|
-
rosybrown: 0xbc8f8f,
|
|
867
|
-
royalblue: 0x4169e1,
|
|
868
|
-
saddlebrown: 0x8b4513,
|
|
869
|
-
salmon: 0xfa8072,
|
|
870
|
-
sandybrown: 0xf4a460,
|
|
871
|
-
seagreen: 0x2e8b57,
|
|
872
|
-
seashell: 0xfff5ee,
|
|
873
|
-
sienna: 0xa0522d,
|
|
874
|
-
silver: 0xc0c0c0,
|
|
875
|
-
skyblue: 0x87ceeb,
|
|
876
|
-
slateblue: 0x6a5acd,
|
|
877
|
-
slategray: 0x708090,
|
|
878
|
-
slategrey: 0x708090,
|
|
879
|
-
snow: 0xfffafa,
|
|
880
|
-
springgreen: 0x00ff7f,
|
|
881
|
-
steelblue: 0x4682b4,
|
|
882
|
-
tan: 0xd2b48c,
|
|
883
|
-
teal: 0x008080,
|
|
884
|
-
thistle: 0xd8bfd8,
|
|
885
|
-
tomato: 0xff6347,
|
|
886
|
-
turquoise: 0x40e0d0,
|
|
887
|
-
violet: 0xee82ee,
|
|
888
|
-
wheat: 0xf5deb3,
|
|
889
|
-
white: 0xffffff,
|
|
890
|
-
whitesmoke: 0xf5f5f5,
|
|
891
|
-
yellow: 0xffff00,
|
|
892
|
-
yellowgreen: 0x9acd32
|
|
84
|
+
// if data set does not exist, there's nothing to track
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function indataVisitor(name, args, scope, params) {
|
|
89
|
+
if (args[0].type !== Literal) error('First argument to indata must be a string literal.');
|
|
90
|
+
if (args[1].type !== Literal) error('Second argument to indata must be a string literal.');
|
|
91
|
+
const data = args[0].value,
|
|
92
|
+
field = args[1].value,
|
|
93
|
+
indexName = IndexPrefix + field;
|
|
94
|
+
if (!hasOwnProperty(indexName, params)) {
|
|
95
|
+
params[indexName] = scope.getData(data).indataRef(scope, field);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function scaleVisitor(name, args, scope, params) {
|
|
99
|
+
if (args[0].type === Literal) {
|
|
100
|
+
// add scale dependency
|
|
101
|
+
addScaleDependency(scope, params, args[0].value);
|
|
102
|
+
} else {
|
|
103
|
+
// indirect scale lookup; add all scales as parameters
|
|
104
|
+
for (name in scope.scales) {
|
|
105
|
+
addScaleDependency(scope, params, name);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function addScaleDependency(scope, params, name) {
|
|
110
|
+
const scaleName = ScalePrefix + name;
|
|
111
|
+
if (!hasOwnProperty(params, scaleName)) {
|
|
112
|
+
try {
|
|
113
|
+
params[scaleName] = scope.scaleRef(name);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
// TODO: error handling? warning?
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* nameOrFunction must be a string or function that was registered.
|
|
122
|
+
* Return undefined if scale is not recognized.
|
|
123
|
+
*/
|
|
124
|
+
function getScale(nameOrFunction, ctx) {
|
|
125
|
+
if (isString(nameOrFunction)) {
|
|
126
|
+
const maybeScale = ctx.scales[nameOrFunction];
|
|
127
|
+
return maybeScale && isRegisteredScale(maybeScale.value) ? maybeScale.value : undefined;
|
|
128
|
+
} else if (isFunction(nameOrFunction)) {
|
|
129
|
+
return isRegisteredScale(nameOrFunction) ? nameOrFunction : undefined;
|
|
130
|
+
}
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
function internalScaleFunctions(codegen, fnctx, visitors) {
|
|
134
|
+
// add helper method to the 'this' expression function context
|
|
135
|
+
fnctx.__bandwidth = s => s && s.bandwidth ? s.bandwidth() : 0;
|
|
136
|
+
|
|
137
|
+
// register AST visitors for internal scale functions
|
|
138
|
+
visitors._bandwidth = scaleVisitor;
|
|
139
|
+
visitors._range = scaleVisitor;
|
|
140
|
+
visitors._scale = scaleVisitor;
|
|
141
|
+
|
|
142
|
+
// resolve scale reference directly to the signal hash argument
|
|
143
|
+
const ref = arg => '_[' + (arg.type === Literal ? stringValue(ScalePrefix + arg.value) : stringValue(ScalePrefix) + '+' + codegen(arg)) + ']';
|
|
144
|
+
|
|
145
|
+
// define and return internal scale function code generators
|
|
146
|
+
// these internal functions are called by mark encoders
|
|
147
|
+
return {
|
|
148
|
+
_bandwidth: args => `this.__bandwidth(${ref(args[0])})`,
|
|
149
|
+
_range: args => `${ref(args[0])}.range()`,
|
|
150
|
+
_scale: args => `${ref(args[0])}(${codegen(args[1])})`
|
|
893
151
|
};
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
// Deprecated! Use color.formatHex.
|
|
903
|
-
formatHex: color_formatHex,
|
|
904
|
-
formatHex8: color_formatHex8,
|
|
905
|
-
formatHsl: color_formatHsl,
|
|
906
|
-
formatRgb: color_formatRgb,
|
|
907
|
-
toString: color_formatRgb
|
|
908
|
-
});
|
|
909
|
-
function color_formatHex() {
|
|
910
|
-
return this.rgb().formatHex();
|
|
911
|
-
}
|
|
912
|
-
function color_formatHex8() {
|
|
913
|
-
return this.rgb().formatHex8();
|
|
914
|
-
}
|
|
915
|
-
function color_formatHsl() {
|
|
916
|
-
return hslConvert(this).formatHsl();
|
|
917
|
-
}
|
|
918
|
-
function color_formatRgb() {
|
|
919
|
-
return this.rgb().formatRgb();
|
|
920
|
-
}
|
|
921
|
-
function color(format) {
|
|
922
|
-
var m, l;
|
|
923
|
-
format = (format + "").trim().toLowerCase();
|
|
924
|
-
return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000
|
|
925
|
-
: l === 3 ? new Rgb(m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, (m & 0xf) << 4 | m & 0xf, 1) // #f00
|
|
926
|
-
: l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000
|
|
927
|
-
: l === 4 ? rgba(m >> 12 & 0xf | m >> 8 & 0xf0, m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, ((m & 0xf) << 4 | m & 0xf) / 0xff) // #f000
|
|
928
|
-
: null // invalid hex
|
|
929
|
-
) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
|
|
930
|
-
: (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
|
|
931
|
-
: (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
|
|
932
|
-
: (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
|
|
933
|
-
: (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
|
|
934
|
-
: (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
|
|
935
|
-
: named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
|
|
936
|
-
: format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
|
|
937
|
-
}
|
|
938
|
-
function rgbn(n) {
|
|
939
|
-
return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
|
|
940
|
-
}
|
|
941
|
-
function rgba(r, g, b, a) {
|
|
942
|
-
if (a <= 0) r = g = b = NaN;
|
|
943
|
-
return new Rgb(r, g, b, a);
|
|
944
|
-
}
|
|
945
|
-
function rgbConvert(o) {
|
|
946
|
-
if (!(o instanceof Color)) o = color(o);
|
|
947
|
-
if (!o) return new Rgb();
|
|
948
|
-
o = o.rgb();
|
|
949
|
-
return new Rgb(o.r, o.g, o.b, o.opacity);
|
|
950
|
-
}
|
|
951
|
-
function rgb(r, g, b, opacity) {
|
|
952
|
-
return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
|
|
953
|
-
}
|
|
954
|
-
function Rgb(r, g, b, opacity) {
|
|
955
|
-
this.r = +r;
|
|
956
|
-
this.g = +g;
|
|
957
|
-
this.b = +b;
|
|
958
|
-
this.opacity = +opacity;
|
|
959
|
-
}
|
|
960
|
-
define(Rgb, rgb, extend(Color, {
|
|
961
|
-
brighter(k) {
|
|
962
|
-
k = k == null ? brighter : Math.pow(brighter, k);
|
|
963
|
-
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
|
|
964
|
-
},
|
|
965
|
-
darker(k) {
|
|
966
|
-
k = k == null ? darker : Math.pow(darker, k);
|
|
967
|
-
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
|
|
968
|
-
},
|
|
969
|
-
rgb() {
|
|
970
|
-
return this;
|
|
971
|
-
},
|
|
972
|
-
clamp() {
|
|
973
|
-
return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity));
|
|
974
|
-
},
|
|
975
|
-
displayable() {
|
|
976
|
-
return -0.5 <= this.r && this.r < 255.5 && -0.5 <= this.g && this.g < 255.5 && -0.5 <= this.b && this.b < 255.5 && 0 <= this.opacity && this.opacity <= 1;
|
|
977
|
-
},
|
|
978
|
-
hex: rgb_formatHex,
|
|
979
|
-
// Deprecated! Use color.formatHex.
|
|
980
|
-
formatHex: rgb_formatHex,
|
|
981
|
-
formatHex8: rgb_formatHex8,
|
|
982
|
-
formatRgb: rgb_formatRgb,
|
|
983
|
-
toString: rgb_formatRgb
|
|
984
|
-
}));
|
|
985
|
-
function rgb_formatHex() {
|
|
986
|
-
return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`;
|
|
987
|
-
}
|
|
988
|
-
function rgb_formatHex8() {
|
|
989
|
-
return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`;
|
|
990
|
-
}
|
|
991
|
-
function rgb_formatRgb() {
|
|
992
|
-
const a = clampa(this.opacity);
|
|
993
|
-
return `${a === 1 ? "rgb(" : "rgba("}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? ")" : `, ${a})`}`;
|
|
994
|
-
}
|
|
995
|
-
function clampa(opacity) {
|
|
996
|
-
return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));
|
|
997
|
-
}
|
|
998
|
-
function clampi(value) {
|
|
999
|
-
return Math.max(0, Math.min(255, Math.round(value) || 0));
|
|
1000
|
-
}
|
|
1001
|
-
function hex(value) {
|
|
1002
|
-
value = clampi(value);
|
|
1003
|
-
return (value < 16 ? "0" : "") + value.toString(16);
|
|
1004
|
-
}
|
|
1005
|
-
function hsla(h, s, l, a) {
|
|
1006
|
-
if (a <= 0) h = s = l = NaN;else if (l <= 0 || l >= 1) h = s = NaN;else if (s <= 0) h = NaN;
|
|
1007
|
-
return new Hsl(h, s, l, a);
|
|
1008
|
-
}
|
|
1009
|
-
function hslConvert(o) {
|
|
1010
|
-
if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
|
|
1011
|
-
if (!(o instanceof Color)) o = color(o);
|
|
1012
|
-
if (!o) return new Hsl();
|
|
1013
|
-
if (o instanceof Hsl) return o;
|
|
1014
|
-
o = o.rgb();
|
|
1015
|
-
var r = o.r / 255,
|
|
1016
|
-
g = o.g / 255,
|
|
1017
|
-
b = o.b / 255,
|
|
1018
|
-
min = Math.min(r, g, b),
|
|
1019
|
-
max = Math.max(r, g, b),
|
|
1020
|
-
h = NaN,
|
|
1021
|
-
s = max - min,
|
|
1022
|
-
l = (max + min) / 2;
|
|
1023
|
-
if (s) {
|
|
1024
|
-
if (r === max) h = (g - b) / s + (g < b) * 6;else if (g === max) h = (b - r) / s + 2;else h = (r - g) / s + 4;
|
|
1025
|
-
s /= l < 0.5 ? max + min : 2 - max - min;
|
|
1026
|
-
h *= 60;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function geoMethod(methodName, globalMethod) {
|
|
155
|
+
return function (projection, geojson, group) {
|
|
156
|
+
if (projection) {
|
|
157
|
+
// projection defined, use it
|
|
158
|
+
const p = getScale(projection, (group || this).context);
|
|
159
|
+
return p && p.path[methodName](geojson);
|
|
1027
160
|
} else {
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
return new Hsl(h, s, l, o.opacity);
|
|
1031
|
-
}
|
|
1032
|
-
function hsl(h, s, l, opacity) {
|
|
1033
|
-
return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
|
|
1034
|
-
}
|
|
1035
|
-
function Hsl(h, s, l, opacity) {
|
|
1036
|
-
this.h = +h;
|
|
1037
|
-
this.s = +s;
|
|
1038
|
-
this.l = +l;
|
|
1039
|
-
this.opacity = +opacity;
|
|
1040
|
-
}
|
|
1041
|
-
define(Hsl, hsl, extend(Color, {
|
|
1042
|
-
brighter(k) {
|
|
1043
|
-
k = k == null ? brighter : Math.pow(brighter, k);
|
|
1044
|
-
return new Hsl(this.h, this.s, this.l * k, this.opacity);
|
|
1045
|
-
},
|
|
1046
|
-
darker(k) {
|
|
1047
|
-
k = k == null ? darker : Math.pow(darker, k);
|
|
1048
|
-
return new Hsl(this.h, this.s, this.l * k, this.opacity);
|
|
1049
|
-
},
|
|
1050
|
-
rgb() {
|
|
1051
|
-
var h = this.h % 360 + (this.h < 0) * 360,
|
|
1052
|
-
s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
|
|
1053
|
-
l = this.l,
|
|
1054
|
-
m2 = l + (l < 0.5 ? l : 1 - l) * s,
|
|
1055
|
-
m1 = 2 * l - m2;
|
|
1056
|
-
return new Rgb(hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2), hsl2rgb(h, m1, m2), hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), this.opacity);
|
|
1057
|
-
},
|
|
1058
|
-
clamp() {
|
|
1059
|
-
return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity));
|
|
1060
|
-
},
|
|
1061
|
-
displayable() {
|
|
1062
|
-
return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
|
|
1063
|
-
},
|
|
1064
|
-
formatHsl() {
|
|
1065
|
-
const a = clampa(this.opacity);
|
|
1066
|
-
return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`;
|
|
1067
|
-
}
|
|
1068
|
-
}));
|
|
1069
|
-
function clamph(value) {
|
|
1070
|
-
value = (value || 0) % 360;
|
|
1071
|
-
return value < 0 ? value + 360 : value;
|
|
1072
|
-
}
|
|
1073
|
-
function clampt(value) {
|
|
1074
|
-
return Math.max(0, Math.min(1, value || 0));
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
/* From FvD 13.37, CSS Color Module Level 3 */
|
|
1078
|
-
function hsl2rgb(h, m1, m2) {
|
|
1079
|
-
return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
const radians = Math.PI / 180;
|
|
1083
|
-
const degrees = 180 / Math.PI;
|
|
1084
|
-
|
|
1085
|
-
// https://observablehq.com/@mbostock/lab-and-rgb
|
|
1086
|
-
const K = 18,
|
|
1087
|
-
Xn = 0.96422,
|
|
1088
|
-
Yn = 1,
|
|
1089
|
-
Zn = 0.82521,
|
|
1090
|
-
t0 = 4 / 29,
|
|
1091
|
-
t1 = 6 / 29,
|
|
1092
|
-
t2 = 3 * t1 * t1,
|
|
1093
|
-
t3 = t1 * t1 * t1;
|
|
1094
|
-
function labConvert(o) {
|
|
1095
|
-
if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
|
|
1096
|
-
if (o instanceof Hcl) return hcl2lab(o);
|
|
1097
|
-
if (!(o instanceof Rgb)) o = rgbConvert(o);
|
|
1098
|
-
var r = rgb2lrgb(o.r),
|
|
1099
|
-
g = rgb2lrgb(o.g),
|
|
1100
|
-
b = rgb2lrgb(o.b),
|
|
1101
|
-
y = xyz2lab((0.2225045 * r + 0.7168786 * g + 0.0606169 * b) / Yn),
|
|
1102
|
-
x,
|
|
1103
|
-
z;
|
|
1104
|
-
if (r === g && g === b) x = z = y;else {
|
|
1105
|
-
x = xyz2lab((0.4360747 * r + 0.3850649 * g + 0.1430804 * b) / Xn);
|
|
1106
|
-
z = xyz2lab((0.0139322 * r + 0.0971045 * g + 0.7141733 * b) / Zn);
|
|
1107
|
-
}
|
|
1108
|
-
return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
|
|
1109
|
-
}
|
|
1110
|
-
function lab(l, a, b, opacity) {
|
|
1111
|
-
return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
|
|
1112
|
-
}
|
|
1113
|
-
function Lab(l, a, b, opacity) {
|
|
1114
|
-
this.l = +l;
|
|
1115
|
-
this.a = +a;
|
|
1116
|
-
this.b = +b;
|
|
1117
|
-
this.opacity = +opacity;
|
|
1118
|
-
}
|
|
1119
|
-
define(Lab, lab, extend(Color, {
|
|
1120
|
-
brighter(k) {
|
|
1121
|
-
return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity);
|
|
1122
|
-
},
|
|
1123
|
-
darker(k) {
|
|
1124
|
-
return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity);
|
|
1125
|
-
},
|
|
1126
|
-
rgb() {
|
|
1127
|
-
var y = (this.l + 16) / 116,
|
|
1128
|
-
x = isNaN(this.a) ? y : y + this.a / 500,
|
|
1129
|
-
z = isNaN(this.b) ? y : y - this.b / 200;
|
|
1130
|
-
x = Xn * lab2xyz(x);
|
|
1131
|
-
y = Yn * lab2xyz(y);
|
|
1132
|
-
z = Zn * lab2xyz(z);
|
|
1133
|
-
return new Rgb(lrgb2rgb(3.1338561 * x - 1.6168667 * y - 0.4906146 * z), lrgb2rgb(-0.9787684 * x + 1.9161415 * y + 0.0334540 * z), lrgb2rgb(0.0719453 * x - 0.2289914 * y + 1.4052427 * z), this.opacity);
|
|
1134
|
-
}
|
|
1135
|
-
}));
|
|
1136
|
-
function xyz2lab(t) {
|
|
1137
|
-
return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
|
|
1138
|
-
}
|
|
1139
|
-
function lab2xyz(t) {
|
|
1140
|
-
return t > t1 ? t * t * t : t2 * (t - t0);
|
|
1141
|
-
}
|
|
1142
|
-
function lrgb2rgb(x) {
|
|
1143
|
-
return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
|
|
1144
|
-
}
|
|
1145
|
-
function rgb2lrgb(x) {
|
|
1146
|
-
return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
|
|
1147
|
-
}
|
|
1148
|
-
function hclConvert(o) {
|
|
1149
|
-
if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
|
|
1150
|
-
if (!(o instanceof Lab)) o = labConvert(o);
|
|
1151
|
-
if (o.a === 0 && o.b === 0) return new Hcl(NaN, 0 < o.l && o.l < 100 ? 0 : NaN, o.l, o.opacity);
|
|
1152
|
-
var h = Math.atan2(o.b, o.a) * degrees;
|
|
1153
|
-
return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
|
|
1154
|
-
}
|
|
1155
|
-
function hcl(h, c, l, opacity) {
|
|
1156
|
-
return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
|
|
1157
|
-
}
|
|
1158
|
-
function Hcl(h, c, l, opacity) {
|
|
1159
|
-
this.h = +h;
|
|
1160
|
-
this.c = +c;
|
|
1161
|
-
this.l = +l;
|
|
1162
|
-
this.opacity = +opacity;
|
|
1163
|
-
}
|
|
1164
|
-
function hcl2lab(o) {
|
|
1165
|
-
if (isNaN(o.h)) return new Lab(o.l, 0, 0, o.opacity);
|
|
1166
|
-
var h = o.h * radians;
|
|
1167
|
-
return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
|
|
1168
|
-
}
|
|
1169
|
-
define(Hcl, hcl, extend(Color, {
|
|
1170
|
-
brighter(k) {
|
|
1171
|
-
return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity);
|
|
1172
|
-
},
|
|
1173
|
-
darker(k) {
|
|
1174
|
-
return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity);
|
|
1175
|
-
},
|
|
1176
|
-
rgb() {
|
|
1177
|
-
return hcl2lab(this).rgb();
|
|
161
|
+
// projection undefined, use global method
|
|
162
|
+
return globalMethod(geojson);
|
|
1178
163
|
}
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const geoArea = geoMethod('area', geoArea$1);
|
|
167
|
+
const geoBounds = geoMethod('bounds', geoBounds$1);
|
|
168
|
+
const geoCentroid = geoMethod('centroid', geoCentroid$1);
|
|
169
|
+
function geoScale(projection, group) {
|
|
170
|
+
const p = getScale(projection, (group || this).context);
|
|
171
|
+
return p && p.scale();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function inScope (item) {
|
|
175
|
+
const group = this.context.group;
|
|
176
|
+
let value = false;
|
|
177
|
+
if (group) while (item) {
|
|
178
|
+
if (item === group) {
|
|
179
|
+
value = true;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
item = item.mark.group;
|
|
183
|
+
}
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function log(df, method, args) {
|
|
188
|
+
try {
|
|
189
|
+
df[method].apply(df, ['EXPRESSION'].concat([].slice.call(args)));
|
|
190
|
+
} catch (err) {
|
|
191
|
+
df.warn(err);
|
|
192
|
+
}
|
|
193
|
+
return args[args.length - 1];
|
|
194
|
+
}
|
|
195
|
+
function warn() {
|
|
196
|
+
return log(this.context.dataflow, 'warn', arguments);
|
|
197
|
+
}
|
|
198
|
+
function info() {
|
|
199
|
+
return log(this.context.dataflow, 'info', arguments);
|
|
200
|
+
}
|
|
201
|
+
function debug() {
|
|
202
|
+
return log(this.context.dataflow, 'debug', arguments);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
|
|
206
|
+
function channel_luminance_value(channelValue) {
|
|
207
|
+
const val = channelValue / 255;
|
|
208
|
+
if (val <= 0.03928) {
|
|
209
|
+
return val / 12.92;
|
|
210
|
+
}
|
|
211
|
+
return Math.pow((val + 0.055) / 1.055, 2.4);
|
|
212
|
+
}
|
|
213
|
+
function luminance(color) {
|
|
214
|
+
const c = rgb(color),
|
|
215
|
+
r = channel_luminance_value(c.r),
|
|
216
|
+
g = channel_luminance_value(c.g),
|
|
217
|
+
b = channel_luminance_value(c.b);
|
|
218
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
|
|
222
|
+
function contrast(color1, color2) {
|
|
223
|
+
const lum1 = luminance(color1),
|
|
224
|
+
lum2 = luminance(color2),
|
|
225
|
+
lumL = Math.max(lum1, lum2),
|
|
226
|
+
lumD = Math.min(lum1, lum2);
|
|
227
|
+
return (lumL + 0.05) / (lumD + 0.05);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function merge () {
|
|
231
|
+
const args = [].slice.call(arguments);
|
|
232
|
+
args.unshift({});
|
|
233
|
+
return extend(...args);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function equal(a, b) {
|
|
237
|
+
return a === b || a !== a && b !== b ? true : isArray(a) ? isArray(b) && a.length === b.length ? equalArray(a, b) : false : isObject(a) && isObject(b) ? equalObject(a, b) : false;
|
|
238
|
+
}
|
|
239
|
+
function equalArray(a, b) {
|
|
240
|
+
for (let i = 0, n = a.length; i < n; ++i) {
|
|
241
|
+
if (!equal(a[i], b[i])) return false;
|
|
242
|
+
}
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
function equalObject(a, b) {
|
|
246
|
+
for (const key in a) {
|
|
247
|
+
if (!equal(a[key], b[key])) return false;
|
|
248
|
+
}
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
function removePredicate(props) {
|
|
252
|
+
return _ => equalObject(props, _);
|
|
253
|
+
}
|
|
254
|
+
function modify (name, insert, remove, toggle, modify, values) {
|
|
255
|
+
const df = this.context.dataflow,
|
|
256
|
+
data = this.context.data[name],
|
|
257
|
+
input = data.input,
|
|
258
|
+
stamp = df.stamp();
|
|
259
|
+
let changes = data.changes,
|
|
260
|
+
predicate,
|
|
261
|
+
key;
|
|
262
|
+
if (df._trigger === false || !(input.value.length || insert || toggle)) {
|
|
263
|
+
// nothing to do!
|
|
264
|
+
return 0;
|
|
265
|
+
}
|
|
266
|
+
if (!changes || changes.stamp < stamp) {
|
|
267
|
+
data.changes = changes = df.changeset();
|
|
268
|
+
changes.stamp = stamp;
|
|
269
|
+
df.runAfter(() => {
|
|
270
|
+
data.modified = true;
|
|
271
|
+
df.pulse(input, changes).run();
|
|
272
|
+
}, true, 1);
|
|
273
|
+
}
|
|
274
|
+
if (remove) {
|
|
275
|
+
predicate = remove === true ? truthy : isArray(remove) || isTuple(remove) ? remove : removePredicate(remove);
|
|
276
|
+
changes.remove(predicate);
|
|
277
|
+
}
|
|
278
|
+
if (insert) {
|
|
279
|
+
changes.insert(insert);
|
|
280
|
+
}
|
|
281
|
+
if (toggle) {
|
|
282
|
+
predicate = removePredicate(toggle);
|
|
283
|
+
if (input.value.some(predicate)) {
|
|
1252
284
|
changes.remove(predicate);
|
|
1253
|
-
}
|
|
1254
|
-
if (insert) {
|
|
1255
|
-
changes.insert(insert);
|
|
1256
|
-
}
|
|
1257
|
-
if (toggle) {
|
|
1258
|
-
predicate = removePredicate(toggle);
|
|
1259
|
-
if (input.value.some(predicate)) {
|
|
1260
|
-
changes.remove(predicate);
|
|
1261
|
-
} else {
|
|
1262
|
-
changes.insert(toggle);
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
if (modify) {
|
|
1266
|
-
for (key in values) {
|
|
1267
|
-
changes.modify(modify, key, values[key]);
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
return 1;
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
function pinchDistance(event) {
|
|
1274
|
-
const t = event.touches,
|
|
1275
|
-
dx = t[0].clientX - t[1].clientX,
|
|
1276
|
-
dy = t[0].clientY - t[1].clientY;
|
|
1277
|
-
return Math.hypot(dx, dy);
|
|
1278
|
-
}
|
|
1279
|
-
function pinchAngle(event) {
|
|
1280
|
-
const t = event.touches;
|
|
1281
|
-
return Math.atan2(t[0].clientY - t[1].clientY, t[0].clientX - t[1].clientX);
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
// memoize accessor functions
|
|
1285
|
-
const accessors = {};
|
|
1286
|
-
function pluck (data, name) {
|
|
1287
|
-
const accessor = accessors[name] || (accessors[name] = vegaUtil.field(name));
|
|
1288
|
-
return vegaUtil.isArray(data) ? data.map(accessor) : accessor(data);
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
function array(seq) {
|
|
1292
|
-
return vegaUtil.isArray(seq) || ArrayBuffer.isView(seq) ? seq : null;
|
|
1293
|
-
}
|
|
1294
|
-
function sequence(seq) {
|
|
1295
|
-
return array(seq) || (vegaUtil.isString(seq) ? seq : null);
|
|
1296
|
-
}
|
|
1297
|
-
function join(seq, ...args) {
|
|
1298
|
-
return array(seq).join(...args);
|
|
1299
|
-
}
|
|
1300
|
-
function indexof(seq, ...args) {
|
|
1301
|
-
return sequence(seq).indexOf(...args);
|
|
1302
|
-
}
|
|
1303
|
-
function lastindexof(seq, ...args) {
|
|
1304
|
-
return sequence(seq).lastIndexOf(...args);
|
|
1305
|
-
}
|
|
1306
|
-
function slice(seq, ...args) {
|
|
1307
|
-
return sequence(seq).slice(...args);
|
|
1308
|
-
}
|
|
1309
|
-
function replace(str, pattern, repl) {
|
|
1310
|
-
if (vegaUtil.isFunction(repl)) vegaUtil.error('Function argument passed to replace.');
|
|
1311
|
-
if (!vegaUtil.isString(pattern) && !vegaUtil.isRegExp(pattern)) vegaUtil.error('Please pass a string or RegExp argument to replace.');
|
|
1312
|
-
return String(str).replace(pattern, repl);
|
|
1313
|
-
}
|
|
1314
|
-
function reverse(seq) {
|
|
1315
|
-
return array(seq).slice().reverse();
|
|
1316
|
-
}
|
|
1317
|
-
function sort(seq) {
|
|
1318
|
-
return array(seq).slice().sort(vegaUtil.ascending);
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
function bandspace(count, paddingInner, paddingOuter) {
|
|
1322
|
-
return vegaScale.bandSpace(count || 0, paddingInner || 0, paddingOuter || 0);
|
|
1323
|
-
}
|
|
1324
|
-
function bandwidth(name, group) {
|
|
1325
|
-
const s = getScale(name, (group || this).context);
|
|
1326
|
-
return s && s.bandwidth ? s.bandwidth() : 0;
|
|
1327
|
-
}
|
|
1328
|
-
function copy(name, group) {
|
|
1329
|
-
const s = getScale(name, (group || this).context);
|
|
1330
|
-
return s ? s.copy() : undefined;
|
|
1331
|
-
}
|
|
1332
|
-
function domain(name, group) {
|
|
1333
|
-
const s = getScale(name, (group || this).context);
|
|
1334
|
-
return s ? s.domain() : [];
|
|
1335
|
-
}
|
|
1336
|
-
function invert(name, range, group) {
|
|
1337
|
-
const s = getScale(name, (group || this).context);
|
|
1338
|
-
return !s ? undefined : vegaUtil.isArray(range) ? (s.invertRange || s.invert)(range) : (s.invert || s.invertExtent)(range);
|
|
1339
|
-
}
|
|
1340
|
-
function range(name, group) {
|
|
1341
|
-
const s = getScale(name, (group || this).context);
|
|
1342
|
-
return s && s.range ? s.range() : [];
|
|
1343
|
-
}
|
|
1344
|
-
function scale(name, value, group) {
|
|
1345
|
-
const s = getScale(name, (group || this).context);
|
|
1346
|
-
return s ? s(value) : undefined;
|
|
1347
|
-
}
|
|
1348
|
-
|
|
1349
|
-
function scaleGradient (scale, p0, p1, count, group) {
|
|
1350
|
-
scale = getScale(scale, (group || this).context);
|
|
1351
|
-
const gradient = vegaScenegraph.Gradient(p0, p1);
|
|
1352
|
-
let stops = scale.domain(),
|
|
1353
|
-
min = stops[0],
|
|
1354
|
-
max = vegaUtil.peek(stops),
|
|
1355
|
-
fraction = vegaUtil.identity;
|
|
1356
|
-
if (!(max - min)) {
|
|
1357
|
-
// expand scale if domain has zero span, fix #1479
|
|
1358
|
-
scale = (scale.interpolator ? vegaScale.scale('sequential')().interpolator(scale.interpolator()) : vegaScale.scale('linear')().interpolate(scale.interpolate()).range(scale.range())).domain([min = 0, max = 1]);
|
|
1359
285
|
} else {
|
|
1360
|
-
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
y,
|
|
1474
|
-
mark
|
|
1475
|
-
} = unit;
|
|
1476
|
-
const bb = new vegaScenegraph.Bounds().set(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
|
|
1477
|
-
|
|
1478
|
-
// Get bounding box around lasso
|
|
1479
|
-
for (const [px, py] of pixelLasso) {
|
|
1480
|
-
if (px < bb.x1) bb.x1 = px;
|
|
1481
|
-
if (px > bb.x2) bb.x2 = px;
|
|
1482
|
-
if (py < bb.y1) bb.y1 = py;
|
|
1483
|
-
if (py > bb.y2) bb.y2 = py;
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
// Translate bb against unit coordinates
|
|
1487
|
-
bb.translate(x, y);
|
|
1488
|
-
const intersection = intersect([[bb.x1, bb.y1], [bb.x2, bb.y2]], markname, mark);
|
|
1489
|
-
|
|
1490
|
-
// Check every point against the lasso
|
|
1491
|
-
return intersection.filter(tuple => pointInPolygon(tuple.x, tuple.y, pixelLasso));
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
/**
|
|
1495
|
-
* Performs a test if a point is inside a polygon based on the idea from
|
|
1496
|
-
* https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
|
|
1497
|
-
*
|
|
1498
|
-
* This method will not need the same start/end point since it wraps around the edges of the array
|
|
1499
|
-
*
|
|
1500
|
-
* @param {*} test a point to test against
|
|
1501
|
-
* @param {*} polygon a polygon in the form [[x,y], [x,y], ...]
|
|
1502
|
-
* @returns true if the point lies inside the polygon, false otherwise
|
|
1503
|
-
*/
|
|
1504
|
-
function pointInPolygon(testx, testy, polygon) {
|
|
1505
|
-
let intersections = 0;
|
|
1506
|
-
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
1507
|
-
const [prevX, prevY] = polygon[j];
|
|
1508
|
-
const [x, y] = polygon[i];
|
|
1509
|
-
|
|
1510
|
-
// count intersections
|
|
1511
|
-
if (y > testy != prevY > testy && testx < (prevX - x) * (testy - y) / (prevY - y) + x) {
|
|
1512
|
-
intersections++;
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
// point is in polygon if intersection count is odd
|
|
1517
|
-
return intersections & 1;
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
// Expression function context object
|
|
1521
|
-
const functionContext = {
|
|
1522
|
-
random() {
|
|
1523
|
-
return vegaStatistics.random();
|
|
1524
|
-
},
|
|
1525
|
-
// override default
|
|
1526
|
-
cumulativeNormal: vegaStatistics.cumulativeNormal,
|
|
1527
|
-
cumulativeLogNormal: vegaStatistics.cumulativeLogNormal,
|
|
1528
|
-
cumulativeUniform: vegaStatistics.cumulativeUniform,
|
|
1529
|
-
densityNormal: vegaStatistics.densityNormal,
|
|
1530
|
-
densityLogNormal: vegaStatistics.densityLogNormal,
|
|
1531
|
-
densityUniform: vegaStatistics.densityUniform,
|
|
1532
|
-
quantileNormal: vegaStatistics.quantileNormal,
|
|
1533
|
-
quantileLogNormal: vegaStatistics.quantileLogNormal,
|
|
1534
|
-
quantileUniform: vegaStatistics.quantileUniform,
|
|
1535
|
-
sampleNormal: vegaStatistics.sampleNormal,
|
|
1536
|
-
sampleLogNormal: vegaStatistics.sampleLogNormal,
|
|
1537
|
-
sampleUniform: vegaStatistics.sampleUniform,
|
|
1538
|
-
isArray: vegaUtil.isArray,
|
|
1539
|
-
isBoolean: vegaUtil.isBoolean,
|
|
1540
|
-
isDate: vegaUtil.isDate,
|
|
1541
|
-
isDefined(_) {
|
|
1542
|
-
return _ !== undefined;
|
|
1543
|
-
},
|
|
1544
|
-
isNumber: vegaUtil.isNumber,
|
|
1545
|
-
isObject: vegaUtil.isObject,
|
|
1546
|
-
isRegExp: vegaUtil.isRegExp,
|
|
1547
|
-
isString: vegaUtil.isString,
|
|
1548
|
-
isTuple: vegaDataflow.isTuple,
|
|
1549
|
-
isValid(_) {
|
|
1550
|
-
return _ != null && _ === _;
|
|
1551
|
-
},
|
|
1552
|
-
toBoolean: vegaUtil.toBoolean,
|
|
1553
|
-
toDate(_) {
|
|
1554
|
-
return vegaUtil.toDate(_);
|
|
1555
|
-
},
|
|
1556
|
-
// suppress extra arguments
|
|
1557
|
-
toNumber: vegaUtil.toNumber,
|
|
1558
|
-
toString: vegaUtil.toString,
|
|
1559
|
-
indexof,
|
|
1560
|
-
join,
|
|
1561
|
-
lastindexof,
|
|
1562
|
-
replace,
|
|
1563
|
-
reverse,
|
|
1564
|
-
sort,
|
|
1565
|
-
slice,
|
|
1566
|
-
flush: vegaUtil.flush,
|
|
1567
|
-
lerp: vegaUtil.lerp,
|
|
1568
|
-
merge,
|
|
1569
|
-
pad: vegaUtil.pad,
|
|
1570
|
-
peek: vegaUtil.peek,
|
|
1571
|
-
pluck,
|
|
1572
|
-
span: vegaUtil.span,
|
|
1573
|
-
inrange: vegaUtil.inrange,
|
|
1574
|
-
truncate: vegaUtil.truncate,
|
|
1575
|
-
rgb,
|
|
1576
|
-
lab,
|
|
1577
|
-
hcl,
|
|
1578
|
-
hsl,
|
|
1579
|
-
luminance,
|
|
1580
|
-
contrast,
|
|
1581
|
-
sequence: range$2,
|
|
1582
|
-
format,
|
|
1583
|
-
utcFormat,
|
|
1584
|
-
utcParse,
|
|
1585
|
-
utcOffset: vegaTime.utcOffset,
|
|
1586
|
-
utcSequence: vegaTime.utcSequence,
|
|
1587
|
-
timeFormat,
|
|
1588
|
-
timeParse,
|
|
1589
|
-
timeOffset: vegaTime.timeOffset,
|
|
1590
|
-
timeSequence: vegaTime.timeSequence,
|
|
1591
|
-
timeUnitSpecifier: vegaTime.timeUnitSpecifier,
|
|
1592
|
-
monthFormat,
|
|
1593
|
-
monthAbbrevFormat,
|
|
1594
|
-
dayFormat,
|
|
1595
|
-
dayAbbrevFormat,
|
|
1596
|
-
quarter: vegaUtil.quarter,
|
|
1597
|
-
utcquarter: vegaUtil.utcquarter,
|
|
1598
|
-
week: vegaTime.week,
|
|
1599
|
-
utcweek: vegaTime.utcweek,
|
|
1600
|
-
dayofyear: vegaTime.dayofyear,
|
|
1601
|
-
utcdayofyear: vegaTime.utcdayofyear,
|
|
1602
|
-
warn,
|
|
1603
|
-
info,
|
|
1604
|
-
debug,
|
|
1605
|
-
extent(_) {
|
|
1606
|
-
return vegaUtil.extent(_);
|
|
1607
|
-
},
|
|
1608
|
-
// suppress extra arguments
|
|
1609
|
-
inScope,
|
|
1610
|
-
intersect,
|
|
1611
|
-
clampRange: vegaUtil.clampRange,
|
|
1612
|
-
pinchDistance,
|
|
1613
|
-
pinchAngle,
|
|
1614
|
-
screen,
|
|
1615
|
-
containerSize,
|
|
1616
|
-
windowSize,
|
|
1617
|
-
bandspace,
|
|
1618
|
-
setdata,
|
|
1619
|
-
pathShape,
|
|
1620
|
-
panLinear: vegaUtil.panLinear,
|
|
1621
|
-
panLog: vegaUtil.panLog,
|
|
1622
|
-
panPow: vegaUtil.panPow,
|
|
1623
|
-
panSymlog: vegaUtil.panSymlog,
|
|
1624
|
-
zoomLinear: vegaUtil.zoomLinear,
|
|
1625
|
-
zoomLog: vegaUtil.zoomLog,
|
|
1626
|
-
zoomPow: vegaUtil.zoomPow,
|
|
1627
|
-
zoomSymlog: vegaUtil.zoomSymlog,
|
|
1628
|
-
encode,
|
|
1629
|
-
modify,
|
|
1630
|
-
lassoAppend,
|
|
1631
|
-
lassoPath,
|
|
1632
|
-
intersectLasso
|
|
286
|
+
changes.insert(toggle);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (modify) {
|
|
290
|
+
for (key in values) {
|
|
291
|
+
changes.modify(modify, key, values[key]);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return 1;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function pinchDistance(event) {
|
|
298
|
+
const t = event.touches,
|
|
299
|
+
dx = t[0].clientX - t[1].clientX,
|
|
300
|
+
dy = t[0].clientY - t[1].clientY;
|
|
301
|
+
return Math.hypot(dx, dy);
|
|
302
|
+
}
|
|
303
|
+
function pinchAngle(event) {
|
|
304
|
+
const t = event.touches;
|
|
305
|
+
return Math.atan2(t[0].clientY - t[1].clientY, t[0].clientX - t[1].clientX);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// memoize accessor functions
|
|
309
|
+
const accessors = {};
|
|
310
|
+
function pluck (data, name) {
|
|
311
|
+
const accessor = accessors[name] || (accessors[name] = field(name));
|
|
312
|
+
return isArray(data) ? data.map(accessor) : accessor(data);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function array(seq) {
|
|
316
|
+
return isArray(seq) || ArrayBuffer.isView(seq) ? seq : null;
|
|
317
|
+
}
|
|
318
|
+
function sequence(seq) {
|
|
319
|
+
return array(seq) || (isString(seq) ? seq : null);
|
|
320
|
+
}
|
|
321
|
+
function join(seq, ...args) {
|
|
322
|
+
return array(seq).join(...args);
|
|
323
|
+
}
|
|
324
|
+
function indexof(seq, ...args) {
|
|
325
|
+
return sequence(seq).indexOf(...args);
|
|
326
|
+
}
|
|
327
|
+
function lastindexof(seq, ...args) {
|
|
328
|
+
return sequence(seq).lastIndexOf(...args);
|
|
329
|
+
}
|
|
330
|
+
function slice(seq, ...args) {
|
|
331
|
+
return sequence(seq).slice(...args);
|
|
332
|
+
}
|
|
333
|
+
function replace(str, pattern, repl) {
|
|
334
|
+
if (isFunction(repl)) error('Function argument passed to replace.');
|
|
335
|
+
if (!isString(pattern) && !isRegExp(pattern)) error('Please pass a string or RegExp argument to replace.');
|
|
336
|
+
return String(str).replace(pattern, repl);
|
|
337
|
+
}
|
|
338
|
+
function reverse(seq) {
|
|
339
|
+
return array(seq).slice().reverse();
|
|
340
|
+
}
|
|
341
|
+
function sort(seq) {
|
|
342
|
+
return array(seq).slice().sort(ascending);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function bandspace(count, paddingInner, paddingOuter) {
|
|
346
|
+
return bandSpace(count || 0, paddingInner || 0, paddingOuter || 0);
|
|
347
|
+
}
|
|
348
|
+
function bandwidth(name, group) {
|
|
349
|
+
const s = getScale(name, (group || this).context);
|
|
350
|
+
return s && s.bandwidth ? s.bandwidth() : 0;
|
|
351
|
+
}
|
|
352
|
+
function copy(name, group) {
|
|
353
|
+
const s = getScale(name, (group || this).context);
|
|
354
|
+
return s ? s.copy() : undefined;
|
|
355
|
+
}
|
|
356
|
+
function domain(name, group) {
|
|
357
|
+
const s = getScale(name, (group || this).context);
|
|
358
|
+
return s ? s.domain() : [];
|
|
359
|
+
}
|
|
360
|
+
function invert(name, range, group) {
|
|
361
|
+
const s = getScale(name, (group || this).context);
|
|
362
|
+
return !s ? undefined : isArray(range) ? (s.invertRange || s.invert)(range) : (s.invert || s.invertExtent)(range);
|
|
363
|
+
}
|
|
364
|
+
function range(name, group) {
|
|
365
|
+
const s = getScale(name, (group || this).context);
|
|
366
|
+
return s && s.range ? s.range() : [];
|
|
367
|
+
}
|
|
368
|
+
function scale(name, value, group) {
|
|
369
|
+
const s = getScale(name, (group || this).context);
|
|
370
|
+
return s ? s(value) : undefined;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function scaleGradient (scale, p0, p1, count, group) {
|
|
374
|
+
scale = getScale(scale, (group || this).context);
|
|
375
|
+
const gradient = Gradient(p0, p1);
|
|
376
|
+
let stops = scale.domain(),
|
|
377
|
+
min = stops[0],
|
|
378
|
+
max = peek(stops),
|
|
379
|
+
fraction = identity;
|
|
380
|
+
if (!(max - min)) {
|
|
381
|
+
// expand scale if domain has zero span, fix #1479
|
|
382
|
+
scale = (scale.interpolator ? scale$1('sequential')().interpolator(scale.interpolator()) : scale$1('linear')().interpolate(scale.interpolate()).range(scale.range())).domain([min = 0, max = 1]);
|
|
383
|
+
} else {
|
|
384
|
+
fraction = scaleFraction(scale, min, max);
|
|
385
|
+
}
|
|
386
|
+
if (scale.ticks) {
|
|
387
|
+
stops = scale.ticks(+count || 15);
|
|
388
|
+
if (min !== stops[0]) stops.unshift(min);
|
|
389
|
+
if (max !== peek(stops)) stops.push(max);
|
|
390
|
+
}
|
|
391
|
+
stops.forEach(_ => gradient.stop(fraction(_), scale(_)));
|
|
392
|
+
return gradient;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function geoShape(projection, geojson, group) {
|
|
396
|
+
const p = getScale(projection, (group || this).context);
|
|
397
|
+
return function (context) {
|
|
398
|
+
return p ? p.path.context(context)(geojson) : '';
|
|
1633
399
|
};
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
// function context prefix
|
|
1640
|
-
astVisitors = {}; // AST visitors for dependency analysis
|
|
1641
|
-
|
|
1642
|
-
// export code generator parameters
|
|
1643
|
-
const codegenParams = {
|
|
1644
|
-
forbidden: ['_'],
|
|
1645
|
-
allowed: ['datum', 'event', 'item'],
|
|
1646
|
-
fieldvar: 'datum',
|
|
1647
|
-
globalvar: id => `_[${vegaUtil.stringValue(SignalPrefix + id)}]`,
|
|
1648
|
-
functions: buildFunctions,
|
|
1649
|
-
constants: vegaExpression.constants,
|
|
1650
|
-
visitors: astVisitors
|
|
400
|
+
}
|
|
401
|
+
function pathShape(path) {
|
|
402
|
+
let p = null;
|
|
403
|
+
return function (context) {
|
|
404
|
+
return context ? pathRender(context, p = p || pathParse(path)) : path;
|
|
1651
405
|
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const datum = d => d.data;
|
|
409
|
+
function treeNodes(name, context) {
|
|
410
|
+
const tree = data.call(context, name);
|
|
411
|
+
return tree.root && tree.root.lookup || {};
|
|
412
|
+
}
|
|
413
|
+
function treePath(name, source, target) {
|
|
414
|
+
const nodes = treeNodes(name, this),
|
|
415
|
+
s = nodes[source],
|
|
416
|
+
t = nodes[target];
|
|
417
|
+
return s && t ? s.path(t).map(datum) : undefined;
|
|
418
|
+
}
|
|
419
|
+
function treeAncestors(name, node) {
|
|
420
|
+
const n = treeNodes(name, this)[node];
|
|
421
|
+
return n ? n.ancestors().map(datum) : undefined;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const _window = () => typeof window !== 'undefined' && window || null;
|
|
425
|
+
function screen() {
|
|
426
|
+
const w = _window();
|
|
427
|
+
return w ? w.screen : {};
|
|
428
|
+
}
|
|
429
|
+
function windowSize() {
|
|
430
|
+
const w = _window();
|
|
431
|
+
return w ? [w.innerWidth, w.innerHeight] : [undefined, undefined];
|
|
432
|
+
}
|
|
433
|
+
function containerSize() {
|
|
434
|
+
const view = this.context.dataflow,
|
|
435
|
+
el = view.container && view.container();
|
|
436
|
+
return el ? [el.clientWidth, el.clientHeight] : [undefined, undefined];
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function intersect (b, opt, group) {
|
|
440
|
+
if (!b) return [];
|
|
441
|
+
const [u, v] = b,
|
|
442
|
+
box = new Bounds().set(u[0], u[1], v[0], v[1]),
|
|
443
|
+
scene = group || this.context.dataflow.scenegraph().root;
|
|
444
|
+
return intersect$1(scene, box, filter(opt));
|
|
445
|
+
}
|
|
446
|
+
function filter(opt) {
|
|
447
|
+
let p = null;
|
|
448
|
+
if (opt) {
|
|
449
|
+
const types = array$1(opt.marktype),
|
|
450
|
+
names = array$1(opt.markname);
|
|
451
|
+
p = _ => (!types.length || types.some(t => _.marktype === t)) && (!names.length || names.some(s => _.name === s));
|
|
452
|
+
}
|
|
453
|
+
return p;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Appends a new point to the lasso
|
|
458
|
+
*
|
|
459
|
+
* @param {*} lasso the lasso in pixel space
|
|
460
|
+
* @param {*} x the x coordinate in pixel space
|
|
461
|
+
* @param {*} y the y coordinate in pixel space
|
|
462
|
+
* @param {*} minDist the minimum distance, in pixels, that thenew point needs to be apart from the last point
|
|
463
|
+
* @returns a new array containing the lasso with the new point
|
|
464
|
+
*/
|
|
465
|
+
function lassoAppend(lasso, x, y, minDist = 5) {
|
|
466
|
+
lasso = array$1(lasso);
|
|
467
|
+
const last = lasso[lasso.length - 1];
|
|
468
|
+
|
|
469
|
+
// Add point to lasso if its the first point or distance to last point exceed minDist
|
|
470
|
+
return last === undefined || Math.hypot(last[0] - x, last[1] - y) > minDist ? [...lasso, [x, y]] : lasso;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Generates a svg path command which draws a lasso
|
|
475
|
+
*
|
|
476
|
+
* @param {*} lasso the lasso in pixel space in the form [[x,y], [x,y], ...]
|
|
477
|
+
* @returns the svg path command that draws the lasso
|
|
478
|
+
*/
|
|
479
|
+
function lassoPath(lasso) {
|
|
480
|
+
return array$1(lasso).reduce((svg, [x, y], i) => {
|
|
481
|
+
return svg += i == 0 ? `M ${x},${y} ` : i === lasso.length - 1 ? ' Z' : `L ${x},${y} `;
|
|
482
|
+
}, '');
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Inverts the lasso from pixel space to an array of vega scenegraph tuples
|
|
487
|
+
*
|
|
488
|
+
* @param {*} data the dataset
|
|
489
|
+
* @param {*} pixelLasso the lasso in pixel space, [[x,y], [x,y], ...]
|
|
490
|
+
* @param {*} unit the unit where the lasso is defined
|
|
491
|
+
*
|
|
492
|
+
* @returns an array of vega scenegraph tuples
|
|
493
|
+
*/
|
|
494
|
+
function intersectLasso(markname, pixelLasso, unit) {
|
|
495
|
+
const {
|
|
496
|
+
x,
|
|
497
|
+
y,
|
|
498
|
+
mark
|
|
499
|
+
} = unit;
|
|
500
|
+
const bb = new Bounds().set(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
|
|
501
|
+
|
|
502
|
+
// Get bounding box around lasso
|
|
503
|
+
for (const [px, py] of pixelLasso) {
|
|
504
|
+
if (px < bb.x1) bb.x1 = px;
|
|
505
|
+
if (px > bb.x2) bb.x2 = px;
|
|
506
|
+
if (py < bb.y1) bb.y1 = py;
|
|
507
|
+
if (py > bb.y2) bb.y2 = py;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Translate bb against unit coordinates
|
|
511
|
+
bb.translate(x, y);
|
|
512
|
+
const intersection = intersect([[bb.x1, bb.y1], [bb.x2, bb.y2]], markname, mark);
|
|
513
|
+
|
|
514
|
+
// Check every point against the lasso
|
|
515
|
+
return intersection.filter(tuple => pointInPolygon(tuple.x, tuple.y, pixelLasso));
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Performs a test if a point is inside a polygon based on the idea from
|
|
520
|
+
* https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
|
|
521
|
+
*
|
|
522
|
+
* This method will not need the same start/end point since it wraps around the edges of the array
|
|
523
|
+
*
|
|
524
|
+
* @param {*} test a point to test against
|
|
525
|
+
* @param {*} polygon a polygon in the form [[x,y], [x,y], ...]
|
|
526
|
+
* @returns true if the point lies inside the polygon, false otherwise
|
|
527
|
+
*/
|
|
528
|
+
function pointInPolygon(testx, testy, polygon) {
|
|
529
|
+
let intersections = 0;
|
|
530
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
531
|
+
const [prevX, prevY] = polygon[j];
|
|
532
|
+
const [x, y] = polygon[i];
|
|
533
|
+
|
|
534
|
+
// count intersections
|
|
535
|
+
if (y > testy != prevY > testy && testx < (prevX - x) * (testy - y) / (prevY - y) + x) {
|
|
536
|
+
intersections++;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// point is in polygon if intersection count is odd
|
|
541
|
+
return intersections & 1;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Expression function context object
|
|
545
|
+
const functionContext = {
|
|
546
|
+
random() {
|
|
547
|
+
return random();
|
|
548
|
+
},
|
|
549
|
+
// override default
|
|
550
|
+
cumulativeNormal,
|
|
551
|
+
cumulativeLogNormal,
|
|
552
|
+
cumulativeUniform,
|
|
553
|
+
densityNormal,
|
|
554
|
+
densityLogNormal,
|
|
555
|
+
densityUniform,
|
|
556
|
+
quantileNormal,
|
|
557
|
+
quantileLogNormal,
|
|
558
|
+
quantileUniform,
|
|
559
|
+
sampleNormal,
|
|
560
|
+
sampleLogNormal,
|
|
561
|
+
sampleUniform,
|
|
562
|
+
isArray,
|
|
563
|
+
isBoolean,
|
|
564
|
+
isDate,
|
|
565
|
+
isDefined(_) {
|
|
566
|
+
return _ !== undefined;
|
|
567
|
+
},
|
|
568
|
+
isNumber,
|
|
569
|
+
isObject,
|
|
570
|
+
isRegExp,
|
|
571
|
+
isString,
|
|
572
|
+
isTuple,
|
|
573
|
+
isValid(_) {
|
|
574
|
+
return _ != null && _ === _;
|
|
575
|
+
},
|
|
576
|
+
toBoolean,
|
|
577
|
+
toDate(_) {
|
|
578
|
+
return toDate(_);
|
|
579
|
+
},
|
|
580
|
+
// suppress extra arguments
|
|
581
|
+
toNumber,
|
|
582
|
+
toString,
|
|
583
|
+
indexof,
|
|
584
|
+
join,
|
|
585
|
+
lastindexof,
|
|
586
|
+
replace,
|
|
587
|
+
reverse,
|
|
588
|
+
sort,
|
|
589
|
+
slice,
|
|
590
|
+
flush,
|
|
591
|
+
lerp,
|
|
592
|
+
merge,
|
|
593
|
+
pad,
|
|
594
|
+
peek,
|
|
595
|
+
pluck,
|
|
596
|
+
span,
|
|
597
|
+
inrange,
|
|
598
|
+
truncate,
|
|
599
|
+
rgb,
|
|
600
|
+
lab,
|
|
601
|
+
hcl,
|
|
602
|
+
hsl,
|
|
603
|
+
luminance,
|
|
604
|
+
contrast,
|
|
605
|
+
sequence: range$1,
|
|
606
|
+
format,
|
|
607
|
+
utcFormat,
|
|
608
|
+
utcParse,
|
|
609
|
+
utcOffset,
|
|
610
|
+
utcSequence,
|
|
611
|
+
timeFormat,
|
|
612
|
+
timeParse,
|
|
613
|
+
timeOffset,
|
|
614
|
+
timeSequence,
|
|
615
|
+
timeUnitSpecifier,
|
|
616
|
+
monthFormat,
|
|
617
|
+
monthAbbrevFormat,
|
|
618
|
+
dayFormat,
|
|
619
|
+
dayAbbrevFormat,
|
|
620
|
+
quarter,
|
|
621
|
+
utcquarter,
|
|
622
|
+
week,
|
|
623
|
+
utcweek,
|
|
624
|
+
dayofyear,
|
|
625
|
+
utcdayofyear,
|
|
626
|
+
warn,
|
|
627
|
+
info,
|
|
628
|
+
debug,
|
|
629
|
+
extent(_) {
|
|
630
|
+
return extent(_);
|
|
631
|
+
},
|
|
632
|
+
// suppress extra arguments
|
|
633
|
+
inScope,
|
|
634
|
+
intersect,
|
|
635
|
+
clampRange,
|
|
636
|
+
pinchDistance,
|
|
637
|
+
pinchAngle,
|
|
638
|
+
screen,
|
|
639
|
+
containerSize,
|
|
640
|
+
windowSize,
|
|
641
|
+
bandspace,
|
|
642
|
+
setdata,
|
|
643
|
+
pathShape,
|
|
644
|
+
panLinear,
|
|
645
|
+
panLog,
|
|
646
|
+
panPow,
|
|
647
|
+
panSymlog,
|
|
648
|
+
zoomLinear,
|
|
649
|
+
zoomLog,
|
|
650
|
+
zoomPow,
|
|
651
|
+
zoomSymlog,
|
|
652
|
+
encode,
|
|
653
|
+
modify,
|
|
654
|
+
lassoAppend,
|
|
655
|
+
lassoPath,
|
|
656
|
+
intersectLasso
|
|
657
|
+
};
|
|
658
|
+
const eventFunctions = ['view', 'item', 'group', 'xy', 'x', 'y'],
|
|
659
|
+
// event functions
|
|
660
|
+
eventPrefix = 'event.vega.',
|
|
661
|
+
// event function prefix
|
|
662
|
+
thisPrefix = 'this.',
|
|
663
|
+
// function context prefix
|
|
664
|
+
astVisitors = {}; // AST visitors for dependency analysis
|
|
665
|
+
|
|
666
|
+
// export code generator parameters
|
|
667
|
+
const codegenParams = {
|
|
668
|
+
forbidden: ['_'],
|
|
669
|
+
allowed: ['datum', 'event', 'item'],
|
|
670
|
+
fieldvar: 'datum',
|
|
671
|
+
globalvar: id => `_[${stringValue(SignalPrefix + id)}]`,
|
|
672
|
+
functions: buildFunctions,
|
|
673
|
+
constants: constants,
|
|
674
|
+
visitors: astVisitors
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
// export code generator
|
|
678
|
+
const codeGenerator = codegenExpression(codegenParams);
|
|
679
|
+
|
|
680
|
+
// Build expression function registry
|
|
681
|
+
function buildFunctions(codegen) {
|
|
682
|
+
const fn = functions(codegen);
|
|
683
|
+
eventFunctions.forEach(name => fn[name] = eventPrefix + name);
|
|
684
|
+
for (const name in functionContext) {
|
|
685
|
+
fn[name] = thisPrefix + name;
|
|
686
|
+
}
|
|
687
|
+
extend(fn, internalScaleFunctions(codegen, functionContext, astVisitors));
|
|
688
|
+
return fn;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Register an expression function
|
|
692
|
+
function expressionFunction(name, fn, visitor) {
|
|
693
|
+
if (arguments.length === 1) {
|
|
694
|
+
return functionContext[name];
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// register with the functionContext
|
|
698
|
+
functionContext[name] = fn;
|
|
699
|
+
|
|
700
|
+
// if there is an astVisitor register that, too
|
|
701
|
+
if (visitor) astVisitors[name] = visitor;
|
|
702
|
+
|
|
703
|
+
// if the code generator has already been initialized,
|
|
704
|
+
// we need to also register the function with it
|
|
705
|
+
if (codeGenerator) codeGenerator.functions[name] = thisPrefix + name;
|
|
706
|
+
return this;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// register expression functions with ast visitors
|
|
710
|
+
expressionFunction('bandwidth', bandwidth, scaleVisitor);
|
|
711
|
+
expressionFunction('copy', copy, scaleVisitor);
|
|
712
|
+
expressionFunction('domain', domain, scaleVisitor);
|
|
713
|
+
expressionFunction('range', range, scaleVisitor);
|
|
714
|
+
expressionFunction('invert', invert, scaleVisitor);
|
|
715
|
+
expressionFunction('scale', scale, scaleVisitor);
|
|
716
|
+
expressionFunction('gradient', scaleGradient, scaleVisitor);
|
|
717
|
+
expressionFunction('geoArea', geoArea, scaleVisitor);
|
|
718
|
+
expressionFunction('geoBounds', geoBounds, scaleVisitor);
|
|
719
|
+
expressionFunction('geoCentroid', geoCentroid, scaleVisitor);
|
|
720
|
+
expressionFunction('geoShape', geoShape, scaleVisitor);
|
|
721
|
+
expressionFunction('geoScale', geoScale, scaleVisitor);
|
|
722
|
+
expressionFunction('indata', indata, indataVisitor);
|
|
723
|
+
expressionFunction('data', data, dataVisitor);
|
|
724
|
+
expressionFunction('treePath', treePath, dataVisitor);
|
|
725
|
+
expressionFunction('treeAncestors', treeAncestors, dataVisitor);
|
|
726
|
+
|
|
727
|
+
// register Vega-Lite selection functions
|
|
728
|
+
expressionFunction('vlSelectionTest', selectionTest, selectionVisitor);
|
|
729
|
+
expressionFunction('vlSelectionIdTest', selectionIdTest, selectionVisitor);
|
|
730
|
+
expressionFunction('vlSelectionResolve', selectionResolve, selectionVisitor);
|
|
731
|
+
expressionFunction('vlSelectionTuples', selectionTuples);
|
|
732
|
+
|
|
733
|
+
function parser (expr, scope) {
|
|
734
|
+
const params = {};
|
|
735
|
+
|
|
736
|
+
// parse the expression to an abstract syntax tree (ast)
|
|
737
|
+
let ast;
|
|
738
|
+
try {
|
|
739
|
+
expr = isString(expr) ? expr : stringValue(expr) + '';
|
|
740
|
+
ast = parseExpression(expr);
|
|
741
|
+
} catch (err) {
|
|
742
|
+
error('Expression parse error: ' + expr);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// analyze ast function calls for dependencies
|
|
746
|
+
ast.visit(node => {
|
|
747
|
+
if (node.type !== CallExpression) return;
|
|
748
|
+
const name = node.callee.name,
|
|
749
|
+
visit = codegenParams.visitors[name];
|
|
750
|
+
if (visit) visit(name, node.arguments, scope, params);
|
|
751
|
+
});
|
|
1652
752
|
|
|
1653
|
-
//
|
|
1654
|
-
const
|
|
1655
|
-
|
|
1656
|
-
// Build expression function registry
|
|
1657
|
-
function buildFunctions(codegen) {
|
|
1658
|
-
const fn = vegaExpression.functions(codegen);
|
|
1659
|
-
eventFunctions.forEach(name => fn[name] = eventPrefix + name);
|
|
1660
|
-
for (const name in functionContext) {
|
|
1661
|
-
fn[name] = thisPrefix + name;
|
|
1662
|
-
}
|
|
1663
|
-
vegaUtil.extend(fn, internalScaleFunctions(codegen, functionContext, astVisitors));
|
|
1664
|
-
return fn;
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
// Register an expression function
|
|
1668
|
-
function expressionFunction(name, fn, visitor) {
|
|
1669
|
-
if (arguments.length === 1) {
|
|
1670
|
-
return functionContext[name];
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
// register with the functionContext
|
|
1674
|
-
functionContext[name] = fn;
|
|
1675
|
-
|
|
1676
|
-
// if there is an astVisitor register that, too
|
|
1677
|
-
if (visitor) astVisitors[name] = visitor;
|
|
1678
|
-
|
|
1679
|
-
// if the code generator has already been initialized,
|
|
1680
|
-
// we need to also register the function with it
|
|
1681
|
-
if (codeGenerator) codeGenerator.functions[name] = thisPrefix + name;
|
|
1682
|
-
return this;
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
// register expression functions with ast visitors
|
|
1686
|
-
expressionFunction('bandwidth', bandwidth, scaleVisitor);
|
|
1687
|
-
expressionFunction('copy', copy, scaleVisitor);
|
|
1688
|
-
expressionFunction('domain', domain, scaleVisitor);
|
|
1689
|
-
expressionFunction('range', range, scaleVisitor);
|
|
1690
|
-
expressionFunction('invert', invert, scaleVisitor);
|
|
1691
|
-
expressionFunction('scale', scale, scaleVisitor);
|
|
1692
|
-
expressionFunction('gradient', scaleGradient, scaleVisitor);
|
|
1693
|
-
expressionFunction('geoArea', geoArea, scaleVisitor);
|
|
1694
|
-
expressionFunction('geoBounds', geoBounds, scaleVisitor);
|
|
1695
|
-
expressionFunction('geoCentroid', geoCentroid, scaleVisitor);
|
|
1696
|
-
expressionFunction('geoShape', geoShape, scaleVisitor);
|
|
1697
|
-
expressionFunction('geoScale', geoScale, scaleVisitor);
|
|
1698
|
-
expressionFunction('indata', indata, indataVisitor);
|
|
1699
|
-
expressionFunction('data', data, dataVisitor);
|
|
1700
|
-
expressionFunction('treePath', treePath, dataVisitor);
|
|
1701
|
-
expressionFunction('treeAncestors', treeAncestors, dataVisitor);
|
|
1702
|
-
|
|
1703
|
-
// register Vega-Lite selection functions
|
|
1704
|
-
expressionFunction('vlSelectionTest', vegaSelections.selectionTest, vegaSelections.selectionVisitor);
|
|
1705
|
-
expressionFunction('vlSelectionIdTest', vegaSelections.selectionIdTest, vegaSelections.selectionVisitor);
|
|
1706
|
-
expressionFunction('vlSelectionResolve', vegaSelections.selectionResolve, vegaSelections.selectionVisitor);
|
|
1707
|
-
expressionFunction('vlSelectionTuples', vegaSelections.selectionTuples);
|
|
1708
|
-
|
|
1709
|
-
function parser (expr, scope) {
|
|
1710
|
-
const params = {};
|
|
753
|
+
// perform code generation
|
|
754
|
+
const gen = codeGenerator(ast);
|
|
1711
755
|
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
} catch (err) {
|
|
1718
|
-
vegaUtil.error('Expression parse error: ' + expr);
|
|
756
|
+
// collect signal dependencies
|
|
757
|
+
gen.globals.forEach(name => {
|
|
758
|
+
const signalName = SignalPrefix + name;
|
|
759
|
+
if (!hasOwnProperty(params, signalName) && scope.getSignal(name)) {
|
|
760
|
+
params[signalName] = scope.signalRef(name);
|
|
1719
761
|
}
|
|
762
|
+
});
|
|
1720
763
|
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
})
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
// collect signal dependencies
|
|
1733
|
-
gen.globals.forEach(name => {
|
|
1734
|
-
const signalName = SignalPrefix + name;
|
|
1735
|
-
if (!vegaUtil.hasOwnProperty(params, signalName) && scope.getSignal(name)) {
|
|
1736
|
-
params[signalName] = scope.signalRef(name);
|
|
1737
|
-
}
|
|
1738
|
-
});
|
|
1739
|
-
|
|
1740
|
-
// return generated expression code and dependencies
|
|
1741
|
-
return {
|
|
1742
|
-
$expr: vegaUtil.extend({
|
|
1743
|
-
code: gen.code
|
|
1744
|
-
}, scope.options.ast ? {
|
|
1745
|
-
ast
|
|
1746
|
-
} : null),
|
|
1747
|
-
$fields: gen.fields,
|
|
1748
|
-
$params: params
|
|
1749
|
-
};
|
|
1750
|
-
}
|
|
1751
|
-
|
|
1752
|
-
exports.DataPrefix = DataPrefix;
|
|
1753
|
-
exports.IndexPrefix = IndexPrefix;
|
|
1754
|
-
exports.ScalePrefix = ScalePrefix;
|
|
1755
|
-
exports.SignalPrefix = SignalPrefix;
|
|
1756
|
-
exports.bandspace = bandspace;
|
|
1757
|
-
exports.bandwidth = bandwidth;
|
|
1758
|
-
exports.codeGenerator = codeGenerator;
|
|
1759
|
-
exports.codegenParams = codegenParams;
|
|
1760
|
-
exports.containerSize = containerSize;
|
|
1761
|
-
exports.contrast = contrast;
|
|
1762
|
-
exports.copy = copy;
|
|
1763
|
-
exports.data = data;
|
|
1764
|
-
exports.dataVisitor = dataVisitor;
|
|
1765
|
-
exports.dayAbbrevFormat = dayAbbrevFormat;
|
|
1766
|
-
exports.dayFormat = dayFormat;
|
|
1767
|
-
exports.debug = debug;
|
|
1768
|
-
exports.domain = domain;
|
|
1769
|
-
exports.encode = encode;
|
|
1770
|
-
exports.expressionFunction = expressionFunction;
|
|
1771
|
-
exports.format = format;
|
|
1772
|
-
exports.functionContext = functionContext;
|
|
1773
|
-
exports.geoArea = geoArea;
|
|
1774
|
-
exports.geoBounds = geoBounds;
|
|
1775
|
-
exports.geoCentroid = geoCentroid;
|
|
1776
|
-
exports.geoScale = geoScale;
|
|
1777
|
-
exports.geoShape = geoShape;
|
|
1778
|
-
exports.inScope = inScope;
|
|
1779
|
-
exports.indata = indata;
|
|
1780
|
-
exports.indataVisitor = indataVisitor;
|
|
1781
|
-
exports.indexof = indexof;
|
|
1782
|
-
exports.info = info;
|
|
1783
|
-
exports.invert = invert;
|
|
1784
|
-
exports.join = join;
|
|
1785
|
-
exports.lastindexof = lastindexof;
|
|
1786
|
-
exports.luminance = luminance;
|
|
1787
|
-
exports.merge = merge;
|
|
1788
|
-
exports.modify = modify;
|
|
1789
|
-
exports.monthAbbrevFormat = monthAbbrevFormat;
|
|
1790
|
-
exports.monthFormat = monthFormat;
|
|
1791
|
-
exports.parseExpression = parser;
|
|
1792
|
-
exports.pathShape = pathShape;
|
|
1793
|
-
exports.pinchAngle = pinchAngle;
|
|
1794
|
-
exports.pinchDistance = pinchDistance;
|
|
1795
|
-
exports.pluck = pluck;
|
|
1796
|
-
exports.range = range;
|
|
1797
|
-
exports.replace = replace;
|
|
1798
|
-
exports.reverse = reverse;
|
|
1799
|
-
exports.scale = scale;
|
|
1800
|
-
exports.scaleGradient = scaleGradient;
|
|
1801
|
-
exports.scaleVisitor = scaleVisitor;
|
|
1802
|
-
exports.screen = screen;
|
|
1803
|
-
exports.setdata = setdata;
|
|
1804
|
-
exports.slice = slice;
|
|
1805
|
-
exports.sort = sort;
|
|
1806
|
-
exports.timeFormat = timeFormat;
|
|
1807
|
-
exports.timeParse = timeParse;
|
|
1808
|
-
exports.treeAncestors = treeAncestors;
|
|
1809
|
-
exports.treePath = treePath;
|
|
1810
|
-
exports.utcFormat = utcFormat;
|
|
1811
|
-
exports.utcParse = utcParse;
|
|
1812
|
-
exports.warn = warn;
|
|
1813
|
-
exports.windowSize = windowSize;
|
|
764
|
+
// return generated expression code and dependencies
|
|
765
|
+
return {
|
|
766
|
+
$expr: extend({
|
|
767
|
+
code: gen.code
|
|
768
|
+
}, scope.options.ast ? {
|
|
769
|
+
ast
|
|
770
|
+
} : null),
|
|
771
|
+
$fields: gen.fields,
|
|
772
|
+
$params: params
|
|
773
|
+
};
|
|
774
|
+
}
|
|
1814
775
|
|
|
1815
|
-
}
|
|
776
|
+
export { DataPrefix, IndexPrefix, ScalePrefix, SignalPrefix, bandspace, bandwidth, codeGenerator, codegenParams, containerSize, contrast, copy, data, dataVisitor, dayAbbrevFormat, dayFormat, debug, domain, encode, expressionFunction, format, functionContext, geoArea, geoBounds, geoCentroid, geoScale, geoShape, inScope, indata, indataVisitor, indexof, info, invert, join, lastindexof, luminance, merge, modify, monthAbbrevFormat, monthFormat, parser as parseExpression, pathShape, pinchAngle, pinchDistance, pluck, range, replace, reverse, scale, scaleGradient, scaleVisitor, screen, setdata, slice, sort, timeFormat, timeParse, treeAncestors, treePath, utcFormat, utcParse, warn, windowSize };
|
|
777
|
+
//# sourceMappingURL=vega-functions.js.map
|