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.

@@ -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('d3-geo'), require('d3-color'), require('vega-dataflow'), require('vega-scale'), require('vega-scenegraph'), require('vega-selections'), require('vega-statistics'), require('vega-time'), require('d3-array')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'vega-util', 'vega-expression', 'd3-geo', 'd3-color', 'vega-dataflow', 'vega-scale', 'vega-scenegraph', 'vega-selections', 'vega-statistics', 'vega-time', 'd3-array'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vega = {}, global.vega, global.vega, global.d3, global.d3, global.vega, global.vega, global.vega, global.vega, global.vega, global.vega, global.d3));
5
- }(this, (function (exports, vegaUtil, vegaExpression, d3Geo, d3Color, vegaDataflow, vegaScale, vegaScenegraph, vegaSelections, vegaStatistics, vegaTime, d3Array) { 'use strict';
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
- entry = index ? index.value.get(value) : undefined;
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
- data = this.context.data[name],
19
- input = data.input;
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
- target = item.mark.source;
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
- dataName = DataPrefix + data;
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) {// if data set does not exist, there's nothing to track
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
- field = args[1].value,
92
- indexName = IndexPrefix + field;
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) {// TODO: error handling? warning?
108
+ } catch (err) {
109
+ // TODO: error handling? warning?
117
110
  }
118
111
  }
119
112
  }
120
113
 
121
- function getScale(name, ctx) {
122
- let s;
123
- return vegaUtil.isFunction(name) ? name : vegaUtil.isString(name) ? (s = ctx.scales[name]) && s.value : undefined;
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; // register AST visitors for internal scale functions
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; // resolve scale reference directly to the signal hash argument
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 geoArea = geoMethod('area', d3Geo.geoArea);
159
- const geoBounds = geoMethod('bounds', d3Geo.geoBounds);
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 = d3Color.rgb(color),
208
- r = channel_luminance_value(c.r),
209
- g = channel_luminance_value(c.g),
210
- b = channel_luminance_value(c.b);
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
- } // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
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
- lum2 = luminance(color2),
217
- lumL = Math.max(lum1, lum2),
218
- lumD = Math.min(lum1, lum2);
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
- data = this.context.data[name],
255
- input = data.input,
256
- stamp = df.stamp();
1225
+ data = this.context.data[name],
1226
+ input = data.input,
1227
+ stamp = df.stamp();
257
1228
  let changes = data.changes,
258
- predicate,
259
- key;
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
- dx = t[0].clientX - t[1].clientX,
306
- dy = t[0].clientY - t[1].clientY;
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
- min = stops[0],
381
- max = vegaUtil.peek(stops),
382
- fraction = vegaUtil.identity;
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
- s = nodes[source],
424
- t = nodes[target];
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
- el = view.container && view.container();
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
- box = new vegaScenegraph.Bounds().set(u[0], u[1], v[0], v[1]),
454
- scene = group || this.context.dataflow.scenegraph().root;
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
- names = vegaUtil.array(opt.markname);
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: vegaUtil.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: d3Color.rgb,
527
- lab: d3Color.lab,
528
- hcl: d3Color.hcl,
529
- hsl: d3Color.hsl,
1563
+ rgb,
1564
+ lab,
1565
+ hcl,
1566
+ hsl,
530
1567
  luminance,
531
1568
  contrast,
532
- sequence: d3Array.range,
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: vegaUtil.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
- // event functions
581
- eventPrefix = 'event.vega.',
582
- // event function prefix
583
- thisPrefix = 'this.',
584
- // function context prefix
585
- astVisitors = {}; // AST visitors for dependency analysis
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
- }; // export code generator
1639
+ };
597
1640
 
598
- const codeGenerator = vegaExpression.codegenExpression(codegenParams); // Build expression function registry
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
- } // Register an expression function
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
- } // register with the functionContext
1659
+ }
617
1660
 
1661
+ // register with the functionContext
1662
+ functionContext[name] = fn;
618
1663
 
619
- functionContext[name] = fn; // if there is an astVisitor register that, too
1664
+ // if there is an astVisitor register that, too
1665
+ if (visitor) astVisitors[name] = visitor;
620
1666
 
621
- if (visitor) astVisitors[name] = visitor; // if the code generator has already been initialized,
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
- } // register expression functions with ast visitors
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); // register Vega-Lite selection functions
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 = {}; // parse the expression to an abstract syntax tree (ast)
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
- } // analyze ast function calls for dependencies
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
- visit = codegenParams.visitors[name];
1712
+ visit = codegenParams.visitors[name];
666
1713
  if (visit) visit(name, node.arguments, scope, params);
667
- }); // perform code generation
1714
+ });
668
1715
 
669
- const gen = codeGenerator(ast); // collect signal dependencies
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
- }); // return generated expression code and dependencies
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
- Object.defineProperty(exports, '__esModule', { value: true });
752
-
753
- })));
1800
+ }));