UNPKG

50.8 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-dataflow'), require('vega-scale'), require('vega-util')) :
3 typeof define === 'function' && define.amd ? define(['exports', 'vega-dataflow', 'vega-scale', 'vega-util'], factory) :
4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vega = {}, global.vega, global.vega, global.vega));
5})(this, (function (exports, vegaDataflow, vegaScale, vegaUtil) { 'use strict';
6
7 /**
8 * Generates axis ticks for visualizing a spatial scale.
9 * @constructor
10 * @param {object} params - The parameters for this operator.
11 * @param {Scale} params.scale - The scale to generate ticks for.
12 * @param {*} [params.count=10] - The approximate number of ticks, or
13 * desired tick interval, to use.
14 * @param {Array<*>} [params.values] - The exact tick values to use.
15 * These must be legal domain values for the provided scale.
16 * If provided, the count argument is ignored.
17 * @param {function(*):string} [params.formatSpecifier] - A format specifier
18 * to use in conjunction with scale.tickFormat. Legal values are
19 * any valid d3 4.0 format specifier.
20 * @param {function(*):string} [params.format] - The format function to use.
21 * If provided, the formatSpecifier argument is ignored.
22 */
23
24 function AxisTicks(params) {
25 vegaDataflow.Transform.call(this, null, params);
26 }
27 vegaUtil.inherits(AxisTicks, vegaDataflow.Transform, {
28 transform(_, pulse) {
29 if (this.value && !_.modified()) {
30 return pulse.StopPropagation;
31 }
32
33 var locale = pulse.dataflow.locale(),
34 out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS),
35 ticks = this.value,
36 scale = _.scale,
37 tally = _.count == null ? _.values ? _.values.length : 10 : _.count,
38 count = vegaScale.tickCount(scale, tally, _.minstep),
39 format = _.format || vegaScale.tickFormat(locale, scale, count, _.formatSpecifier, _.formatType, !!_.values),
40 values = _.values ? vegaScale.validTicks(scale, _.values, count) : vegaScale.tickValues(scale, count);
41 if (ticks) out.rem = ticks;
42 ticks = values.map((value, i) => vegaDataflow.ingest({
43 index: i / (values.length - 1 || 1),
44 value: value,
45 label: format(value)
46 }));
47
48 if (_.extra && ticks.length) {
49 // add an extra tick pegged to the initial domain value
50 // this is used to generate axes with 'binned' domains
51 ticks.push(vegaDataflow.ingest({
52 index: -1,
53 extra: {
54 value: ticks[0].value
55 },
56 label: ''
57 }));
58 }
59
60 out.source = ticks;
61 out.add = ticks;
62 this.value = ticks;
63 return out;
64 }
65
66 });
67
68 /**
69 * Joins a set of data elements against a set of visual items.
70 * @constructor
71 * @param {object} params - The parameters for this operator.
72 * @param {function(object): object} [params.item] - An item generator function.
73 * @param {function(object): *} [params.key] - The key field associating data and visual items.
74 */
75
76 function DataJoin(params) {
77 vegaDataflow.Transform.call(this, null, params);
78 }
79
80 function defaultItemCreate() {
81 return vegaDataflow.ingest({});
82 }
83
84 function newMap(key) {
85 const map = vegaUtil.fastmap().test(t => t.exit);
86
87 map.lookup = t => map.get(key(t));
88
89 return map;
90 }
91
92 vegaUtil.inherits(DataJoin, vegaDataflow.Transform, {
93 transform(_, pulse) {
94 var df = pulse.dataflow,
95 out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS),
96 item = _.item || defaultItemCreate,
97 key = _.key || vegaDataflow.tupleid,
98 map = this.value; // prevent transient (e.g., hover) requests from
99 // cascading across marks derived from marks
100
101 if (vegaUtil.isArray(out.encode)) {
102 out.encode = null;
103 }
104
105 if (map && (_.modified('key') || pulse.modified(key))) {
106 vegaUtil.error('DataJoin does not support modified key function or fields.');
107 }
108
109 if (!map) {
110 pulse = pulse.addAll();
111 this.value = map = newMap(key);
112 }
113
114 pulse.visit(pulse.ADD, t => {
115 const k = key(t);
116 let x = map.get(k);
117
118 if (x) {
119 if (x.exit) {
120 map.empty--;
121 out.add.push(x);
122 } else {
123 out.mod.push(x);
124 }
125 } else {
126 x = item(t);
127 map.set(k, x);
128 out.add.push(x);
129 }
130
131 x.datum = t;
132 x.exit = false;
133 });
134 pulse.visit(pulse.MOD, t => {
135 const k = key(t),
136 x = map.get(k);
137
138 if (x) {
139 x.datum = t;
140 out.mod.push(x);
141 }
142 });
143 pulse.visit(pulse.REM, t => {
144 const k = key(t),
145 x = map.get(k);
146
147 if (t === x.datum && !x.exit) {
148 out.rem.push(x);
149 x.exit = true;
150 ++map.empty;
151 }
152 });
153 if (pulse.changed(pulse.ADD_MOD)) out.modifies('datum');
154
155 if (pulse.clean() || _.clean && map.empty > df.cleanThreshold) {
156 df.runAfter(map.clean);
157 }
158
159 return out;
160 }
161
162 });
163
164 /**
165 * Invokes encoding functions for visual items.
166 * @constructor
167 * @param {object} params - The parameters to the encoding functions. This
168 * parameter object will be passed through to all invoked encoding functions.
169 * @param {object} [params.mod=false] - Flag indicating if tuples in the input
170 * mod set that are unmodified by encoders should be included in the output.
171 * @param {object} param.encoders - The encoding functions
172 * @param {function(object, object): boolean} [param.encoders.update] - Update encoding set
173 * @param {function(object, object): boolean} [param.encoders.enter] - Enter encoding set
174 * @param {function(object, object): boolean} [param.encoders.exit] - Exit encoding set
175 */
176
177 function Encode(params) {
178 vegaDataflow.Transform.call(this, null, params);
179 }
180 vegaUtil.inherits(Encode, vegaDataflow.Transform, {
181 transform(_, pulse) {
182 var out = pulse.fork(pulse.ADD_REM),
183 fmod = _.mod || false,
184 encoders = _.encoders,
185 encode = pulse.encode; // if an array, the encode directive includes additional sets
186 // that must be defined in order for the primary set to be invoked
187 // e.g., only run the update set if the hover set is defined
188
189 if (vegaUtil.isArray(encode)) {
190 if (out.changed() || encode.every(e => encoders[e])) {
191 encode = encode[0];
192 out.encode = null; // consume targeted encode directive
193 } else {
194 return pulse.StopPropagation;
195 }
196 } // marshall encoder functions
197
198
199 var reenter = encode === 'enter',
200 update = encoders.update || vegaUtil.falsy,
201 enter = encoders.enter || vegaUtil.falsy,
202 exit = encoders.exit || vegaUtil.falsy,
203 set = (encode && !reenter ? encoders[encode] : update) || vegaUtil.falsy;
204
205 if (pulse.changed(pulse.ADD)) {
206 pulse.visit(pulse.ADD, t => {
207 enter(t, _);
208 update(t, _);
209 });
210 out.modifies(enter.output);
211 out.modifies(update.output);
212
213 if (set !== vegaUtil.falsy && set !== update) {
214 pulse.visit(pulse.ADD, t => {
215 set(t, _);
216 });
217 out.modifies(set.output);
218 }
219 }
220
221 if (pulse.changed(pulse.REM) && exit !== vegaUtil.falsy) {
222 pulse.visit(pulse.REM, t => {
223 exit(t, _);
224 });
225 out.modifies(exit.output);
226 }
227
228 if (reenter || set !== vegaUtil.falsy) {
229 const flag = pulse.MOD | (_.modified() ? pulse.REFLOW : 0);
230
231 if (reenter) {
232 pulse.visit(flag, t => {
233 const mod = enter(t, _) || fmod;
234 if (set(t, _) || mod) out.mod.push(t);
235 });
236 if (out.mod.length) out.modifies(enter.output);
237 } else {
238 pulse.visit(flag, t => {
239 if (set(t, _) || fmod) out.mod.push(t);
240 });
241 }
242
243 if (out.mod.length) out.modifies(set.output);
244 }
245
246 return out.changed() ? out : pulse.StopPropagation;
247 }
248
249 });
250
251 /**
252 * Generates legend entries for visualizing a scale.
253 * @constructor
254 * @param {object} params - The parameters for this operator.
255 * @param {Scale} params.scale - The scale to generate items for.
256 * @param {*} [params.count=5] - The approximate number of items, or
257 * desired tick interval, to use.
258 * @param {*} [params.limit] - The maximum number of entries to
259 * include in a symbol legend.
260 * @param {Array<*>} [params.values] - The exact tick values to use.
261 * These must be legal domain values for the provided scale.
262 * If provided, the count argument is ignored.
263 * @param {string} [params.formatSpecifier] - A format specifier
264 * to use in conjunction with scale.tickFormat. Legal values are
265 * any valid D3 format specifier string.
266 * @param {function(*):string} [params.format] - The format function to use.
267 * If provided, the formatSpecifier argument is ignored.
268 */
269
270 function LegendEntries(params) {
271 vegaDataflow.Transform.call(this, [], params);
272 }
273 vegaUtil.inherits(LegendEntries, vegaDataflow.Transform, {
274 transform(_, pulse) {
275 if (this.value != null && !_.modified()) {
276 return pulse.StopPropagation;
277 }
278
279 var locale = pulse.dataflow.locale(),
280 out = pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS),
281 items = this.value,
282 type = _.type || vegaScale.SymbolLegend,
283 scale = _.scale,
284 limit = +_.limit,
285 count = vegaScale.tickCount(scale, _.count == null ? 5 : _.count, _.minstep),
286 lskip = !!_.values || type === vegaScale.SymbolLegend,
287 format = _.format || vegaScale.labelFormat(locale, scale, count, type, _.formatSpecifier, _.formatType, lskip),
288 values = _.values || vegaScale.labelValues(scale, count),
289 domain,
290 fraction,
291 size,
292 offset,
293 ellipsis;
294 if (items) out.rem = items;
295
296 if (type === vegaScale.SymbolLegend) {
297 if (limit && values.length > limit) {
298 pulse.dataflow.warn('Symbol legend count exceeds limit, filtering items.');
299 items = values.slice(0, limit - 1);
300 ellipsis = true;
301 } else {
302 items = values;
303 }
304
305 if (vegaUtil.isFunction(size = _.size)) {
306 // if first value maps to size zero, remove from list (vega#717)
307 if (!_.values && scale(items[0]) === 0) {
308 items = items.slice(1);
309 } // compute size offset for legend entries
310
311
312 offset = items.reduce((max, value) => Math.max(max, size(value, _)), 0);
313 } else {
314 size = vegaUtil.constant(offset = size || 8);
315 }
316
317 items = items.map((value, index) => vegaDataflow.ingest({
318 index: index,
319 label: format(value, index, items),
320 value: value,
321 offset: offset,
322 size: size(value, _)
323 }));
324
325 if (ellipsis) {
326 ellipsis = values[items.length];
327 items.push(vegaDataflow.ingest({
328 index: items.length,
329 label: `\u2026${values.length - items.length} entries`,
330 value: ellipsis,
331 offset: offset,
332 size: size(ellipsis, _)
333 }));
334 }
335 } else if (type === vegaScale.GradientLegend) {
336 domain = scale.domain(), fraction = vegaScale.scaleFraction(scale, domain[0], vegaUtil.peek(domain)); // if automatic label generation produces 2 or fewer values,
337 // use the domain end points instead (fixes vega/vega#1364)
338
339 if (values.length < 3 && !_.values && domain[0] !== vegaUtil.peek(domain)) {
340 values = [domain[0], vegaUtil.peek(domain)];
341 }
342
343 items = values.map((value, index) => vegaDataflow.ingest({
344 index: index,
345 label: format(value, index, values),
346 value: value,
347 perc: fraction(value)
348 }));
349 } else {
350 size = values.length - 1;
351 fraction = vegaScale.labelFraction(scale);
352 items = values.map((value, index) => vegaDataflow.ingest({
353 index: index,
354 label: format(value, index, values),
355 value: value,
356 perc: index ? fraction(value) : 0,
357 perc2: index === size ? 1 : fraction(values[index + 1])
358 }));
359 }
360
361 out.source = items;
362 out.add = items;
363 this.value = items;
364 return out;
365 }
366
367 });
368
369 const sourceX = t => t.source.x;
370
371 const sourceY = t => t.source.y;
372
373 const targetX = t => t.target.x;
374
375 const targetY = t => t.target.y;
376 /**
377 * Layout paths linking source and target elements.
378 * @constructor
379 * @param {object} params - The parameters for this operator.
380 */
381
382
383 function LinkPath(params) {
384 vegaDataflow.Transform.call(this, {}, params);
385 }
386 LinkPath.Definition = {
387 'type': 'LinkPath',
388 'metadata': {
389 'modifies': true
390 },
391 'params': [{
392 'name': 'sourceX',
393 'type': 'field',
394 'default': 'source.x'
395 }, {
396 'name': 'sourceY',
397 'type': 'field',
398 'default': 'source.y'
399 }, {
400 'name': 'targetX',
401 'type': 'field',
402 'default': 'target.x'
403 }, {
404 'name': 'targetY',
405 'type': 'field',
406 'default': 'target.y'
407 }, {
408 'name': 'orient',
409 'type': 'enum',
410 'default': 'vertical',
411 'values': ['horizontal', 'vertical', 'radial']
412 }, {
413 'name': 'shape',
414 'type': 'enum',
415 'default': 'line',
416 'values': ['line', 'arc', 'curve', 'diagonal', 'orthogonal']
417 }, {
418 'name': 'require',
419 'type': 'signal'
420 }, {
421 'name': 'as',
422 'type': 'string',
423 'default': 'path'
424 }]
425 };
426 vegaUtil.inherits(LinkPath, vegaDataflow.Transform, {
427 transform(_, pulse) {
428 var sx = _.sourceX || sourceX,
429 sy = _.sourceY || sourceY,
430 tx = _.targetX || targetX,
431 ty = _.targetY || targetY,
432 as = _.as || 'path',
433 orient = _.orient || 'vertical',
434 shape = _.shape || 'line',
435 path = Paths.get(shape + '-' + orient) || Paths.get(shape);
436
437 if (!path) {
438 vegaUtil.error('LinkPath unsupported type: ' + _.shape + (_.orient ? '-' + _.orient : ''));
439 }
440
441 pulse.visit(pulse.SOURCE, t => {
442 t[as] = path(sx(t), sy(t), tx(t), ty(t));
443 });
444 return pulse.reflow(_.modified()).modifies(as);
445 }
446
447 });
448
449 const line = (sx, sy, tx, ty) => 'M' + sx + ',' + sy + 'L' + tx + ',' + ty;
450
451 const lineR = (sa, sr, ta, tr) => line(sr * Math.cos(sa), sr * Math.sin(sa), tr * Math.cos(ta), tr * Math.sin(ta));
452
453 const arc = (sx, sy, tx, ty) => {
454 var dx = tx - sx,
455 dy = ty - sy,
456 rr = Math.sqrt(dx * dx + dy * dy) / 2,
457 ra = 180 * Math.atan2(dy, dx) / Math.PI;
458 return 'M' + sx + ',' + sy + 'A' + rr + ',' + rr + ' ' + ra + ' 0 1' + ' ' + tx + ',' + ty;
459 };
460
461 const arcR = (sa, sr, ta, tr) => arc(sr * Math.cos(sa), sr * Math.sin(sa), tr * Math.cos(ta), tr * Math.sin(ta));
462
463 const curve = (sx, sy, tx, ty) => {
464 const dx = tx - sx,
465 dy = ty - sy,
466 ix = 0.2 * (dx + dy),
467 iy = 0.2 * (dy - dx);
468 return 'M' + sx + ',' + sy + 'C' + (sx + ix) + ',' + (sy + iy) + ' ' + (tx + iy) + ',' + (ty - ix) + ' ' + tx + ',' + ty;
469 };
470
471 const curveR = (sa, sr, ta, tr) => curve(sr * Math.cos(sa), sr * Math.sin(sa), tr * Math.cos(ta), tr * Math.sin(ta));
472
473 const orthoX = (sx, sy, tx, ty) => 'M' + sx + ',' + sy + 'V' + ty + 'H' + tx;
474
475 const orthoY = (sx, sy, tx, ty) => 'M' + sx + ',' + sy + 'H' + tx + 'V' + ty;
476
477 const orthoR = (sa, sr, ta, tr) => {
478 const sc = Math.cos(sa),
479 ss = Math.sin(sa),
480 tc = Math.cos(ta),
481 ts = Math.sin(ta),
482 sf = Math.abs(ta - sa) > Math.PI ? ta <= sa : ta > sa;
483 return 'M' + sr * sc + ',' + sr * ss + 'A' + sr + ',' + sr + ' 0 0,' + (sf ? 1 : 0) + ' ' + sr * tc + ',' + sr * ts + 'L' + tr * tc + ',' + tr * ts;
484 };
485
486 const diagonalX = (sx, sy, tx, ty) => {
487 const m = (sx + tx) / 2;
488 return 'M' + sx + ',' + sy + 'C' + m + ',' + sy + ' ' + m + ',' + ty + ' ' + tx + ',' + ty;
489 };
490
491 const diagonalY = (sx, sy, tx, ty) => {
492 const m = (sy + ty) / 2;
493 return 'M' + sx + ',' + sy + 'C' + sx + ',' + m + ' ' + tx + ',' + m + ' ' + tx + ',' + ty;
494 };
495
496 const diagonalR = (sa, sr, ta, tr) => {
497 const sc = Math.cos(sa),
498 ss = Math.sin(sa),
499 tc = Math.cos(ta),
500 ts = Math.sin(ta),
501 mr = (sr + tr) / 2;
502 return 'M' + sr * sc + ',' + sr * ss + 'C' + mr * sc + ',' + mr * ss + ' ' + mr * tc + ',' + mr * ts + ' ' + tr * tc + ',' + tr * ts;
503 };
504
505 const Paths = vegaUtil.fastmap({
506 'line': line,
507 'line-radial': lineR,
508 'arc': arc,
509 'arc-radial': arcR,
510 'curve': curve,
511 'curve-radial': curveR,
512 'orthogonal-horizontal': orthoX,
513 'orthogonal-vertical': orthoY,
514 'orthogonal-radial': orthoR,
515 'diagonal-horizontal': diagonalX,
516 'diagonal-vertical': diagonalY,
517 'diagonal-radial': diagonalR
518 });
519
520 function range(start, stop, step) {
521 start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
522 var i = -1,
523 n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
524 range = new Array(n);
525
526 while (++i < n) {
527 range[i] = start + i * step;
528 }
529
530 return range;
531 }
532
533 function sum(values, valueof) {
534 let sum = 0;
535
536 if (valueof === undefined) {
537 for (let value of values) {
538 if (value = +value) {
539 sum += value;
540 }
541 }
542 } else {
543 let index = -1;
544
545 for (let value of values) {
546 if (value = +valueof(value, ++index, values)) {
547 sum += value;
548 }
549 }
550 }
551
552 return sum;
553 }
554
555 /**
556 * Pie and donut chart layout.
557 * @constructor
558 * @param {object} params - The parameters for this operator.
559 * @param {function(object): *} params.field - The value field to size pie segments.
560 * @param {number} [params.startAngle=0] - The start angle (in radians) of the layout.
561 * @param {number} [params.endAngle=2π] - The end angle (in radians) of the layout.
562 * @param {boolean} [params.sort] - Boolean flag for sorting sectors by value.
563 */
564
565 function Pie(params) {
566 vegaDataflow.Transform.call(this, null, params);
567 }
568 Pie.Definition = {
569 'type': 'Pie',
570 'metadata': {
571 'modifies': true
572 },
573 'params': [{
574 'name': 'field',
575 'type': 'field'
576 }, {
577 'name': 'startAngle',
578 'type': 'number',
579 'default': 0
580 }, {
581 'name': 'endAngle',
582 'type': 'number',
583 'default': 6.283185307179586
584 }, {
585 'name': 'sort',
586 'type': 'boolean',
587 'default': false
588 }, {
589 'name': 'as',
590 'type': 'string',
591 'array': true,
592 'length': 2,
593 'default': ['startAngle', 'endAngle']
594 }]
595 };
596 vegaUtil.inherits(Pie, vegaDataflow.Transform, {
597 transform(_, pulse) {
598 var as = _.as || ['startAngle', 'endAngle'],
599 startAngle = as[0],
600 endAngle = as[1],
601 field = _.field || vegaUtil.one,
602 start = _.startAngle || 0,
603 stop = _.endAngle != null ? _.endAngle : 2 * Math.PI,
604 data = pulse.source,
605 values = data.map(field),
606 n = values.length,
607 a = start,
608 k = (stop - start) / sum(values),
609 index = range(n),
610 i,
611 t,
612 v;
613
614 if (_.sort) {
615 index.sort((a, b) => values[a] - values[b]);
616 }
617
618 for (i = 0; i < n; ++i) {
619 v = values[index[i]];
620 t = data[index[i]];
621 t[startAngle] = a;
622 t[endAngle] = a += v * k;
623 }
624
625 this.value = values;
626 return pulse.reflow(_.modified()).modifies(as);
627 }
628
629 });
630
631 function define (constructor, factory, prototype) {
632 constructor.prototype = factory.prototype = prototype;
633 prototype.constructor = constructor;
634 }
635 function extend(parent, definition) {
636 var prototype = Object.create(parent.prototype);
637
638 for (var key in definition) prototype[key] = definition[key];
639
640 return prototype;
641 }
642
643 function Color() {}
644 var darker = 0.7;
645 var brighter = 1 / darker;
646 var reI = "\\s*([+-]?\\d+)\\s*",
647 reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
648 reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
649 reHex = /^#([0-9a-f]{3,8})$/,
650 reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
651 reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
652 reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
653 reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
654 reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
655 reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
656 var named = {
657 aliceblue: 0xf0f8ff,
658 antiquewhite: 0xfaebd7,
659 aqua: 0x00ffff,
660 aquamarine: 0x7fffd4,
661 azure: 0xf0ffff,
662 beige: 0xf5f5dc,
663 bisque: 0xffe4c4,
664 black: 0x000000,
665 blanchedalmond: 0xffebcd,
666 blue: 0x0000ff,
667 blueviolet: 0x8a2be2,
668 brown: 0xa52a2a,
669 burlywood: 0xdeb887,
670 cadetblue: 0x5f9ea0,
671 chartreuse: 0x7fff00,
672 chocolate: 0xd2691e,
673 coral: 0xff7f50,
674 cornflowerblue: 0x6495ed,
675 cornsilk: 0xfff8dc,
676 crimson: 0xdc143c,
677 cyan: 0x00ffff,
678 darkblue: 0x00008b,
679 darkcyan: 0x008b8b,
680 darkgoldenrod: 0xb8860b,
681 darkgray: 0xa9a9a9,
682 darkgreen: 0x006400,
683 darkgrey: 0xa9a9a9,
684 darkkhaki: 0xbdb76b,
685 darkmagenta: 0x8b008b,
686 darkolivegreen: 0x556b2f,
687 darkorange: 0xff8c00,
688 darkorchid: 0x9932cc,
689 darkred: 0x8b0000,
690 darksalmon: 0xe9967a,
691 darkseagreen: 0x8fbc8f,
692 darkslateblue: 0x483d8b,
693 darkslategray: 0x2f4f4f,
694 darkslategrey: 0x2f4f4f,
695 darkturquoise: 0x00ced1,
696 darkviolet: 0x9400d3,
697 deeppink: 0xff1493,
698 deepskyblue: 0x00bfff,
699 dimgray: 0x696969,
700 dimgrey: 0x696969,
701 dodgerblue: 0x1e90ff,
702 firebrick: 0xb22222,
703 floralwhite: 0xfffaf0,
704 forestgreen: 0x228b22,
705 fuchsia: 0xff00ff,
706 gainsboro: 0xdcdcdc,
707 ghostwhite: 0xf8f8ff,
708 gold: 0xffd700,
709 goldenrod: 0xdaa520,
710 gray: 0x808080,
711 green: 0x008000,
712 greenyellow: 0xadff2f,
713 grey: 0x808080,
714 honeydew: 0xf0fff0,
715 hotpink: 0xff69b4,
716 indianred: 0xcd5c5c,
717 indigo: 0x4b0082,
718 ivory: 0xfffff0,
719 khaki: 0xf0e68c,
720 lavender: 0xe6e6fa,
721 lavenderblush: 0xfff0f5,
722 lawngreen: 0x7cfc00,
723 lemonchiffon: 0xfffacd,
724 lightblue: 0xadd8e6,
725 lightcoral: 0xf08080,
726 lightcyan: 0xe0ffff,
727 lightgoldenrodyellow: 0xfafad2,
728 lightgray: 0xd3d3d3,
729 lightgreen: 0x90ee90,
730 lightgrey: 0xd3d3d3,
731 lightpink: 0xffb6c1,
732 lightsalmon: 0xffa07a,
733 lightseagreen: 0x20b2aa,
734 lightskyblue: 0x87cefa,
735 lightslategray: 0x778899,
736 lightslategrey: 0x778899,
737 lightsteelblue: 0xb0c4de,
738 lightyellow: 0xffffe0,
739 lime: 0x00ff00,
740 limegreen: 0x32cd32,
741 linen: 0xfaf0e6,
742 magenta: 0xff00ff,
743 maroon: 0x800000,
744 mediumaquamarine: 0x66cdaa,
745 mediumblue: 0x0000cd,
746 mediumorchid: 0xba55d3,
747 mediumpurple: 0x9370db,
748 mediumseagreen: 0x3cb371,
749 mediumslateblue: 0x7b68ee,
750 mediumspringgreen: 0x00fa9a,
751 mediumturquoise: 0x48d1cc,
752 mediumvioletred: 0xc71585,
753 midnightblue: 0x191970,
754 mintcream: 0xf5fffa,
755 mistyrose: 0xffe4e1,
756 moccasin: 0xffe4b5,
757 navajowhite: 0xffdead,
758 navy: 0x000080,
759 oldlace: 0xfdf5e6,
760 olive: 0x808000,
761 olivedrab: 0x6b8e23,
762 orange: 0xffa500,
763 orangered: 0xff4500,
764 orchid: 0xda70d6,
765 palegoldenrod: 0xeee8aa,
766 palegreen: 0x98fb98,
767 paleturquoise: 0xafeeee,
768 palevioletred: 0xdb7093,
769 papayawhip: 0xffefd5,
770 peachpuff: 0xffdab9,
771 peru: 0xcd853f,
772 pink: 0xffc0cb,
773 plum: 0xdda0dd,
774 powderblue: 0xb0e0e6,
775 purple: 0x800080,
776 rebeccapurple: 0x663399,
777 red: 0xff0000,
778 rosybrown: 0xbc8f8f,
779 royalblue: 0x4169e1,
780 saddlebrown: 0x8b4513,
781 salmon: 0xfa8072,
782 sandybrown: 0xf4a460,
783 seagreen: 0x2e8b57,
784 seashell: 0xfff5ee,
785 sienna: 0xa0522d,
786 silver: 0xc0c0c0,
787 skyblue: 0x87ceeb,
788 slateblue: 0x6a5acd,
789 slategray: 0x708090,
790 slategrey: 0x708090,
791 snow: 0xfffafa,
792 springgreen: 0x00ff7f,
793 steelblue: 0x4682b4,
794 tan: 0xd2b48c,
795 teal: 0x008080,
796 thistle: 0xd8bfd8,
797 tomato: 0xff6347,
798 turquoise: 0x40e0d0,
799 violet: 0xee82ee,
800 wheat: 0xf5deb3,
801 white: 0xffffff,
802 whitesmoke: 0xf5f5f5,
803 yellow: 0xffff00,
804 yellowgreen: 0x9acd32
805 };
806 define(Color, color, {
807 copy: function (channels) {
808 return Object.assign(new this.constructor(), this, channels);
809 },
810 displayable: function () {
811 return this.rgb().displayable();
812 },
813 hex: color_formatHex,
814 // Deprecated! Use color.formatHex.
815 formatHex: color_formatHex,
816 formatHsl: color_formatHsl,
817 formatRgb: color_formatRgb,
818 toString: color_formatRgb
819 });
820
821 function color_formatHex() {
822 return this.rgb().formatHex();
823 }
824
825 function color_formatHsl() {
826 return hslConvert(this).formatHsl();
827 }
828
829 function color_formatRgb() {
830 return this.rgb().formatRgb();
831 }
832
833 function color(format) {
834 var m, l;
835 format = (format + "").trim().toLowerCase();
836 return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000
837 : l === 3 ? new Rgb(m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, (m & 0xf) << 4 | m & 0xf, 1) // #f00
838 : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000
839 : l === 4 ? rgba(m >> 12 & 0xf | m >> 8 & 0xf0, m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, ((m & 0xf) << 4 | m & 0xf) / 0xff) // #f000
840 : null // invalid hex
841 ) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
842 : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
843 : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
844 : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
845 : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
846 : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
847 : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
848 : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
849 }
850
851 function rgbn(n) {
852 return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
853 }
854
855 function rgba(r, g, b, a) {
856 if (a <= 0) r = g = b = NaN;
857 return new Rgb(r, g, b, a);
858 }
859
860 function rgbConvert(o) {
861 if (!(o instanceof Color)) o = color(o);
862 if (!o) return new Rgb();
863 o = o.rgb();
864 return new Rgb(o.r, o.g, o.b, o.opacity);
865 }
866 function rgb$1(r, g, b, opacity) {
867 return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
868 }
869 function Rgb(r, g, b, opacity) {
870 this.r = +r;
871 this.g = +g;
872 this.b = +b;
873 this.opacity = +opacity;
874 }
875 define(Rgb, rgb$1, extend(Color, {
876 brighter: function (k) {
877 k = k == null ? brighter : Math.pow(brighter, k);
878 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
879 },
880 darker: function (k) {
881 k = k == null ? darker : Math.pow(darker, k);
882 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
883 },
884 rgb: function () {
885 return this;
886 },
887 displayable: function () {
888 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;
889 },
890 hex: rgb_formatHex,
891 // Deprecated! Use color.formatHex.
892 formatHex: rgb_formatHex,
893 formatRgb: rgb_formatRgb,
894 toString: rgb_formatRgb
895 }));
896
897 function rgb_formatHex() {
898 return "#" + hex(this.r) + hex(this.g) + hex(this.b);
899 }
900
901 function rgb_formatRgb() {
902 var a = this.opacity;
903 a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
904 return (a === 1 ? "rgb(" : "rgba(") + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", " + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", " + Math.max(0, Math.min(255, Math.round(this.b) || 0)) + (a === 1 ? ")" : ", " + a + ")");
905 }
906
907 function hex(value) {
908 value = Math.max(0, Math.min(255, Math.round(value) || 0));
909 return (value < 16 ? "0" : "") + value.toString(16);
910 }
911
912 function hsla(h, s, l, a) {
913 if (a <= 0) h = s = l = NaN;else if (l <= 0 || l >= 1) h = s = NaN;else if (s <= 0) h = NaN;
914 return new Hsl(h, s, l, a);
915 }
916
917 function hslConvert(o) {
918 if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
919 if (!(o instanceof Color)) o = color(o);
920 if (!o) return new Hsl();
921 if (o instanceof Hsl) return o;
922 o = o.rgb();
923 var r = o.r / 255,
924 g = o.g / 255,
925 b = o.b / 255,
926 min = Math.min(r, g, b),
927 max = Math.max(r, g, b),
928 h = NaN,
929 s = max - min,
930 l = (max + min) / 2;
931
932 if (s) {
933 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;
934 s /= l < 0.5 ? max + min : 2 - max - min;
935 h *= 60;
936 } else {
937 s = l > 0 && l < 1 ? 0 : h;
938 }
939
940 return new Hsl(h, s, l, o.opacity);
941 }
942 function hsl(h, s, l, opacity) {
943 return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
944 }
945
946 function Hsl(h, s, l, opacity) {
947 this.h = +h;
948 this.s = +s;
949 this.l = +l;
950 this.opacity = +opacity;
951 }
952
953 define(Hsl, hsl, extend(Color, {
954 brighter: function (k) {
955 k = k == null ? brighter : Math.pow(brighter, k);
956 return new Hsl(this.h, this.s, this.l * k, this.opacity);
957 },
958 darker: function (k) {
959 k = k == null ? darker : Math.pow(darker, k);
960 return new Hsl(this.h, this.s, this.l * k, this.opacity);
961 },
962 rgb: function () {
963 var h = this.h % 360 + (this.h < 0) * 360,
964 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
965 l = this.l,
966 m2 = l + (l < 0.5 ? l : 1 - l) * s,
967 m1 = 2 * l - m2;
968 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);
969 },
970 displayable: function () {
971 return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
972 },
973 formatHsl: function () {
974 var a = this.opacity;
975 a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
976 return (a === 1 ? "hsl(" : "hsla(") + (this.h || 0) + ", " + (this.s || 0) * 100 + "%, " + (this.l || 0) * 100 + "%" + (a === 1 ? ")" : ", " + a + ")");
977 }
978 }));
979 /* From FvD 13.37, CSS Color Module Level 3 */
980
981 function hsl2rgb(h, m1, m2) {
982 return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
983 }
984
985 var constant = (x => () => x);
986
987 function linear(a, d) {
988 return function (t) {
989 return a + t * d;
990 };
991 }
992
993 function exponential(a, b, y) {
994 return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function (t) {
995 return Math.pow(a + t * b, y);
996 };
997 }
998 function gamma(y) {
999 return (y = +y) === 1 ? nogamma : function (a, b) {
1000 return b - a ? exponential(a, b, y) : constant(isNaN(a) ? b : a);
1001 };
1002 }
1003 function nogamma(a, b) {
1004 var d = b - a;
1005 return d ? linear(a, d) : constant(isNaN(a) ? b : a);
1006 }
1007
1008 var rgb = (function rgbGamma(y) {
1009 var color = gamma(y);
1010
1011 function rgb(start, end) {
1012 var r = color((start = rgb$1(start)).r, (end = rgb$1(end)).r),
1013 g = color(start.g, end.g),
1014 b = color(start.b, end.b),
1015 opacity = nogamma(start.opacity, end.opacity);
1016 return function (t) {
1017 start.r = r(t);
1018 start.g = g(t);
1019 start.b = b(t);
1020 start.opacity = opacity(t);
1021 return start + "";
1022 };
1023 }
1024
1025 rgb.gamma = rgbGamma;
1026 return rgb;
1027 })(1);
1028
1029 function numberArray (a, b) {
1030 if (!b) b = [];
1031 var n = a ? Math.min(b.length, a.length) : 0,
1032 c = b.slice(),
1033 i;
1034 return function (t) {
1035 for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t;
1036
1037 return c;
1038 };
1039 }
1040 function isNumberArray(x) {
1041 return ArrayBuffer.isView(x) && !(x instanceof DataView);
1042 }
1043
1044 function genericArray(a, b) {
1045 var nb = b ? b.length : 0,
1046 na = a ? Math.min(nb, a.length) : 0,
1047 x = new Array(na),
1048 c = new Array(nb),
1049 i;
1050
1051 for (i = 0; i < na; ++i) x[i] = interpolate(a[i], b[i]);
1052
1053 for (; i < nb; ++i) c[i] = b[i];
1054
1055 return function (t) {
1056 for (i = 0; i < na; ++i) c[i] = x[i](t);
1057
1058 return c;
1059 };
1060 }
1061
1062 function date (a, b) {
1063 var d = new Date();
1064 return a = +a, b = +b, function (t) {
1065 return d.setTime(a * (1 - t) + b * t), d;
1066 };
1067 }
1068
1069 function number (a, b) {
1070 return a = +a, b = +b, function (t) {
1071 return a * (1 - t) + b * t;
1072 };
1073 }
1074
1075 function object (a, b) {
1076 var i = {},
1077 c = {},
1078 k;
1079 if (a === null || typeof a !== "object") a = {};
1080 if (b === null || typeof b !== "object") b = {};
1081
1082 for (k in b) {
1083 if (k in a) {
1084 i[k] = interpolate(a[k], b[k]);
1085 } else {
1086 c[k] = b[k];
1087 }
1088 }
1089
1090 return function (t) {
1091 for (k in i) c[k] = i[k](t);
1092
1093 return c;
1094 };
1095 }
1096
1097 var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
1098 reB = new RegExp(reA.source, "g");
1099
1100 function zero(b) {
1101 return function () {
1102 return b;
1103 };
1104 }
1105
1106 function one(b) {
1107 return function (t) {
1108 return b(t) + "";
1109 };
1110 }
1111
1112 function string (a, b) {
1113 var bi = reA.lastIndex = reB.lastIndex = 0,
1114 // scan index for next number in b
1115 am,
1116 // current match in a
1117 bm,
1118 // current match in b
1119 bs,
1120 // string preceding current number in b, if any
1121 i = -1,
1122 // index in s
1123 s = [],
1124 // string constants and placeholders
1125 q = []; // number interpolators
1126 // Coerce inputs to strings.
1127
1128 a = a + "", b = b + ""; // Interpolate pairs of numbers in a & b.
1129
1130 while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
1131 if ((bs = bm.index) > bi) {
1132 // a string precedes the next number in b
1133 bs = b.slice(bi, bs);
1134 if (s[i]) s[i] += bs; // coalesce with previous string
1135 else s[++i] = bs;
1136 }
1137
1138 if ((am = am[0]) === (bm = bm[0])) {
1139 // numbers in a & b match
1140 if (s[i]) s[i] += bm; // coalesce with previous string
1141 else s[++i] = bm;
1142 } else {
1143 // interpolate non-matching numbers
1144 s[++i] = null;
1145 q.push({
1146 i: i,
1147 x: number(am, bm)
1148 });
1149 }
1150
1151 bi = reB.lastIndex;
1152 } // Add remains of b.
1153
1154
1155 if (bi < b.length) {
1156 bs = b.slice(bi);
1157 if (s[i]) s[i] += bs; // coalesce with previous string
1158 else s[++i] = bs;
1159 } // Special optimization for only a single match.
1160 // Otherwise, interpolate each of the numbers and rejoin the string.
1161
1162
1163 return s.length < 2 ? q[0] ? one(q[0].x) : zero(b) : (b = q.length, function (t) {
1164 for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
1165
1166 return s.join("");
1167 });
1168 }
1169
1170 function interpolate (a, b) {
1171 var t = typeof b,
1172 c;
1173 return b == null || t === "boolean" ? constant(b) : (t === "number" ? number : t === "string" ? (c = color(b)) ? (b = c, rgb) : string : b instanceof color ? rgb : b instanceof Date ? date : isNumberArray(b) ? numberArray : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object : number)(a, b);
1174 }
1175
1176 function interpolateRound (a, b) {
1177 return a = +a, b = +b, function (t) {
1178 return Math.round(a * (1 - t) + b * t);
1179 };
1180 }
1181
1182 const DEFAULT_COUNT = 5;
1183
1184 function includeZero(scale) {
1185 const type = scale.type;
1186 return !scale.bins && (type === vegaScale.Linear || type === vegaScale.Pow || type === vegaScale.Sqrt);
1187 }
1188
1189 function includePad(type) {
1190 return vegaScale.isContinuous(type) && type !== vegaScale.Sequential;
1191 }
1192
1193 const SKIP = vegaUtil.toSet(['set', 'modified', 'clear', 'type', 'scheme', 'schemeExtent', 'schemeCount', 'domain', 'domainMin', 'domainMid', 'domainMax', 'domainRaw', 'domainImplicit', 'nice', 'zero', 'bins', 'range', 'rangeStep', 'round', 'reverse', 'interpolate', 'interpolateGamma']);
1194 /**
1195 * Maintains a scale function mapping data values to visual channels.
1196 * @constructor
1197 * @param {object} params - The parameters for this operator.
1198 */
1199
1200 function Scale(params) {
1201 vegaDataflow.Transform.call(this, null, params);
1202 this.modified(true); // always treat as modified
1203 }
1204 vegaUtil.inherits(Scale, vegaDataflow.Transform, {
1205 transform(_, pulse) {
1206 var df = pulse.dataflow,
1207 scale = this.value,
1208 key = scaleKey(_);
1209
1210 if (!scale || key !== scale.type) {
1211 this.value = scale = vegaScale.scale(key)();
1212 }
1213
1214 for (key in _) if (!SKIP[key]) {
1215 // padding is a scale property for band/point but not others
1216 if (key === 'padding' && includePad(scale.type)) continue; // invoke scale property setter, raise warning if not found
1217
1218 vegaUtil.isFunction(scale[key]) ? scale[key](_[key]) : df.warn('Unsupported scale property: ' + key);
1219 }
1220
1221 configureRange(scale, _, configureBins(scale, _, configureDomain(scale, _, df)));
1222 return pulse.fork(pulse.NO_SOURCE | pulse.NO_FIELDS);
1223 }
1224
1225 });
1226
1227 function scaleKey(_) {
1228 var t = _.type,
1229 d = '',
1230 n; // backwards compatibility pre Vega 5.
1231
1232 if (t === vegaScale.Sequential) return vegaScale.Sequential + '-' + vegaScale.Linear;
1233
1234 if (isContinuousColor(_)) {
1235 n = _.rawDomain ? _.rawDomain.length : _.domain ? _.domain.length + +(_.domainMid != null) : 0;
1236 d = n === 2 ? vegaScale.Sequential + '-' : n === 3 ? vegaScale.Diverging + '-' : '';
1237 }
1238
1239 return (d + t || vegaScale.Linear).toLowerCase();
1240 }
1241
1242 function isContinuousColor(_) {
1243 const t = _.type;
1244 return vegaScale.isContinuous(t) && t !== vegaScale.Time && t !== vegaScale.UTC && (_.scheme || _.range && _.range.length && _.range.every(vegaUtil.isString));
1245 }
1246
1247 function configureDomain(scale, _, df) {
1248 // check raw domain, if provided use that and exit early
1249 const raw = rawDomain(scale, _.domainRaw, df);
1250 if (raw > -1) return raw;
1251 var domain = _.domain,
1252 type = scale.type,
1253 zero = _.zero || _.zero === undefined && includeZero(scale),
1254 n,
1255 mid;
1256 if (!domain) return 0; // adjust continuous domain for minimum pixel padding
1257
1258 if (includePad(type) && _.padding && domain[0] !== vegaUtil.peek(domain)) {
1259 domain = padDomain(type, domain, _.range, _.padding, _.exponent, _.constant);
1260 } // adjust domain based on zero, min, max settings
1261
1262
1263 if (zero || _.domainMin != null || _.domainMax != null || _.domainMid != null) {
1264 n = (domain = domain.slice()).length - 1 || 1;
1265
1266 if (zero) {
1267 if (domain[0] > 0) domain[0] = 0;
1268 if (domain[n] < 0) domain[n] = 0;
1269 }
1270
1271 if (_.domainMin != null) domain[0] = _.domainMin;
1272 if (_.domainMax != null) domain[n] = _.domainMax;
1273
1274 if (_.domainMid != null) {
1275 mid = _.domainMid;
1276 const i = mid > domain[n] ? n + 1 : mid < domain[0] ? 0 : n;
1277 if (i !== n) df.warn('Scale domainMid exceeds domain min or max.', mid);
1278 domain.splice(i, 0, mid);
1279 }
1280 } // set the scale domain
1281
1282
1283 scale.domain(domainCheck(type, domain, df)); // if ordinal scale domain is defined, prevent implicit
1284 // domain construction as side-effect of scale lookup
1285
1286 if (type === vegaScale.Ordinal) {
1287 scale.unknown(_.domainImplicit ? vegaScale.scaleImplicit : undefined);
1288 } // perform 'nice' adjustment as requested
1289
1290
1291 if (_.nice && scale.nice) {
1292 scale.nice(_.nice !== true && vegaScale.tickCount(scale, _.nice) || null);
1293 } // return the cardinality of the domain
1294
1295
1296 return domain.length;
1297 }
1298
1299 function rawDomain(scale, raw, df) {
1300 if (raw) {
1301 scale.domain(domainCheck(scale.type, raw, df));
1302 return raw.length;
1303 } else {
1304 return -1;
1305 }
1306 }
1307
1308 function padDomain(type, domain, range, pad, exponent, constant) {
1309 var span = Math.abs(vegaUtil.peek(range) - range[0]),
1310 frac = span / (span - 2 * pad),
1311 d = type === vegaScale.Log ? vegaUtil.zoomLog(domain, null, frac) : type === vegaScale.Sqrt ? vegaUtil.zoomPow(domain, null, frac, 0.5) : type === vegaScale.Pow ? vegaUtil.zoomPow(domain, null, frac, exponent || 1) : type === vegaScale.Symlog ? vegaUtil.zoomSymlog(domain, null, frac, constant || 1) : vegaUtil.zoomLinear(domain, null, frac);
1312 domain = domain.slice();
1313 domain[0] = d[0];
1314 domain[domain.length - 1] = d[1];
1315 return domain;
1316 }
1317
1318 function domainCheck(type, domain, df) {
1319 if (vegaScale.isLogarithmic(type)) {
1320 // sum signs of domain values
1321 // if all pos or all neg, abs(sum) === domain.length
1322 var s = Math.abs(domain.reduce((s, v) => s + (v < 0 ? -1 : v > 0 ? 1 : 0), 0));
1323
1324 if (s !== domain.length) {
1325 df.warn('Log scale domain includes zero: ' + vegaUtil.stringValue(domain));
1326 }
1327 }
1328
1329 return domain;
1330 }
1331
1332 function configureBins(scale, _, count) {
1333 let bins = _.bins;
1334
1335 if (bins && !vegaUtil.isArray(bins)) {
1336 // generate bin boundary array
1337 const domain = scale.domain(),
1338 lo = domain[0],
1339 hi = vegaUtil.peek(domain),
1340 step = bins.step;
1341 let start = bins.start == null ? lo : bins.start,
1342 stop = bins.stop == null ? hi : bins.stop;
1343 if (!step) vegaUtil.error('Scale bins parameter missing step property.');
1344 if (start < lo) start = step * Math.ceil(lo / step);
1345 if (stop > hi) stop = step * Math.floor(hi / step);
1346 bins = range(start, stop + step / 2, step);
1347 }
1348
1349 if (bins) {
1350 // assign bin boundaries to scale instance
1351 scale.bins = bins;
1352 } else if (scale.bins) {
1353 // no current bins, remove bins if previously set
1354 delete scale.bins;
1355 } // special handling for bin-ordinal scales
1356
1357
1358 if (scale.type === vegaScale.BinOrdinal) {
1359 if (!bins) {
1360 // the domain specifies the bins
1361 scale.bins = scale.domain();
1362 } else if (!_.domain && !_.domainRaw) {
1363 // the bins specify the domain
1364 scale.domain(bins);
1365 count = bins.length;
1366 }
1367 } // return domain cardinality
1368
1369
1370 return count;
1371 }
1372
1373 function configureRange(scale, _, count) {
1374 var type = scale.type,
1375 round = _.round || false,
1376 range = _.range; // if range step specified, calculate full range extent
1377
1378 if (_.rangeStep != null) {
1379 range = configureRangeStep(type, _, count);
1380 } // else if a range scheme is defined, use that
1381 else if (_.scheme) {
1382 range = configureScheme(type, _, count);
1383
1384 if (vegaUtil.isFunction(range)) {
1385 if (scale.interpolator) {
1386 return scale.interpolator(range);
1387 } else {
1388 vegaUtil.error(`Scale type ${type} does not support interpolating color schemes.`);
1389 }
1390 }
1391 } // given a range array for an interpolating scale, convert to interpolator
1392
1393
1394 if (range && vegaScale.isInterpolating(type)) {
1395 return scale.interpolator(vegaScale.interpolateColors(flip(range, _.reverse), _.interpolate, _.interpolateGamma));
1396 } // configure rounding / interpolation
1397
1398
1399 if (range && _.interpolate && scale.interpolate) {
1400 scale.interpolate(vegaScale.interpolate(_.interpolate, _.interpolateGamma));
1401 } else if (vegaUtil.isFunction(scale.round)) {
1402 scale.round(round);
1403 } else if (vegaUtil.isFunction(scale.rangeRound)) {
1404 scale.interpolate(round ? interpolateRound : interpolate);
1405 }
1406
1407 if (range) scale.range(flip(range, _.reverse));
1408 }
1409
1410 function configureRangeStep(type, _, count) {
1411 if (type !== vegaScale.Band && type !== vegaScale.Point) {
1412 vegaUtil.error('Only band and point scales support rangeStep.');
1413 } // calculate full range based on requested step size and padding
1414
1415
1416 var outer = (_.paddingOuter != null ? _.paddingOuter : _.padding) || 0,
1417 inner = type === vegaScale.Point ? 1 : (_.paddingInner != null ? _.paddingInner : _.padding) || 0;
1418 return [0, _.rangeStep * vegaScale.bandSpace(count, inner, outer)];
1419 }
1420
1421 function configureScheme(type, _, count) {
1422 var extent = _.schemeExtent,
1423 name,
1424 scheme;
1425
1426 if (vegaUtil.isArray(_.scheme)) {
1427 scheme = vegaScale.interpolateColors(_.scheme, _.interpolate, _.interpolateGamma);
1428 } else {
1429 name = _.scheme.toLowerCase();
1430 scheme = vegaScale.scheme(name);
1431 if (!scheme) vegaUtil.error(`Unrecognized scheme name: ${_.scheme}`);
1432 } // determine size for potential discrete range
1433
1434
1435 count = type === vegaScale.Threshold ? count + 1 : type === vegaScale.BinOrdinal ? count - 1 : type === vegaScale.Quantile || type === vegaScale.Quantize ? +_.schemeCount || DEFAULT_COUNT : count; // adjust and/or quantize scheme as appropriate
1436
1437 return vegaScale.isInterpolating(type) ? adjustScheme(scheme, extent, _.reverse) : vegaUtil.isFunction(scheme) ? vegaScale.quantizeInterpolator(adjustScheme(scheme, extent), count) : type === vegaScale.Ordinal ? scheme : scheme.slice(0, count);
1438 }
1439
1440 function adjustScheme(scheme, extent, reverse) {
1441 return vegaUtil.isFunction(scheme) && (extent || reverse) ? vegaScale.interpolateRange(scheme, flip(extent || [0, 1], reverse)) : scheme;
1442 }
1443
1444 function flip(array, reverse) {
1445 return reverse ? array.slice().reverse() : array;
1446 }
1447
1448 /**
1449 * Sorts scenegraph items in the pulse source array.
1450 * @constructor
1451 * @param {object} params - The parameters for this operator.
1452 * @param {function(*,*): number} [params.sort] - A comparator
1453 * function for sorting tuples.
1454 */
1455
1456 function SortItems(params) {
1457 vegaDataflow.Transform.call(this, null, params);
1458 }
1459 vegaUtil.inherits(SortItems, vegaDataflow.Transform, {
1460 transform(_, pulse) {
1461 const mod = _.modified('sort') || pulse.changed(pulse.ADD) || pulse.modified(_.sort.fields) || pulse.modified('datum');
1462 if (mod) pulse.source.sort(vegaDataflow.stableCompare(_.sort));
1463 this.modified(mod);
1464 return pulse;
1465 }
1466
1467 });
1468
1469 const Zero = 'zero',
1470 Center = 'center',
1471 Normalize = 'normalize',
1472 DefOutput = ['y0', 'y1'];
1473 /**
1474 * Stack layout for visualization elements.
1475 * @constructor
1476 * @param {object} params - The parameters for this operator.
1477 * @param {function(object): *} params.field - The value field to stack.
1478 * @param {Array<function(object): *>} [params.groupby] - An array of accessors to groupby.
1479 * @param {function(object,object): number} [params.sort] - A comparator for stack sorting.
1480 * @param {string} [offset='zero'] - Stack baseline offset. One of 'zero', 'center', 'normalize'.
1481 */
1482
1483 function Stack(params) {
1484 vegaDataflow.Transform.call(this, null, params);
1485 }
1486 Stack.Definition = {
1487 'type': 'Stack',
1488 'metadata': {
1489 'modifies': true
1490 },
1491 'params': [{
1492 'name': 'field',
1493 'type': 'field'
1494 }, {
1495 'name': 'groupby',
1496 'type': 'field',
1497 'array': true
1498 }, {
1499 'name': 'sort',
1500 'type': 'compare'
1501 }, {
1502 'name': 'offset',
1503 'type': 'enum',
1504 'default': Zero,
1505 'values': [Zero, Center, Normalize]
1506 }, {
1507 'name': 'as',
1508 'type': 'string',
1509 'array': true,
1510 'length': 2,
1511 'default': DefOutput
1512 }]
1513 };
1514 vegaUtil.inherits(Stack, vegaDataflow.Transform, {
1515 transform(_, pulse) {
1516 var as = _.as || DefOutput,
1517 y0 = as[0],
1518 y1 = as[1],
1519 sort = vegaDataflow.stableCompare(_.sort),
1520 field = _.field || vegaUtil.one,
1521 stack = _.offset === Center ? stackCenter : _.offset === Normalize ? stackNormalize : stackZero,
1522 groups,
1523 i,
1524 n,
1525 max; // partition, sum, and sort the stack groups
1526
1527 groups = partition(pulse.source, _.groupby, sort, field); // compute stack layouts per group
1528
1529 for (i = 0, n = groups.length, max = groups.max; i < n; ++i) {
1530 stack(groups[i], max, field, y0, y1);
1531 }
1532
1533 return pulse.reflow(_.modified()).modifies(as);
1534 }
1535
1536 });
1537
1538 function stackCenter(group, max, field, y0, y1) {
1539 var last = (max - group.sum) / 2,
1540 m = group.length,
1541 j = 0,
1542 t;
1543
1544 for (; j < m; ++j) {
1545 t = group[j];
1546 t[y0] = last;
1547 t[y1] = last += Math.abs(field(t));
1548 }
1549 }
1550
1551 function stackNormalize(group, max, field, y0, y1) {
1552 var scale = 1 / group.sum,
1553 last = 0,
1554 m = group.length,
1555 j = 0,
1556 v = 0,
1557 t;
1558
1559 for (; j < m; ++j) {
1560 t = group[j];
1561 t[y0] = last;
1562 t[y1] = last = scale * (v += Math.abs(field(t)));
1563 }
1564 }
1565
1566 function stackZero(group, max, field, y0, y1) {
1567 var lastPos = 0,
1568 lastNeg = 0,
1569 m = group.length,
1570 j = 0,
1571 v,
1572 t;
1573
1574 for (; j < m; ++j) {
1575 t = group[j];
1576 v = +field(t);
1577
1578 if (v < 0) {
1579 t[y0] = lastNeg;
1580 t[y1] = lastNeg += v;
1581 } else {
1582 t[y0] = lastPos;
1583 t[y1] = lastPos += v;
1584 }
1585 }
1586 }
1587
1588 function partition(data, groupby, sort, field) {
1589 var groups = [],
1590 get = f => f(t),
1591 map,
1592 i,
1593 n,
1594 m,
1595 t,
1596 k,
1597 g,
1598 s,
1599 max; // partition data points into stack groups
1600
1601
1602 if (groupby == null) {
1603 groups.push(data.slice());
1604 } else {
1605 for (map = {}, i = 0, n = data.length; i < n; ++i) {
1606 t = data[i];
1607 k = groupby.map(get);
1608 g = map[k];
1609
1610 if (!g) {
1611 map[k] = g = [];
1612 groups.push(g);
1613 }
1614
1615 g.push(t);
1616 }
1617 } // compute sums of groups, sort groups as needed
1618
1619
1620 for (k = 0, max = 0, m = groups.length; k < m; ++k) {
1621 g = groups[k];
1622
1623 for (i = 0, s = 0, n = g.length; i < n; ++i) {
1624 s += Math.abs(field(g[i]));
1625 }
1626
1627 g.sum = s;
1628 if (s > max) max = s;
1629 if (sort) g.sort(sort);
1630 }
1631
1632 groups.max = max;
1633 return groups;
1634 }
1635
1636 exports.axisticks = AxisTicks;
1637 exports.datajoin = DataJoin;
1638 exports.encode = Encode;
1639 exports.legendentries = LegendEntries;
1640 exports.linkpath = LinkPath;
1641 exports.pie = Pie;
1642 exports.scale = Scale;
1643 exports.sortitems = SortItems;
1644 exports.stack = Stack;
1645
1646 Object.defineProperty(exports, '__esModule', { value: true });
1647
1648}));