vega-functions 5.13.0 → 5.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of vega-functions might be problematic. Click here for more details.
- package/LICENSE +1 -1
- package/build/vega-functions.js +300 -382
- package/build/vega-functions.min.js +1 -1
- package/build/vega-functions.min.js.map +1 -1
- package/build/vega-functions.module.js +119 -159
- package/package.json +14 -14
- package/rollup.config.mjs +1 -0
- package/src/functions/lasso.js +57 -59
- package/src/scales.js +14 -5
- package/rollup.config.js +0 -1
package/build/vega-functions.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-util'), require('vega-expression'), require('vega-
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports', 'vega-util', 'vega-expression', 'vega-
|
|
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
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,
|
|
5
|
+
})(this, (function (exports, vegaUtil, vegaExpression, vegaScale, vegaDataflow, vegaScenegraph, vegaSelections, vegaStatistics, vegaTime) { 'use strict';
|
|
6
6
|
|
|
7
7
|
function data(name) {
|
|
8
8
|
const data = this.context.data[name];
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
}
|
|
11
11
|
function indata(name, field, value) {
|
|
12
12
|
const index = this.context.data[name]['index:' + field],
|
|
13
|
-
|
|
13
|
+
entry = index ? index.value.get(value) : undefined;
|
|
14
14
|
return entry ? entry.count : entry;
|
|
15
15
|
}
|
|
16
16
|
function setdata(name, tuples) {
|
|
17
17
|
const df = this.context.dataflow,
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
data = this.context.data[name],
|
|
19
|
+
input = data.input;
|
|
20
20
|
df.pulse(input, df.changeset().remove(vegaUtil.truthy).insert(tuples));
|
|
21
21
|
return 1;
|
|
22
22
|
}
|
|
@@ -24,10 +24,9 @@
|
|
|
24
24
|
function encode (item, name, retval) {
|
|
25
25
|
if (item) {
|
|
26
26
|
const df = this.context.dataflow,
|
|
27
|
-
|
|
27
|
+
target = item.mark.source;
|
|
28
28
|
df.pulse(target, df.changeset().encode(item, name));
|
|
29
29
|
}
|
|
30
|
-
|
|
31
30
|
return retval !== undefined ? retval : item;
|
|
32
31
|
}
|
|
33
32
|
|
|
@@ -35,14 +34,12 @@
|
|
|
35
34
|
const locale = this.context.dataflow.locale();
|
|
36
35
|
return locale[method](spec)(value);
|
|
37
36
|
};
|
|
38
|
-
|
|
39
37
|
const format = wrap('format');
|
|
40
38
|
const timeFormat = wrap('timeFormat');
|
|
41
39
|
const utcFormat = wrap('utcFormat');
|
|
42
40
|
const timeParse = wrap('timeParse');
|
|
43
41
|
const utcParse = wrap('utcParse');
|
|
44
42
|
const dateObj = new Date(2000, 0, 1);
|
|
45
|
-
|
|
46
43
|
function time(month, day, specifier) {
|
|
47
44
|
if (!Number.isInteger(month) || !Number.isInteger(day)) return '';
|
|
48
45
|
dateObj.setYear(2000);
|
|
@@ -50,7 +47,6 @@
|
|
|
50
47
|
dateObj.setDate(day);
|
|
51
48
|
return timeFormat.call(this, dateObj, specifier);
|
|
52
49
|
}
|
|
53
|
-
|
|
54
50
|
function monthFormat(month) {
|
|
55
51
|
return time.call(this, month, 1, '%B');
|
|
56
52
|
}
|
|
@@ -73,14 +69,13 @@
|
|
|
73
69
|
if (args[0].type !== vegaExpression.Literal) {
|
|
74
70
|
vegaUtil.error('First argument to data functions must be a string literal.');
|
|
75
71
|
}
|
|
76
|
-
|
|
77
72
|
const data = args[0].value,
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
dataName = DataPrefix + data;
|
|
80
74
|
if (!vegaUtil.hasOwnProperty(dataName, params)) {
|
|
81
75
|
try {
|
|
82
76
|
params[dataName] = scope.getData(data).tuplesRef();
|
|
83
|
-
} catch (err) {
|
|
77
|
+
} catch (err) {
|
|
78
|
+
// if data set does not exist, there's nothing to track
|
|
84
79
|
}
|
|
85
80
|
}
|
|
86
81
|
}
|
|
@@ -88,9 +83,8 @@
|
|
|
88
83
|
if (args[0].type !== vegaExpression.Literal) vegaUtil.error('First argument to indata must be a string literal.');
|
|
89
84
|
if (args[1].type !== vegaExpression.Literal) vegaUtil.error('Second argument to indata must be a string literal.');
|
|
90
85
|
const data = args[0].value,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
field = args[1].value,
|
|
87
|
+
indexName = IndexPrefix + field;
|
|
94
88
|
if (!vegaUtil.hasOwnProperty(indexName, params)) {
|
|
95
89
|
params[indexName] = scope.getData(data).indataRef(scope, field);
|
|
96
90
|
}
|
|
@@ -106,35 +100,41 @@
|
|
|
106
100
|
}
|
|
107
101
|
}
|
|
108
102
|
}
|
|
109
|
-
|
|
110
103
|
function addScaleDependency(scope, params, name) {
|
|
111
104
|
const scaleName = ScalePrefix + name;
|
|
112
|
-
|
|
113
105
|
if (!vegaUtil.hasOwnProperty(params, scaleName)) {
|
|
114
106
|
try {
|
|
115
107
|
params[scaleName] = scope.scaleRef(name);
|
|
116
|
-
} catch (err) {
|
|
108
|
+
} catch (err) {
|
|
109
|
+
// TODO: error handling? warning?
|
|
117
110
|
}
|
|
118
111
|
}
|
|
119
112
|
}
|
|
120
113
|
|
|
121
|
-
function getScale(
|
|
122
|
-
|
|
123
|
-
|
|
114
|
+
function getScale(nameOrFunction, ctx) {
|
|
115
|
+
if (vegaUtil.isFunction(nameOrFunction)) {
|
|
116
|
+
return nameOrFunction;
|
|
117
|
+
}
|
|
118
|
+
if (vegaUtil.isString(nameOrFunction)) {
|
|
119
|
+
const maybeScale = ctx.scales[nameOrFunction];
|
|
120
|
+
return maybeScale && vegaScale.isRegisteredScale(maybeScale.value) ? maybeScale.value : undefined;
|
|
121
|
+
}
|
|
122
|
+
return undefined;
|
|
124
123
|
}
|
|
125
124
|
function internalScaleFunctions(codegen, fnctx, visitors) {
|
|
126
125
|
// add helper method to the 'this' expression function context
|
|
127
|
-
fnctx.__bandwidth = s => s && s.bandwidth ? s.bandwidth() : 0;
|
|
128
|
-
|
|
126
|
+
fnctx.__bandwidth = s => s && s.bandwidth ? s.bandwidth() : 0;
|
|
129
127
|
|
|
128
|
+
// register AST visitors for internal scale functions
|
|
130
129
|
visitors._bandwidth = scaleVisitor;
|
|
131
130
|
visitors._range = scaleVisitor;
|
|
132
|
-
visitors._scale = scaleVisitor;
|
|
133
|
-
|
|
134
|
-
const ref = arg => '_[' + (arg.type === vegaExpression.Literal ? vegaUtil.stringValue(ScalePrefix + arg.value) : vegaUtil.stringValue(ScalePrefix) + '+' + codegen(arg)) + ']'; // define and return internal scale function code generators
|
|
135
|
-
// these internal functions are called by mark encoders
|
|
131
|
+
visitors._scale = scaleVisitor;
|
|
136
132
|
|
|
133
|
+
// resolve scale reference directly to the signal hash argument
|
|
134
|
+
const ref = arg => '_[' + (arg.type === vegaExpression.Literal ? vegaUtil.stringValue(ScalePrefix + arg.value) : vegaUtil.stringValue(ScalePrefix) + '+' + codegen(arg)) + ']';
|
|
137
135
|
|
|
136
|
+
// define and return internal scale function code generators
|
|
137
|
+
// these internal functions are called by mark encoders
|
|
138
138
|
return {
|
|
139
139
|
_bandwidth: args => `this.__bandwidth(${ref(args[0])})`,
|
|
140
140
|
_range: args => `${ref(args[0])}.range()`,
|
|
@@ -148,35 +148,29 @@
|
|
|
148
148
|
this._partials = new Float64Array(32);
|
|
149
149
|
this._n = 0;
|
|
150
150
|
}
|
|
151
|
-
|
|
152
151
|
add(x) {
|
|
153
152
|
const p = this._partials;
|
|
154
153
|
let i = 0;
|
|
155
|
-
|
|
156
154
|
for (let j = 0; j < this._n && j < 32; j++) {
|
|
157
155
|
const y = p[j],
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
hi = x + y,
|
|
157
|
+
lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
|
|
160
158
|
if (lo) p[i++] = lo;
|
|
161
159
|
x = hi;
|
|
162
160
|
}
|
|
163
|
-
|
|
164
161
|
p[i] = x;
|
|
165
162
|
this._n = i + 1;
|
|
166
163
|
return this;
|
|
167
164
|
}
|
|
168
|
-
|
|
169
165
|
valueOf() {
|
|
170
166
|
const p = this._partials;
|
|
171
167
|
let n = this._n,
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
168
|
+
x,
|
|
169
|
+
y,
|
|
170
|
+
lo,
|
|
171
|
+
hi = 0;
|
|
177
172
|
if (n > 0) {
|
|
178
173
|
hi = p[--n];
|
|
179
|
-
|
|
180
174
|
while (n > 0) {
|
|
181
175
|
x = hi;
|
|
182
176
|
y = p[--n];
|
|
@@ -184,29 +178,24 @@
|
|
|
184
178
|
lo = y - (hi - x);
|
|
185
179
|
if (lo) break;
|
|
186
180
|
}
|
|
187
|
-
|
|
188
181
|
if (n > 0 && (lo < 0 && p[n - 1] < 0 || lo > 0 && p[n - 1] > 0)) {
|
|
189
182
|
y = lo * 2;
|
|
190
183
|
x = hi + y;
|
|
191
184
|
if (y == x - hi) hi = x;
|
|
192
185
|
}
|
|
193
186
|
}
|
|
194
|
-
|
|
195
187
|
return hi;
|
|
196
188
|
}
|
|
197
|
-
|
|
198
189
|
}
|
|
199
190
|
|
|
200
191
|
function range$2(start, stop, step) {
|
|
201
192
|
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
|
|
202
193
|
var i = -1,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
194
|
+
n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
|
|
195
|
+
range = new Array(n);
|
|
206
196
|
while (++i < n) {
|
|
207
197
|
range[i] = start + i * step;
|
|
208
198
|
}
|
|
209
|
-
|
|
210
199
|
return range;
|
|
211
200
|
}
|
|
212
201
|
|
|
@@ -235,16 +224,14 @@
|
|
|
235
224
|
streamGeometryType[geometry.type](geometry, stream);
|
|
236
225
|
}
|
|
237
226
|
}
|
|
238
|
-
|
|
239
227
|
var streamObjectType = {
|
|
240
228
|
Feature: function (object, stream) {
|
|
241
229
|
streamGeometry(object.geometry, stream);
|
|
242
230
|
},
|
|
243
231
|
FeatureCollection: function (object, stream) {
|
|
244
232
|
var features = object.features,
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
233
|
+
i = -1,
|
|
234
|
+
n = features.length;
|
|
248
235
|
while (++i < n) streamGeometry(features[i].geometry, stream);
|
|
249
236
|
}
|
|
250
237
|
};
|
|
@@ -258,9 +245,8 @@
|
|
|
258
245
|
},
|
|
259
246
|
MultiPoint: function (object, stream) {
|
|
260
247
|
var coordinates = object.coordinates,
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
248
|
+
i = -1,
|
|
249
|
+
n = coordinates.length;
|
|
264
250
|
while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
|
|
265
251
|
},
|
|
266
252
|
LineString: function (object, stream) {
|
|
@@ -268,9 +254,8 @@
|
|
|
268
254
|
},
|
|
269
255
|
MultiLineString: function (object, stream) {
|
|
270
256
|
var coordinates = object.coordinates,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
257
|
+
i = -1,
|
|
258
|
+
n = coordinates.length;
|
|
274
259
|
while (++i < n) streamLine(coordinates[i], stream, 0);
|
|
275
260
|
},
|
|
276
261
|
Polygon: function (object, stream) {
|
|
@@ -278,41 +263,32 @@
|
|
|
278
263
|
},
|
|
279
264
|
MultiPolygon: function (object, stream) {
|
|
280
265
|
var coordinates = object.coordinates,
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
266
|
+
i = -1,
|
|
267
|
+
n = coordinates.length;
|
|
284
268
|
while (++i < n) streamPolygon(coordinates[i], stream);
|
|
285
269
|
},
|
|
286
270
|
GeometryCollection: function (object, stream) {
|
|
287
271
|
var geometries = object.geometries,
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
272
|
+
i = -1,
|
|
273
|
+
n = geometries.length;
|
|
291
274
|
while (++i < n) streamGeometry(geometries[i], stream);
|
|
292
275
|
}
|
|
293
276
|
};
|
|
294
|
-
|
|
295
277
|
function streamLine(coordinates, stream, closed) {
|
|
296
278
|
var i = -1,
|
|
297
|
-
|
|
298
|
-
|
|
279
|
+
n = coordinates.length - closed,
|
|
280
|
+
coordinate;
|
|
299
281
|
stream.lineStart();
|
|
300
|
-
|
|
301
282
|
while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
|
|
302
|
-
|
|
303
283
|
stream.lineEnd();
|
|
304
284
|
}
|
|
305
|
-
|
|
306
285
|
function streamPolygon(coordinates, stream) {
|
|
307
286
|
var i = -1,
|
|
308
|
-
|
|
287
|
+
n = coordinates.length;
|
|
309
288
|
stream.polygonStart();
|
|
310
|
-
|
|
311
289
|
while (++i < n) streamLine(coordinates[i], stream, 1);
|
|
312
|
-
|
|
313
290
|
stream.polygonEnd();
|
|
314
291
|
}
|
|
315
|
-
|
|
316
292
|
function geoStream (object, stream) {
|
|
317
293
|
if (object && streamObjectType.hasOwnProperty(object.type)) {
|
|
318
294
|
streamObjectType[object.type](object, stream);
|
|
@@ -321,14 +297,16 @@
|
|
|
321
297
|
}
|
|
322
298
|
}
|
|
323
299
|
|
|
324
|
-
var areaRingSum = new Adder();
|
|
300
|
+
var areaRingSum = new Adder();
|
|
301
|
+
|
|
302
|
+
// hello?
|
|
325
303
|
|
|
326
304
|
var areaSum = new Adder(),
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
305
|
+
lambda00$2,
|
|
306
|
+
phi00$2,
|
|
307
|
+
lambda0$1,
|
|
308
|
+
cosPhi0,
|
|
309
|
+
sinPhi0;
|
|
332
310
|
var areaStream = {
|
|
333
311
|
point: noop,
|
|
334
312
|
lineStart: noop,
|
|
@@ -347,42 +325,38 @@
|
|
|
347
325
|
areaSum.add(tau);
|
|
348
326
|
}
|
|
349
327
|
};
|
|
350
|
-
|
|
351
328
|
function areaRingStart() {
|
|
352
329
|
areaStream.point = areaPointFirst;
|
|
353
330
|
}
|
|
354
|
-
|
|
355
331
|
function areaRingEnd() {
|
|
356
332
|
areaPoint(lambda00$2, phi00$2);
|
|
357
333
|
}
|
|
358
|
-
|
|
359
334
|
function areaPointFirst(lambda, phi) {
|
|
360
335
|
areaStream.point = areaPoint;
|
|
361
336
|
lambda00$2 = lambda, phi00$2 = phi;
|
|
362
337
|
lambda *= radians$1, phi *= radians$1;
|
|
363
338
|
lambda0$1 = lambda, cosPhi0 = cos(phi = phi / 2 + quarterPi), sinPhi0 = sin(phi);
|
|
364
339
|
}
|
|
365
|
-
|
|
366
340
|
function areaPoint(lambda, phi) {
|
|
367
341
|
lambda *= radians$1, phi *= radians$1;
|
|
368
342
|
phi = phi / 2 + quarterPi; // half the angular distance from south pole
|
|
343
|
+
|
|
369
344
|
// Spherical excess E for a spherical triangle with vertices: south pole,
|
|
370
345
|
// previous point, current point. Uses a formula derived from Cagnoli’s
|
|
371
346
|
// theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
|
|
372
|
-
|
|
373
347
|
var dLambda = lambda - lambda0$1,
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
areaRingSum.add(atan2(v, u));
|
|
382
|
-
|
|
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.
|
|
383
358
|
lambda0$1 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
|
|
384
359
|
}
|
|
385
|
-
|
|
386
360
|
function area (object) {
|
|
387
361
|
areaSum = new Adder();
|
|
388
362
|
geoStream(object, areaStream);
|
|
@@ -394,24 +368,29 @@
|
|
|
394
368
|
}
|
|
395
369
|
function cartesian(spherical) {
|
|
396
370
|
var lambda = spherical[0],
|
|
397
|
-
|
|
398
|
-
|
|
371
|
+
phi = spherical[1],
|
|
372
|
+
cosPhi = cos(phi);
|
|
399
373
|
return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
|
|
400
374
|
}
|
|
401
375
|
function cartesianCross(a, b) {
|
|
402
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]];
|
|
403
|
-
}
|
|
377
|
+
}
|
|
404
378
|
|
|
379
|
+
// TODO return d
|
|
405
380
|
function cartesianNormalizeInPlace(d) {
|
|
406
381
|
var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
|
|
407
382
|
d[0] /= l, d[1] /= l, d[2] /= l;
|
|
408
383
|
}
|
|
409
384
|
|
|
410
|
-
var lambda0, phi0, lambda1, phi1,
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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;
|
|
415
394
|
var boundsStream = {
|
|
416
395
|
point: boundsPoint,
|
|
417
396
|
lineStart: boundsLineStart,
|
|
@@ -435,28 +414,24 @@
|
|
|
435
414
|
lambda0 = -(lambda1 = 180), phi0 = -(phi1 = 90);
|
|
436
415
|
}
|
|
437
416
|
};
|
|
438
|
-
|
|
439
417
|
function boundsPoint(lambda, phi) {
|
|
440
418
|
ranges.push(range$1 = [lambda0 = lambda, lambda1 = lambda]);
|
|
441
419
|
if (phi < phi0) phi0 = phi;
|
|
442
420
|
if (phi > phi1) phi1 = phi;
|
|
443
421
|
}
|
|
444
|
-
|
|
445
422
|
function linePoint(lambda, phi) {
|
|
446
423
|
var p = cartesian([lambda * radians$1, phi * radians$1]);
|
|
447
|
-
|
|
448
424
|
if (p0) {
|
|
449
425
|
var normal = cartesianCross(p0, p),
|
|
450
|
-
|
|
451
|
-
|
|
426
|
+
equatorial = [normal[1], -normal[0], 0],
|
|
427
|
+
inflection = cartesianCross(equatorial, normal);
|
|
452
428
|
cartesianNormalizeInPlace(inflection);
|
|
453
429
|
inflection = spherical(inflection);
|
|
454
430
|
var delta = lambda - lambda2,
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
431
|
+
sign = delta > 0 ? 1 : -1,
|
|
432
|
+
lambdai = inflection[0] * degrees$1 * sign,
|
|
433
|
+
phii,
|
|
434
|
+
antimeridian = abs(delta) > 180;
|
|
460
435
|
if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
|
|
461
436
|
phii = inflection[1] * degrees$1;
|
|
462
437
|
if (phii > phi1) phi1 = phii;
|
|
@@ -467,7 +442,6 @@
|
|
|
467
442
|
if (phi < phi0) phi0 = phi;
|
|
468
443
|
if (phi > phi1) phi1 = phi;
|
|
469
444
|
}
|
|
470
|
-
|
|
471
445
|
if (antimeridian) {
|
|
472
446
|
if (lambda < lambda2) {
|
|
473
447
|
if (angle(lambda0, lambda) > angle(lambda0, lambda1)) lambda1 = lambda;
|
|
@@ -489,22 +463,18 @@
|
|
|
489
463
|
} else {
|
|
490
464
|
ranges.push(range$1 = [lambda0 = lambda, lambda1 = lambda]);
|
|
491
465
|
}
|
|
492
|
-
|
|
493
466
|
if (phi < phi0) phi0 = phi;
|
|
494
467
|
if (phi > phi1) phi1 = phi;
|
|
495
468
|
p0 = p, lambda2 = lambda;
|
|
496
469
|
}
|
|
497
|
-
|
|
498
470
|
function boundsLineStart() {
|
|
499
471
|
boundsStream.point = linePoint;
|
|
500
472
|
}
|
|
501
|
-
|
|
502
473
|
function boundsLineEnd() {
|
|
503
474
|
range$1[0] = lambda0, range$1[1] = lambda1;
|
|
504
475
|
boundsStream.point = boundsPoint;
|
|
505
476
|
p0 = null;
|
|
506
477
|
}
|
|
507
|
-
|
|
508
478
|
function boundsRingPoint(lambda, phi) {
|
|
509
479
|
if (p0) {
|
|
510
480
|
var delta = lambda - lambda2;
|
|
@@ -512,72 +482,67 @@
|
|
|
512
482
|
} else {
|
|
513
483
|
lambda00$1 = lambda, phi00$1 = phi;
|
|
514
484
|
}
|
|
515
|
-
|
|
516
485
|
areaStream.point(lambda, phi);
|
|
517
486
|
linePoint(lambda, phi);
|
|
518
487
|
}
|
|
519
|
-
|
|
520
488
|
function boundsRingStart() {
|
|
521
489
|
areaStream.lineStart();
|
|
522
490
|
}
|
|
523
|
-
|
|
524
491
|
function boundsRingEnd() {
|
|
525
492
|
boundsRingPoint(lambda00$1, phi00$1);
|
|
526
493
|
areaStream.lineEnd();
|
|
527
494
|
if (abs(deltaSum) > epsilon) lambda0 = -(lambda1 = 180);
|
|
528
495
|
range$1[0] = lambda0, range$1[1] = lambda1;
|
|
529
496
|
p0 = null;
|
|
530
|
-
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Finds the left-right distance between two longitudes.
|
|
531
500
|
// This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
|
|
532
501
|
// the distance between ±180° to be 360°.
|
|
533
|
-
|
|
534
|
-
|
|
535
502
|
function angle(lambda0, lambda1) {
|
|
536
503
|
return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
|
|
537
504
|
}
|
|
538
|
-
|
|
539
505
|
function rangeCompare(a, b) {
|
|
540
506
|
return a[0] - b[0];
|
|
541
507
|
}
|
|
542
|
-
|
|
543
508
|
function rangeContains(range, x) {
|
|
544
509
|
return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
|
|
545
510
|
}
|
|
546
|
-
|
|
547
511
|
function bounds (feature) {
|
|
548
512
|
var i, n, a, b, merged, deltaMax, delta;
|
|
549
513
|
phi1 = lambda1 = -(lambda0 = phi0 = Infinity);
|
|
550
514
|
ranges = [];
|
|
551
|
-
geoStream(feature, boundsStream);
|
|
515
|
+
geoStream(feature, boundsStream);
|
|
552
516
|
|
|
517
|
+
// First, sort ranges by their minimum longitudes.
|
|
553
518
|
if (n = ranges.length) {
|
|
554
|
-
ranges.sort(rangeCompare);
|
|
519
|
+
ranges.sort(rangeCompare);
|
|
555
520
|
|
|
521
|
+
// Then, merge any ranges that overlap.
|
|
556
522
|
for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
|
|
557
523
|
b = ranges[i];
|
|
558
|
-
|
|
559
524
|
if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
|
|
560
525
|
if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
|
|
561
526
|
if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
|
|
562
527
|
} else {
|
|
563
528
|
merged.push(a = b);
|
|
564
529
|
}
|
|
565
|
-
}
|
|
566
|
-
// The final bounding box will be the inverse of this gap.
|
|
567
|
-
|
|
530
|
+
}
|
|
568
531
|
|
|
532
|
+
// Finally, find the largest gap between the merged ranges.
|
|
533
|
+
// The final bounding box will be the inverse of this gap.
|
|
569
534
|
for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
|
|
570
535
|
b = merged[i];
|
|
571
536
|
if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0 = b[0], lambda1 = a[1];
|
|
572
537
|
}
|
|
573
538
|
}
|
|
574
|
-
|
|
575
539
|
ranges = range$1 = null;
|
|
576
540
|
return lambda0 === Infinity || phi0 === Infinity ? [[NaN, NaN], [NaN, NaN]] : [[lambda0, phi0], [lambda1, phi1]];
|
|
577
541
|
}
|
|
578
542
|
|
|
579
|
-
var W0, W1, X0, Y0, Z0, X1, Y1, Z1, X2, Y2, Z2, lambda00, phi00,
|
|
580
|
-
|
|
543
|
+
var W0, W1, X0, Y0, Z0, X1, Y1, Z1, X2, Y2, Z2, lambda00, phi00,
|
|
544
|
+
// first point
|
|
545
|
+
x0, y0, z0; // previous point
|
|
581
546
|
|
|
582
547
|
var centroidStream = {
|
|
583
548
|
sphere: noop,
|
|
@@ -592,25 +557,23 @@
|
|
|
592
557
|
centroidStream.lineStart = centroidLineStart;
|
|
593
558
|
centroidStream.lineEnd = centroidLineEnd;
|
|
594
559
|
}
|
|
595
|
-
};
|
|
560
|
+
};
|
|
596
561
|
|
|
562
|
+
// Arithmetic mean of Cartesian vectors.
|
|
597
563
|
function centroidPoint(lambda, phi) {
|
|
598
564
|
lambda *= radians$1, phi *= radians$1;
|
|
599
565
|
var cosPhi = cos(phi);
|
|
600
566
|
centroidPointCartesian(cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi));
|
|
601
567
|
}
|
|
602
|
-
|
|
603
568
|
function centroidPointCartesian(x, y, z) {
|
|
604
569
|
++W0;
|
|
605
570
|
X0 += (x - X0) / W0;
|
|
606
571
|
Y0 += (y - Y0) / W0;
|
|
607
572
|
Z0 += (z - Z0) / W0;
|
|
608
573
|
}
|
|
609
|
-
|
|
610
574
|
function centroidLineStart() {
|
|
611
575
|
centroidStream.point = centroidLinePointFirst;
|
|
612
576
|
}
|
|
613
|
-
|
|
614
577
|
function centroidLinePointFirst(lambda, phi) {
|
|
615
578
|
lambda *= radians$1, phi *= radians$1;
|
|
616
579
|
var cosPhi = cos(phi);
|
|
@@ -620,36 +583,32 @@
|
|
|
620
583
|
centroidStream.point = centroidLinePoint;
|
|
621
584
|
centroidPointCartesian(x0, y0, z0);
|
|
622
585
|
}
|
|
623
|
-
|
|
624
586
|
function centroidLinePoint(lambda, phi) {
|
|
625
587
|
lambda *= radians$1, phi *= radians$1;
|
|
626
588
|
var cosPhi = cos(phi),
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
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);
|
|
631
593
|
W1 += w;
|
|
632
594
|
X1 += w * (x0 + (x0 = x));
|
|
633
595
|
Y1 += w * (y0 + (y0 = y));
|
|
634
596
|
Z1 += w * (z0 + (z0 = z));
|
|
635
597
|
centroidPointCartesian(x0, y0, z0);
|
|
636
598
|
}
|
|
637
|
-
|
|
638
599
|
function centroidLineEnd() {
|
|
639
600
|
centroidStream.point = centroidPoint;
|
|
640
|
-
}
|
|
641
|
-
// J. Applied Mechanics 42, 239 (1975).
|
|
642
|
-
|
|
601
|
+
}
|
|
643
602
|
|
|
603
|
+
// See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
|
|
604
|
+
// J. Applied Mechanics 42, 239 (1975).
|
|
644
605
|
function centroidRingStart() {
|
|
645
606
|
centroidStream.point = centroidRingPointFirst;
|
|
646
607
|
}
|
|
647
|
-
|
|
648
608
|
function centroidRingEnd() {
|
|
649
609
|
centroidRingPoint(lambda00, phi00);
|
|
650
610
|
centroidStream.point = centroidPoint;
|
|
651
611
|
}
|
|
652
|
-
|
|
653
612
|
function centroidRingPointFirst(lambda, phi) {
|
|
654
613
|
lambda00 = lambda, phi00 = phi;
|
|
655
614
|
lambda *= radians$1, phi *= radians$1;
|
|
@@ -660,21 +619,19 @@
|
|
|
660
619
|
z0 = sin(phi);
|
|
661
620
|
centroidPointCartesian(x0, y0, z0);
|
|
662
621
|
}
|
|
663
|
-
|
|
664
622
|
function centroidRingPoint(lambda, phi) {
|
|
665
623
|
lambda *= radians$1, phi *= radians$1;
|
|
666
624
|
var cosPhi = cos(phi),
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
|
678
635
|
X2.add(v * cx);
|
|
679
636
|
Y2.add(v * cy);
|
|
680
637
|
Z2.add(v * cz);
|
|
@@ -684,7 +641,6 @@
|
|
|
684
641
|
Z1 += w * (z0 + (z0 = z));
|
|
685
642
|
centroidPointCartesian(x0, y0, z0);
|
|
686
643
|
}
|
|
687
|
-
|
|
688
644
|
function centroid (object) {
|
|
689
645
|
W0 = W1 = X0 = Y0 = Z0 = X1 = Y1 = Z1 = 0;
|
|
690
646
|
X2 = new Adder();
|
|
@@ -692,19 +648,19 @@
|
|
|
692
648
|
Z2 = new Adder();
|
|
693
649
|
geoStream(object, centroidStream);
|
|
694
650
|
var x = +X2,
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
651
|
+
y = +Y2,
|
|
652
|
+
z = +Z2,
|
|
653
|
+
m = hypot(x, y, z);
|
|
698
654
|
|
|
655
|
+
// If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
|
|
699
656
|
if (m < epsilon2) {
|
|
700
|
-
x = X1, y = Y1, z = Z1;
|
|
701
|
-
|
|
657
|
+
x = X1, y = Y1, z = Z1;
|
|
658
|
+
// If the feature has zero length, fall back to arithmetic mean of point vectors.
|
|
702
659
|
if (W1 < epsilon) x = X0, y = Y0, z = Z0;
|
|
703
|
-
m = hypot(x, y, z);
|
|
704
|
-
|
|
660
|
+
m = hypot(x, y, z);
|
|
661
|
+
// If the feature still has an undefined ccentroid, then return.
|
|
705
662
|
if (m < epsilon2) return [NaN, NaN];
|
|
706
663
|
}
|
|
707
|
-
|
|
708
664
|
return [atan2(y, x) * degrees$1, asin(z / m) * degrees$1];
|
|
709
665
|
}
|
|
710
666
|
|
|
@@ -720,7 +676,6 @@
|
|
|
720
676
|
}
|
|
721
677
|
};
|
|
722
678
|
}
|
|
723
|
-
|
|
724
679
|
const geoArea = geoMethod('area', area);
|
|
725
680
|
const geoBounds = geoMethod('bounds', bounds);
|
|
726
681
|
const geoCentroid = geoMethod('centroid', centroid);
|
|
@@ -733,7 +688,6 @@
|
|
|
733
688
|
value = true;
|
|
734
689
|
break;
|
|
735
690
|
}
|
|
736
|
-
|
|
737
691
|
item = item.mark.group;
|
|
738
692
|
}
|
|
739
693
|
return value;
|
|
@@ -745,10 +699,8 @@
|
|
|
745
699
|
} catch (err) {
|
|
746
700
|
df.warn(err);
|
|
747
701
|
}
|
|
748
|
-
|
|
749
702
|
return args[args.length - 1];
|
|
750
703
|
}
|
|
751
|
-
|
|
752
704
|
function warn() {
|
|
753
705
|
return log(this.context.dataflow, 'warn', arguments);
|
|
754
706
|
}
|
|
@@ -765,9 +717,7 @@
|
|
|
765
717
|
}
|
|
766
718
|
function extend(parent, definition) {
|
|
767
719
|
var prototype = Object.create(parent.prototype);
|
|
768
|
-
|
|
769
720
|
for (var key in definition) prototype[key] = definition[key];
|
|
770
|
-
|
|
771
721
|
return prototype;
|
|
772
722
|
}
|
|
773
723
|
|
|
@@ -775,15 +725,15 @@
|
|
|
775
725
|
var darker = 0.7;
|
|
776
726
|
var brighter = 1 / darker;
|
|
777
727
|
var reI = "\\s*([+-]?\\d+)\\s*",
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
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}\\)$`);
|
|
787
737
|
var named = {
|
|
788
738
|
aliceblue: 0xf0f8ff,
|
|
789
739
|
antiquewhite: 0xfaebd7,
|
|
@@ -935,32 +885,32 @@
|
|
|
935
885
|
yellowgreen: 0x9acd32
|
|
936
886
|
};
|
|
937
887
|
define(Color, color, {
|
|
938
|
-
copy
|
|
888
|
+
copy(channels) {
|
|
939
889
|
return Object.assign(new this.constructor(), this, channels);
|
|
940
890
|
},
|
|
941
|
-
displayable
|
|
891
|
+
displayable() {
|
|
942
892
|
return this.rgb().displayable();
|
|
943
893
|
},
|
|
944
894
|
hex: color_formatHex,
|
|
945
895
|
// Deprecated! Use color.formatHex.
|
|
946
896
|
formatHex: color_formatHex,
|
|
897
|
+
formatHex8: color_formatHex8,
|
|
947
898
|
formatHsl: color_formatHsl,
|
|
948
899
|
formatRgb: color_formatRgb,
|
|
949
900
|
toString: color_formatRgb
|
|
950
901
|
});
|
|
951
|
-
|
|
952
902
|
function color_formatHex() {
|
|
953
903
|
return this.rgb().formatHex();
|
|
954
904
|
}
|
|
955
|
-
|
|
905
|
+
function color_formatHex8() {
|
|
906
|
+
return this.rgb().formatHex8();
|
|
907
|
+
}
|
|
956
908
|
function color_formatHsl() {
|
|
957
909
|
return hslConvert(this).formatHsl();
|
|
958
910
|
}
|
|
959
|
-
|
|
960
911
|
function color_formatRgb() {
|
|
961
912
|
return this.rgb().formatRgb();
|
|
962
913
|
}
|
|
963
|
-
|
|
964
914
|
function color(format) {
|
|
965
915
|
var m, l;
|
|
966
916
|
format = (format + "").trim().toLowerCase();
|
|
@@ -978,16 +928,13 @@
|
|
|
978
928
|
: named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
|
|
979
929
|
: format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
|
|
980
930
|
}
|
|
981
|
-
|
|
982
931
|
function rgbn(n) {
|
|
983
932
|
return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
|
|
984
933
|
}
|
|
985
|
-
|
|
986
934
|
function rgba(r, g, b, a) {
|
|
987
935
|
if (a <= 0) r = g = b = NaN;
|
|
988
936
|
return new Rgb(r, g, b, a);
|
|
989
937
|
}
|
|
990
|
-
|
|
991
938
|
function rgbConvert(o) {
|
|
992
939
|
if (!(o instanceof Color)) o = color(o);
|
|
993
940
|
if (!o) return new Rgb();
|
|
@@ -1004,47 +951,54 @@
|
|
|
1004
951
|
this.opacity = +opacity;
|
|
1005
952
|
}
|
|
1006
953
|
define(Rgb, rgb, extend(Color, {
|
|
1007
|
-
brighter
|
|
954
|
+
brighter(k) {
|
|
1008
955
|
k = k == null ? brighter : Math.pow(brighter, k);
|
|
1009
956
|
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
|
|
1010
957
|
},
|
|
1011
|
-
darker
|
|
958
|
+
darker(k) {
|
|
1012
959
|
k = k == null ? darker : Math.pow(darker, k);
|
|
1013
960
|
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
|
|
1014
961
|
},
|
|
1015
|
-
rgb
|
|
962
|
+
rgb() {
|
|
1016
963
|
return this;
|
|
1017
964
|
},
|
|
1018
|
-
|
|
965
|
+
clamp() {
|
|
966
|
+
return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity));
|
|
967
|
+
},
|
|
968
|
+
displayable() {
|
|
1019
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;
|
|
1020
970
|
},
|
|
1021
971
|
hex: rgb_formatHex,
|
|
1022
972
|
// Deprecated! Use color.formatHex.
|
|
1023
973
|
formatHex: rgb_formatHex,
|
|
974
|
+
formatHex8: rgb_formatHex8,
|
|
1024
975
|
formatRgb: rgb_formatRgb,
|
|
1025
976
|
toString: rgb_formatRgb
|
|
1026
977
|
}));
|
|
1027
|
-
|
|
1028
978
|
function rgb_formatHex() {
|
|
1029
|
-
return
|
|
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)}`;
|
|
1030
983
|
}
|
|
1031
|
-
|
|
1032
984
|
function rgb_formatRgb() {
|
|
1033
|
-
|
|
1034
|
-
a
|
|
1035
|
-
|
|
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));
|
|
1036
993
|
}
|
|
1037
|
-
|
|
1038
994
|
function hex(value) {
|
|
1039
|
-
value =
|
|
995
|
+
value = clampi(value);
|
|
1040
996
|
return (value < 16 ? "0" : "") + value.toString(16);
|
|
1041
997
|
}
|
|
1042
|
-
|
|
1043
998
|
function hsla(h, s, l, a) {
|
|
1044
999
|
if (a <= 0) h = s = l = NaN;else if (l <= 0 || l >= 1) h = s = NaN;else if (s <= 0) h = NaN;
|
|
1045
1000
|
return new Hsl(h, s, l, a);
|
|
1046
1001
|
}
|
|
1047
|
-
|
|
1048
1002
|
function hslConvert(o) {
|
|
1049
1003
|
if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
|
|
1050
1004
|
if (!(o instanceof Color)) o = color(o);
|
|
@@ -1052,14 +1006,13 @@
|
|
|
1052
1006
|
if (o instanceof Hsl) return o;
|
|
1053
1007
|
o = o.rgb();
|
|
1054
1008
|
var r = o.r / 255,
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
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;
|
|
1063
1016
|
if (s) {
|
|
1064
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;
|
|
1065
1018
|
s /= l < 0.5 ? max + min : 2 - max - min;
|
|
@@ -1067,48 +1020,54 @@
|
|
|
1067
1020
|
} else {
|
|
1068
1021
|
s = l > 0 && l < 1 ? 0 : h;
|
|
1069
1022
|
}
|
|
1070
|
-
|
|
1071
1023
|
return new Hsl(h, s, l, o.opacity);
|
|
1072
1024
|
}
|
|
1073
1025
|
function hsl(h, s, l, opacity) {
|
|
1074
1026
|
return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
|
|
1075
1027
|
}
|
|
1076
|
-
|
|
1077
1028
|
function Hsl(h, s, l, opacity) {
|
|
1078
1029
|
this.h = +h;
|
|
1079
1030
|
this.s = +s;
|
|
1080
1031
|
this.l = +l;
|
|
1081
1032
|
this.opacity = +opacity;
|
|
1082
1033
|
}
|
|
1083
|
-
|
|
1084
1034
|
define(Hsl, hsl, extend(Color, {
|
|
1085
|
-
brighter
|
|
1035
|
+
brighter(k) {
|
|
1086
1036
|
k = k == null ? brighter : Math.pow(brighter, k);
|
|
1087
1037
|
return new Hsl(this.h, this.s, this.l * k, this.opacity);
|
|
1088
1038
|
},
|
|
1089
|
-
darker
|
|
1039
|
+
darker(k) {
|
|
1090
1040
|
k = k == null ? darker : Math.pow(darker, k);
|
|
1091
1041
|
return new Hsl(this.h, this.s, this.l * k, this.opacity);
|
|
1092
1042
|
},
|
|
1093
|
-
rgb
|
|
1043
|
+
rgb() {
|
|
1094
1044
|
var h = this.h % 360 + (this.h < 0) * 360,
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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;
|
|
1099
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);
|
|
1100
1050
|
},
|
|
1101
|
-
|
|
1051
|
+
clamp() {
|
|
1052
|
+
return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity));
|
|
1053
|
+
},
|
|
1054
|
+
displayable() {
|
|
1102
1055
|
return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
|
|
1103
1056
|
},
|
|
1104
|
-
formatHsl
|
|
1105
|
-
|
|
1106
|
-
a
|
|
1107
|
-
return (a === 1 ? "hsl(" : "hsla(") + (this.h || 0) + ", " + (this.s || 0) * 100 + "%, " + (this.l || 0) * 100 + "%" + (a === 1 ? ")" : ", " + a + ")");
|
|
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})`}`;
|
|
1108
1060
|
}
|
|
1109
1061
|
}));
|
|
1110
|
-
|
|
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
|
+
}
|
|
1111
1069
|
|
|
1070
|
+
/* From FvD 13.37, CSS Color Module Level 3 */
|
|
1112
1071
|
function hsl2rgb(h, m1, m2) {
|
|
1113
1072
|
return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
|
|
1114
1073
|
}
|
|
@@ -1116,25 +1075,25 @@
|
|
|
1116
1075
|
const radians = Math.PI / 180;
|
|
1117
1076
|
const degrees = 180 / Math.PI;
|
|
1118
1077
|
|
|
1078
|
+
// https://observablehq.com/@mbostock/lab-and-rgb
|
|
1119
1079
|
const K = 18,
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
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;
|
|
1128
1087
|
function labConvert(o) {
|
|
1129
1088
|
if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
|
|
1130
1089
|
if (o instanceof Hcl) return hcl2lab(o);
|
|
1131
1090
|
if (!(o instanceof Rgb)) o = rgbConvert(o);
|
|
1132
1091
|
var r = rgb2lrgb(o.r),
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
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;
|
|
1138
1097
|
if (r === g && g === b) x = z = y;else {
|
|
1139
1098
|
x = xyz2lab((0.4360747 * r + 0.3850649 * g + 0.1430804 * b) / Xn);
|
|
1140
1099
|
z = xyz2lab((0.0139322 * r + 0.0971045 * g + 0.7141733 * b) / Zn);
|
|
@@ -1151,39 +1110,34 @@
|
|
|
1151
1110
|
this.opacity = +opacity;
|
|
1152
1111
|
}
|
|
1153
1112
|
define(Lab, lab, extend(Color, {
|
|
1154
|
-
brighter
|
|
1113
|
+
brighter(k) {
|
|
1155
1114
|
return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity);
|
|
1156
1115
|
},
|
|
1157
|
-
darker
|
|
1116
|
+
darker(k) {
|
|
1158
1117
|
return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity);
|
|
1159
1118
|
},
|
|
1160
|
-
rgb
|
|
1119
|
+
rgb() {
|
|
1161
1120
|
var y = (this.l + 16) / 116,
|
|
1162
|
-
|
|
1163
|
-
|
|
1121
|
+
x = isNaN(this.a) ? y : y + this.a / 500,
|
|
1122
|
+
z = isNaN(this.b) ? y : y - this.b / 200;
|
|
1164
1123
|
x = Xn * lab2xyz(x);
|
|
1165
1124
|
y = Yn * lab2xyz(y);
|
|
1166
1125
|
z = Zn * lab2xyz(z);
|
|
1167
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);
|
|
1168
1127
|
}
|
|
1169
1128
|
}));
|
|
1170
|
-
|
|
1171
1129
|
function xyz2lab(t) {
|
|
1172
1130
|
return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
|
|
1173
1131
|
}
|
|
1174
|
-
|
|
1175
1132
|
function lab2xyz(t) {
|
|
1176
1133
|
return t > t1 ? t * t * t : t2 * (t - t0);
|
|
1177
1134
|
}
|
|
1178
|
-
|
|
1179
1135
|
function lrgb2rgb(x) {
|
|
1180
1136
|
return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
|
|
1181
1137
|
}
|
|
1182
|
-
|
|
1183
1138
|
function rgb2lrgb(x) {
|
|
1184
1139
|
return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
|
|
1185
1140
|
}
|
|
1186
|
-
|
|
1187
1141
|
function hclConvert(o) {
|
|
1188
1142
|
if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
|
|
1189
1143
|
if (!(o instanceof Lab)) o = labConvert(o);
|
|
@@ -1200,48 +1154,45 @@
|
|
|
1200
1154
|
this.l = +l;
|
|
1201
1155
|
this.opacity = +opacity;
|
|
1202
1156
|
}
|
|
1203
|
-
|
|
1204
1157
|
function hcl2lab(o) {
|
|
1205
1158
|
if (isNaN(o.h)) return new Lab(o.l, 0, 0, o.opacity);
|
|
1206
1159
|
var h = o.h * radians;
|
|
1207
1160
|
return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
|
|
1208
1161
|
}
|
|
1209
|
-
|
|
1210
1162
|
define(Hcl, hcl, extend(Color, {
|
|
1211
|
-
brighter
|
|
1163
|
+
brighter(k) {
|
|
1212
1164
|
return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity);
|
|
1213
1165
|
},
|
|
1214
|
-
darker
|
|
1166
|
+
darker(k) {
|
|
1215
1167
|
return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity);
|
|
1216
1168
|
},
|
|
1217
|
-
rgb
|
|
1169
|
+
rgb() {
|
|
1218
1170
|
return hcl2lab(this).rgb();
|
|
1219
1171
|
}
|
|
1220
1172
|
}));
|
|
1221
1173
|
|
|
1174
|
+
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
|
|
1222
1175
|
function channel_luminance_value(channelValue) {
|
|
1223
1176
|
const val = channelValue / 255;
|
|
1224
|
-
|
|
1225
1177
|
if (val <= 0.03928) {
|
|
1226
1178
|
return val / 12.92;
|
|
1227
1179
|
}
|
|
1228
|
-
|
|
1229
1180
|
return Math.pow((val + 0.055) / 1.055, 2.4);
|
|
1230
1181
|
}
|
|
1231
|
-
|
|
1232
1182
|
function luminance(color) {
|
|
1233
1183
|
const c = rgb(color),
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1184
|
+
r = channel_luminance_value(c.r),
|
|
1185
|
+
g = channel_luminance_value(c.g),
|
|
1186
|
+
b = channel_luminance_value(c.b);
|
|
1237
1187
|
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
1238
|
-
}
|
|
1188
|
+
}
|
|
1239
1189
|
|
|
1190
|
+
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
|
|
1240
1191
|
function contrast(color1, color2) {
|
|
1241
1192
|
const lum1 = luminance(color1),
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1193
|
+
lum2 = luminance(color2),
|
|
1194
|
+
lumL = Math.max(lum1, lum2),
|
|
1195
|
+
lumD = Math.min(lum1, lum2);
|
|
1245
1196
|
return (lumL + 0.05) / (lumD + 0.05);
|
|
1246
1197
|
}
|
|
1247
1198
|
|
|
@@ -1254,41 +1205,33 @@
|
|
|
1254
1205
|
function equal(a, b) {
|
|
1255
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;
|
|
1256
1207
|
}
|
|
1257
|
-
|
|
1258
1208
|
function equalArray(a, b) {
|
|
1259
1209
|
for (let i = 0, n = a.length; i < n; ++i) {
|
|
1260
1210
|
if (!equal(a[i], b[i])) return false;
|
|
1261
1211
|
}
|
|
1262
|
-
|
|
1263
1212
|
return true;
|
|
1264
1213
|
}
|
|
1265
|
-
|
|
1266
1214
|
function equalObject(a, b) {
|
|
1267
1215
|
for (const key in a) {
|
|
1268
1216
|
if (!equal(a[key], b[key])) return false;
|
|
1269
1217
|
}
|
|
1270
|
-
|
|
1271
1218
|
return true;
|
|
1272
1219
|
}
|
|
1273
|
-
|
|
1274
1220
|
function removePredicate(props) {
|
|
1275
1221
|
return _ => equalObject(props, _);
|
|
1276
1222
|
}
|
|
1277
|
-
|
|
1278
1223
|
function modify (name, insert, remove, toggle, modify, values) {
|
|
1279
1224
|
const df = this.context.dataflow,
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1225
|
+
data = this.context.data[name],
|
|
1226
|
+
input = data.input,
|
|
1227
|
+
stamp = df.stamp();
|
|
1283
1228
|
let changes = data.changes,
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1229
|
+
predicate,
|
|
1230
|
+
key;
|
|
1287
1231
|
if (df._trigger === false || !(input.value.length || insert || toggle)) {
|
|
1288
1232
|
// nothing to do!
|
|
1289
1233
|
return 0;
|
|
1290
1234
|
}
|
|
1291
|
-
|
|
1292
1235
|
if (!changes || changes.stamp < stamp) {
|
|
1293
1236
|
data.changes = changes = df.changeset();
|
|
1294
1237
|
changes.stamp = stamp;
|
|
@@ -1297,39 +1240,33 @@
|
|
|
1297
1240
|
df.pulse(input, changes).run();
|
|
1298
1241
|
}, true, 1);
|
|
1299
1242
|
}
|
|
1300
|
-
|
|
1301
1243
|
if (remove) {
|
|
1302
1244
|
predicate = remove === true ? vegaUtil.truthy : vegaUtil.isArray(remove) || vegaDataflow.isTuple(remove) ? remove : removePredicate(remove);
|
|
1303
1245
|
changes.remove(predicate);
|
|
1304
1246
|
}
|
|
1305
|
-
|
|
1306
1247
|
if (insert) {
|
|
1307
1248
|
changes.insert(insert);
|
|
1308
1249
|
}
|
|
1309
|
-
|
|
1310
1250
|
if (toggle) {
|
|
1311
1251
|
predicate = removePredicate(toggle);
|
|
1312
|
-
|
|
1313
1252
|
if (input.value.some(predicate)) {
|
|
1314
1253
|
changes.remove(predicate);
|
|
1315
1254
|
} else {
|
|
1316
1255
|
changes.insert(toggle);
|
|
1317
1256
|
}
|
|
1318
1257
|
}
|
|
1319
|
-
|
|
1320
1258
|
if (modify) {
|
|
1321
1259
|
for (key in values) {
|
|
1322
1260
|
changes.modify(modify, key, values[key]);
|
|
1323
1261
|
}
|
|
1324
1262
|
}
|
|
1325
|
-
|
|
1326
1263
|
return 1;
|
|
1327
1264
|
}
|
|
1328
1265
|
|
|
1329
1266
|
function pinchDistance(event) {
|
|
1330
1267
|
const t = event.touches,
|
|
1331
|
-
|
|
1332
|
-
|
|
1268
|
+
dx = t[0].clientX - t[1].clientX,
|
|
1269
|
+
dy = t[0].clientY - t[1].clientY;
|
|
1333
1270
|
return Math.sqrt(dx * dx + dy * dy);
|
|
1334
1271
|
}
|
|
1335
1272
|
function pinchAngle(event) {
|
|
@@ -1337,6 +1274,7 @@
|
|
|
1337
1274
|
return Math.atan2(t[0].clientY - t[1].clientY, t[0].clientX - t[1].clientX);
|
|
1338
1275
|
}
|
|
1339
1276
|
|
|
1277
|
+
// memoize accessor functions
|
|
1340
1278
|
const accessors = {};
|
|
1341
1279
|
function pluck (data, name) {
|
|
1342
1280
|
const accessor = accessors[name] || (accessors[name] = vegaUtil.field(name));
|
|
@@ -1346,11 +1284,9 @@
|
|
|
1346
1284
|
function array(seq) {
|
|
1347
1285
|
return vegaUtil.isArray(seq) || ArrayBuffer.isView(seq) ? seq : null;
|
|
1348
1286
|
}
|
|
1349
|
-
|
|
1350
1287
|
function sequence(seq) {
|
|
1351
1288
|
return array(seq) || (vegaUtil.isString(seq) ? seq : null);
|
|
1352
1289
|
}
|
|
1353
|
-
|
|
1354
1290
|
function join(seq, ...args) {
|
|
1355
1291
|
return array(seq).join(...args);
|
|
1356
1292
|
}
|
|
@@ -1403,23 +1339,20 @@
|
|
|
1403
1339
|
scale = getScale(scale, (group || this).context);
|
|
1404
1340
|
const gradient = vegaScenegraph.Gradient(p0, p1);
|
|
1405
1341
|
let stops = scale.domain(),
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1342
|
+
min = stops[0],
|
|
1343
|
+
max = vegaUtil.peek(stops),
|
|
1344
|
+
fraction = vegaUtil.identity;
|
|
1410
1345
|
if (!(max - min)) {
|
|
1411
1346
|
// expand scale if domain has zero span, fix #1479
|
|
1412
1347
|
scale = (scale.interpolator ? vegaScale.scale('sequential')().interpolator(scale.interpolator()) : vegaScale.scale('linear')().interpolate(scale.interpolate()).range(scale.range())).domain([min = 0, max = 1]);
|
|
1413
1348
|
} else {
|
|
1414
1349
|
fraction = vegaScale.scaleFraction(scale, min, max);
|
|
1415
1350
|
}
|
|
1416
|
-
|
|
1417
1351
|
if (scale.ticks) {
|
|
1418
1352
|
stops = scale.ticks(+count || 15);
|
|
1419
1353
|
if (min !== stops[0]) stops.unshift(min);
|
|
1420
1354
|
if (max !== vegaUtil.peek(stops)) stops.push(max);
|
|
1421
1355
|
}
|
|
1422
|
-
|
|
1423
1356
|
stops.forEach(_ => gradient.stop(fraction(_), scale(_)));
|
|
1424
1357
|
return gradient;
|
|
1425
1358
|
}
|
|
@@ -1438,16 +1371,14 @@
|
|
|
1438
1371
|
}
|
|
1439
1372
|
|
|
1440
1373
|
const datum = d => d.data;
|
|
1441
|
-
|
|
1442
1374
|
function treeNodes(name, context) {
|
|
1443
1375
|
const tree = data.call(context, name);
|
|
1444
1376
|
return tree.root && tree.root.lookup || {};
|
|
1445
1377
|
}
|
|
1446
|
-
|
|
1447
1378
|
function treePath(name, source, target) {
|
|
1448
1379
|
const nodes = treeNodes(name, this),
|
|
1449
|
-
|
|
1450
|
-
|
|
1380
|
+
s = nodes[source],
|
|
1381
|
+
t = nodes[target];
|
|
1451
1382
|
return s && t ? s.path(t).map(datum) : undefined;
|
|
1452
1383
|
}
|
|
1453
1384
|
function treeAncestors(name, node) {
|
|
@@ -1456,139 +1387,130 @@
|
|
|
1456
1387
|
}
|
|
1457
1388
|
|
|
1458
1389
|
const _window = () => typeof window !== 'undefined' && window || null;
|
|
1459
|
-
|
|
1460
1390
|
function screen() {
|
|
1461
1391
|
const w = _window();
|
|
1462
|
-
|
|
1463
1392
|
return w ? w.screen : {};
|
|
1464
1393
|
}
|
|
1465
1394
|
function windowSize() {
|
|
1466
1395
|
const w = _window();
|
|
1467
|
-
|
|
1468
1396
|
return w ? [w.innerWidth, w.innerHeight] : [undefined, undefined];
|
|
1469
1397
|
}
|
|
1470
1398
|
function containerSize() {
|
|
1471
1399
|
const view = this.context.dataflow,
|
|
1472
|
-
|
|
1400
|
+
el = view.container && view.container();
|
|
1473
1401
|
return el ? [el.clientWidth, el.clientHeight] : [undefined, undefined];
|
|
1474
1402
|
}
|
|
1475
1403
|
|
|
1476
1404
|
function intersect (b, opt, group) {
|
|
1477
1405
|
if (!b) return [];
|
|
1478
1406
|
const [u, v] = b,
|
|
1479
|
-
|
|
1480
|
-
|
|
1407
|
+
box = new vegaScenegraph.Bounds().set(u[0], u[1], v[0], v[1]),
|
|
1408
|
+
scene = group || this.context.dataflow.scenegraph().root;
|
|
1481
1409
|
return vegaScenegraph.intersect(scene, box, filter(opt));
|
|
1482
1410
|
}
|
|
1483
|
-
|
|
1484
1411
|
function filter(opt) {
|
|
1485
1412
|
let p = null;
|
|
1486
|
-
|
|
1487
1413
|
if (opt) {
|
|
1488
1414
|
const types = vegaUtil.array(opt.marktype),
|
|
1489
|
-
|
|
1490
|
-
|
|
1415
|
+
names = vegaUtil.array(opt.markname);
|
|
1491
1416
|
p = _ => (!types.length || types.some(t => _.marktype === t)) && (!names.length || names.some(s => _.name === s));
|
|
1492
1417
|
}
|
|
1493
|
-
|
|
1494
1418
|
return p;
|
|
1495
1419
|
}
|
|
1496
1420
|
|
|
1497
1421
|
/**
|
|
1498
1422
|
* Appends a new point to the lasso
|
|
1499
|
-
*
|
|
1423
|
+
*
|
|
1500
1424
|
* @param {*} lasso the lasso in pixel space
|
|
1501
1425
|
* @param {*} x the x coordinate in pixel space
|
|
1502
1426
|
* @param {*} y the y coordinate in pixel space
|
|
1503
1427
|
* @param {*} minDist the minimum distance, in pixels, that thenew point needs to be apart from the last point
|
|
1504
1428
|
* @returns a new array containing the lasso with the new point
|
|
1505
1429
|
*/
|
|
1506
|
-
|
|
1507
1430
|
function lassoAppend(lasso, x, y, minDist = 5) {
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
if (last === undefined || Math.sqrt((last[0] - x) ** 2 + (last[1] - y) ** 2) > minDist) {
|
|
1511
|
-
lasso.push([x, y]);
|
|
1512
|
-
return [...lasso];
|
|
1513
|
-
}
|
|
1431
|
+
lasso = vegaUtil.array(lasso);
|
|
1432
|
+
const last = lasso[lasso.length - 1];
|
|
1514
1433
|
|
|
1515
|
-
|
|
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;
|
|
1516
1436
|
}
|
|
1437
|
+
|
|
1517
1438
|
/**
|
|
1518
1439
|
* Generates a svg path command which draws a lasso
|
|
1519
|
-
*
|
|
1440
|
+
*
|
|
1520
1441
|
* @param {*} lasso the lasso in pixel space in the form [[x,y], [x,y], ...]
|
|
1521
1442
|
* @returns the svg path command that draws the lasso
|
|
1522
1443
|
*/
|
|
1523
|
-
|
|
1524
1444
|
function lassoPath(lasso) {
|
|
1525
|
-
return (lasso
|
|
1445
|
+
return vegaUtil.array(lasso).reduce((svg, [x, y], i) => {
|
|
1526
1446
|
return svg += i == 0 ? `M ${x},${y} ` : i === lasso.length - 1 ? ' Z' : `L ${x},${y} `;
|
|
1527
1447
|
}, '');
|
|
1528
1448
|
}
|
|
1449
|
+
|
|
1529
1450
|
/**
|
|
1530
1451
|
* Inverts the lasso from pixel space to an array of vega scenegraph tuples
|
|
1531
|
-
*
|
|
1452
|
+
*
|
|
1532
1453
|
* @param {*} data the dataset
|
|
1533
1454
|
* @param {*} pixelLasso the lasso in pixel space, [[x,y], [x,y], ...]
|
|
1534
1455
|
* @param {*} unit the unit where the lasso is defined
|
|
1535
|
-
*
|
|
1456
|
+
*
|
|
1536
1457
|
* @returns an array of vega scenegraph tuples
|
|
1537
1458
|
*/
|
|
1538
|
-
|
|
1539
1459
|
function intersectLasso(markname, pixelLasso, unit) {
|
|
1540
1460
|
const {
|
|
1541
1461
|
x,
|
|
1542
1462
|
y,
|
|
1543
1463
|
mark
|
|
1544
1464
|
} = unit;
|
|
1545
|
-
const bb = new vegaScenegraph.Bounds().set(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
|
|
1465
|
+
const bb = new vegaScenegraph.Bounds().set(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
|
|
1546
1466
|
|
|
1467
|
+
// Get bounding box around lasso
|
|
1547
1468
|
for (const [px, py] of pixelLasso) {
|
|
1548
1469
|
if (px < bb.x1) bb.x1 = px;
|
|
1549
1470
|
if (px > bb.x2) bb.x2 = px;
|
|
1550
1471
|
if (py < bb.y1) bb.y1 = py;
|
|
1551
1472
|
if (py > bb.y2) bb.y2 = py;
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1473
|
+
}
|
|
1554
1474
|
|
|
1475
|
+
// Translate bb against unit coordinates
|
|
1555
1476
|
bb.translate(x, y);
|
|
1556
|
-
const intersection = intersect([[bb.x1, bb.y1], [bb.x2, bb.y2]], markname, mark);
|
|
1477
|
+
const intersection = intersect([[bb.x1, bb.y1], [bb.x2, bb.y2]], markname, mark);
|
|
1557
1478
|
|
|
1479
|
+
// Check every point against the lasso
|
|
1558
1480
|
return intersection.filter(tuple => pointInPolygon(tuple.x, tuple.y, pixelLasso));
|
|
1559
1481
|
}
|
|
1482
|
+
|
|
1560
1483
|
/**
|
|
1561
1484
|
* Performs a test if a point is inside a polygon based on the idea from
|
|
1562
1485
|
* https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
|
|
1563
|
-
*
|
|
1486
|
+
*
|
|
1564
1487
|
* This method will not need the same start/end point since it wraps around the edges of the array
|
|
1565
|
-
*
|
|
1488
|
+
*
|
|
1566
1489
|
* @param {*} test a point to test against
|
|
1567
1490
|
* @param {*} polygon a polygon in the form [[x,y], [x,y], ...]
|
|
1568
1491
|
* @returns true if the point lies inside the polygon, false otherwise
|
|
1569
1492
|
*/
|
|
1570
|
-
|
|
1571
1493
|
function pointInPolygon(testx, testy, polygon) {
|
|
1572
1494
|
let intersections = 0;
|
|
1573
|
-
|
|
1574
1495
|
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
1575
1496
|
const [prevX, prevY] = polygon[j];
|
|
1576
|
-
const [x, y] = polygon[i];
|
|
1497
|
+
const [x, y] = polygon[i];
|
|
1577
1498
|
|
|
1499
|
+
// count intersections
|
|
1578
1500
|
if (y > testy != prevY > testy && testx < (prevX - x) * (testy - y) / (prevY - y) + x) {
|
|
1579
1501
|
intersections++;
|
|
1580
1502
|
}
|
|
1581
|
-
}
|
|
1582
|
-
|
|
1503
|
+
}
|
|
1583
1504
|
|
|
1505
|
+
// point is in polygon if intersection count is odd
|
|
1584
1506
|
return intersections & 1;
|
|
1585
1507
|
}
|
|
1586
1508
|
|
|
1509
|
+
// Expression function context object
|
|
1587
1510
|
const functionContext = {
|
|
1588
1511
|
random() {
|
|
1589
1512
|
return vegaStatistics.random();
|
|
1590
1513
|
},
|
|
1591
|
-
|
|
1592
1514
|
// override default
|
|
1593
1515
|
cumulativeNormal: vegaStatistics.cumulativeNormal,
|
|
1594
1516
|
cumulativeLogNormal: vegaStatistics.cumulativeLogNormal,
|
|
@@ -1605,27 +1527,21 @@
|
|
|
1605
1527
|
isArray: vegaUtil.isArray,
|
|
1606
1528
|
isBoolean: vegaUtil.isBoolean,
|
|
1607
1529
|
isDate: vegaUtil.isDate,
|
|
1608
|
-
|
|
1609
1530
|
isDefined(_) {
|
|
1610
1531
|
return _ !== undefined;
|
|
1611
1532
|
},
|
|
1612
|
-
|
|
1613
1533
|
isNumber: vegaUtil.isNumber,
|
|
1614
1534
|
isObject: vegaUtil.isObject,
|
|
1615
1535
|
isRegExp: vegaUtil.isRegExp,
|
|
1616
1536
|
isString: vegaUtil.isString,
|
|
1617
1537
|
isTuple: vegaDataflow.isTuple,
|
|
1618
|
-
|
|
1619
1538
|
isValid(_) {
|
|
1620
1539
|
return _ != null && _ === _;
|
|
1621
1540
|
},
|
|
1622
|
-
|
|
1623
1541
|
toBoolean: vegaUtil.toBoolean,
|
|
1624
|
-
|
|
1625
1542
|
toDate(_) {
|
|
1626
1543
|
return vegaUtil.toDate(_);
|
|
1627
1544
|
},
|
|
1628
|
-
|
|
1629
1545
|
// suppress extra arguments
|
|
1630
1546
|
toNumber: vegaUtil.toNumber,
|
|
1631
1547
|
toString: vegaUtil.toString,
|
|
@@ -1674,11 +1590,9 @@
|
|
|
1674
1590
|
warn,
|
|
1675
1591
|
info,
|
|
1676
1592
|
debug,
|
|
1677
|
-
|
|
1678
1593
|
extent(_) {
|
|
1679
1594
|
return vegaUtil.extent(_);
|
|
1680
1595
|
},
|
|
1681
|
-
|
|
1682
1596
|
// suppress extra arguments
|
|
1683
1597
|
inScope,
|
|
1684
1598
|
intersect,
|
|
@@ -1706,14 +1620,14 @@
|
|
|
1706
1620
|
intersectLasso
|
|
1707
1621
|
};
|
|
1708
1622
|
const eventFunctions = ['view', 'item', 'group', 'xy', 'x', 'y'],
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
// 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
|
|
1716
1629
|
|
|
1630
|
+
// export code generator parameters
|
|
1717
1631
|
const codegenParams = {
|
|
1718
1632
|
forbidden: ['_'],
|
|
1719
1633
|
allowed: ['datum', 'event', 'item'],
|
|
@@ -1722,38 +1636,41 @@
|
|
|
1722
1636
|
functions: buildFunctions,
|
|
1723
1637
|
constants: vegaExpression.constants,
|
|
1724
1638
|
visitors: astVisitors
|
|
1725
|
-
};
|
|
1639
|
+
};
|
|
1726
1640
|
|
|
1727
|
-
|
|
1641
|
+
// export code generator
|
|
1642
|
+
const codeGenerator = vegaExpression.codegenExpression(codegenParams);
|
|
1728
1643
|
|
|
1644
|
+
// Build expression function registry
|
|
1729
1645
|
function buildFunctions(codegen) {
|
|
1730
1646
|
const fn = vegaExpression.functions(codegen);
|
|
1731
1647
|
eventFunctions.forEach(name => fn[name] = eventPrefix + name);
|
|
1732
|
-
|
|
1733
1648
|
for (const name in functionContext) {
|
|
1734
1649
|
fn[name] = thisPrefix + name;
|
|
1735
1650
|
}
|
|
1736
|
-
|
|
1737
1651
|
vegaUtil.extend(fn, internalScaleFunctions(codegen, functionContext, astVisitors));
|
|
1738
1652
|
return fn;
|
|
1739
|
-
}
|
|
1740
|
-
|
|
1653
|
+
}
|
|
1741
1654
|
|
|
1655
|
+
// Register an expression function
|
|
1742
1656
|
function expressionFunction(name, fn, visitor) {
|
|
1743
1657
|
if (arguments.length === 1) {
|
|
1744
1658
|
return functionContext[name];
|
|
1745
|
-
}
|
|
1659
|
+
}
|
|
1746
1660
|
|
|
1661
|
+
// register with the functionContext
|
|
1662
|
+
functionContext[name] = fn;
|
|
1747
1663
|
|
|
1748
|
-
|
|
1664
|
+
// if there is an astVisitor register that, too
|
|
1665
|
+
if (visitor) astVisitors[name] = visitor;
|
|
1749
1666
|
|
|
1750
|
-
|
|
1667
|
+
// if the code generator has already been initialized,
|
|
1751
1668
|
// we need to also register the function with it
|
|
1752
|
-
|
|
1753
1669
|
if (codeGenerator) codeGenerator.functions[name] = thisPrefix + name;
|
|
1754
1670
|
return this;
|
|
1755
|
-
}
|
|
1671
|
+
}
|
|
1756
1672
|
|
|
1673
|
+
// register expression functions with ast visitors
|
|
1757
1674
|
expressionFunction('bandwidth', bandwidth, scaleVisitor);
|
|
1758
1675
|
expressionFunction('copy', copy, scaleVisitor);
|
|
1759
1676
|
expressionFunction('domain', domain, scaleVisitor);
|
|
@@ -1768,43 +1685,46 @@
|
|
|
1768
1685
|
expressionFunction('indata', indata, indataVisitor);
|
|
1769
1686
|
expressionFunction('data', data, dataVisitor);
|
|
1770
1687
|
expressionFunction('treePath', treePath, dataVisitor);
|
|
1771
|
-
expressionFunction('treeAncestors', treeAncestors, dataVisitor);
|
|
1688
|
+
expressionFunction('treeAncestors', treeAncestors, dataVisitor);
|
|
1772
1689
|
|
|
1690
|
+
// register Vega-Lite selection functions
|
|
1773
1691
|
expressionFunction('vlSelectionTest', vegaSelections.selectionTest, vegaSelections.selectionVisitor);
|
|
1774
1692
|
expressionFunction('vlSelectionIdTest', vegaSelections.selectionIdTest, vegaSelections.selectionVisitor);
|
|
1775
1693
|
expressionFunction('vlSelectionResolve', vegaSelections.selectionResolve, vegaSelections.selectionVisitor);
|
|
1776
1694
|
expressionFunction('vlSelectionTuples', vegaSelections.selectionTuples);
|
|
1777
1695
|
|
|
1778
1696
|
function parser (expr, scope) {
|
|
1779
|
-
const params = {};
|
|
1697
|
+
const params = {};
|
|
1780
1698
|
|
|
1699
|
+
// parse the expression to an abstract syntax tree (ast)
|
|
1781
1700
|
let ast;
|
|
1782
|
-
|
|
1783
1701
|
try {
|
|
1784
1702
|
expr = vegaUtil.isString(expr) ? expr : vegaUtil.stringValue(expr) + '';
|
|
1785
1703
|
ast = vegaExpression.parseExpression(expr);
|
|
1786
1704
|
} catch (err) {
|
|
1787
1705
|
vegaUtil.error('Expression parse error: ' + expr);
|
|
1788
|
-
}
|
|
1789
|
-
|
|
1706
|
+
}
|
|
1790
1707
|
|
|
1708
|
+
// analyze ast function calls for dependencies
|
|
1791
1709
|
ast.visit(node => {
|
|
1792
1710
|
if (node.type !== vegaExpression.CallExpression) return;
|
|
1793
1711
|
const name = node.callee.name,
|
|
1794
|
-
|
|
1712
|
+
visit = codegenParams.visitors[name];
|
|
1795
1713
|
if (visit) visit(name, node.arguments, scope, params);
|
|
1796
|
-
});
|
|
1714
|
+
});
|
|
1797
1715
|
|
|
1798
|
-
|
|
1716
|
+
// perform code generation
|
|
1717
|
+
const gen = codeGenerator(ast);
|
|
1799
1718
|
|
|
1719
|
+
// collect signal dependencies
|
|
1800
1720
|
gen.globals.forEach(name => {
|
|
1801
1721
|
const signalName = SignalPrefix + name;
|
|
1802
|
-
|
|
1803
1722
|
if (!vegaUtil.hasOwnProperty(params, signalName) && scope.getSignal(name)) {
|
|
1804
1723
|
params[signalName] = scope.signalRef(name);
|
|
1805
1724
|
}
|
|
1806
|
-
});
|
|
1725
|
+
});
|
|
1807
1726
|
|
|
1727
|
+
// return generated expression code and dependencies
|
|
1808
1728
|
return {
|
|
1809
1729
|
$expr: vegaUtil.extend({
|
|
1810
1730
|
code: gen.code
|
|
@@ -1877,6 +1797,4 @@
|
|
|
1877
1797
|
exports.warn = warn;
|
|
1878
1798
|
exports.windowSize = windowSize;
|
|
1879
1799
|
|
|
1880
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1881
|
-
|
|
1882
1800
|
}));
|