vega-functions 5.12.1 → 5.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of vega-functions might be problematic. Click here for more details.

@@ -142,9 +142,9 @@ function internalScaleFunctions(codegen, fnctx, visitors) {
142
142
 
143
143
 
144
144
  return {
145
- _bandwidth: args => `this.__bandwidth(${ref(args[0])})`,
146
- _range: args => `${ref(args[0])}.range()`,
147
- _scale: args => `${ref(args[0])}(${codegen(args[1])})`
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]), ")")
148
148
  };
149
149
  }
150
150
 
@@ -331,16 +331,32 @@ function sequence(seq) {
331
331
  return array(seq) || (isString(seq) ? seq : null);
332
332
  }
333
333
 
334
- function join(seq, ...args) {
334
+ function join(seq) {
335
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
336
+ args[_key - 1] = arguments[_key];
337
+ }
338
+
335
339
  return array(seq).join(...args);
336
340
  }
337
- function indexof(seq, ...args) {
341
+ function indexof(seq) {
342
+ for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
343
+ args[_key2 - 1] = arguments[_key2];
344
+ }
345
+
338
346
  return sequence(seq).indexOf(...args);
339
347
  }
340
- function lastindexof(seq, ...args) {
348
+ function lastindexof(seq) {
349
+ for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
350
+ args[_key3 - 1] = arguments[_key3];
351
+ }
352
+
341
353
  return sequence(seq).lastIndexOf(...args);
342
354
  }
343
- function slice(seq, ...args) {
355
+ function slice(seq) {
356
+ for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
357
+ args[_key4 - 1] = arguments[_key4];
358
+ }
359
+
344
360
  return sequence(seq).slice(...args);
345
361
  }
346
362
  function replace(str, pattern, repl) {
@@ -474,6 +490,98 @@ function filter(opt) {
474
490
  return p;
475
491
  }
476
492
 
493
+ /**
494
+ * Appends a new point to the lasso
495
+ *
496
+ * @param {*} lasso the lasso in pixel space
497
+ * @param {*} x the x coordinate in pixel space
498
+ * @param {*} y the y coordinate in pixel space
499
+ * @param {*} minDist the minimum distance, in pixels, that thenew point needs to be apart from the last point
500
+ * @returns a new array containing the lasso with the new point
501
+ */
502
+
503
+ function lassoAppend(lasso, x, y) {
504
+ 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
+ }
511
+
512
+ return lasso;
513
+ }
514
+ /**
515
+ * Generates a svg path command which draws a lasso
516
+ *
517
+ * @param {*} lasso the lasso in pixel space in the form [[x,y], [x,y], ...]
518
+ * @returns the svg path command that draws the lasso
519
+ */
520
+
521
+ function lassoPath(lasso) {
522
+ return (lasso !== null && lasso !== void 0 ? lasso : []).reduce((svg, _ref, i) => {
523
+ let [x, y] = _ref;
524
+ return svg += i == 0 ? "M ".concat(x, ",").concat(y, " ") : i === lasso.length - 1 ? ' Z' : "L ".concat(x, ",").concat(y, " ");
525
+ }, '');
526
+ }
527
+ /**
528
+ * Inverts the lasso from pixel space to an array of vega scenegraph tuples
529
+ *
530
+ * @param {*} data the dataset
531
+ * @param {*} pixelLasso the lasso in pixel space, [[x,y], [x,y], ...]
532
+ * @param {*} unit the unit where the lasso is defined
533
+ *
534
+ * @returns an array of vega scenegraph tuples
535
+ */
536
+
537
+ function intersectLasso(markname, pixelLasso, unit) {
538
+ const {
539
+ x,
540
+ y,
541
+ mark
542
+ } = 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
544
+
545
+ for (const [px, py] of pixelLasso) {
546
+ if (px < bb.x1) bb.x1 = px;
547
+ if (px > bb.x2) bb.x2 = px;
548
+ if (py < bb.y1) bb.y1 = py;
549
+ if (py > bb.y2) bb.y2 = py;
550
+ } // Translate bb against unit coordinates
551
+
552
+
553
+ bb.translate(x, y);
554
+ const intersection = intersect([[bb.x1, bb.y1], [bb.x2, bb.y2]], markname, mark); // Check every point against the lasso
555
+
556
+ return intersection.filter(tuple => pointInPolygon(tuple.x, tuple.y, pixelLasso));
557
+ }
558
+ /**
559
+ * Performs a test if a point is inside a polygon based on the idea from
560
+ * https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
561
+ *
562
+ * This method will not need the same start/end point since it wraps around the edges of the array
563
+ *
564
+ * @param {*} test a point to test against
565
+ * @param {*} polygon a polygon in the form [[x,y], [x,y], ...]
566
+ * @returns true if the point lies inside the polygon, false otherwise
567
+ */
568
+
569
+ function pointInPolygon(testx, testy, polygon) {
570
+ let intersections = 0;
571
+
572
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
573
+ const [prevX, prevY] = polygon[j];
574
+ const [x, y] = polygon[i]; // count intersections
575
+
576
+ if (y > testy != prevY > testy && testx < (prevX - x) * (testy - y) / (prevY - y) + x) {
577
+ intersections++;
578
+ }
579
+ } // point is in polygon if intersection count is odd
580
+
581
+
582
+ return intersections & 1;
583
+ }
584
+
477
585
  const functionContext = {
478
586
  random() {
479
587
  return random();
@@ -511,7 +619,12 @@ const functionContext = {
511
619
  },
512
620
 
513
621
  toBoolean,
514
- toDate,
622
+
623
+ toDate(_) {
624
+ return toDate(_);
625
+ },
626
+
627
+ // suppress extra arguments
515
628
  toNumber,
516
629
  toString,
517
630
  indexof,
@@ -559,7 +672,12 @@ const functionContext = {
559
672
  warn,
560
673
  info,
561
674
  debug,
562
- extent,
675
+
676
+ extent(_) {
677
+ return extent(_);
678
+ },
679
+
680
+ // suppress extra arguments
563
681
  inScope,
564
682
  intersect,
565
683
  clampRange,
@@ -580,7 +698,10 @@ const functionContext = {
580
698
  zoomPow,
581
699
  zoomSymlog,
582
700
  encode,
583
- modify
701
+ modify,
702
+ lassoAppend,
703
+ lassoPath,
704
+ intersectLasso
584
705
  };
585
706
  const eventFunctions = ['view', 'item', 'group', 'xy', 'x', 'y'],
586
707
  // event functions
@@ -595,7 +716,7 @@ const codegenParams = {
595
716
  forbidden: ['_'],
596
717
  allowed: ['datum', 'event', 'item'],
597
718
  fieldvar: 'datum',
598
- globalvar: id => `_[${stringValue(SignalPrefix + id)}]`,
719
+ globalvar: id => "_[".concat(stringValue(SignalPrefix + id), "]"),
599
720
  functions: buildFunctions,
600
721
  constants: constants,
601
722
  visitors: astVisitors
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vega-functions",
3
- "version": "5.12.1",
3
+ "version": "5.13.0",
4
4
  "description": "Custom functions for the Vega expression language.",
5
5
  "keywords": [
6
6
  "vega",
@@ -21,20 +21,20 @@
21
21
  "prepublishOnly": "yarn test && yarn build"
22
22
  },
23
23
  "dependencies": {
24
- "d3-array": "^2.7.1",
25
- "d3-color": "^2.0.0",
26
- "d3-geo": "^2.0.1",
24
+ "d3-array": "^3.1.1",
25
+ "d3-color": "^3.0.1",
26
+ "d3-geo": "^3.0.1",
27
27
  "vega-dataflow": "^5.7.3",
28
28
  "vega-expression": "^5.0.0",
29
- "vega-scale": "^7.1.1",
29
+ "vega-scale": "^7.2.0",
30
30
  "vega-scenegraph": "^4.9.3",
31
31
  "vega-selections": "^5.3.1",
32
32
  "vega-statistics": "^1.7.9",
33
- "vega-time": "^2.0.4",
33
+ "vega-time": "^2.1.0",
34
34
  "vega-util": "^1.16.0"
35
35
  },
36
36
  "devDependencies": {
37
- "vega-format": "^1.0.4"
37
+ "vega-format": "^1.1.0"
38
38
  },
39
- "gitHead": "774165e29850b66ec8b79ba52a7955f1ab936ea6"
39
+ "gitHead": "9a3faca4395cade9ecdfde90af98f1c53e9916b2"
40
40
  }
package/src/codegen.js CHANGED
@@ -151,6 +151,12 @@ import {
151
151
  slice
152
152
  } from './functions/sequence';
153
153
 
154
+ import {
155
+ intersectLasso,
156
+ lassoAppend,
157
+ lassoPath
158
+ } from './functions/lasso';
159
+
154
160
  import {
155
161
  bandspace,
156
162
  bandwidth,
@@ -219,7 +225,7 @@ export const functionContext = {
219
225
  isTuple,
220
226
  isValid(_) { return _ != null && _ === _; },
221
227
  toBoolean,
222
- toDate,
228
+ toDate(_) { return toDate(_); }, // suppress extra arguments
223
229
  toNumber,
224
230
  toString,
225
231
  indexof,
@@ -267,7 +273,7 @@ export const functionContext = {
267
273
  warn,
268
274
  info,
269
275
  debug,
270
- extent,
276
+ extent(_) { return extent(_); }, // suppress extra arguments
271
277
  inScope,
272
278
  intersect,
273
279
  clampRange,
@@ -288,7 +294,10 @@ export const functionContext = {
288
294
  zoomPow,
289
295
  zoomSymlog,
290
296
  encode,
291
- modify
297
+ modify,
298
+ lassoAppend,
299
+ lassoPath,
300
+ intersectLasso
292
301
  };
293
302
 
294
303
  const eventFunctions = ['view', 'item', 'group', 'xy', 'x', 'y'], // event functions
@@ -0,0 +1,110 @@
1
+ import intersect from './intersect';
2
+ import { Bounds } from 'vega-scenegraph';
3
+
4
+ /**
5
+ * Appends a new point to the lasso
6
+ *
7
+ * @param {*} lasso the lasso in pixel space
8
+ * @param {*} x the x coordinate in pixel space
9
+ * @param {*} y the y coordinate in pixel space
10
+ * @param {*} minDist the minimum distance, in pixels, that thenew point needs to be apart from the last point
11
+ * @returns a new array containing the lasso with the new point
12
+ */
13
+ export function lassoAppend(lasso, x, y, minDist = 5) {
14
+ const last = lasso[lasso.length - 1];
15
+
16
+ // Add point to lasso if distance to last point exceed minDist or its the first point
17
+ if (last === undefined || Math.sqrt(((last[0] - x) ** 2) + ((last[1] - y) ** 2)) > minDist) {
18
+ lasso.push([x, y]);
19
+
20
+ return [...lasso];
21
+ }
22
+
23
+ return lasso;
24
+ }
25
+
26
+
27
+ /**
28
+ * Generates a svg path command which draws a lasso
29
+ *
30
+ * @param {*} lasso the lasso in pixel space in the form [[x,y], [x,y], ...]
31
+ * @returns the svg path command that draws the lasso
32
+ */
33
+ export function lassoPath(lasso) {
34
+ return (lasso ?? []).reduce((svg, [x, y], i) => {
35
+ return svg += i == 0
36
+ ? `M ${x},${y} `
37
+ : i === lasso.length - 1
38
+ ? ' Z'
39
+ : `L ${x},${y} `;
40
+ }, '');
41
+ }
42
+
43
+
44
+
45
+ /**
46
+ * Inverts the lasso from pixel space to an array of vega scenegraph tuples
47
+ *
48
+ * @param {*} data the dataset
49
+ * @param {*} pixelLasso the lasso in pixel space, [[x,y], [x,y], ...]
50
+ * @param {*} unit the unit where the lasso is defined
51
+ *
52
+ * @returns an array of vega scenegraph tuples
53
+ */
54
+ export function intersectLasso(markname, pixelLasso, unit) {
55
+ const { x, y, mark } = unit;
56
+
57
+ const bb = new Bounds().set(
58
+ Number.MAX_SAFE_INTEGER,
59
+ Number.MAX_SAFE_INTEGER,
60
+ Number.MIN_SAFE_INTEGER,
61
+ Number.MIN_SAFE_INTEGER
62
+ );
63
+
64
+ // Get bounding box around lasso
65
+ for (const [px, py] of pixelLasso) {
66
+ if (px < bb.x1) bb.x1 = px;
67
+ if (px > bb.x2) bb.x2 = px;
68
+ if (py < bb.y1) bb.y1 = py;
69
+ if (py > bb.y2) bb.y2 = py;
70
+ }
71
+
72
+ // Translate bb against unit coordinates
73
+ bb.translate(x, y);
74
+
75
+ const intersection = intersect([[bb.x1, bb.y1], [bb.x2, bb.y2]],
76
+ markname,
77
+ mark);
78
+
79
+ // Check every point against the lasso
80
+ return intersection.filter(tuple => pointInPolygon(tuple.x, tuple.y, pixelLasso));
81
+ }
82
+
83
+
84
+
85
+ /**
86
+ * Performs a test if a point is inside a polygon based on the idea from
87
+ * https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
88
+ *
89
+ * This method will not need the same start/end point since it wraps around the edges of the array
90
+ *
91
+ * @param {*} test a point to test against
92
+ * @param {*} polygon a polygon in the form [[x,y], [x,y], ...]
93
+ * @returns true if the point lies inside the polygon, false otherwise
94
+ */
95
+ function pointInPolygon(testx, testy, polygon) {
96
+ let intersections = 0;
97
+
98
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
99
+ const [prevX, prevY] = polygon[j];
100
+ const [x, y] = polygon[i];
101
+
102
+ // count intersections
103
+ if (((y > testy) != (prevY > testy)) && (testx < (prevX - x) * (testy - y) / (prevY - y) + x)) {
104
+ intersections++;
105
+ }
106
+ }
107
+
108
+ // point is in polygon if intersection count is odd
109
+ return intersections & 1;
110
+ }