vega-functions 5.13.0 → 5.13.2

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,9 +1,9 @@
1
1
  import { truthy, error, hasOwnProperty, isFunction, isString, stringValue, extend, isArray, isObject, field, peek, identity, array as array$1, isBoolean, isDate, isNumber, isRegExp, toBoolean, toDate, toNumber, toString, flush, lerp, pad, span, inrange, truncate, quarter, utcquarter, extent, clampRange, panLinear, panLog, panPow, panSymlog, zoomLinear, zoomLog, zoomPow, zoomSymlog } from 'vega-util';
2
2
  import { Literal, codegenExpression, constants, functions, parseExpression, CallExpression } from 'vega-expression';
3
- import { geoBounds as geoBounds$1, geoCentroid as geoCentroid$1, geoArea as geoArea$1 } from 'd3-geo';
3
+ import { isRegisteredScale, bandSpace, scale as scale$1, scaleFraction } from 'vega-scale';
4
+ import { geoArea as geoArea$1, geoBounds as geoBounds$1, geoCentroid as geoCentroid$1 } from 'd3-geo';
4
5
  import { rgb, lab, hcl, hsl } from 'd3-color';
5
6
  import { isTuple } from 'vega-dataflow';
6
- import { bandSpace, scale as scale$1, scaleFraction } from 'vega-scale';
7
7
  import { Gradient, pathRender, pathParse, Bounds, intersect as intersect$1 } from 'vega-scenegraph';
8
8
  import { selectionVisitor, selectionTest, selectionIdTest, selectionResolve, selectionTuples } from 'vega-selections';
9
9
  import { random, cumulativeNormal, cumulativeLogNormal, cumulativeUniform, densityNormal, densityLogNormal, densityUniform, quantileNormal, quantileLogNormal, quantileUniform, sampleNormal, sampleLogNormal, sampleUniform } from 'vega-statistics';
@@ -16,13 +16,13 @@ function data(name) {
16
16
  }
17
17
  function indata(name, field, value) {
18
18
  const index = this.context.data[name]['index:' + field],
19
- entry = index ? index.value.get(value) : undefined;
19
+ entry = index ? index.value.get(value) : undefined;
20
20
  return entry ? entry.count : entry;
21
21
  }
22
22
  function setdata(name, tuples) {
23
23
  const df = this.context.dataflow,
24
- data = this.context.data[name],
25
- input = data.input;
24
+ data = this.context.data[name],
25
+ input = data.input;
26
26
  df.pulse(input, df.changeset().remove(truthy).insert(tuples));
27
27
  return 1;
28
28
  }
@@ -30,10 +30,9 @@ function setdata(name, tuples) {
30
30
  function encode (item, name, retval) {
31
31
  if (item) {
32
32
  const df = this.context.dataflow,
33
- target = item.mark.source;
33
+ target = item.mark.source;
34
34
  df.pulse(target, df.changeset().encode(item, name));
35
35
  }
36
-
37
36
  return retval !== undefined ? retval : item;
38
37
  }
39
38
 
@@ -41,14 +40,12 @@ const wrap = method => function (value, spec) {
41
40
  const locale = this.context.dataflow.locale();
42
41
  return locale[method](spec)(value);
43
42
  };
44
-
45
43
  const format = wrap('format');
46
44
  const timeFormat = wrap('timeFormat');
47
45
  const utcFormat = wrap('utcFormat');
48
46
  const timeParse = wrap('timeParse');
49
47
  const utcParse = wrap('utcParse');
50
48
  const dateObj = new Date(2000, 0, 1);
51
-
52
49
  function time(month, day, specifier) {
53
50
  if (!Number.isInteger(month) || !Number.isInteger(day)) return '';
54
51
  dateObj.setYear(2000);
@@ -56,7 +53,6 @@ function time(month, day, specifier) {
56
53
  dateObj.setDate(day);
57
54
  return timeFormat.call(this, dateObj, specifier);
58
55
  }
59
-
60
56
  function monthFormat(month) {
61
57
  return time.call(this, month, 1, '%B');
62
58
  }
@@ -79,14 +75,13 @@ function dataVisitor(name, args, scope, params) {
79
75
  if (args[0].type !== Literal) {
80
76
  error('First argument to data functions must be a string literal.');
81
77
  }
82
-
83
78
  const data = args[0].value,
84
- dataName = DataPrefix + data;
85
-
79
+ dataName = DataPrefix + data;
86
80
  if (!hasOwnProperty(dataName, params)) {
87
81
  try {
88
82
  params[dataName] = scope.getData(data).tuplesRef();
89
- } catch (err) {// if data set does not exist, there's nothing to track
83
+ } catch (err) {
84
+ // if data set does not exist, there's nothing to track
90
85
  }
91
86
  }
92
87
  }
@@ -94,9 +89,8 @@ function indataVisitor(name, args, scope, params) {
94
89
  if (args[0].type !== Literal) error('First argument to indata must be a string literal.');
95
90
  if (args[1].type !== Literal) error('Second argument to indata must be a string literal.');
96
91
  const data = args[0].value,
97
- field = args[1].value,
98
- indexName = IndexPrefix + field;
99
-
92
+ field = args[1].value,
93
+ indexName = IndexPrefix + field;
100
94
  if (!hasOwnProperty(indexName, params)) {
101
95
  params[indexName] = scope.getData(data).indataRef(scope, field);
102
96
  }
@@ -112,39 +106,45 @@ function scaleVisitor(name, args, scope, params) {
112
106
  }
113
107
  }
114
108
  }
115
-
116
109
  function addScaleDependency(scope, params, name) {
117
110
  const scaleName = ScalePrefix + name;
118
-
119
111
  if (!hasOwnProperty(params, scaleName)) {
120
112
  try {
121
113
  params[scaleName] = scope.scaleRef(name);
122
- } catch (err) {// TODO: error handling? warning?
114
+ } catch (err) {
115
+ // TODO: error handling? warning?
123
116
  }
124
117
  }
125
118
  }
126
119
 
127
- function getScale(name, ctx) {
128
- let s;
129
- return isFunction(name) ? name : isString(name) ? (s = ctx.scales[name]) && s.value : undefined;
120
+ function getScale(nameOrFunction, ctx) {
121
+ if (isFunction(nameOrFunction)) {
122
+ return nameOrFunction;
123
+ }
124
+ if (isString(nameOrFunction)) {
125
+ const maybeScale = ctx.scales[nameOrFunction];
126
+ return maybeScale && isRegisteredScale(maybeScale.value) ? maybeScale.value : undefined;
127
+ }
128
+ return undefined;
130
129
  }
131
130
  function internalScaleFunctions(codegen, fnctx, visitors) {
132
131
  // add helper method to the 'this' expression function context
133
- fnctx.__bandwidth = s => s && s.bandwidth ? s.bandwidth() : 0; // register AST visitors for internal scale functions
134
-
132
+ fnctx.__bandwidth = s => s && s.bandwidth ? s.bandwidth() : 0;
135
133
 
134
+ // register AST visitors for internal scale functions
136
135
  visitors._bandwidth = scaleVisitor;
137
136
  visitors._range = scaleVisitor;
138
- visitors._scale = scaleVisitor; // resolve scale reference directly to the signal hash argument
139
-
140
- const ref = arg => '_[' + (arg.type === Literal ? stringValue(ScalePrefix + arg.value) : stringValue(ScalePrefix) + '+' + codegen(arg)) + ']'; // define and return internal scale function code generators
141
- // these internal functions are called by mark encoders
137
+ visitors._scale = scaleVisitor;
142
138
 
139
+ // resolve scale reference directly to the signal hash argument
140
+ const ref = arg => '_[' + (arg.type === Literal ? stringValue(ScalePrefix + arg.value) : stringValue(ScalePrefix) + '+' + codegen(arg)) + ']';
143
141
 
142
+ // define and return internal scale function code generators
143
+ // these internal functions are called by mark encoders
144
144
  return {
145
- _bandwidth: args => "this.__bandwidth(".concat(ref(args[0]), ")"),
146
- _range: args => "".concat(ref(args[0]), ".range()"),
147
- _scale: args => "".concat(ref(args[0]), "(").concat(codegen(args[1]), ")")
145
+ _bandwidth: args => `this.__bandwidth(${ref(args[0])})`,
146
+ _range: args => `${ref(args[0])}.range()`,
147
+ _scale: args => `${ref(args[0])}(${codegen(args[1])})`
148
148
  };
149
149
  }
150
150
 
@@ -160,7 +160,6 @@ function geoMethod(methodName, globalMethod) {
160
160
  }
161
161
  };
162
162
  }
163
-
164
163
  const geoArea = geoMethod('area', geoArea$1);
165
164
  const geoBounds = geoMethod('bounds', geoBounds$1);
166
165
  const geoCentroid = geoMethod('centroid', geoCentroid$1);
@@ -173,7 +172,6 @@ function inScope (item) {
173
172
  value = true;
174
173
  break;
175
174
  }
176
-
177
175
  item = item.mark.group;
178
176
  }
179
177
  return value;
@@ -185,10 +183,8 @@ function log(df, method, args) {
185
183
  } catch (err) {
186
184
  df.warn(err);
187
185
  }
188
-
189
186
  return args[args.length - 1];
190
187
  }
191
-
192
188
  function warn() {
193
189
  return log(this.context.dataflow, 'warn', arguments);
194
190
  }
@@ -199,29 +195,28 @@ function debug() {
199
195
  return log(this.context.dataflow, 'debug', arguments);
200
196
  }
201
197
 
198
+ // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
202
199
  function channel_luminance_value(channelValue) {
203
200
  const val = channelValue / 255;
204
-
205
201
  if (val <= 0.03928) {
206
202
  return val / 12.92;
207
203
  }
208
-
209
204
  return Math.pow((val + 0.055) / 1.055, 2.4);
210
205
  }
211
-
212
206
  function luminance(color) {
213
207
  const c = rgb(color),
214
- r = channel_luminance_value(c.r),
215
- g = channel_luminance_value(c.g),
216
- b = channel_luminance_value(c.b);
208
+ r = channel_luminance_value(c.r),
209
+ g = channel_luminance_value(c.g),
210
+ b = channel_luminance_value(c.b);
217
211
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
218
- } // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
212
+ }
219
213
 
214
+ // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
220
215
  function contrast(color1, color2) {
221
216
  const lum1 = luminance(color1),
222
- lum2 = luminance(color2),
223
- lumL = Math.max(lum1, lum2),
224
- lumD = Math.min(lum1, lum2);
217
+ lum2 = luminance(color2),
218
+ lumL = Math.max(lum1, lum2),
219
+ lumD = Math.min(lum1, lum2);
225
220
  return (lumL + 0.05) / (lumD + 0.05);
226
221
  }
227
222
 
@@ -234,41 +229,33 @@ function merge () {
234
229
  function equal(a, b) {
235
230
  return a === b || a !== a && b !== b ? true : isArray(a) ? isArray(b) && a.length === b.length ? equalArray(a, b) : false : isObject(a) && isObject(b) ? equalObject(a, b) : false;
236
231
  }
237
-
238
232
  function equalArray(a, b) {
239
233
  for (let i = 0, n = a.length; i < n; ++i) {
240
234
  if (!equal(a[i], b[i])) return false;
241
235
  }
242
-
243
236
  return true;
244
237
  }
245
-
246
238
  function equalObject(a, b) {
247
239
  for (const key in a) {
248
240
  if (!equal(a[key], b[key])) return false;
249
241
  }
250
-
251
242
  return true;
252
243
  }
253
-
254
244
  function removePredicate(props) {
255
245
  return _ => equalObject(props, _);
256
246
  }
257
-
258
247
  function modify (name, insert, remove, toggle, modify, values) {
259
248
  const df = this.context.dataflow,
260
- data = this.context.data[name],
261
- input = data.input,
262
- stamp = df.stamp();
249
+ data = this.context.data[name],
250
+ input = data.input,
251
+ stamp = df.stamp();
263
252
  let changes = data.changes,
264
- predicate,
265
- key;
266
-
253
+ predicate,
254
+ key;
267
255
  if (df._trigger === false || !(input.value.length || insert || toggle)) {
268
256
  // nothing to do!
269
257
  return 0;
270
258
  }
271
-
272
259
  if (!changes || changes.stamp < stamp) {
273
260
  data.changes = changes = df.changeset();
274
261
  changes.stamp = stamp;
@@ -277,46 +264,41 @@ function modify (name, insert, remove, toggle, modify, values) {
277
264
  df.pulse(input, changes).run();
278
265
  }, true, 1);
279
266
  }
280
-
281
267
  if (remove) {
282
268
  predicate = remove === true ? truthy : isArray(remove) || isTuple(remove) ? remove : removePredicate(remove);
283
269
  changes.remove(predicate);
284
270
  }
285
-
286
271
  if (insert) {
287
272
  changes.insert(insert);
288
273
  }
289
-
290
274
  if (toggle) {
291
275
  predicate = removePredicate(toggle);
292
-
293
276
  if (input.value.some(predicate)) {
294
277
  changes.remove(predicate);
295
278
  } else {
296
279
  changes.insert(toggle);
297
280
  }
298
281
  }
299
-
300
282
  if (modify) {
301
283
  for (key in values) {
302
284
  changes.modify(modify, key, values[key]);
303
285
  }
304
286
  }
305
-
306
287
  return 1;
307
288
  }
308
289
 
309
290
  function pinchDistance(event) {
310
291
  const t = event.touches,
311
- dx = t[0].clientX - t[1].clientX,
312
- dy = t[0].clientY - t[1].clientY;
313
- return Math.sqrt(dx * dx + dy * dy);
292
+ dx = t[0].clientX - t[1].clientX,
293
+ dy = t[0].clientY - t[1].clientY;
294
+ return Math.hypot(dx, dy);
314
295
  }
315
296
  function pinchAngle(event) {
316
297
  const t = event.touches;
317
298
  return Math.atan2(t[0].clientY - t[1].clientY, t[0].clientX - t[1].clientX);
318
299
  }
319
300
 
301
+ // memoize accessor functions
320
302
  const accessors = {};
321
303
  function pluck (data, name) {
322
304
  const accessor = accessors[name] || (accessors[name] = field(name));
@@ -326,37 +308,31 @@ function pluck (data, name) {
326
308
  function array(seq) {
327
309
  return isArray(seq) || ArrayBuffer.isView(seq) ? seq : null;
328
310
  }
329
-
330
311
  function sequence(seq) {
331
312
  return array(seq) || (isString(seq) ? seq : null);
332
313
  }
333
-
334
314
  function join(seq) {
335
315
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
336
316
  args[_key - 1] = arguments[_key];
337
317
  }
338
-
339
318
  return array(seq).join(...args);
340
319
  }
341
320
  function indexof(seq) {
342
321
  for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
343
322
  args[_key2 - 1] = arguments[_key2];
344
323
  }
345
-
346
324
  return sequence(seq).indexOf(...args);
347
325
  }
348
326
  function lastindexof(seq) {
349
327
  for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
350
328
  args[_key3 - 1] = arguments[_key3];
351
329
  }
352
-
353
330
  return sequence(seq).lastIndexOf(...args);
354
331
  }
355
332
  function slice(seq) {
356
333
  for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
357
334
  args[_key4 - 1] = arguments[_key4];
358
335
  }
359
-
360
336
  return sequence(seq).slice(...args);
361
337
  }
362
338
  function replace(str, pattern, repl) {
@@ -399,23 +375,20 @@ function scaleGradient (scale, p0, p1, count, group) {
399
375
  scale = getScale(scale, (group || this).context);
400
376
  const gradient = Gradient(p0, p1);
401
377
  let stops = scale.domain(),
402
- min = stops[0],
403
- max = peek(stops),
404
- fraction = identity;
405
-
378
+ min = stops[0],
379
+ max = peek(stops),
380
+ fraction = identity;
406
381
  if (!(max - min)) {
407
382
  // expand scale if domain has zero span, fix #1479
408
383
  scale = (scale.interpolator ? scale$1('sequential')().interpolator(scale.interpolator()) : scale$1('linear')().interpolate(scale.interpolate()).range(scale.range())).domain([min = 0, max = 1]);
409
384
  } else {
410
385
  fraction = scaleFraction(scale, min, max);
411
386
  }
412
-
413
387
  if (scale.ticks) {
414
388
  stops = scale.ticks(+count || 15);
415
389
  if (min !== stops[0]) stops.unshift(min);
416
390
  if (max !== peek(stops)) stops.push(max);
417
391
  }
418
-
419
392
  stops.forEach(_ => gradient.stop(fraction(_), scale(_)));
420
393
  return gradient;
421
394
  }
@@ -434,16 +407,14 @@ function pathShape(path) {
434
407
  }
435
408
 
436
409
  const datum = d => d.data;
437
-
438
410
  function treeNodes(name, context) {
439
411
  const tree = data.call(context, name);
440
412
  return tree.root && tree.root.lookup || {};
441
413
  }
442
-
443
414
  function treePath(name, source, target) {
444
415
  const nodes = treeNodes(name, this),
445
- s = nodes[source],
446
- t = nodes[target];
416
+ s = nodes[source],
417
+ t = nodes[target];
447
418
  return s && t ? s.path(t).map(datum) : undefined;
448
419
  }
449
420
  function treeAncestors(name, node) {
@@ -452,141 +423,132 @@ function treeAncestors(name, node) {
452
423
  }
453
424
 
454
425
  const _window = () => typeof window !== 'undefined' && window || null;
455
-
456
426
  function screen() {
457
427
  const w = _window();
458
-
459
428
  return w ? w.screen : {};
460
429
  }
461
430
  function windowSize() {
462
431
  const w = _window();
463
-
464
432
  return w ? [w.innerWidth, w.innerHeight] : [undefined, undefined];
465
433
  }
466
434
  function containerSize() {
467
435
  const view = this.context.dataflow,
468
- el = view.container && view.container();
436
+ el = view.container && view.container();
469
437
  return el ? [el.clientWidth, el.clientHeight] : [undefined, undefined];
470
438
  }
471
439
 
472
440
  function intersect (b, opt, group) {
473
441
  if (!b) return [];
474
442
  const [u, v] = b,
475
- box = new Bounds().set(u[0], u[1], v[0], v[1]),
476
- scene = group || this.context.dataflow.scenegraph().root;
443
+ box = new Bounds().set(u[0], u[1], v[0], v[1]),
444
+ scene = group || this.context.dataflow.scenegraph().root;
477
445
  return intersect$1(scene, box, filter(opt));
478
446
  }
479
-
480
447
  function filter(opt) {
481
448
  let p = null;
482
-
483
449
  if (opt) {
484
450
  const types = array$1(opt.marktype),
485
- names = array$1(opt.markname);
486
-
451
+ names = array$1(opt.markname);
487
452
  p = _ => (!types.length || types.some(t => _.marktype === t)) && (!names.length || names.some(s => _.name === s));
488
453
  }
489
-
490
454
  return p;
491
455
  }
492
456
 
493
457
  /**
494
458
  * Appends a new point to the lasso
495
- *
459
+ *
496
460
  * @param {*} lasso the lasso in pixel space
497
461
  * @param {*} x the x coordinate in pixel space
498
462
  * @param {*} y the y coordinate in pixel space
499
463
  * @param {*} minDist the minimum distance, in pixels, that thenew point needs to be apart from the last point
500
464
  * @returns a new array containing the lasso with the new point
501
465
  */
502
-
503
466
  function lassoAppend(lasso, x, y) {
504
467
  let minDist = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5;
505
- const last = lasso[lasso.length - 1]; // Add point to lasso if distance to last point exceed minDist or its the first point
506
-
507
- if (last === undefined || Math.sqrt((last[0] - x) ** 2 + (last[1] - y) ** 2) > minDist) {
508
- lasso.push([x, y]);
509
- return [...lasso];
510
- }
468
+ lasso = array$1(lasso);
469
+ const last = lasso[lasso.length - 1];
511
470
 
512
- return lasso;
471
+ // Add point to lasso if its the first point or distance to last point exceed minDist
472
+ return last === undefined || Math.hypot(last[0] - x, last[1] - y) > minDist ? [...lasso, [x, y]] : lasso;
513
473
  }
474
+
514
475
  /**
515
476
  * Generates a svg path command which draws a lasso
516
- *
477
+ *
517
478
  * @param {*} lasso the lasso in pixel space in the form [[x,y], [x,y], ...]
518
479
  * @returns the svg path command that draws the lasso
519
480
  */
520
-
521
481
  function lassoPath(lasso) {
522
- return (lasso !== null && lasso !== void 0 ? lasso : []).reduce((svg, _ref, i) => {
482
+ return array$1(lasso).reduce((svg, _ref, i) => {
523
483
  let [x, y] = _ref;
524
- return svg += i == 0 ? "M ".concat(x, ",").concat(y, " ") : i === lasso.length - 1 ? ' Z' : "L ".concat(x, ",").concat(y, " ");
484
+ return svg += i == 0 ? `M ${x},${y} ` : i === lasso.length - 1 ? ' Z' : `L ${x},${y} `;
525
485
  }, '');
526
486
  }
487
+
527
488
  /**
528
489
  * Inverts the lasso from pixel space to an array of vega scenegraph tuples
529
- *
490
+ *
530
491
  * @param {*} data the dataset
531
492
  * @param {*} pixelLasso the lasso in pixel space, [[x,y], [x,y], ...]
532
493
  * @param {*} unit the unit where the lasso is defined
533
- *
494
+ *
534
495
  * @returns an array of vega scenegraph tuples
535
496
  */
536
-
537
497
  function intersectLasso(markname, pixelLasso, unit) {
538
498
  const {
539
499
  x,
540
500
  y,
541
501
  mark
542
502
  } = unit;
543
- const bb = new Bounds().set(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER); // Get bounding box around lasso
503
+ const bb = new Bounds().set(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
544
504
 
505
+ // Get bounding box around lasso
545
506
  for (const [px, py] of pixelLasso) {
546
507
  if (px < bb.x1) bb.x1 = px;
547
508
  if (px > bb.x2) bb.x2 = px;
548
509
  if (py < bb.y1) bb.y1 = py;
549
510
  if (py > bb.y2) bb.y2 = py;
550
- } // Translate bb against unit coordinates
551
-
511
+ }
552
512
 
513
+ // Translate bb against unit coordinates
553
514
  bb.translate(x, y);
554
- const intersection = intersect([[bb.x1, bb.y1], [bb.x2, bb.y2]], markname, mark); // Check every point against the lasso
515
+ const intersection = intersect([[bb.x1, bb.y1], [bb.x2, bb.y2]], markname, mark);
555
516
 
517
+ // Check every point against the lasso
556
518
  return intersection.filter(tuple => pointInPolygon(tuple.x, tuple.y, pixelLasso));
557
519
  }
520
+
558
521
  /**
559
522
  * Performs a test if a point is inside a polygon based on the idea from
560
523
  * https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
561
- *
524
+ *
562
525
  * This method will not need the same start/end point since it wraps around the edges of the array
563
- *
526
+ *
564
527
  * @param {*} test a point to test against
565
528
  * @param {*} polygon a polygon in the form [[x,y], [x,y], ...]
566
529
  * @returns true if the point lies inside the polygon, false otherwise
567
530
  */
568
-
569
531
  function pointInPolygon(testx, testy, polygon) {
570
532
  let intersections = 0;
571
-
572
533
  for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
573
534
  const [prevX, prevY] = polygon[j];
574
- const [x, y] = polygon[i]; // count intersections
535
+ const [x, y] = polygon[i];
575
536
 
537
+ // count intersections
576
538
  if (y > testy != prevY > testy && testx < (prevX - x) * (testy - y) / (prevY - y) + x) {
577
539
  intersections++;
578
540
  }
579
- } // point is in polygon if intersection count is odd
580
-
541
+ }
581
542
 
543
+ // point is in polygon if intersection count is odd
582
544
  return intersections & 1;
583
545
  }
584
546
 
547
+ // Expression function context object
585
548
  const functionContext = {
586
549
  random() {
587
550
  return random();
588
551
  },
589
-
590
552
  // override default
591
553
  cumulativeNormal,
592
554
  cumulativeLogNormal,
@@ -603,27 +565,21 @@ const functionContext = {
603
565
  isArray,
604
566
  isBoolean,
605
567
  isDate,
606
-
607
568
  isDefined(_) {
608
569
  return _ !== undefined;
609
570
  },
610
-
611
571
  isNumber,
612
572
  isObject,
613
573
  isRegExp,
614
574
  isString,
615
575
  isTuple,
616
-
617
576
  isValid(_) {
618
577
  return _ != null && _ === _;
619
578
  },
620
-
621
579
  toBoolean,
622
-
623
580
  toDate(_) {
624
581
  return toDate(_);
625
582
  },
626
-
627
583
  // suppress extra arguments
628
584
  toNumber,
629
585
  toString,
@@ -672,11 +628,9 @@ const functionContext = {
672
628
  warn,
673
629
  info,
674
630
  debug,
675
-
676
631
  extent(_) {
677
632
  return extent(_);
678
633
  },
679
-
680
634
  // suppress extra arguments
681
635
  inScope,
682
636
  intersect,
@@ -704,54 +658,57 @@ const functionContext = {
704
658
  intersectLasso
705
659
  };
706
660
  const eventFunctions = ['view', 'item', 'group', 'xy', 'x', 'y'],
707
- // event functions
708
- eventPrefix = 'event.vega.',
709
- // event function prefix
710
- thisPrefix = 'this.',
711
- // function context prefix
712
- astVisitors = {}; // AST visitors for dependency analysis
713
- // export code generator parameters
661
+ // event functions
662
+ eventPrefix = 'event.vega.',
663
+ // event function prefix
664
+ thisPrefix = 'this.',
665
+ // function context prefix
666
+ astVisitors = {}; // AST visitors for dependency analysis
714
667
 
668
+ // export code generator parameters
715
669
  const codegenParams = {
716
670
  forbidden: ['_'],
717
671
  allowed: ['datum', 'event', 'item'],
718
672
  fieldvar: 'datum',
719
- globalvar: id => "_[".concat(stringValue(SignalPrefix + id), "]"),
673
+ globalvar: id => `_[${stringValue(SignalPrefix + id)}]`,
720
674
  functions: buildFunctions,
721
675
  constants: constants,
722
676
  visitors: astVisitors
723
- }; // export code generator
677
+ };
724
678
 
725
- const codeGenerator = codegenExpression(codegenParams); // Build expression function registry
679
+ // export code generator
680
+ const codeGenerator = codegenExpression(codegenParams);
726
681
 
682
+ // Build expression function registry
727
683
  function buildFunctions(codegen) {
728
684
  const fn = functions(codegen);
729
685
  eventFunctions.forEach(name => fn[name] = eventPrefix + name);
730
-
731
686
  for (const name in functionContext) {
732
687
  fn[name] = thisPrefix + name;
733
688
  }
734
-
735
689
  extend(fn, internalScaleFunctions(codegen, functionContext, astVisitors));
736
690
  return fn;
737
- } // Register an expression function
738
-
691
+ }
739
692
 
693
+ // Register an expression function
740
694
  function expressionFunction(name, fn, visitor) {
741
695
  if (arguments.length === 1) {
742
696
  return functionContext[name];
743
- } // register with the functionContext
697
+ }
744
698
 
699
+ // register with the functionContext
700
+ functionContext[name] = fn;
745
701
 
746
- functionContext[name] = fn; // if there is an astVisitor register that, too
702
+ // if there is an astVisitor register that, too
703
+ if (visitor) astVisitors[name] = visitor;
747
704
 
748
- if (visitor) astVisitors[name] = visitor; // if the code generator has already been initialized,
705
+ // if the code generator has already been initialized,
749
706
  // we need to also register the function with it
750
-
751
707
  if (codeGenerator) codeGenerator.functions[name] = thisPrefix + name;
752
708
  return this;
753
- } // register expression functions with ast visitors
709
+ }
754
710
 
711
+ // register expression functions with ast visitors
755
712
  expressionFunction('bandwidth', bandwidth, scaleVisitor);
756
713
  expressionFunction('copy', copy, scaleVisitor);
757
714
  expressionFunction('domain', domain, scaleVisitor);
@@ -766,43 +723,46 @@ expressionFunction('geoShape', geoShape, scaleVisitor);
766
723
  expressionFunction('indata', indata, indataVisitor);
767
724
  expressionFunction('data', data, dataVisitor);
768
725
  expressionFunction('treePath', treePath, dataVisitor);
769
- expressionFunction('treeAncestors', treeAncestors, dataVisitor); // register Vega-Lite selection functions
726
+ expressionFunction('treeAncestors', treeAncestors, dataVisitor);
770
727
 
728
+ // register Vega-Lite selection functions
771
729
  expressionFunction('vlSelectionTest', selectionTest, selectionVisitor);
772
730
  expressionFunction('vlSelectionIdTest', selectionIdTest, selectionVisitor);
773
731
  expressionFunction('vlSelectionResolve', selectionResolve, selectionVisitor);
774
732
  expressionFunction('vlSelectionTuples', selectionTuples);
775
733
 
776
734
  function parser (expr, scope) {
777
- const params = {}; // parse the expression to an abstract syntax tree (ast)
735
+ const params = {};
778
736
 
737
+ // parse the expression to an abstract syntax tree (ast)
779
738
  let ast;
780
-
781
739
  try {
782
740
  expr = isString(expr) ? expr : stringValue(expr) + '';
783
741
  ast = parseExpression(expr);
784
742
  } catch (err) {
785
743
  error('Expression parse error: ' + expr);
786
- } // analyze ast function calls for dependencies
787
-
744
+ }
788
745
 
746
+ // analyze ast function calls for dependencies
789
747
  ast.visit(node => {
790
748
  if (node.type !== CallExpression) return;
791
749
  const name = node.callee.name,
792
- visit = codegenParams.visitors[name];
750
+ visit = codegenParams.visitors[name];
793
751
  if (visit) visit(name, node.arguments, scope, params);
794
- }); // perform code generation
752
+ });
795
753
 
796
- const gen = codeGenerator(ast); // collect signal dependencies
754
+ // perform code generation
755
+ const gen = codeGenerator(ast);
797
756
 
757
+ // collect signal dependencies
798
758
  gen.globals.forEach(name => {
799
759
  const signalName = SignalPrefix + name;
800
-
801
760
  if (!hasOwnProperty(params, signalName) && scope.getSignal(name)) {
802
761
  params[signalName] = scope.signalRef(name);
803
762
  }
804
- }); // return generated expression code and dependencies
763
+ });
805
764
 
765
+ // return generated expression code and dependencies
806
766
  return {
807
767
  $expr: extend({
808
768
  code: gen.code