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