UNPKG

1.33 MBJavaScriptView Raw
1/**
2 * vis-network
3 * https://visjs.github.io/vis-network/
4 *
5 * A dynamic, browser-based visualization library.
6 *
7 * @version 9.1.0
8 * @date 2021-08-29T08:47:25.454Z
9 *
10 * @copyright (c) 2011-2017 Almende B.V, http://almende.com
11 * @copyright (c) 2017-2019 visjs contributors, https://github.com/visjs
12 *
13 * @license
14 * vis.js is dual licensed under both
15 *
16 * 1. The Apache 2.0 License
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * and
20 *
21 * 2. The MIT License
22 * http://opensource.org/licenses/MIT
23 *
24 * vis.js may be distributed under either license.
25 */
26
27var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
28
29function unwrapExports (x) {
30 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
31}
32
33function createCommonjsModule(fn, module) {
34 return module = { exports: {} }, fn(module, module.exports), module.exports;
35}
36
37var check = function (it) {
38 return it && it.Math == Math && it;
39}; // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
40
41
42var global_1 = // eslint-disable-next-line es/no-global-this -- safe
43check(typeof globalThis == 'object' && globalThis) || check(typeof window == 'object' && window) || // eslint-disable-next-line no-restricted-globals -- safe
44check(typeof self == 'object' && self) || check(typeof commonjsGlobal == 'object' && commonjsGlobal) || // eslint-disable-next-line no-new-func -- fallback
45function () {
46 return this;
47}() || Function('return this')();
48
49var fails = function (exec) {
50 try {
51 return !!exec();
52 } catch (error) {
53 return true;
54 }
55};
56
57var descriptors = !fails(function () {
58 // eslint-disable-next-line es/no-object-defineproperty -- required for testing
59 return Object.defineProperty({}, 1, {
60 get: function () {
61 return 7;
62 }
63 })[1] != 7;
64});
65
66var $propertyIsEnumerable$1 = {}.propertyIsEnumerable; // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
67
68var getOwnPropertyDescriptor$5 = Object.getOwnPropertyDescriptor; // Nashorn ~ JDK8 bug
69
70var NASHORN_BUG = getOwnPropertyDescriptor$5 && !$propertyIsEnumerable$1.call({
71 1: 2
72}, 1); // `Object.prototype.propertyIsEnumerable` method implementation
73// https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
74
75var f$6 = NASHORN_BUG ? function propertyIsEnumerable(V) {
76 var descriptor = getOwnPropertyDescriptor$5(this, V);
77 return !!descriptor && descriptor.enumerable;
78} : $propertyIsEnumerable$1;
79var objectPropertyIsEnumerable = {
80 f: f$6
81};
82
83var createPropertyDescriptor = function (bitmap, value) {
84 return {
85 enumerable: !(bitmap & 1),
86 configurable: !(bitmap & 2),
87 writable: !(bitmap & 4),
88 value: value
89 };
90};
91
92var toString$1 = {}.toString;
93
94var classofRaw = function (it) {
95 return toString$1.call(it).slice(8, -1);
96};
97
98var split = ''.split; // fallback for non-array-like ES3 and non-enumerable old V8 strings
99
100var indexedObject = fails(function () {
101 // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
102 // eslint-disable-next-line no-prototype-builtins -- safe
103 return !Object('z').propertyIsEnumerable(0);
104}) ? function (it) {
105 return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
106} : Object;
107
108// `RequireObjectCoercible` abstract operation
109// https://tc39.es/ecma262/#sec-requireobjectcoercible
110var requireObjectCoercible = function (it) {
111 if (it == undefined) throw TypeError("Can't call method on " + it);
112 return it;
113};
114
115var toIndexedObject = function (it) {
116 return indexedObject(requireObjectCoercible(it));
117};
118
119var isObject$1 = function (it) {
120 return typeof it === 'object' ? it !== null : typeof it === 'function';
121};
122
123var path = {};
124
125var aFunction$1 = function (variable) {
126 return typeof variable == 'function' ? variable : undefined;
127};
128
129var getBuiltIn = function (namespace, method) {
130 return arguments.length < 2 ? aFunction$1(path[namespace]) || aFunction$1(global_1[namespace]) : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method];
131};
132
133var engineUserAgent = getBuiltIn('navigator', 'userAgent') || '';
134
135var process = global_1.process;
136var Deno = global_1.Deno;
137var versions = process && process.versions || Deno && Deno.version;
138var v8 = versions && versions.v8;
139var match, version;
140
141if (v8) {
142 match = v8.split('.');
143 version = match[0] < 4 ? 1 : match[0] + match[1];
144} else if (engineUserAgent) {
145 match = engineUserAgent.match(/Edge\/(\d+)/);
146
147 if (!match || match[1] >= 74) {
148 match = engineUserAgent.match(/Chrome\/(\d+)/);
149 if (match) version = match[1];
150 }
151}
152
153var engineV8Version = version && +version;
154
155/* eslint-disable es/no-symbol -- required for testing */
156// eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
157
158var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
159 var symbol = Symbol(); // Chrome 38 Symbol has incorrect toString conversion
160 // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
161
162 return !String(symbol) || !(Object(symbol) instanceof Symbol) || // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
163 !Symbol.sham && engineV8Version && engineV8Version < 41;
164});
165
166/* eslint-disable es/no-symbol -- required for testing */
167
168var useSymbolAsUid = nativeSymbol && !Symbol.sham && typeof Symbol.iterator == 'symbol';
169
170var isSymbol = useSymbolAsUid ? function (it) {
171 return typeof it == 'symbol';
172} : function (it) {
173 var $Symbol = getBuiltIn('Symbol');
174 return typeof $Symbol == 'function' && Object(it) instanceof $Symbol;
175};
176
177// https://tc39.es/ecma262/#sec-ordinarytoprimitive
178
179var ordinaryToPrimitive = function (input, pref) {
180 var fn, val;
181 if (pref === 'string' && typeof (fn = input.toString) == 'function' && !isObject$1(val = fn.call(input))) return val;
182 if (typeof (fn = input.valueOf) == 'function' && !isObject$1(val = fn.call(input))) return val;
183 if (pref !== 'string' && typeof (fn = input.toString) == 'function' && !isObject$1(val = fn.call(input))) return val;
184 throw TypeError("Can't convert object to primitive value");
185};
186
187var setGlobal = function (key, value) {
188 try {
189 // eslint-disable-next-line es/no-object-defineproperty -- safe
190 Object.defineProperty(global_1, key, {
191 value: value,
192 configurable: true,
193 writable: true
194 });
195 } catch (error) {
196 global_1[key] = value;
197 }
198
199 return value;
200};
201
202var SHARED = '__core-js_shared__';
203var store$1 = global_1[SHARED] || setGlobal(SHARED, {});
204var sharedStore = store$1;
205
206var shared = createCommonjsModule(function (module) {
207 (module.exports = function (key, value) {
208 return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
209 })('versions', []).push({
210 version: '3.16.1',
211 mode: 'pure' ,
212 copyright: '© 2021 Denis Pushkarev (zloirock.ru)'
213 });
214});
215
216// https://tc39.es/ecma262/#sec-toobject
217
218var toObject = function (argument) {
219 return Object(requireObjectCoercible(argument));
220};
221
222var hasOwnProperty = {}.hasOwnProperty;
223
224var has$1 = Object.hasOwn || function hasOwn(it, key) {
225 return hasOwnProperty.call(toObject(it), key);
226};
227
228var id$1 = 0;
229var postfix = Math.random();
230
231var uid = function (key) {
232 return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id$1 + postfix).toString(36);
233};
234
235var WellKnownSymbolsStore$1 = shared('wks');
236var Symbol$1 = global_1.Symbol;
237var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid;
238
239var wellKnownSymbol = function (name) {
240 if (!has$1(WellKnownSymbolsStore$1, name) || !(nativeSymbol || typeof WellKnownSymbolsStore$1[name] == 'string')) {
241 if (nativeSymbol && has$1(Symbol$1, name)) {
242 WellKnownSymbolsStore$1[name] = Symbol$1[name];
243 } else {
244 WellKnownSymbolsStore$1[name] = createWellKnownSymbol('Symbol.' + name);
245 }
246 }
247
248 return WellKnownSymbolsStore$1[name];
249};
250
251var TO_PRIMITIVE$1 = wellKnownSymbol('toPrimitive'); // `ToPrimitive` abstract operation
252// https://tc39.es/ecma262/#sec-toprimitive
253
254var toPrimitive = function (input, pref) {
255 if (!isObject$1(input) || isSymbol(input)) return input;
256 var exoticToPrim = input[TO_PRIMITIVE$1];
257 var result;
258
259 if (exoticToPrim !== undefined) {
260 if (pref === undefined) pref = 'default';
261 result = exoticToPrim.call(input, pref);
262 if (!isObject$1(result) || isSymbol(result)) return result;
263 throw TypeError("Can't convert object to primitive value");
264 }
265
266 if (pref === undefined) pref = 'number';
267 return ordinaryToPrimitive(input, pref);
268};
269
270// https://tc39.es/ecma262/#sec-topropertykey
271
272var toPropertyKey = function (argument) {
273 var key = toPrimitive(argument, 'string');
274 return isSymbol(key) ? key : String(key);
275};
276
277var document$1 = global_1.document; // typeof document.createElement is 'object' in old IE
278
279var EXISTS = isObject$1(document$1) && isObject$1(document$1.createElement);
280
281var documentCreateElement = function (it) {
282 return EXISTS ? document$1.createElement(it) : {};
283};
284
285var ie8DomDefine = !descriptors && !fails(function () {
286 // eslint-disable-next-line es/no-object-defineproperty -- requied for testing
287 return Object.defineProperty(documentCreateElement('div'), 'a', {
288 get: function () {
289 return 7;
290 }
291 }).a != 7;
292});
293
294var $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor; // `Object.getOwnPropertyDescriptor` method
295// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
296
297var f$5 = descriptors ? $getOwnPropertyDescriptor$1 : function getOwnPropertyDescriptor(O, P) {
298 O = toIndexedObject(O);
299 P = toPropertyKey(P);
300 if (ie8DomDefine) try {
301 return $getOwnPropertyDescriptor$1(O, P);
302 } catch (error) {
303 /* empty */
304 }
305 if (has$1(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
306};
307var objectGetOwnPropertyDescriptor = {
308 f: f$5
309};
310
311var replacement = /#|\.prototype\./;
312
313var isForced = function (feature, detection) {
314 var value = data[normalize(feature)];
315 return value == POLYFILL ? true : value == NATIVE ? false : typeof detection == 'function' ? fails(detection) : !!detection;
316};
317
318var normalize = isForced.normalize = function (string) {
319 return String(string).replace(replacement, '.').toLowerCase();
320};
321
322var data = isForced.data = {};
323var NATIVE = isForced.NATIVE = 'N';
324var POLYFILL = isForced.POLYFILL = 'P';
325var isForced_1 = isForced;
326
327var aFunction = function (it) {
328 if (typeof it != 'function') {
329 throw TypeError(String(it) + ' is not a function');
330 }
331
332 return it;
333};
334
335var functionBindContext = function (fn, that, length) {
336 aFunction(fn);
337 if (that === undefined) return fn;
338
339 switch (length) {
340 case 0:
341 return function () {
342 return fn.call(that);
343 };
344
345 case 1:
346 return function (a) {
347 return fn.call(that, a);
348 };
349
350 case 2:
351 return function (a, b) {
352 return fn.call(that, a, b);
353 };
354
355 case 3:
356 return function (a, b, c) {
357 return fn.call(that, a, b, c);
358 };
359 }
360
361 return function () {
362 return fn.apply(that, arguments);
363 };
364};
365
366var anObject = function (it) {
367 if (!isObject$1(it)) {
368 throw TypeError(String(it) + ' is not an object');
369 }
370
371 return it;
372};
373
374var $defineProperty$1 = Object.defineProperty; // `Object.defineProperty` method
375// https://tc39.es/ecma262/#sec-object.defineproperty
376
377var f$4 = descriptors ? $defineProperty$1 : function defineProperty(O, P, Attributes) {
378 anObject(O);
379 P = toPropertyKey(P);
380 anObject(Attributes);
381 if (ie8DomDefine) try {
382 return $defineProperty$1(O, P, Attributes);
383 } catch (error) {
384 /* empty */
385 }
386 if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
387 if ('value' in Attributes) O[P] = Attributes.value;
388 return O;
389};
390var objectDefineProperty = {
391 f: f$4
392};
393
394var createNonEnumerableProperty = descriptors ? function (object, key, value) {
395 return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
396} : function (object, key, value) {
397 object[key] = value;
398 return object;
399};
400
401var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;
402
403var wrapConstructor = function (NativeConstructor) {
404 var Wrapper = function (a, b, c) {
405 if (this instanceof NativeConstructor) {
406 switch (arguments.length) {
407 case 0:
408 return new NativeConstructor();
409
410 case 1:
411 return new NativeConstructor(a);
412
413 case 2:
414 return new NativeConstructor(a, b);
415 }
416
417 return new NativeConstructor(a, b, c);
418 }
419
420 return NativeConstructor.apply(this, arguments);
421 };
422
423 Wrapper.prototype = NativeConstructor.prototype;
424 return Wrapper;
425};
426/*
427 options.target - name of the target object
428 options.global - target is the global object
429 options.stat - export as static methods of target
430 options.proto - export as prototype methods of target
431 options.real - real prototype method for the `pure` version
432 options.forced - export even if the native feature is available
433 options.bind - bind methods to the target, required for the `pure` version
434 options.wrap - wrap constructors to preventing global pollution, required for the `pure` version
435 options.unsafe - use the simple assignment of property instead of delete + defineProperty
436 options.sham - add a flag to not completely full polyfills
437 options.enumerable - export as enumerable property
438 options.noTargetGet - prevent calling a getter on target
439*/
440
441
442var _export = function (options, source) {
443 var TARGET = options.target;
444 var GLOBAL = options.global;
445 var STATIC = options.stat;
446 var PROTO = options.proto;
447 var nativeSource = GLOBAL ? global_1 : STATIC ? global_1[TARGET] : (global_1[TARGET] || {}).prototype;
448 var target = GLOBAL ? path : path[TARGET] || (path[TARGET] = {});
449 var targetPrototype = target.prototype;
450 var FORCED, USE_NATIVE, VIRTUAL_PROTOTYPE;
451 var key, sourceProperty, targetProperty, nativeProperty, resultProperty, descriptor;
452
453 for (key in source) {
454 FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced); // contains in native
455
456 USE_NATIVE = !FORCED && nativeSource && has$1(nativeSource, key);
457 targetProperty = target[key];
458 if (USE_NATIVE) if (options.noTargetGet) {
459 descriptor = getOwnPropertyDescriptor$4(nativeSource, key);
460 nativeProperty = descriptor && descriptor.value;
461 } else nativeProperty = nativeSource[key]; // export native or implementation
462
463 sourceProperty = USE_NATIVE && nativeProperty ? nativeProperty : source[key];
464 if (USE_NATIVE && typeof targetProperty === typeof sourceProperty) continue; // bind timers to global for call from export context
465
466 if (options.bind && USE_NATIVE) resultProperty = functionBindContext(sourceProperty, global_1); // wrap global constructors for prevent changs in this version
467 else if (options.wrap && USE_NATIVE) resultProperty = wrapConstructor(sourceProperty); // make static versions for prototype methods
468 else if (PROTO && typeof sourceProperty == 'function') resultProperty = functionBindContext(Function.call, sourceProperty); // default case
469 else resultProperty = sourceProperty; // add a flag to not completely full polyfills
470
471 if (options.sham || sourceProperty && sourceProperty.sham || targetProperty && targetProperty.sham) {
472 createNonEnumerableProperty(resultProperty, 'sham', true);
473 }
474
475 target[key] = resultProperty;
476
477 if (PROTO) {
478 VIRTUAL_PROTOTYPE = TARGET + 'Prototype';
479
480 if (!has$1(path, VIRTUAL_PROTOTYPE)) {
481 createNonEnumerableProperty(path, VIRTUAL_PROTOTYPE, {});
482 } // export virtual prototype methods
483
484
485 path[VIRTUAL_PROTOTYPE][key] = sourceProperty; // export real prototype methods
486
487 if (options.real && targetPrototype && !targetPrototype[key]) {
488 createNonEnumerableProperty(targetPrototype, key, sourceProperty);
489 }
490 }
491 }
492};
493
494var ceil = Math.ceil;
495var floor$1 = Math.floor; // `ToInteger` abstract operation
496// https://tc39.es/ecma262/#sec-tointeger
497
498var toInteger = function (argument) {
499 return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor$1 : ceil)(argument);
500};
501
502var min$2 = Math.min; // `ToLength` abstract operation
503// https://tc39.es/ecma262/#sec-tolength
504
505var toLength = function (argument) {
506 return argument > 0 ? min$2(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
507};
508
509var max$2 = Math.max;
510var min$1 = Math.min; // Helper for a popular repeating case of the spec:
511// Let integer be ? ToInteger(index).
512// If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
513
514var toAbsoluteIndex = function (index, length) {
515 var integer = toInteger(index);
516 return integer < 0 ? max$2(integer + length, 0) : min$1(integer, length);
517};
518
519var createMethod$5 = function (IS_INCLUDES) {
520 return function ($this, el, fromIndex) {
521 var O = toIndexedObject($this);
522 var length = toLength(O.length);
523 var index = toAbsoluteIndex(fromIndex, length);
524 var value; // Array#includes uses SameValueZero equality algorithm
525 // eslint-disable-next-line no-self-compare -- NaN check
526
527 if (IS_INCLUDES && el != el) while (length > index) {
528 value = O[index++]; // eslint-disable-next-line no-self-compare -- NaN check
529
530 if (value != value) return true; // Array#indexOf ignores holes, Array#includes - not
531 } else for (; length > index; index++) {
532 if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
533 }
534 return !IS_INCLUDES && -1;
535 };
536};
537
538var arrayIncludes = {
539 // `Array.prototype.includes` method
540 // https://tc39.es/ecma262/#sec-array.prototype.includes
541 includes: createMethod$5(true),
542 // `Array.prototype.indexOf` method
543 // https://tc39.es/ecma262/#sec-array.prototype.indexof
544 indexOf: createMethod$5(false)
545};
546
547var hiddenKeys$1 = {};
548
549var indexOf$3 = arrayIncludes.indexOf;
550
551var objectKeysInternal = function (object, names) {
552 var O = toIndexedObject(object);
553 var i = 0;
554 var result = [];
555 var key;
556
557 for (key in O) !has$1(hiddenKeys$1, key) && has$1(O, key) && result.push(key); // Don't enum bug & hidden keys
558
559
560 while (names.length > i) if (has$1(O, key = names[i++])) {
561 ~indexOf$3(result, key) || result.push(key);
562 }
563
564 return result;
565};
566
567// IE8- don't enum bug keys
568var enumBugKeys = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'];
569
570// https://tc39.es/ecma262/#sec-object.keys
571// eslint-disable-next-line es/no-object-keys -- safe
572
573var objectKeys = Object.keys || function keys(O) {
574 return objectKeysInternal(O, enumBugKeys);
575};
576
577// eslint-disable-next-line es/no-object-getownpropertysymbols -- safe
578var f$3 = Object.getOwnPropertySymbols;
579var objectGetOwnPropertySymbols = {
580 f: f$3
581};
582
583var $assign = Object.assign; // eslint-disable-next-line es/no-object-defineproperty -- required for testing
584
585var defineProperty$9 = Object.defineProperty; // `Object.assign` method
586// https://tc39.es/ecma262/#sec-object.assign
587
588var objectAssign = !$assign || fails(function () {
589 // should have correct order of operations (Edge bug)
590 if (descriptors && $assign({
591 b: 1
592 }, $assign(defineProperty$9({}, 'a', {
593 enumerable: true,
594 get: function () {
595 defineProperty$9(this, 'b', {
596 value: 3,
597 enumerable: false
598 });
599 }
600 }), {
601 b: 2
602 })).b !== 1) return true; // should work with symbols and should have deterministic property order (V8 bug)
603
604 var A = {};
605 var B = {}; // eslint-disable-next-line es/no-symbol -- safe
606
607 var symbol = Symbol();
608 var alphabet = 'abcdefghijklmnopqrst';
609 A[symbol] = 7;
610 alphabet.split('').forEach(function (chr) {
611 B[chr] = chr;
612 });
613 return $assign({}, A)[symbol] != 7 || objectKeys($assign({}, B)).join('') != alphabet;
614}) ? function assign(target, source) {
615 // eslint-disable-line no-unused-vars -- required for `.length`
616 var T = toObject(target);
617 var argumentsLength = arguments.length;
618 var index = 1;
619 var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
620 var propertyIsEnumerable = objectPropertyIsEnumerable.f;
621
622 while (argumentsLength > index) {
623 var S = indexedObject(arguments[index++]);
624 var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
625 var length = keys.length;
626 var j = 0;
627 var key;
628
629 while (length > j) {
630 key = keys[j++];
631 if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
632 }
633 }
634
635 return T;
636} : $assign;
637
638// https://tc39.es/ecma262/#sec-object.assign
639// eslint-disable-next-line es/no-object-assign -- required for testing
640
641_export({
642 target: 'Object',
643 stat: true,
644 forced: Object.assign !== objectAssign
645}, {
646 assign: objectAssign
647});
648
649var assign$4 = path.Object.assign;
650
651var assign$3 = assign$4;
652
653var assign$2 = assign$3;
654
655var slice$6 = [].slice;
656var factories = {};
657
658var construct$3 = function (C, argsLength, args) {
659 if (!(argsLength in factories)) {
660 for (var list = [], i = 0; i < argsLength; i++) list[i] = 'a[' + i + ']'; // eslint-disable-next-line no-new-func -- we have no proper alternatives, IE8- only
661
662
663 factories[argsLength] = Function('C,a', 'return new C(' + list.join(',') + ')');
664 }
665
666 return factories[argsLength](C, args);
667}; // `Function.prototype.bind` method implementation
668// https://tc39.es/ecma262/#sec-function.prototype.bind
669
670
671var functionBind = Function.bind || function bind(that
672/* , ...args */
673) {
674 var fn = aFunction(this);
675 var partArgs = slice$6.call(arguments, 1);
676
677 var boundFunction = function bound() {
678 var args = partArgs.concat(slice$6.call(arguments));
679 return this instanceof boundFunction ? construct$3(fn, args.length, args) : fn.apply(that, args);
680 };
681
682 if (isObject$1(fn.prototype)) boundFunction.prototype = fn.prototype;
683 return boundFunction;
684};
685
686// https://tc39.es/ecma262/#sec-function.prototype.bind
687
688_export({
689 target: 'Function',
690 proto: true
691}, {
692 bind: functionBind
693});
694
695var entryVirtual = function (CONSTRUCTOR) {
696 return path[CONSTRUCTOR + 'Prototype'];
697};
698
699var bind$2 = entryVirtual('Function').bind;
700
701var FunctionPrototype = Function.prototype;
702
703var bind_1 = function (it) {
704 var own = it.bind;
705 return it === FunctionPrototype || it instanceof Function && own === FunctionPrototype.bind ? bind$2 : own;
706};
707
708var bind$1 = bind_1;
709
710var bind = bind$1;
711
712/**
713 * Draw a circle.
714 *
715 * @param ctx - The context this shape will be rendered to.
716 * @param x - The position of the center on the x axis.
717 * @param y - The position of the center on the y axis.
718 * @param r - The radius of the circle.
719 */
720function drawCircle(ctx, x, y, r) {
721 ctx.beginPath();
722 ctx.arc(x, y, r, 0, 2 * Math.PI, false);
723 ctx.closePath();
724}
725/**
726 * Draw a square.
727 *
728 * @param ctx - The context this shape will be rendered to.
729 * @param x - The position of the center on the x axis.
730 * @param y - The position of the center on the y axis.
731 * @param r - Half of the width and height of the square.
732 */
733
734function drawSquare(ctx, x, y, r) {
735 ctx.beginPath();
736 ctx.rect(x - r, y - r, r * 2, r * 2);
737 ctx.closePath();
738}
739/**
740 * Draw an equilateral triangle standing on a side.
741 *
742 * @param ctx - The context this shape will be rendered to.
743 * @param x - The position of the center on the x axis.
744 * @param y - The position of the center on the y axis.
745 * @param r - Half of the length of the sides.
746 *
747 * @remarks
748 * http://en.wikipedia.org/wiki/Equilateral_triangle
749 */
750
751function drawTriangle(ctx, x, y, r) {
752 ctx.beginPath(); // the change in radius and the offset is here to center the shape
753
754 r *= 1.15;
755 y += 0.275 * r;
756 var s = r * 2;
757 var s2 = s / 2;
758 var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
759
760 var h = Math.sqrt(s * s - s2 * s2); // height
761
762 ctx.moveTo(x, y - (h - ir));
763 ctx.lineTo(x + s2, y + ir);
764 ctx.lineTo(x - s2, y + ir);
765 ctx.lineTo(x, y - (h - ir));
766 ctx.closePath();
767}
768/**
769 * Draw an equilateral triangle standing on a vertex.
770 *
771 * @param ctx - The context this shape will be rendered to.
772 * @param x - The position of the center on the x axis.
773 * @param y - The position of the center on the y axis.
774 * @param r - Half of the length of the sides.
775 *
776 * @remarks
777 * http://en.wikipedia.org/wiki/Equilateral_triangle
778 */
779
780function drawTriangleDown(ctx, x, y, r) {
781 ctx.beginPath(); // the change in radius and the offset is here to center the shape
782
783 r *= 1.15;
784 y -= 0.275 * r;
785 var s = r * 2;
786 var s2 = s / 2;
787 var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
788
789 var h = Math.sqrt(s * s - s2 * s2); // height
790
791 ctx.moveTo(x, y + (h - ir));
792 ctx.lineTo(x + s2, y - ir);
793 ctx.lineTo(x - s2, y - ir);
794 ctx.lineTo(x, y + (h - ir));
795 ctx.closePath();
796}
797/**
798 * Draw a star.
799 *
800 * @param ctx - The context this shape will be rendered to.
801 * @param x - The position of the center on the x axis.
802 * @param y - The position of the center on the y axis.
803 * @param r - The outer radius of the star.
804 */
805
806function drawStar(ctx, x, y, r) {
807 // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
808 ctx.beginPath(); // the change in radius and the offset is here to center the shape
809
810 r *= 0.82;
811 y += 0.1 * r;
812
813 for (var n = 0; n < 10; n++) {
814 var radius = n % 2 === 0 ? r * 1.3 : r * 0.5;
815 ctx.lineTo(x + radius * Math.sin(n * 2 * Math.PI / 10), y - radius * Math.cos(n * 2 * Math.PI / 10));
816 }
817
818 ctx.closePath();
819}
820/**
821 * Draw a diamond.
822 *
823 * @param ctx - The context this shape will be rendered to.
824 * @param x - The position of the center on the x axis.
825 * @param y - The position of the center on the y axis.
826 * @param r - Half of the width and height of the diamond.
827 *
828 * @remarks
829 * http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
830 */
831
832function drawDiamond(ctx, x, y, r) {
833 ctx.beginPath();
834 ctx.lineTo(x, y + r);
835 ctx.lineTo(x + r, y);
836 ctx.lineTo(x, y - r);
837 ctx.lineTo(x - r, y);
838 ctx.closePath();
839}
840/**
841 * Draw a rectangle with rounded corners.
842 *
843 * @param ctx - The context this shape will be rendered to.
844 * @param x - The position of the center on the x axis.
845 * @param y - The position of the center on the y axis.
846 * @param w - The width of the rectangle.
847 * @param h - The height of the rectangle.
848 * @param r - The radius of the corners.
849 *
850 * @remarks
851 * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas
852 */
853
854function drawRoundRect(ctx, x, y, w, h, r) {
855 var r2d = Math.PI / 180;
856
857 if (w - 2 * r < 0) {
858 r = w / 2;
859 } //ensure that the radius isn't too large for x
860
861
862 if (h - 2 * r < 0) {
863 r = h / 2;
864 } //ensure that the radius isn't too large for y
865
866
867 ctx.beginPath();
868 ctx.moveTo(x + r, y);
869 ctx.lineTo(x + w - r, y);
870 ctx.arc(x + w - r, y + r, r, r2d * 270, r2d * 360, false);
871 ctx.lineTo(x + w, y + h - r);
872 ctx.arc(x + w - r, y + h - r, r, 0, r2d * 90, false);
873 ctx.lineTo(x + r, y + h);
874 ctx.arc(x + r, y + h - r, r, r2d * 90, r2d * 180, false);
875 ctx.lineTo(x, y + r);
876 ctx.arc(x + r, y + r, r, r2d * 180, r2d * 270, false);
877 ctx.closePath();
878}
879/**
880 * Draw an ellipse.
881 *
882 * @param ctx - The context this shape will be rendered to.
883 * @param x - The position of the center on the x axis.
884 * @param y - The position of the center on the y axis.
885 * @param w - The width of the ellipse.
886 * @param h - The height of the ellipse.
887 *
888 * @remarks
889 * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
890 *
891 * Postfix '_vis' added to discern it from standard method ellipse().
892 */
893
894function drawEllipse(ctx, x, y, w, h) {
895 var kappa = 0.5522848,
896 ox = w / 2 * kappa,
897 // control point offset horizontal
898 oy = h / 2 * kappa,
899 // control point offset vertical
900 xe = x + w,
901 // x-end
902 ye = y + h,
903 // y-end
904 xm = x + w / 2,
905 // x-middle
906 ym = y + h / 2; // y-middle
907
908 ctx.beginPath();
909 ctx.moveTo(x, ym);
910 ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
911 ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
912 ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
913 ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
914 ctx.closePath();
915}
916/**
917 * Draw an isometric cylinder.
918 *
919 * @param ctx - The context this shape will be rendered to.
920 * @param x - The position of the center on the x axis.
921 * @param y - The position of the center on the y axis.
922 * @param w - The width of the database.
923 * @param h - The height of the database.
924 *
925 * @remarks
926 * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
927 */
928
929function drawDatabase(ctx, x, y, w, h) {
930 var f = 1 / 3;
931 var wEllipse = w;
932 var hEllipse = h * f;
933 var kappa = 0.5522848,
934 ox = wEllipse / 2 * kappa,
935 // control point offset horizontal
936 oy = hEllipse / 2 * kappa,
937 // control point offset vertical
938 xe = x + wEllipse,
939 // x-end
940 ye = y + hEllipse,
941 // y-end
942 xm = x + wEllipse / 2,
943 // x-middle
944 ym = y + hEllipse / 2,
945 // y-middle
946 ymb = y + (h - hEllipse / 2),
947 // y-midlle, bottom ellipse
948 yeb = y + h; // y-end, bottom ellipse
949
950 ctx.beginPath();
951 ctx.moveTo(xe, ym);
952 ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
953 ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
954 ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
955 ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
956 ctx.lineTo(xe, ymb);
957 ctx.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb);
958 ctx.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb);
959 ctx.lineTo(x, ym);
960}
961/**
962 * Draw a dashed line.
963 *
964 * @param ctx - The context this shape will be rendered to.
965 * @param x - The start position on the x axis.
966 * @param y - The start position on the y axis.
967 * @param x2 - The end position on the x axis.
968 * @param y2 - The end position on the y axis.
969 * @param pattern - List of lengths starting with line and then alternating between space and line.
970 *
971 * @author David Jordan
972 * @remarks
973 * date 2012-08-08
974 * http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas
975 */
976
977function drawDashedLine(ctx, x, y, x2, y2, pattern) {
978 ctx.beginPath();
979 ctx.moveTo(x, y);
980 var patternLength = pattern.length;
981 var dx = x2 - x;
982 var dy = y2 - y;
983 var slope = dy / dx;
984 var distRemaining = Math.sqrt(dx * dx + dy * dy);
985 var patternIndex = 0;
986 var draw = true;
987 var xStep = 0;
988 var dashLength = +pattern[0];
989
990 while (distRemaining >= 0.1) {
991 dashLength = +pattern[patternIndex++ % patternLength];
992
993 if (dashLength > distRemaining) {
994 dashLength = distRemaining;
995 }
996
997 xStep = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
998 xStep = dx < 0 ? -xStep : xStep;
999 x += xStep;
1000 y += slope * xStep;
1001
1002 if (draw === true) {
1003 ctx.lineTo(x, y);
1004 } else {
1005 ctx.moveTo(x, y);
1006 }
1007
1008 distRemaining -= dashLength;
1009 draw = !draw;
1010 }
1011}
1012/**
1013 * Draw a hexagon.
1014 *
1015 * @param ctx - The context this shape will be rendered to.
1016 * @param x - The position of the center on the x axis.
1017 * @param y - The position of the center on the y axis.
1018 * @param r - The radius of the hexagon.
1019 */
1020
1021function drawHexagon(ctx, x, y, r) {
1022 ctx.beginPath();
1023 var sides = 6;
1024 var a = Math.PI * 2 / sides;
1025 ctx.moveTo(x + r, y);
1026
1027 for (var i = 1; i < sides; i++) {
1028 ctx.lineTo(x + r * Math.cos(a * i), y + r * Math.sin(a * i));
1029 }
1030
1031 ctx.closePath();
1032}
1033var shapeMap = {
1034 circle: drawCircle,
1035 dashedLine: drawDashedLine,
1036 database: drawDatabase,
1037 diamond: drawDiamond,
1038 ellipse: drawEllipse,
1039 ellipse_vis: drawEllipse,
1040 hexagon: drawHexagon,
1041 roundRect: drawRoundRect,
1042 square: drawSquare,
1043 star: drawStar,
1044 triangle: drawTriangle,
1045 triangleDown: drawTriangleDown
1046};
1047/**
1048 * Returns either custom or native drawing function base on supplied name.
1049 *
1050 * @param name - The name of the function. Either the name of a
1051 * CanvasRenderingContext2D property or an export from shapes.ts without the
1052 * draw prefix.
1053 *
1054 * @returns The function that can be used for rendering. In case of native
1055 * CanvasRenderingContext2D function the API is normalized to
1056 * `(ctx: CanvasRenderingContext2D, ...originalArgs) => void`.
1057 */
1058
1059function getShape(name) {
1060 if (Object.prototype.hasOwnProperty.call(shapeMap, name)) {
1061 return shapeMap[name];
1062 } else {
1063 return function (ctx) {
1064 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
1065 args[_key - 1] = arguments[_key];
1066 }
1067
1068 CanvasRenderingContext2D.prototype[name].call(ctx, args);
1069 };
1070 }
1071}
1072
1073var componentEmitter = createCommonjsModule(function (module) {
1074 /**
1075 * Expose `Emitter`.
1076 */
1077 {
1078 module.exports = Emitter;
1079 }
1080 /**
1081 * Initialize a new `Emitter`.
1082 *
1083 * @api public
1084 */
1085
1086
1087 function Emitter(obj) {
1088 if (obj) return mixin(obj);
1089 }
1090 /**
1091 * Mixin the emitter properties.
1092 *
1093 * @param {Object} obj
1094 * @return {Object}
1095 * @api private
1096 */
1097
1098 function mixin(obj) {
1099 for (var key in Emitter.prototype) {
1100 obj[key] = Emitter.prototype[key];
1101 }
1102
1103 return obj;
1104 }
1105 /**
1106 * Listen on the given `event` with `fn`.
1107 *
1108 * @param {String} event
1109 * @param {Function} fn
1110 * @return {Emitter}
1111 * @api public
1112 */
1113
1114
1115 Emitter.prototype.on = Emitter.prototype.addEventListener = function (event, fn) {
1116 this._callbacks = this._callbacks || {};
1117 (this._callbacks['$' + event] = this._callbacks['$' + event] || []).push(fn);
1118 return this;
1119 };
1120 /**
1121 * Adds an `event` listener that will be invoked a single
1122 * time then automatically removed.
1123 *
1124 * @param {String} event
1125 * @param {Function} fn
1126 * @return {Emitter}
1127 * @api public
1128 */
1129
1130
1131 Emitter.prototype.once = function (event, fn) {
1132 function on() {
1133 this.off(event, on);
1134 fn.apply(this, arguments);
1135 }
1136
1137 on.fn = fn;
1138 this.on(event, on);
1139 return this;
1140 };
1141 /**
1142 * Remove the given callback for `event` or all
1143 * registered callbacks.
1144 *
1145 * @param {String} event
1146 * @param {Function} fn
1147 * @return {Emitter}
1148 * @api public
1149 */
1150
1151
1152 Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function (event, fn) {
1153 this._callbacks = this._callbacks || {}; // all
1154
1155 if (0 == arguments.length) {
1156 this._callbacks = {};
1157 return this;
1158 } // specific event
1159
1160
1161 var callbacks = this._callbacks['$' + event];
1162 if (!callbacks) return this; // remove all handlers
1163
1164 if (1 == arguments.length) {
1165 delete this._callbacks['$' + event];
1166 return this;
1167 } // remove specific handler
1168
1169
1170 var cb;
1171
1172 for (var i = 0; i < callbacks.length; i++) {
1173 cb = callbacks[i];
1174
1175 if (cb === fn || cb.fn === fn) {
1176 callbacks.splice(i, 1);
1177 break;
1178 }
1179 } // Remove event specific arrays for event types that no
1180 // one is subscribed for to avoid memory leak.
1181
1182
1183 if (callbacks.length === 0) {
1184 delete this._callbacks['$' + event];
1185 }
1186
1187 return this;
1188 };
1189 /**
1190 * Emit `event` with the given args.
1191 *
1192 * @param {String} event
1193 * @param {Mixed} ...
1194 * @return {Emitter}
1195 */
1196
1197
1198 Emitter.prototype.emit = function (event) {
1199 this._callbacks = this._callbacks || {};
1200 var args = new Array(arguments.length - 1),
1201 callbacks = this._callbacks['$' + event];
1202
1203 for (var i = 1; i < arguments.length; i++) {
1204 args[i - 1] = arguments[i];
1205 }
1206
1207 if (callbacks) {
1208 callbacks = callbacks.slice(0);
1209
1210 for (var i = 0, len = callbacks.length; i < len; ++i) {
1211 callbacks[i].apply(this, args);
1212 }
1213 }
1214
1215 return this;
1216 };
1217 /**
1218 * Return array of callbacks for `event`.
1219 *
1220 * @param {String} event
1221 * @return {Array}
1222 * @api public
1223 */
1224
1225
1226 Emitter.prototype.listeners = function (event) {
1227 this._callbacks = this._callbacks || {};
1228 return this._callbacks['$' + event] || [];
1229 };
1230 /**
1231 * Check if this emitter has `event` handlers.
1232 *
1233 * @param {String} event
1234 * @return {Boolean}
1235 * @api public
1236 */
1237
1238
1239 Emitter.prototype.hasListeners = function (event) {
1240 return !!this.listeners(event).length;
1241 };
1242});
1243
1244var toString_1 = function (argument) {
1245 if (isSymbol(argument)) throw TypeError('Cannot convert a Symbol value to a string');
1246 return String(argument);
1247};
1248
1249var createMethod$4 = function (CONVERT_TO_STRING) {
1250 return function ($this, pos) {
1251 var S = toString_1(requireObjectCoercible($this));
1252 var position = toInteger(pos);
1253 var size = S.length;
1254 var first, second;
1255 if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
1256 first = S.charCodeAt(position);
1257 return first < 0xD800 || first > 0xDBFF || position + 1 === size || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF ? CONVERT_TO_STRING ? S.charAt(position) : first : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
1258 };
1259};
1260
1261var stringMultibyte = {
1262 // `String.prototype.codePointAt` method
1263 // https://tc39.es/ecma262/#sec-string.prototype.codepointat
1264 codeAt: createMethod$4(false),
1265 // `String.prototype.at` method
1266 // https://github.com/mathiasbynens/String.prototype.at
1267 charAt: createMethod$4(true)
1268};
1269
1270var functionToString = Function.toString; // this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper
1271
1272if (typeof sharedStore.inspectSource != 'function') {
1273 sharedStore.inspectSource = function (it) {
1274 return functionToString.call(it);
1275 };
1276}
1277
1278var inspectSource = sharedStore.inspectSource;
1279
1280var WeakMap$1 = global_1.WeakMap;
1281var nativeWeakMap = typeof WeakMap$1 === 'function' && /native code/.test(inspectSource(WeakMap$1));
1282
1283var keys$6 = shared('keys');
1284
1285var sharedKey = function (key) {
1286 return keys$6[key] || (keys$6[key] = uid(key));
1287};
1288
1289var OBJECT_ALREADY_INITIALIZED = 'Object already initialized';
1290var WeakMap = global_1.WeakMap;
1291var set$3, get$6, has;
1292
1293var enforce = function (it) {
1294 return has(it) ? get$6(it) : set$3(it, {});
1295};
1296
1297var getterFor = function (TYPE) {
1298 return function (it) {
1299 var state;
1300
1301 if (!isObject$1(it) || (state = get$6(it)).type !== TYPE) {
1302 throw TypeError('Incompatible receiver, ' + TYPE + ' required');
1303 }
1304
1305 return state;
1306 };
1307};
1308
1309if (nativeWeakMap || sharedStore.state) {
1310 var store = sharedStore.state || (sharedStore.state = new WeakMap());
1311 var wmget = store.get;
1312 var wmhas = store.has;
1313 var wmset = store.set;
1314
1315 set$3 = function (it, metadata) {
1316 if (wmhas.call(store, it)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
1317 metadata.facade = it;
1318 wmset.call(store, it, metadata);
1319 return metadata;
1320 };
1321
1322 get$6 = function (it) {
1323 return wmget.call(store, it) || {};
1324 };
1325
1326 has = function (it) {
1327 return wmhas.call(store, it);
1328 };
1329} else {
1330 var STATE = sharedKey('state');
1331 hiddenKeys$1[STATE] = true;
1332
1333 set$3 = function (it, metadata) {
1334 if (has$1(it, STATE)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
1335 metadata.facade = it;
1336 createNonEnumerableProperty(it, STATE, metadata);
1337 return metadata;
1338 };
1339
1340 get$6 = function (it) {
1341 return has$1(it, STATE) ? it[STATE] : {};
1342 };
1343
1344 has = function (it) {
1345 return has$1(it, STATE);
1346 };
1347}
1348
1349var internalState = {
1350 set: set$3,
1351 get: get$6,
1352 has: has,
1353 enforce: enforce,
1354 getterFor: getterFor
1355};
1356
1357var correctPrototypeGetter = !fails(function () {
1358 function F() {
1359 /* empty */
1360 }
1361
1362 F.prototype.constructor = null; // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
1363
1364 return Object.getPrototypeOf(new F()) !== F.prototype;
1365});
1366
1367var IE_PROTO$1 = sharedKey('IE_PROTO');
1368var ObjectPrototype$1 = Object.prototype; // `Object.getPrototypeOf` method
1369// https://tc39.es/ecma262/#sec-object.getprototypeof
1370// eslint-disable-next-line es/no-object-getprototypeof -- safe
1371
1372var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
1373 O = toObject(O);
1374 if (has$1(O, IE_PROTO$1)) return O[IE_PROTO$1];
1375
1376 if (typeof O.constructor == 'function' && O instanceof O.constructor) {
1377 return O.constructor.prototype;
1378 }
1379
1380 return O instanceof Object ? ObjectPrototype$1 : null;
1381};
1382
1383var ITERATOR$4 = wellKnownSymbol('iterator');
1384var BUGGY_SAFARI_ITERATORS$1 = false;
1385
1386var returnThis$2 = function () {
1387 return this;
1388}; // `%IteratorPrototype%` object
1389// https://tc39.es/ecma262/#sec-%iteratorprototype%-object
1390
1391
1392var IteratorPrototype$2, PrototypeOfArrayIteratorPrototype, arrayIterator;
1393/* eslint-disable es/no-array-prototype-keys -- safe */
1394
1395if ([].keys) {
1396 arrayIterator = [].keys(); // Safari 8 has buggy iterators w/o `next`
1397
1398 if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS$1 = true;else {
1399 PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
1400 if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype$2 = PrototypeOfArrayIteratorPrototype;
1401 }
1402}
1403
1404var NEW_ITERATOR_PROTOTYPE = IteratorPrototype$2 == undefined || fails(function () {
1405 var test = {}; // FF44- legacy iterators case
1406
1407 return IteratorPrototype$2[ITERATOR$4].call(test) !== test;
1408});
1409if (NEW_ITERATOR_PROTOTYPE) IteratorPrototype$2 = {}; // `%IteratorPrototype%[@@iterator]()` method
1410// https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator
1411
1412if ((NEW_ITERATOR_PROTOTYPE) && !has$1(IteratorPrototype$2, ITERATOR$4)) {
1413 createNonEnumerableProperty(IteratorPrototype$2, ITERATOR$4, returnThis$2);
1414}
1415
1416var iteratorsCore = {
1417 IteratorPrototype: IteratorPrototype$2,
1418 BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS$1
1419};
1420
1421// https://tc39.es/ecma262/#sec-object.defineproperties
1422// eslint-disable-next-line es/no-object-defineproperties -- safe
1423
1424var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
1425 anObject(O);
1426 var keys = objectKeys(Properties);
1427 var length = keys.length;
1428 var index = 0;
1429 var key;
1430
1431 while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);
1432
1433 return O;
1434};
1435
1436var html = getBuiltIn('document', 'documentElement');
1437
1438/* global ActiveXObject -- old IE, WSH */
1439
1440var GT = '>';
1441var LT = '<';
1442var PROTOTYPE$1 = 'prototype';
1443var SCRIPT = 'script';
1444var IE_PROTO = sharedKey('IE_PROTO');
1445
1446var EmptyConstructor = function () {
1447 /* empty */
1448};
1449
1450var scriptTag = function (content) {
1451 return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
1452}; // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
1453
1454
1455var NullProtoObjectViaActiveX = function (activeXDocument) {
1456 activeXDocument.write(scriptTag(''));
1457 activeXDocument.close();
1458 var temp = activeXDocument.parentWindow.Object;
1459 activeXDocument = null; // avoid memory leak
1460
1461 return temp;
1462}; // Create object with fake `null` prototype: use iframe Object with cleared prototype
1463
1464
1465var NullProtoObjectViaIFrame = function () {
1466 // Thrash, waste and sodomy: IE GC bug
1467 var iframe = documentCreateElement('iframe');
1468 var JS = 'java' + SCRIPT + ':';
1469 var iframeDocument;
1470
1471 if (iframe.style) {
1472 iframe.style.display = 'none';
1473 html.appendChild(iframe); // https://github.com/zloirock/core-js/issues/475
1474
1475 iframe.src = String(JS);
1476 iframeDocument = iframe.contentWindow.document;
1477 iframeDocument.open();
1478 iframeDocument.write(scriptTag('document.F=Object'));
1479 iframeDocument.close();
1480 return iframeDocument.F;
1481 }
1482}; // Check for document.domain and active x support
1483// No need to use active x approach when document.domain is not set
1484// see https://github.com/es-shims/es5-shim/issues/150
1485// variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
1486// avoid IE GC bug
1487
1488
1489var activeXDocument;
1490
1491var NullProtoObject = function () {
1492 try {
1493 activeXDocument = new ActiveXObject('htmlfile');
1494 } catch (error) {
1495 /* ignore */
1496 }
1497
1498 NullProtoObject = document.domain && activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : // old IE
1499 NullProtoObjectViaIFrame() || NullProtoObjectViaActiveX(activeXDocument); // WSH
1500
1501 var length = enumBugKeys.length;
1502
1503 while (length--) delete NullProtoObject[PROTOTYPE$1][enumBugKeys[length]];
1504
1505 return NullProtoObject();
1506};
1507
1508hiddenKeys$1[IE_PROTO] = true; // `Object.create` method
1509// https://tc39.es/ecma262/#sec-object.create
1510
1511var objectCreate = Object.create || function create(O, Properties) {
1512 var result;
1513
1514 if (O !== null) {
1515 EmptyConstructor[PROTOTYPE$1] = anObject(O);
1516 result = new EmptyConstructor();
1517 EmptyConstructor[PROTOTYPE$1] = null; // add "__proto__" for Object.getPrototypeOf polyfill
1518
1519 result[IE_PROTO] = O;
1520 } else result = NullProtoObject();
1521
1522 return Properties === undefined ? result : objectDefineProperties(result, Properties);
1523};
1524
1525var TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');
1526var test$2 = {};
1527test$2[TO_STRING_TAG$3] = 'z';
1528var toStringTagSupport = String(test$2) === '[object z]';
1529
1530var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag'); // ES3 wrong here
1531
1532var CORRECT_ARGUMENTS = classofRaw(function () {
1533 return arguments;
1534}()) == 'Arguments'; // fallback for IE11 Script Access Denied error
1535
1536var tryGet = function (it, key) {
1537 try {
1538 return it[key];
1539 } catch (error) {
1540 /* empty */
1541 }
1542}; // getting tag from ES6+ `Object.prototype.toString`
1543
1544
1545var classof = toStringTagSupport ? classofRaw : function (it) {
1546 var O, tag, result;
1547 return it === undefined ? 'Undefined' : it === null ? 'Null' // @@toStringTag case
1548 : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag // builtinTag case
1549 : CORRECT_ARGUMENTS ? classofRaw(O) // ES3 arguments fallback
1550 : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
1551};
1552
1553// https://tc39.es/ecma262/#sec-object.prototype.tostring
1554
1555
1556var objectToString = toStringTagSupport ? {}.toString : function toString() {
1557 return '[object ' + classof(this) + ']';
1558};
1559
1560var defineProperty$8 = objectDefineProperty.f;
1561var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
1562
1563var setToStringTag = function (it, TAG, STATIC, SET_METHOD) {
1564 if (it) {
1565 var target = STATIC ? it : it.prototype;
1566
1567 if (!has$1(target, TO_STRING_TAG$1)) {
1568 defineProperty$8(target, TO_STRING_TAG$1, {
1569 configurable: true,
1570 value: TAG
1571 });
1572 }
1573
1574 if (SET_METHOD && !toStringTagSupport) {
1575 createNonEnumerableProperty(target, 'toString', objectToString);
1576 }
1577 }
1578};
1579
1580var iterators = {};
1581
1582var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;
1583
1584var returnThis$1 = function () {
1585 return this;
1586};
1587
1588var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
1589 var TO_STRING_TAG = NAME + ' Iterator';
1590 IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, {
1591 next: createPropertyDescriptor(1, next)
1592 });
1593 setToStringTag(IteratorConstructor, TO_STRING_TAG, false, true);
1594 iterators[TO_STRING_TAG] = returnThis$1;
1595 return IteratorConstructor;
1596};
1597
1598var aPossiblePrototype = function (it) {
1599 if (!isObject$1(it) && it !== null) {
1600 throw TypeError("Can't set " + String(it) + ' as a prototype');
1601 }
1602
1603 return it;
1604};
1605
1606/* eslint-disable no-proto -- safe */
1607// `Object.setPrototypeOf` method
1608// https://tc39.es/ecma262/#sec-object.setprototypeof
1609// Works with __proto__ only. Old v8 can't work with null proto objects.
1610// eslint-disable-next-line es/no-object-setprototypeof -- safe
1611
1612var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
1613 var CORRECT_SETTER = false;
1614 var test = {};
1615 var setter;
1616
1617 try {
1618 // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
1619 setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
1620 setter.call(test, []);
1621 CORRECT_SETTER = test instanceof Array;
1622 } catch (error) {
1623 /* empty */
1624 }
1625
1626 return function setPrototypeOf(O, proto) {
1627 anObject(O);
1628 aPossiblePrototype(proto);
1629 if (CORRECT_SETTER) setter.call(O, proto);else O.__proto__ = proto;
1630 return O;
1631 };
1632}() : undefined);
1633
1634var redefine = function (target, key, value, options) {
1635 if (options && options.enumerable) target[key] = value;else createNonEnumerableProperty(target, key, value);
1636};
1637
1638var IteratorPrototype = iteratorsCore.IteratorPrototype;
1639var BUGGY_SAFARI_ITERATORS = iteratorsCore.BUGGY_SAFARI_ITERATORS;
1640var ITERATOR$3 = wellKnownSymbol('iterator');
1641var KEYS = 'keys';
1642var VALUES = 'values';
1643var ENTRIES = 'entries';
1644
1645var returnThis = function () {
1646 return this;
1647};
1648
1649var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
1650 createIteratorConstructor(IteratorConstructor, NAME, next);
1651
1652 var getIterationMethod = function (KIND) {
1653 if (KIND === DEFAULT && defaultIterator) return defaultIterator;
1654 if (!BUGGY_SAFARI_ITERATORS && KIND in IterablePrototype) return IterablePrototype[KIND];
1655
1656 switch (KIND) {
1657 case KEYS:
1658 return function keys() {
1659 return new IteratorConstructor(this, KIND);
1660 };
1661
1662 case VALUES:
1663 return function values() {
1664 return new IteratorConstructor(this, KIND);
1665 };
1666
1667 case ENTRIES:
1668 return function entries() {
1669 return new IteratorConstructor(this, KIND);
1670 };
1671 }
1672
1673 return function () {
1674 return new IteratorConstructor(this);
1675 };
1676 };
1677
1678 var TO_STRING_TAG = NAME + ' Iterator';
1679 var INCORRECT_VALUES_NAME = false;
1680 var IterablePrototype = Iterable.prototype;
1681 var nativeIterator = IterablePrototype[ITERATOR$3] || IterablePrototype['@@iterator'] || DEFAULT && IterablePrototype[DEFAULT];
1682 var defaultIterator = !BUGGY_SAFARI_ITERATORS && nativeIterator || getIterationMethod(DEFAULT);
1683 var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
1684 var CurrentIteratorPrototype, methods, KEY; // fix native
1685
1686 if (anyNativeIterator) {
1687 CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));
1688
1689 if (IteratorPrototype !== Object.prototype && CurrentIteratorPrototype.next) {
1690
1691
1692 setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true, true);
1693 iterators[TO_STRING_TAG] = returnThis;
1694 }
1695 } // fix Array.prototype.{ values, @@iterator }.name in V8 / FF
1696
1697
1698 if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
1699 INCORRECT_VALUES_NAME = true;
1700
1701 defaultIterator = function values() {
1702 return nativeIterator.call(this);
1703 };
1704 } // define iterator
1705
1706
1707 if ((FORCED) && IterablePrototype[ITERATOR$3] !== defaultIterator) {
1708 createNonEnumerableProperty(IterablePrototype, ITERATOR$3, defaultIterator);
1709 }
1710
1711 iterators[NAME] = defaultIterator; // export additional methods
1712
1713 if (DEFAULT) {
1714 methods = {
1715 values: getIterationMethod(VALUES),
1716 keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
1717 entries: getIterationMethod(ENTRIES)
1718 };
1719 if (FORCED) for (KEY in methods) {
1720 if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
1721 redefine(IterablePrototype, KEY, methods[KEY]);
1722 }
1723 } else _export({
1724 target: NAME,
1725 proto: true,
1726 forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME
1727 }, methods);
1728 }
1729
1730 return methods;
1731};
1732
1733var charAt = stringMultibyte.charAt;
1734var STRING_ITERATOR = 'String Iterator';
1735var setInternalState$5 = internalState.set;
1736var getInternalState$2 = internalState.getterFor(STRING_ITERATOR); // `String.prototype[@@iterator]` method
1737// https://tc39.es/ecma262/#sec-string.prototype-@@iterator
1738
1739defineIterator(String, 'String', function (iterated) {
1740 setInternalState$5(this, {
1741 type: STRING_ITERATOR,
1742 string: toString_1(iterated),
1743 index: 0
1744 }); // `%StringIteratorPrototype%.next` method
1745 // https://tc39.es/ecma262/#sec-%stringiteratorprototype%.next
1746}, function next() {
1747 var state = getInternalState$2(this);
1748 var string = state.string;
1749 var index = state.index;
1750 var point;
1751 if (index >= string.length) return {
1752 value: undefined,
1753 done: true
1754 };
1755 point = charAt(string, index);
1756 state.index += point.length;
1757 return {
1758 value: point,
1759 done: false
1760 };
1761});
1762
1763var iteratorClose = function (iterator) {
1764 var returnMethod = iterator['return'];
1765
1766 if (returnMethod !== undefined) {
1767 return anObject(returnMethod.call(iterator)).value;
1768 }
1769};
1770
1771var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
1772 try {
1773 return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
1774 } catch (error) {
1775 iteratorClose(iterator);
1776 throw error;
1777 }
1778};
1779
1780var ITERATOR$2 = wellKnownSymbol('iterator');
1781var ArrayPrototype$i = Array.prototype; // check on default Array iterator
1782
1783var isArrayIteratorMethod = function (it) {
1784 return it !== undefined && (iterators.Array === it || ArrayPrototype$i[ITERATOR$2] === it);
1785};
1786
1787var createProperty = function (object, key, value) {
1788 var propertyKey = toPropertyKey(key);
1789 if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));else object[propertyKey] = value;
1790};
1791
1792var ITERATOR$1 = wellKnownSymbol('iterator');
1793
1794var getIteratorMethod$3 = function (it) {
1795 if (it != undefined) return it[ITERATOR$1] || it['@@iterator'] || iterators[classof(it)];
1796};
1797
1798// https://tc39.es/ecma262/#sec-array.from
1799
1800
1801var arrayFrom = function from(arrayLike
1802/* , mapfn = undefined, thisArg = undefined */
1803) {
1804 var O = toObject(arrayLike);
1805 var C = typeof this == 'function' ? this : Array;
1806 var argumentsLength = arguments.length;
1807 var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
1808 var mapping = mapfn !== undefined;
1809 var iteratorMethod = getIteratorMethod$3(O);
1810 var index = 0;
1811 var length, result, step, iterator, next, value;
1812 if (mapping) mapfn = functionBindContext(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2); // if the target is not iterable or it's an array with the default iterator - use a simple case
1813
1814 if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod(iteratorMethod))) {
1815 iterator = iteratorMethod.call(O);
1816 next = iterator.next;
1817 result = new C();
1818
1819 for (; !(step = next.call(iterator)).done; index++) {
1820 value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
1821 createProperty(result, index, value);
1822 }
1823 } else {
1824 length = toLength(O.length);
1825 result = new C(length);
1826
1827 for (; length > index; index++) {
1828 value = mapping ? mapfn(O[index], index) : O[index];
1829 createProperty(result, index, value);
1830 }
1831 }
1832
1833 result.length = index;
1834 return result;
1835};
1836
1837var ITERATOR = wellKnownSymbol('iterator');
1838var SAFE_CLOSING = false;
1839
1840try {
1841 var called = 0;
1842 var iteratorWithReturn = {
1843 next: function () {
1844 return {
1845 done: !!called++
1846 };
1847 },
1848 'return': function () {
1849 SAFE_CLOSING = true;
1850 }
1851 };
1852
1853 iteratorWithReturn[ITERATOR] = function () {
1854 return this;
1855 }; // eslint-disable-next-line es/no-array-from, no-throw-literal -- required for testing
1856
1857
1858 Array.from(iteratorWithReturn, function () {
1859 throw 2;
1860 });
1861} catch (error) {
1862 /* empty */
1863}
1864
1865var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
1866 if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
1867 var ITERATION_SUPPORT = false;
1868
1869 try {
1870 var object = {};
1871
1872 object[ITERATOR] = function () {
1873 return {
1874 next: function () {
1875 return {
1876 done: ITERATION_SUPPORT = true
1877 };
1878 }
1879 };
1880 };
1881
1882 exec(object);
1883 } catch (error) {
1884 /* empty */
1885 }
1886
1887 return ITERATION_SUPPORT;
1888};
1889
1890var INCORRECT_ITERATION = !checkCorrectnessOfIteration(function (iterable) {
1891 // eslint-disable-next-line es/no-array-from -- required for testing
1892 Array.from(iterable);
1893}); // `Array.from` method
1894// https://tc39.es/ecma262/#sec-array.from
1895
1896_export({
1897 target: 'Array',
1898 stat: true,
1899 forced: INCORRECT_ITERATION
1900}, {
1901 from: arrayFrom
1902});
1903
1904var from_1$4 = path.Array.from;
1905
1906var from_1$3 = from_1$4;
1907
1908var from_1$2 = from_1$3;
1909
1910var ARRAY_ITERATOR = 'Array Iterator';
1911var setInternalState$4 = internalState.set;
1912var getInternalState$1 = internalState.getterFor(ARRAY_ITERATOR); // `Array.prototype.entries` method
1913// https://tc39.es/ecma262/#sec-array.prototype.entries
1914// `Array.prototype.keys` method
1915// https://tc39.es/ecma262/#sec-array.prototype.keys
1916// `Array.prototype.values` method
1917// https://tc39.es/ecma262/#sec-array.prototype.values
1918// `Array.prototype[@@iterator]` method
1919// https://tc39.es/ecma262/#sec-array.prototype-@@iterator
1920// `CreateArrayIterator` internal method
1921// https://tc39.es/ecma262/#sec-createarrayiterator
1922
1923defineIterator(Array, 'Array', function (iterated, kind) {
1924 setInternalState$4(this, {
1925 type: ARRAY_ITERATOR,
1926 target: toIndexedObject(iterated),
1927 // target
1928 index: 0,
1929 // next index
1930 kind: kind // kind
1931
1932 }); // `%ArrayIteratorPrototype%.next` method
1933 // https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
1934}, function () {
1935 var state = getInternalState$1(this);
1936 var target = state.target;
1937 var kind = state.kind;
1938 var index = state.index++;
1939
1940 if (!target || index >= target.length) {
1941 state.target = undefined;
1942 return {
1943 value: undefined,
1944 done: true
1945 };
1946 }
1947
1948 if (kind == 'keys') return {
1949 value: index,
1950 done: false
1951 };
1952 if (kind == 'values') return {
1953 value: target[index],
1954 done: false
1955 };
1956 return {
1957 value: [index, target[index]],
1958 done: false
1959 };
1960}, 'values'); // argumentsList[@@iterator] is %ArrayProto_values%
1961// https://tc39.es/ecma262/#sec-createunmappedargumentsobject
1962// https://tc39.es/ecma262/#sec-createmappedargumentsobject
1963
1964iterators.Arguments = iterators.Array; // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
1965
1966var getIteratorMethod_1 = getIteratorMethod$3;
1967
1968// iterable DOM collections
1969// flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
1970var domIterables = {
1971 CSSRuleList: 0,
1972 CSSStyleDeclaration: 0,
1973 CSSValueList: 0,
1974 ClientRectList: 0,
1975 DOMRectList: 0,
1976 DOMStringList: 0,
1977 DOMTokenList: 1,
1978 DataTransferItemList: 0,
1979 FileList: 0,
1980 HTMLAllCollection: 0,
1981 HTMLCollection: 0,
1982 HTMLFormElement: 0,
1983 HTMLSelectElement: 0,
1984 MediaList: 0,
1985 MimeTypeArray: 0,
1986 NamedNodeMap: 0,
1987 NodeList: 1,
1988 PaintRequestList: 0,
1989 Plugin: 0,
1990 PluginArray: 0,
1991 SVGLengthList: 0,
1992 SVGNumberList: 0,
1993 SVGPathSegList: 0,
1994 SVGPointList: 0,
1995 SVGStringList: 0,
1996 SVGTransformList: 0,
1997 SourceBufferList: 0,
1998 StyleSheetList: 0,
1999 TextTrackCueList: 0,
2000 TextTrackList: 0,
2001 TouchList: 0
2002};
2003
2004var TO_STRING_TAG = wellKnownSymbol('toStringTag');
2005
2006for (var COLLECTION_NAME in domIterables) {
2007 var Collection = global_1[COLLECTION_NAME];
2008 var CollectionPrototype = Collection && Collection.prototype;
2009
2010 if (CollectionPrototype && classof(CollectionPrototype) !== TO_STRING_TAG) {
2011 createNonEnumerableProperty(CollectionPrototype, TO_STRING_TAG, COLLECTION_NAME);
2012 }
2013
2014 iterators[COLLECTION_NAME] = iterators.Array;
2015}
2016
2017var getIteratorMethod$2 = getIteratorMethod_1;
2018
2019var getIteratorMethod$1 = getIteratorMethod$2;
2020
2021var getIteratorMethod = getIteratorMethod$1;
2022
2023// https://tc39.es/ecma262/#sec-isarray
2024// eslint-disable-next-line es/no-array-isarray -- safe
2025
2026var isArray$5 = Array.isArray || function isArray(arg) {
2027 return classofRaw(arg) == 'Array';
2028};
2029
2030var hiddenKeys = enumBugKeys.concat('length', 'prototype'); // `Object.getOwnPropertyNames` method
2031// https://tc39.es/ecma262/#sec-object.getownpropertynames
2032// eslint-disable-next-line es/no-object-getownpropertynames -- safe
2033
2034var f$2 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
2035 return objectKeysInternal(O, hiddenKeys);
2036};
2037
2038var objectGetOwnPropertyNames = {
2039 f: f$2
2040};
2041
2042/* eslint-disable es/no-object-getownpropertynames -- safe */
2043
2044var $getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
2045var toString = {}.toString;
2046var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : [];
2047
2048var getWindowNames = function (it) {
2049 try {
2050 return $getOwnPropertyNames$1(it);
2051 } catch (error) {
2052 return windowNames.slice();
2053 }
2054}; // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
2055
2056
2057var f$1 = function getOwnPropertyNames(it) {
2058 return windowNames && toString.call(it) == '[object Window]' ? getWindowNames(it) : $getOwnPropertyNames$1(toIndexedObject(it));
2059};
2060
2061var objectGetOwnPropertyNamesExternal = {
2062 f: f$1
2063};
2064
2065var f = wellKnownSymbol;
2066var wellKnownSymbolWrapped = {
2067 f: f
2068};
2069
2070var defineProperty$7 = objectDefineProperty.f;
2071
2072var defineWellKnownSymbol = function (NAME) {
2073 var Symbol = path.Symbol || (path.Symbol = {});
2074 if (!has$1(Symbol, NAME)) defineProperty$7(Symbol, NAME, {
2075 value: wellKnownSymbolWrapped.f(NAME)
2076 });
2077};
2078
2079var SPECIES$3 = wellKnownSymbol('species'); // a part of `ArraySpeciesCreate` abstract operation
2080// https://tc39.es/ecma262/#sec-arrayspeciescreate
2081
2082var arraySpeciesConstructor = function (originalArray) {
2083 var C;
2084
2085 if (isArray$5(originalArray)) {
2086 C = originalArray.constructor; // cross-realm fallback
2087
2088 if (typeof C == 'function' && (C === Array || isArray$5(C.prototype))) C = undefined;else if (isObject$1(C)) {
2089 C = C[SPECIES$3];
2090 if (C === null) C = undefined;
2091 }
2092 }
2093
2094 return C === undefined ? Array : C;
2095};
2096
2097// https://tc39.es/ecma262/#sec-arrayspeciescreate
2098
2099var arraySpeciesCreate = function (originalArray, length) {
2100 return new (arraySpeciesConstructor(originalArray))(length === 0 ? 0 : length);
2101};
2102
2103var push = [].push; // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterReject }` methods implementation
2104
2105var createMethod$3 = function (TYPE) {
2106 var IS_MAP = TYPE == 1;
2107 var IS_FILTER = TYPE == 2;
2108 var IS_SOME = TYPE == 3;
2109 var IS_EVERY = TYPE == 4;
2110 var IS_FIND_INDEX = TYPE == 6;
2111 var IS_FILTER_REJECT = TYPE == 7;
2112 var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
2113 return function ($this, callbackfn, that, specificCreate) {
2114 var O = toObject($this);
2115 var self = indexedObject(O);
2116 var boundFunction = functionBindContext(callbackfn, that, 3);
2117 var length = toLength(self.length);
2118 var index = 0;
2119 var create = specificCreate || arraySpeciesCreate;
2120 var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_REJECT ? create($this, 0) : undefined;
2121 var value, result;
2122
2123 for (; length > index; index++) if (NO_HOLES || index in self) {
2124 value = self[index];
2125 result = boundFunction(value, index, O);
2126
2127 if (TYPE) {
2128 if (IS_MAP) target[index] = result; // map
2129 else if (result) switch (TYPE) {
2130 case 3:
2131 return true;
2132 // some
2133
2134 case 5:
2135 return value;
2136 // find
2137
2138 case 6:
2139 return index;
2140 // findIndex
2141
2142 case 2:
2143 push.call(target, value);
2144 // filter
2145 } else switch (TYPE) {
2146 case 4:
2147 return false;
2148 // every
2149
2150 case 7:
2151 push.call(target, value);
2152 // filterReject
2153 }
2154 }
2155 }
2156
2157 return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
2158 };
2159};
2160
2161var arrayIteration = {
2162 // `Array.prototype.forEach` method
2163 // https://tc39.es/ecma262/#sec-array.prototype.foreach
2164 forEach: createMethod$3(0),
2165 // `Array.prototype.map` method
2166 // https://tc39.es/ecma262/#sec-array.prototype.map
2167 map: createMethod$3(1),
2168 // `Array.prototype.filter` method
2169 // https://tc39.es/ecma262/#sec-array.prototype.filter
2170 filter: createMethod$3(2),
2171 // `Array.prototype.some` method
2172 // https://tc39.es/ecma262/#sec-array.prototype.some
2173 some: createMethod$3(3),
2174 // `Array.prototype.every` method
2175 // https://tc39.es/ecma262/#sec-array.prototype.every
2176 every: createMethod$3(4),
2177 // `Array.prototype.find` method
2178 // https://tc39.es/ecma262/#sec-array.prototype.find
2179 find: createMethod$3(5),
2180 // `Array.prototype.findIndex` method
2181 // https://tc39.es/ecma262/#sec-array.prototype.findIndex
2182 findIndex: createMethod$3(6),
2183 // `Array.prototype.filterReject` method
2184 // https://github.com/tc39/proposal-array-filtering
2185 filterReject: createMethod$3(7)
2186};
2187
2188var $forEach$1 = arrayIteration.forEach;
2189var HIDDEN = sharedKey('hidden');
2190var SYMBOL = 'Symbol';
2191var PROTOTYPE = 'prototype';
2192var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');
2193var setInternalState$3 = internalState.set;
2194var getInternalState = internalState.getterFor(SYMBOL);
2195var ObjectPrototype = Object[PROTOTYPE];
2196var $Symbol = global_1.Symbol;
2197var $stringify$1 = getBuiltIn('JSON', 'stringify');
2198var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
2199var nativeDefineProperty = objectDefineProperty.f;
2200var nativeGetOwnPropertyNames = objectGetOwnPropertyNamesExternal.f;
2201var nativePropertyIsEnumerable = objectPropertyIsEnumerable.f;
2202var AllSymbols = shared('symbols');
2203var ObjectPrototypeSymbols = shared('op-symbols');
2204var StringToSymbolRegistry = shared('string-to-symbol-registry');
2205var SymbolToStringRegistry = shared('symbol-to-string-registry');
2206var WellKnownSymbolsStore = shared('wks');
2207var QObject = global_1.QObject; // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
2208
2209var USE_SETTER = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild; // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
2210
2211var setSymbolDescriptor = descriptors && fails(function () {
2212 return objectCreate(nativeDefineProperty({}, 'a', {
2213 get: function () {
2214 return nativeDefineProperty(this, 'a', {
2215 value: 7
2216 }).a;
2217 }
2218 })).a != 7;
2219}) ? function (O, P, Attributes) {
2220 var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype, P);
2221 if (ObjectPrototypeDescriptor) delete ObjectPrototype[P];
2222 nativeDefineProperty(O, P, Attributes);
2223
2224 if (ObjectPrototypeDescriptor && O !== ObjectPrototype) {
2225 nativeDefineProperty(ObjectPrototype, P, ObjectPrototypeDescriptor);
2226 }
2227} : nativeDefineProperty;
2228
2229var wrap$1 = function (tag, description) {
2230 var symbol = AllSymbols[tag] = objectCreate($Symbol[PROTOTYPE]);
2231 setInternalState$3(symbol, {
2232 type: SYMBOL,
2233 tag: tag,
2234 description: description
2235 });
2236 if (!descriptors) symbol.description = description;
2237 return symbol;
2238};
2239
2240var $defineProperty = function defineProperty(O, P, Attributes) {
2241 if (O === ObjectPrototype) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
2242 anObject(O);
2243 var key = toPropertyKey(P);
2244 anObject(Attributes);
2245
2246 if (has$1(AllSymbols, key)) {
2247 if (!Attributes.enumerable) {
2248 if (!has$1(O, HIDDEN)) nativeDefineProperty(O, HIDDEN, createPropertyDescriptor(1, {}));
2249 O[HIDDEN][key] = true;
2250 } else {
2251 if (has$1(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
2252 Attributes = objectCreate(Attributes, {
2253 enumerable: createPropertyDescriptor(0, false)
2254 });
2255 }
2256
2257 return setSymbolDescriptor(O, key, Attributes);
2258 }
2259
2260 return nativeDefineProperty(O, key, Attributes);
2261};
2262
2263var $defineProperties = function defineProperties(O, Properties) {
2264 anObject(O);
2265 var properties = toIndexedObject(Properties);
2266 var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties));
2267 $forEach$1(keys, function (key) {
2268 if (!descriptors || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
2269 });
2270 return O;
2271};
2272
2273var $create = function create(O, Properties) {
2274 return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties);
2275};
2276
2277var $propertyIsEnumerable = function propertyIsEnumerable(V) {
2278 var P = toPropertyKey(V);
2279 var enumerable = nativePropertyIsEnumerable.call(this, P);
2280 if (this === ObjectPrototype && has$1(AllSymbols, P) && !has$1(ObjectPrototypeSymbols, P)) return false;
2281 return enumerable || !has$1(this, P) || !has$1(AllSymbols, P) || has$1(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
2282};
2283
2284var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
2285 var it = toIndexedObject(O);
2286 var key = toPropertyKey(P);
2287 if (it === ObjectPrototype && has$1(AllSymbols, key) && !has$1(ObjectPrototypeSymbols, key)) return;
2288 var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);
2289
2290 if (descriptor && has$1(AllSymbols, key) && !(has$1(it, HIDDEN) && it[HIDDEN][key])) {
2291 descriptor.enumerable = true;
2292 }
2293
2294 return descriptor;
2295};
2296
2297var $getOwnPropertyNames = function getOwnPropertyNames(O) {
2298 var names = nativeGetOwnPropertyNames(toIndexedObject(O));
2299 var result = [];
2300 $forEach$1(names, function (key) {
2301 if (!has$1(AllSymbols, key) && !has$1(hiddenKeys$1, key)) result.push(key);
2302 });
2303 return result;
2304};
2305
2306var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
2307 var IS_OBJECT_PROTOTYPE = O === ObjectPrototype;
2308 var names = nativeGetOwnPropertyNames(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));
2309 var result = [];
2310 $forEach$1(names, function (key) {
2311 if (has$1(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has$1(ObjectPrototype, key))) {
2312 result.push(AllSymbols[key]);
2313 }
2314 });
2315 return result;
2316}; // `Symbol` constructor
2317// https://tc39.es/ecma262/#sec-symbol-constructor
2318
2319
2320if (!nativeSymbol) {
2321 $Symbol = function Symbol() {
2322 if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
2323 var description = !arguments.length || arguments[0] === undefined ? undefined : toString_1(arguments[0]);
2324 var tag = uid(description);
2325
2326 var setter = function (value) {
2327 if (this === ObjectPrototype) setter.call(ObjectPrototypeSymbols, value);
2328 if (has$1(this, HIDDEN) && has$1(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
2329 setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
2330 };
2331
2332 if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype, tag, {
2333 configurable: true,
2334 set: setter
2335 });
2336 return wrap$1(tag, description);
2337 };
2338
2339 redefine($Symbol[PROTOTYPE], 'toString', function toString() {
2340 return getInternalState(this).tag;
2341 });
2342 redefine($Symbol, 'withoutSetter', function (description) {
2343 return wrap$1(uid(description), description);
2344 });
2345 objectPropertyIsEnumerable.f = $propertyIsEnumerable;
2346 objectDefineProperty.f = $defineProperty;
2347 objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor;
2348 objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames;
2349 objectGetOwnPropertySymbols.f = $getOwnPropertySymbols;
2350
2351 wellKnownSymbolWrapped.f = function (name) {
2352 return wrap$1(wellKnownSymbol(name), name);
2353 };
2354
2355 if (descriptors) {
2356 // https://github.com/tc39/proposal-Symbol-description
2357 nativeDefineProperty($Symbol[PROTOTYPE], 'description', {
2358 configurable: true,
2359 get: function description() {
2360 return getInternalState(this).description;
2361 }
2362 });
2363 }
2364}
2365
2366_export({
2367 global: true,
2368 wrap: true,
2369 forced: !nativeSymbol,
2370 sham: !nativeSymbol
2371}, {
2372 Symbol: $Symbol
2373});
2374$forEach$1(objectKeys(WellKnownSymbolsStore), function (name) {
2375 defineWellKnownSymbol(name);
2376});
2377_export({
2378 target: SYMBOL,
2379 stat: true,
2380 forced: !nativeSymbol
2381}, {
2382 // `Symbol.for` method
2383 // https://tc39.es/ecma262/#sec-symbol.for
2384 'for': function (key) {
2385 var string = toString_1(key);
2386 if (has$1(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
2387 var symbol = $Symbol(string);
2388 StringToSymbolRegistry[string] = symbol;
2389 SymbolToStringRegistry[symbol] = string;
2390 return symbol;
2391 },
2392 // `Symbol.keyFor` method
2393 // https://tc39.es/ecma262/#sec-symbol.keyfor
2394 keyFor: function keyFor(sym) {
2395 if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol');
2396 if (has$1(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
2397 },
2398 useSetter: function () {
2399 USE_SETTER = true;
2400 },
2401 useSimple: function () {
2402 USE_SETTER = false;
2403 }
2404});
2405_export({
2406 target: 'Object',
2407 stat: true,
2408 forced: !nativeSymbol,
2409 sham: !descriptors
2410}, {
2411 // `Object.create` method
2412 // https://tc39.es/ecma262/#sec-object.create
2413 create: $create,
2414 // `Object.defineProperty` method
2415 // https://tc39.es/ecma262/#sec-object.defineproperty
2416 defineProperty: $defineProperty,
2417 // `Object.defineProperties` method
2418 // https://tc39.es/ecma262/#sec-object.defineproperties
2419 defineProperties: $defineProperties,
2420 // `Object.getOwnPropertyDescriptor` method
2421 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
2422 getOwnPropertyDescriptor: $getOwnPropertyDescriptor
2423});
2424_export({
2425 target: 'Object',
2426 stat: true,
2427 forced: !nativeSymbol
2428}, {
2429 // `Object.getOwnPropertyNames` method
2430 // https://tc39.es/ecma262/#sec-object.getownpropertynames
2431 getOwnPropertyNames: $getOwnPropertyNames,
2432 // `Object.getOwnPropertySymbols` method
2433 // https://tc39.es/ecma262/#sec-object.getownpropertysymbols
2434 getOwnPropertySymbols: $getOwnPropertySymbols
2435}); // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
2436// https://bugs.chromium.org/p/v8/issues/detail?id=3443
2437
2438_export({
2439 target: 'Object',
2440 stat: true,
2441 forced: fails(function () {
2442 objectGetOwnPropertySymbols.f(1);
2443 })
2444}, {
2445 getOwnPropertySymbols: function getOwnPropertySymbols(it) {
2446 return objectGetOwnPropertySymbols.f(toObject(it));
2447 }
2448}); // `JSON.stringify` method behavior with symbols
2449// https://tc39.es/ecma262/#sec-json.stringify
2450
2451if ($stringify$1) {
2452 var FORCED_JSON_STRINGIFY = !nativeSymbol || fails(function () {
2453 var symbol = $Symbol(); // MS Edge converts symbol values to JSON as {}
2454
2455 return $stringify$1([symbol]) != '[null]' // WebKit converts symbol values to JSON as null
2456 || $stringify$1({
2457 a: symbol
2458 }) != '{}' // V8 throws on boxed symbols
2459 || $stringify$1(Object(symbol)) != '{}';
2460 });
2461 _export({
2462 target: 'JSON',
2463 stat: true,
2464 forced: FORCED_JSON_STRINGIFY
2465 }, {
2466 // eslint-disable-next-line no-unused-vars -- required for `.length`
2467 stringify: function stringify(it, replacer, space) {
2468 var args = [it];
2469 var index = 1;
2470 var $replacer;
2471
2472 while (arguments.length > index) args.push(arguments[index++]);
2473
2474 $replacer = replacer;
2475 if (!isObject$1(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined
2476
2477 if (!isArray$5(replacer)) replacer = function (key, value) {
2478 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
2479 if (!isSymbol(value)) return value;
2480 };
2481 args[1] = replacer;
2482 return $stringify$1.apply(null, args);
2483 }
2484 });
2485} // `Symbol.prototype[@@toPrimitive]` method
2486// https://tc39.es/ecma262/#sec-symbol.prototype-@@toprimitive
2487
2488
2489if (!$Symbol[PROTOTYPE][TO_PRIMITIVE]) {
2490 createNonEnumerableProperty($Symbol[PROTOTYPE], TO_PRIMITIVE, $Symbol[PROTOTYPE].valueOf);
2491} // `Symbol.prototype[@@toStringTag]` property
2492// https://tc39.es/ecma262/#sec-symbol.prototype-@@tostringtag
2493
2494
2495setToStringTag($Symbol, SYMBOL);
2496hiddenKeys$1[HIDDEN] = true;
2497
2498var getOwnPropertySymbols$2 = path.Object.getOwnPropertySymbols;
2499
2500var getOwnPropertySymbols$1 = getOwnPropertySymbols$2;
2501
2502var getOwnPropertySymbols = getOwnPropertySymbols$1;
2503
2504var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
2505var FAILS_ON_PRIMITIVES$3 = fails(function () {
2506 nativeGetOwnPropertyDescriptor(1);
2507});
2508var FORCED$6 = !descriptors || FAILS_ON_PRIMITIVES$3; // `Object.getOwnPropertyDescriptor` method
2509// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
2510
2511_export({
2512 target: 'Object',
2513 stat: true,
2514 forced: FORCED$6,
2515 sham: !descriptors
2516}, {
2517 getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
2518 return nativeGetOwnPropertyDescriptor(toIndexedObject(it), key);
2519 }
2520});
2521
2522var getOwnPropertyDescriptor_1 = createCommonjsModule(function (module) {
2523 var Object = path.Object;
2524
2525 var getOwnPropertyDescriptor = module.exports = function getOwnPropertyDescriptor(it, key) {
2526 return Object.getOwnPropertyDescriptor(it, key);
2527 };
2528
2529 if (Object.getOwnPropertyDescriptor.sham) getOwnPropertyDescriptor.sham = true;
2530});
2531
2532var getOwnPropertyDescriptor$3 = getOwnPropertyDescriptor_1;
2533
2534var getOwnPropertyDescriptor$2 = getOwnPropertyDescriptor$3;
2535
2536var ownKeys$9 = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
2537 var keys = objectGetOwnPropertyNames.f(anObject(it));
2538 var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
2539 return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
2540};
2541
2542// https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
2543
2544_export({
2545 target: 'Object',
2546 stat: true,
2547 sham: !descriptors
2548}, {
2549 getOwnPropertyDescriptors: function getOwnPropertyDescriptors(object) {
2550 var O = toIndexedObject(object);
2551 var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
2552 var keys = ownKeys$9(O);
2553 var result = {};
2554 var index = 0;
2555 var key, descriptor;
2556
2557 while (keys.length > index) {
2558 descriptor = getOwnPropertyDescriptor(O, key = keys[index++]);
2559 if (descriptor !== undefined) createProperty(result, key, descriptor);
2560 }
2561
2562 return result;
2563 }
2564});
2565
2566var getOwnPropertyDescriptors$2 = path.Object.getOwnPropertyDescriptors;
2567
2568var getOwnPropertyDescriptors$1 = getOwnPropertyDescriptors$2;
2569
2570var getOwnPropertyDescriptors = getOwnPropertyDescriptors$1;
2571
2572// https://tc39.es/ecma262/#sec-object.defineproperties
2573
2574_export({
2575 target: 'Object',
2576 stat: true,
2577 forced: !descriptors,
2578 sham: !descriptors
2579}, {
2580 defineProperties: objectDefineProperties
2581});
2582
2583var defineProperties_1 = createCommonjsModule(function (module) {
2584 var Object = path.Object;
2585
2586 var defineProperties = module.exports = function defineProperties(T, D) {
2587 return Object.defineProperties(T, D);
2588 };
2589
2590 if (Object.defineProperties.sham) defineProperties.sham = true;
2591});
2592
2593var defineProperties$1 = defineProperties_1;
2594
2595var defineProperties = defineProperties$1;
2596
2597// https://tc39.es/ecma262/#sec-object.defineproperty
2598
2599_export({
2600 target: 'Object',
2601 stat: true,
2602 forced: !descriptors,
2603 sham: !descriptors
2604}, {
2605 defineProperty: objectDefineProperty.f
2606});
2607
2608var defineProperty_1 = createCommonjsModule(function (module) {
2609 var Object = path.Object;
2610
2611 var defineProperty = module.exports = function defineProperty(it, key, desc) {
2612 return Object.defineProperty(it, key, desc);
2613 };
2614
2615 if (Object.defineProperty.sham) defineProperty.sham = true;
2616});
2617
2618var defineProperty$6 = defineProperty_1;
2619
2620var defineProperty$5 = defineProperty$6;
2621
2622var classCallCheck = createCommonjsModule(function (module) {
2623 function _classCallCheck(instance, Constructor) {
2624 if (!(instance instanceof Constructor)) {
2625 throw new TypeError("Cannot call a class as a function");
2626 }
2627 }
2628
2629 module.exports = _classCallCheck;
2630 module.exports["default"] = module.exports, module.exports.__esModule = true;
2631});
2632var _classCallCheck = unwrapExports(classCallCheck);
2633
2634var defineProperty$4 = defineProperty$6;
2635
2636var defineProperty$3 = defineProperty$4;
2637
2638var createClass = createCommonjsModule(function (module) {
2639 function _defineProperties(target, props) {
2640 for (var i = 0; i < props.length; i++) {
2641 var descriptor = props[i];
2642 descriptor.enumerable = descriptor.enumerable || false;
2643 descriptor.configurable = true;
2644 if ("value" in descriptor) descriptor.writable = true;
2645
2646 defineProperty$3(target, descriptor.key, descriptor);
2647 }
2648 }
2649
2650 function _createClass(Constructor, protoProps, staticProps) {
2651 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
2652 if (staticProps) _defineProperties(Constructor, staticProps);
2653 return Constructor;
2654 }
2655
2656 module.exports = _createClass;
2657 module.exports["default"] = module.exports, module.exports.__esModule = true;
2658});
2659var _createClass = unwrapExports(createClass);
2660
2661var defineProperty$2 = createCommonjsModule(function (module) {
2662 function _defineProperty(obj, key, value) {
2663 if (key in obj) {
2664 defineProperty$3(obj, key, {
2665 value: value,
2666 enumerable: true,
2667 configurable: true,
2668 writable: true
2669 });
2670 } else {
2671 obj[key] = value;
2672 }
2673
2674 return obj;
2675 }
2676
2677 module.exports = _defineProperty;
2678 module.exports["default"] = module.exports, module.exports.__esModule = true;
2679});
2680var _defineProperty = unwrapExports(defineProperty$2);
2681
2682// https://tc39.es/ecma262/#sec-array.isarray
2683
2684_export({
2685 target: 'Array',
2686 stat: true
2687}, {
2688 isArray: isArray$5
2689});
2690
2691var isArray$4 = path.Array.isArray;
2692
2693var isArray$3 = isArray$4;
2694
2695var isArray$2 = isArray$3;
2696
2697var isArray$1 = isArray$2;
2698
2699var arrayWithHoles = createCommonjsModule(function (module) {
2700 function _arrayWithHoles(arr) {
2701 if (isArray$1(arr)) return arr;
2702 }
2703
2704 module.exports = _arrayWithHoles;
2705 module.exports["default"] = module.exports, module.exports.__esModule = true;
2706});
2707unwrapExports(arrayWithHoles);
2708
2709var SPECIES$2 = wellKnownSymbol('species');
2710
2711var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
2712 // We can't use this feature detection in V8 since it causes
2713 // deoptimization and serious performance degradation
2714 // https://github.com/zloirock/core-js/issues/677
2715 return engineV8Version >= 51 || !fails(function () {
2716 var array = [];
2717 var constructor = array.constructor = {};
2718
2719 constructor[SPECIES$2] = function () {
2720 return {
2721 foo: 1
2722 };
2723 };
2724
2725 return array[METHOD_NAME](Boolean).foo !== 1;
2726 });
2727};
2728
2729var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
2730var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
2731var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded'; // We can't use this feature detection in V8 since it causes
2732// deoptimization and serious performance degradation
2733// https://github.com/zloirock/core-js/issues/679
2734
2735var IS_CONCAT_SPREADABLE_SUPPORT = engineV8Version >= 51 || !fails(function () {
2736 var array = [];
2737 array[IS_CONCAT_SPREADABLE] = false;
2738 return array.concat()[0] !== array;
2739});
2740var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');
2741
2742var isConcatSpreadable = function (O) {
2743 if (!isObject$1(O)) return false;
2744 var spreadable = O[IS_CONCAT_SPREADABLE];
2745 return spreadable !== undefined ? !!spreadable : isArray$5(O);
2746};
2747
2748var FORCED$5 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT; // `Array.prototype.concat` method
2749// https://tc39.es/ecma262/#sec-array.prototype.concat
2750// with adding support of @@isConcatSpreadable and @@species
2751
2752_export({
2753 target: 'Array',
2754 proto: true,
2755 forced: FORCED$5
2756}, {
2757 // eslint-disable-next-line no-unused-vars -- required for `.length`
2758 concat: function concat(arg) {
2759 var O = toObject(this);
2760 var A = arraySpeciesCreate(O, 0);
2761 var n = 0;
2762 var i, k, length, len, E;
2763
2764 for (i = -1, length = arguments.length; i < length; i++) {
2765 E = i === -1 ? O : arguments[i];
2766
2767 if (isConcatSpreadable(E)) {
2768 len = toLength(E.length);
2769 if (n + len > MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
2770
2771 for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
2772 } else {
2773 if (n >= MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
2774 createProperty(A, n++, E);
2775 }
2776 }
2777
2778 A.length = n;
2779 return A;
2780 }
2781});
2782
2783// https://tc39.es/ecma262/#sec-symbol.asynciterator
2784
2785defineWellKnownSymbol('asyncIterator');
2786
2787// https://tc39.es/ecma262/#sec-symbol.hasinstance
2788
2789defineWellKnownSymbol('hasInstance');
2790
2791// https://tc39.es/ecma262/#sec-symbol.isconcatspreadable
2792
2793defineWellKnownSymbol('isConcatSpreadable');
2794
2795// https://tc39.es/ecma262/#sec-symbol.iterator
2796
2797defineWellKnownSymbol('iterator');
2798
2799// https://tc39.es/ecma262/#sec-symbol.match
2800
2801defineWellKnownSymbol('match');
2802
2803// https://tc39.es/ecma262/#sec-symbol.matchall
2804
2805defineWellKnownSymbol('matchAll');
2806
2807// https://tc39.es/ecma262/#sec-symbol.replace
2808
2809defineWellKnownSymbol('replace');
2810
2811// https://tc39.es/ecma262/#sec-symbol.search
2812
2813defineWellKnownSymbol('search');
2814
2815// https://tc39.es/ecma262/#sec-symbol.species
2816
2817defineWellKnownSymbol('species');
2818
2819// https://tc39.es/ecma262/#sec-symbol.split
2820
2821defineWellKnownSymbol('split');
2822
2823// https://tc39.es/ecma262/#sec-symbol.toprimitive
2824
2825defineWellKnownSymbol('toPrimitive');
2826
2827// https://tc39.es/ecma262/#sec-symbol.tostringtag
2828
2829defineWellKnownSymbol('toStringTag');
2830
2831// https://tc39.es/ecma262/#sec-symbol.unscopables
2832
2833defineWellKnownSymbol('unscopables');
2834
2835// https://tc39.es/ecma262/#sec-json-@@tostringtag
2836
2837setToStringTag(global_1.JSON, 'JSON', true);
2838
2839var symbol$4 = path.Symbol;
2840
2841var symbol$3 = symbol$4;
2842
2843// https://github.com/tc39/proposal-using-statement
2844
2845defineWellKnownSymbol('asyncDispose');
2846
2847// https://github.com/tc39/proposal-using-statement
2848
2849defineWellKnownSymbol('dispose');
2850
2851// https://github.com/tc39/proposal-pattern-matching
2852
2853defineWellKnownSymbol('matcher');
2854
2855// https://github.com/tc39/proposal-decorators
2856
2857defineWellKnownSymbol('metadata');
2858
2859// https://github.com/tc39/proposal-observable
2860
2861defineWellKnownSymbol('observable');
2862
2863// `Symbol.patternMatch` well-known symbol
2864// https://github.com/tc39/proposal-pattern-matching
2865
2866defineWellKnownSymbol('patternMatch');
2867
2868defineWellKnownSymbol('replaceAll');
2869
2870// TODO: Remove from `core-js@4`
2871
2872var symbol$2 = symbol$3;
2873
2874var symbol$1 = symbol$2;
2875
2876var iterableToArrayLimit = createCommonjsModule(function (module) {
2877 function _iterableToArrayLimit(arr, i) {
2878 var _i = arr == null ? null : typeof symbol$1 !== "undefined" && getIteratorMethod(arr) || arr["@@iterator"];
2879
2880 if (_i == null) return;
2881 var _arr = [];
2882 var _n = true;
2883 var _d = false;
2884
2885 var _s, _e;
2886
2887 try {
2888 for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
2889 _arr.push(_s.value);
2890
2891 if (i && _arr.length === i) break;
2892 }
2893 } catch (err) {
2894 _d = true;
2895 _e = err;
2896 } finally {
2897 try {
2898 if (!_n && _i["return"] != null) _i["return"]();
2899 } finally {
2900 if (_d) throw _e;
2901 }
2902 }
2903
2904 return _arr;
2905 }
2906
2907 module.exports = _iterableToArrayLimit;
2908 module.exports["default"] = module.exports, module.exports.__esModule = true;
2909});
2910unwrapExports(iterableToArrayLimit);
2911
2912var HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport('slice');
2913var SPECIES$1 = wellKnownSymbol('species');
2914var nativeSlice = [].slice;
2915var max$1 = Math.max; // `Array.prototype.slice` method
2916// https://tc39.es/ecma262/#sec-array.prototype.slice
2917// fallback for not array-like ES3 strings and DOM objects
2918
2919_export({
2920 target: 'Array',
2921 proto: true,
2922 forced: !HAS_SPECIES_SUPPORT$3
2923}, {
2924 slice: function slice(start, end) {
2925 var O = toIndexedObject(this);
2926 var length = toLength(O.length);
2927 var k = toAbsoluteIndex(start, length);
2928 var fin = toAbsoluteIndex(end === undefined ? length : end, length); // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
2929
2930 var Constructor, result, n;
2931
2932 if (isArray$5(O)) {
2933 Constructor = O.constructor; // cross-realm fallback
2934
2935 if (typeof Constructor == 'function' && (Constructor === Array || isArray$5(Constructor.prototype))) {
2936 Constructor = undefined;
2937 } else if (isObject$1(Constructor)) {
2938 Constructor = Constructor[SPECIES$1];
2939 if (Constructor === null) Constructor = undefined;
2940 }
2941
2942 if (Constructor === Array || Constructor === undefined) {
2943 return nativeSlice.call(O, k, fin);
2944 }
2945 }
2946
2947 result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0));
2948
2949 for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);
2950
2951 result.length = n;
2952 return result;
2953 }
2954});
2955
2956var slice$5 = entryVirtual('Array').slice;
2957
2958var ArrayPrototype$h = Array.prototype;
2959
2960var slice_1 = function (it) {
2961 var own = it.slice;
2962 return it === ArrayPrototype$h || it instanceof Array && own === ArrayPrototype$h.slice ? slice$5 : own;
2963};
2964
2965var slice$4 = slice_1;
2966
2967var slice$3 = slice$4;
2968
2969var slice$2 = slice$3;
2970
2971var from_1$1 = from_1$3;
2972
2973var from_1 = from_1$1;
2974
2975var arrayLikeToArray = createCommonjsModule(function (module) {
2976 function _arrayLikeToArray(arr, len) {
2977 if (len == null || len > arr.length) len = arr.length;
2978
2979 for (var i = 0, arr2 = new Array(len); i < len; i++) {
2980 arr2[i] = arr[i];
2981 }
2982
2983 return arr2;
2984 }
2985
2986 module.exports = _arrayLikeToArray;
2987 module.exports["default"] = module.exports, module.exports.__esModule = true;
2988});
2989unwrapExports(arrayLikeToArray);
2990
2991var unsupportedIterableToArray = createCommonjsModule(function (module) {
2992 function _unsupportedIterableToArray(o, minLen) {
2993 var _context;
2994
2995 if (!o) return;
2996 if (typeof o === "string") return arrayLikeToArray(o, minLen);
2997
2998 var n = slice$2(_context = Object.prototype.toString.call(o)).call(_context, 8, -1);
2999
3000 if (n === "Object" && o.constructor) n = o.constructor.name;
3001 if (n === "Map" || n === "Set") return from_1(o);
3002 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen);
3003 }
3004
3005 module.exports = _unsupportedIterableToArray;
3006 module.exports["default"] = module.exports, module.exports.__esModule = true;
3007});
3008unwrapExports(unsupportedIterableToArray);
3009
3010var nonIterableRest = createCommonjsModule(function (module) {
3011 function _nonIterableRest() {
3012 throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
3013 }
3014
3015 module.exports = _nonIterableRest;
3016 module.exports["default"] = module.exports, module.exports.__esModule = true;
3017});
3018unwrapExports(nonIterableRest);
3019
3020var slicedToArray = createCommonjsModule(function (module) {
3021 function _slicedToArray(arr, i) {
3022 return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || unsupportedIterableToArray(arr, i) || nonIterableRest();
3023 }
3024
3025 module.exports = _slicedToArray;
3026 module.exports["default"] = module.exports, module.exports.__esModule = true;
3027});
3028var _slicedToArray = unwrapExports(slicedToArray);
3029
3030var iterator$4 = wellKnownSymbolWrapped.f('iterator');
3031
3032var iterator$3 = iterator$4;
3033
3034var iterator$2 = iterator$3;
3035
3036var iterator$1 = iterator$2;
3037
3038var _typeof_1 = createCommonjsModule(function (module) {
3039 function _typeof(obj) {
3040 "@babel/helpers - typeof";
3041
3042 if (typeof symbol$1 === "function" && typeof iterator$1 === "symbol") {
3043 module.exports = _typeof = function _typeof(obj) {
3044 return typeof obj;
3045 };
3046
3047 module.exports["default"] = module.exports, module.exports.__esModule = true;
3048 } else {
3049 module.exports = _typeof = function _typeof(obj) {
3050 return obj && typeof symbol$1 === "function" && obj.constructor === symbol$1 && obj !== symbol$1.prototype ? "symbol" : typeof obj;
3051 };
3052
3053 module.exports["default"] = module.exports, module.exports.__esModule = true;
3054 }
3055
3056 return _typeof(obj);
3057 }
3058
3059 module.exports = _typeof;
3060 module.exports["default"] = module.exports, module.exports.__esModule = true;
3061});
3062
3063var _typeof = unwrapExports(_typeof_1);
3064
3065var arrayWithoutHoles = createCommonjsModule(function (module) {
3066 function _arrayWithoutHoles(arr) {
3067 if (isArray$1(arr)) return arrayLikeToArray(arr);
3068 }
3069
3070 module.exports = _arrayWithoutHoles;
3071 module.exports["default"] = module.exports, module.exports.__esModule = true;
3072});
3073unwrapExports(arrayWithoutHoles);
3074
3075var iterableToArray = createCommonjsModule(function (module) {
3076 function _iterableToArray(iter) {
3077 if (typeof symbol$1 !== "undefined" && getIteratorMethod(iter) != null || iter["@@iterator"] != null) return from_1(iter);
3078 }
3079
3080 module.exports = _iterableToArray;
3081 module.exports["default"] = module.exports, module.exports.__esModule = true;
3082});
3083unwrapExports(iterableToArray);
3084
3085var nonIterableSpread = createCommonjsModule(function (module) {
3086 function _nonIterableSpread() {
3087 throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
3088 }
3089
3090 module.exports = _nonIterableSpread;
3091 module.exports["default"] = module.exports, module.exports.__esModule = true;
3092});
3093unwrapExports(nonIterableSpread);
3094
3095var toConsumableArray = createCommonjsModule(function (module) {
3096 function _toConsumableArray(arr) {
3097 return arrayWithoutHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableSpread();
3098 }
3099
3100 module.exports = _toConsumableArray;
3101 module.exports["default"] = module.exports, module.exports.__esModule = true;
3102});
3103var _toConsumableArray = unwrapExports(toConsumableArray);
3104
3105var symbol = symbol$3;
3106
3107var concat$2 = entryVirtual('Array').concat;
3108
3109var ArrayPrototype$g = Array.prototype;
3110
3111var concat_1 = function (it) {
3112 var own = it.concat;
3113 return it === ArrayPrototype$g || it instanceof Array && own === ArrayPrototype$g.concat ? concat$2 : own;
3114};
3115
3116var concat$1 = concat_1;
3117
3118var concat = concat$1;
3119
3120var slice$1 = slice$4;
3121
3122// https://tc39.es/ecma262/#sec-reflect.ownkeys
3123
3124_export({
3125 target: 'Reflect',
3126 stat: true
3127}, {
3128 ownKeys: ownKeys$9
3129});
3130
3131var ownKeys$8 = path.Reflect.ownKeys;
3132
3133var ownKeys$7 = ownKeys$8;
3134
3135var ownKeys$6 = ownKeys$7;
3136
3137var isArray = isArray$3;
3138
3139var $map = arrayIteration.map;
3140var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport('map'); // `Array.prototype.map` method
3141// https://tc39.es/ecma262/#sec-array.prototype.map
3142// with adding support of @@species
3143
3144_export({
3145 target: 'Array',
3146 proto: true,
3147 forced: !HAS_SPECIES_SUPPORT$2
3148}, {
3149 map: function map(callbackfn
3150 /* , thisArg */
3151 ) {
3152 return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3153 }
3154});
3155
3156var map$5 = entryVirtual('Array').map;
3157
3158var ArrayPrototype$f = Array.prototype;
3159
3160var map_1 = function (it) {
3161 var own = it.map;
3162 return it === ArrayPrototype$f || it instanceof Array && own === ArrayPrototype$f.map ? map$5 : own;
3163};
3164
3165var map$4 = map_1;
3166
3167var map$3 = map$4;
3168
3169var FAILS_ON_PRIMITIVES$2 = fails(function () {
3170 objectKeys(1);
3171}); // `Object.keys` method
3172// https://tc39.es/ecma262/#sec-object.keys
3173
3174_export({
3175 target: 'Object',
3176 stat: true,
3177 forced: FAILS_ON_PRIMITIVES$2
3178}, {
3179 keys: function keys(it) {
3180 return objectKeys(toObject(it));
3181 }
3182});
3183
3184var keys$5 = path.Object.keys;
3185
3186var keys$4 = keys$5;
3187
3188var keys$3 = keys$4;
3189
3190// https://tc39.es/ecma262/#sec-date.now
3191
3192_export({
3193 target: 'Date',
3194 stat: true
3195}, {
3196 now: function now() {
3197 return new Date().getTime();
3198 }
3199});
3200
3201var now$3 = path.Date.now;
3202
3203var now$2 = now$3;
3204
3205var now$1 = now$2;
3206
3207var arrayMethodIsStrict = function (METHOD_NAME, argument) {
3208 var method = [][METHOD_NAME];
3209 return !!method && fails(function () {
3210 // eslint-disable-next-line no-useless-call,no-throw-literal -- required for testing
3211 method.call(null, argument || function () {
3212 throw 1;
3213 }, 1);
3214 });
3215};
3216
3217var $forEach = arrayIteration.forEach;
3218var STRICT_METHOD$5 = arrayMethodIsStrict('forEach'); // `Array.prototype.forEach` method implementation
3219// https://tc39.es/ecma262/#sec-array.prototype.foreach
3220
3221var arrayForEach = !STRICT_METHOD$5 ? function forEach(callbackfn
3222/* , thisArg */
3223) {
3224 return $forEach(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); // eslint-disable-next-line es/no-array-prototype-foreach -- safe
3225} : [].forEach;
3226
3227// https://tc39.es/ecma262/#sec-array.prototype.foreach
3228// eslint-disable-next-line es/no-array-prototype-foreach -- safe
3229
3230
3231_export({
3232 target: 'Array',
3233 proto: true,
3234 forced: [].forEach != arrayForEach
3235}, {
3236 forEach: arrayForEach
3237});
3238
3239var forEach$4 = entryVirtual('Array').forEach;
3240
3241var forEach$3 = forEach$4;
3242
3243var ArrayPrototype$e = Array.prototype;
3244var DOMIterables$3 = {
3245 DOMTokenList: true,
3246 NodeList: true
3247};
3248
3249var forEach_1 = function (it) {
3250 var own = it.forEach;
3251 return it === ArrayPrototype$e || it instanceof Array && own === ArrayPrototype$e.forEach // eslint-disable-next-line no-prototype-builtins -- safe
3252 || DOMIterables$3.hasOwnProperty(classof(it)) ? forEach$3 : own;
3253};
3254
3255var forEach$2 = forEach_1;
3256
3257var nativeReverse = [].reverse;
3258var test$1 = [1, 2]; // `Array.prototype.reverse` method
3259// https://tc39.es/ecma262/#sec-array.prototype.reverse
3260// fix for Safari 12.0 bug
3261// https://bugs.webkit.org/show_bug.cgi?id=188794
3262
3263_export({
3264 target: 'Array',
3265 proto: true,
3266 forced: String(test$1) === String(test$1.reverse())
3267}, {
3268 reverse: function reverse() {
3269 // eslint-disable-next-line no-self-assign -- dirty hack
3270 if (isArray$5(this)) this.length = this.length;
3271 return nativeReverse.call(this);
3272 }
3273});
3274
3275var reverse$2 = entryVirtual('Array').reverse;
3276
3277var ArrayPrototype$d = Array.prototype;
3278
3279var reverse_1 = function (it) {
3280 var own = it.reverse;
3281 return it === ArrayPrototype$d || it instanceof Array && own === ArrayPrototype$d.reverse ? reverse$2 : own;
3282};
3283
3284var reverse$1 = reverse_1;
3285
3286var reverse = reverse$1;
3287
3288var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('splice');
3289var max = Math.max;
3290var min = Math.min;
3291var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
3292var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded'; // `Array.prototype.splice` method
3293// https://tc39.es/ecma262/#sec-array.prototype.splice
3294// with adding support of @@species
3295
3296_export({
3297 target: 'Array',
3298 proto: true,
3299 forced: !HAS_SPECIES_SUPPORT$1
3300}, {
3301 splice: function splice(start, deleteCount
3302 /* , ...items */
3303 ) {
3304 var O = toObject(this);
3305 var len = toLength(O.length);
3306 var actualStart = toAbsoluteIndex(start, len);
3307 var argumentsLength = arguments.length;
3308 var insertCount, actualDeleteCount, A, k, from, to;
3309
3310 if (argumentsLength === 0) {
3311 insertCount = actualDeleteCount = 0;
3312 } else if (argumentsLength === 1) {
3313 insertCount = 0;
3314 actualDeleteCount = len - actualStart;
3315 } else {
3316 insertCount = argumentsLength - 2;
3317 actualDeleteCount = min(max(toInteger(deleteCount), 0), len - actualStart);
3318 }
3319
3320 if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER) {
3321 throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
3322 }
3323
3324 A = arraySpeciesCreate(O, actualDeleteCount);
3325
3326 for (k = 0; k < actualDeleteCount; k++) {
3327 from = actualStart + k;
3328 if (from in O) createProperty(A, k, O[from]);
3329 }
3330
3331 A.length = actualDeleteCount;
3332
3333 if (insertCount < actualDeleteCount) {
3334 for (k = actualStart; k < len - actualDeleteCount; k++) {
3335 from = k + actualDeleteCount;
3336 to = k + insertCount;
3337 if (from in O) O[to] = O[from];else delete O[to];
3338 }
3339
3340 for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
3341 } else if (insertCount > actualDeleteCount) {
3342 for (k = len - actualDeleteCount; k > actualStart; k--) {
3343 from = k + actualDeleteCount - 1;
3344 to = k + insertCount - 1;
3345 if (from in O) O[to] = O[from];else delete O[to];
3346 }
3347 }
3348
3349 for (k = 0; k < insertCount; k++) {
3350 O[k + actualStart] = arguments[k + 2];
3351 }
3352
3353 O.length = len - actualDeleteCount + insertCount;
3354 return A;
3355 }
3356});
3357
3358var splice$2 = entryVirtual('Array').splice;
3359
3360var ArrayPrototype$c = Array.prototype;
3361
3362var splice_1 = function (it) {
3363 var own = it.splice;
3364 return it === ArrayPrototype$c || it instanceof Array && own === ArrayPrototype$c.splice ? splice$2 : own;
3365};
3366
3367var splice$1 = splice_1;
3368
3369var splice = splice$1;
3370
3371var $includes = arrayIncludes.includes; // `Array.prototype.includes` method
3372// https://tc39.es/ecma262/#sec-array.prototype.includes
3373
3374_export({
3375 target: 'Array',
3376 proto: true
3377}, {
3378 includes: function includes(el
3379 /* , fromIndex = 0 */
3380 ) {
3381 return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
3382 }
3383}); // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
3384
3385var includes$4 = entryVirtual('Array').includes;
3386
3387var MATCH$1 = wellKnownSymbol('match'); // `IsRegExp` abstract operation
3388// https://tc39.es/ecma262/#sec-isregexp
3389
3390var isRegexp = function (it) {
3391 var isRegExp;
3392 return isObject$1(it) && ((isRegExp = it[MATCH$1]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
3393};
3394
3395var notARegexp = function (it) {
3396 if (isRegexp(it)) {
3397 throw TypeError("The method doesn't accept regular expressions");
3398 }
3399
3400 return it;
3401};
3402
3403var MATCH = wellKnownSymbol('match');
3404
3405var correctIsRegexpLogic = function (METHOD_NAME) {
3406 var regexp = /./;
3407
3408 try {
3409 '/./'[METHOD_NAME](regexp);
3410 } catch (error1) {
3411 try {
3412 regexp[MATCH] = false;
3413 return '/./'[METHOD_NAME](regexp);
3414 } catch (error2) {
3415 /* empty */
3416 }
3417 }
3418
3419 return false;
3420};
3421
3422// https://tc39.es/ecma262/#sec-string.prototype.includes
3423
3424
3425_export({
3426 target: 'String',
3427 proto: true,
3428 forced: !correctIsRegexpLogic('includes')
3429}, {
3430 includes: function includes(searchString
3431 /* , position = 0 */
3432 ) {
3433 return !!~toString_1(requireObjectCoercible(this)).indexOf(toString_1(notARegexp(searchString)), arguments.length > 1 ? arguments[1] : undefined);
3434 }
3435});
3436
3437var includes$3 = entryVirtual('String').includes;
3438
3439var ArrayPrototype$b = Array.prototype;
3440var StringPrototype$1 = String.prototype;
3441
3442var includes$2 = function (it) {
3443 var own = it.includes;
3444 if (it === ArrayPrototype$b || it instanceof Array && own === ArrayPrototype$b.includes) return includes$4;
3445
3446 if (typeof it === 'string' || it === StringPrototype$1 || it instanceof String && own === StringPrototype$1.includes) {
3447 return includes$3;
3448 }
3449
3450 return own;
3451};
3452
3453var includes$1 = includes$2;
3454
3455var includes = includes$1;
3456
3457var FAILS_ON_PRIMITIVES$1 = fails(function () {
3458 objectGetPrototypeOf(1);
3459}); // `Object.getPrototypeOf` method
3460// https://tc39.es/ecma262/#sec-object.getprototypeof
3461
3462_export({
3463 target: 'Object',
3464 stat: true,
3465 forced: FAILS_ON_PRIMITIVES$1,
3466 sham: !correctPrototypeGetter
3467}, {
3468 getPrototypeOf: function getPrototypeOf(it) {
3469 return objectGetPrototypeOf(toObject(it));
3470 }
3471});
3472
3473var getPrototypeOf$5 = path.Object.getPrototypeOf;
3474
3475var getPrototypeOf$4 = getPrototypeOf$5;
3476
3477var getPrototypeOf$3 = getPrototypeOf$4;
3478
3479var $filter = arrayIteration.filter;
3480var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('filter'); // `Array.prototype.filter` method
3481// https://tc39.es/ecma262/#sec-array.prototype.filter
3482// with adding support of @@species
3483
3484_export({
3485 target: 'Array',
3486 proto: true,
3487 forced: !HAS_SPECIES_SUPPORT
3488}, {
3489 filter: function filter(callbackfn
3490 /* , thisArg */
3491 ) {
3492 return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3493 }
3494});
3495
3496var filter$2 = entryVirtual('Array').filter;
3497
3498var ArrayPrototype$a = Array.prototype;
3499
3500var filter_1 = function (it) {
3501 var own = it.filter;
3502 return it === ArrayPrototype$a || it instanceof Array && own === ArrayPrototype$a.filter ? filter$2 : own;
3503};
3504
3505var filter$1 = filter_1;
3506
3507var filter = filter$1;
3508
3509var propertyIsEnumerable = objectPropertyIsEnumerable.f; // `Object.{ entries, values }` methods implementation
3510
3511var createMethod$2 = function (TO_ENTRIES) {
3512 return function (it) {
3513 var O = toIndexedObject(it);
3514 var keys = objectKeys(O);
3515 var length = keys.length;
3516 var i = 0;
3517 var result = [];
3518 var key;
3519
3520 while (length > i) {
3521 key = keys[i++];
3522
3523 if (!descriptors || propertyIsEnumerable.call(O, key)) {
3524 result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
3525 }
3526 }
3527
3528 return result;
3529 };
3530};
3531
3532var objectToArray = {
3533 // `Object.entries` method
3534 // https://tc39.es/ecma262/#sec-object.entries
3535 entries: createMethod$2(true),
3536 // `Object.values` method
3537 // https://tc39.es/ecma262/#sec-object.values
3538 values: createMethod$2(false)
3539};
3540
3541var $values = objectToArray.values; // `Object.values` method
3542// https://tc39.es/ecma262/#sec-object.values
3543
3544_export({
3545 target: 'Object',
3546 stat: true
3547}, {
3548 values: function values(O) {
3549 return $values(O);
3550 }
3551});
3552
3553var values$5 = path.Object.values;
3554
3555var values$4 = values$5;
3556
3557var values$3 = values$4;
3558
3559// a string of all valid unicode whitespaces
3560var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002' + '\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
3561
3562var whitespace = '[' + whitespaces + ']';
3563var ltrim = RegExp('^' + whitespace + whitespace + '*');
3564var rtrim = RegExp(whitespace + whitespace + '*$'); // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
3565
3566var createMethod$1 = function (TYPE) {
3567 return function ($this) {
3568 var string = toString_1(requireObjectCoercible($this));
3569 if (TYPE & 1) string = string.replace(ltrim, '');
3570 if (TYPE & 2) string = string.replace(rtrim, '');
3571 return string;
3572 };
3573};
3574
3575var stringTrim = {
3576 // `String.prototype.{ trimLeft, trimStart }` methods
3577 // https://tc39.es/ecma262/#sec-string.prototype.trimstart
3578 start: createMethod$1(1),
3579 // `String.prototype.{ trimRight, trimEnd }` methods
3580 // https://tc39.es/ecma262/#sec-string.prototype.trimend
3581 end: createMethod$1(2),
3582 // `String.prototype.trim` method
3583 // https://tc39.es/ecma262/#sec-string.prototype.trim
3584 trim: createMethod$1(3)
3585};
3586
3587var trim$4 = stringTrim.trim;
3588var $parseInt = global_1.parseInt;
3589var hex = /^[+-]?0[Xx]/;
3590var FORCED$4 = $parseInt(whitespaces + '08') !== 8 || $parseInt(whitespaces + '0x16') !== 22; // `parseInt` method
3591// https://tc39.es/ecma262/#sec-parseint-string-radix
3592
3593var numberParseInt = FORCED$4 ? function parseInt(string, radix) {
3594 var S = trim$4(toString_1(string));
3595 return $parseInt(S, radix >>> 0 || (hex.test(S) ? 16 : 10));
3596} : $parseInt;
3597
3598// https://tc39.es/ecma262/#sec-parseint-string-radix
3599
3600_export({
3601 global: true,
3602 forced: parseInt != numberParseInt
3603}, {
3604 parseInt: numberParseInt
3605});
3606
3607var _parseInt$2 = path.parseInt;
3608
3609var _parseInt$1 = _parseInt$2;
3610
3611var _parseInt = _parseInt$1;
3612
3613/* eslint-disable es/no-array-prototype-indexof -- required for testing */
3614
3615
3616var $indexOf = arrayIncludes.indexOf;
3617var nativeIndexOf = [].indexOf;
3618var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
3619var STRICT_METHOD$4 = arrayMethodIsStrict('indexOf'); // `Array.prototype.indexOf` method
3620// https://tc39.es/ecma262/#sec-array.prototype.indexof
3621
3622_export({
3623 target: 'Array',
3624 proto: true,
3625 forced: NEGATIVE_ZERO || !STRICT_METHOD$4
3626}, {
3627 indexOf: function indexOf(searchElement
3628 /* , fromIndex = 0 */
3629 ) {
3630 return NEGATIVE_ZERO // convert -0 to +0
3631 ? nativeIndexOf.apply(this, arguments) || 0 : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
3632 }
3633});
3634
3635var indexOf$2 = entryVirtual('Array').indexOf;
3636
3637var ArrayPrototype$9 = Array.prototype;
3638
3639var indexOf_1 = function (it) {
3640 var own = it.indexOf;
3641 return it === ArrayPrototype$9 || it instanceof Array && own === ArrayPrototype$9.indexOf ? indexOf$2 : own;
3642};
3643
3644var indexOf$1 = indexOf_1;
3645
3646var indexOf = indexOf$1;
3647
3648var non = '\u200B\u0085\u180E'; // check that a method works with the correct list
3649// of whitespaces and has a correct name
3650
3651var stringTrimForced = function (METHOD_NAME) {
3652 return fails(function () {
3653 return !!whitespaces[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces[METHOD_NAME].name !== METHOD_NAME;
3654 });
3655};
3656
3657var $trim = stringTrim.trim; // `String.prototype.trim` method
3658// https://tc39.es/ecma262/#sec-string.prototype.trim
3659
3660_export({
3661 target: 'String',
3662 proto: true,
3663 forced: stringTrimForced('trim')
3664}, {
3665 trim: function trim() {
3666 return $trim(this);
3667 }
3668});
3669
3670var trim$3 = entryVirtual('String').trim;
3671
3672var StringPrototype = String.prototype;
3673
3674var trim_1 = function (it) {
3675 var own = it.trim;
3676 return typeof it === 'string' || it === StringPrototype || it instanceof String && own === StringPrototype.trim ? trim$3 : own;
3677};
3678
3679var trim$2 = trim_1;
3680
3681var trim$1 = trim$2;
3682
3683// https://tc39.es/ecma262/#sec-object.create
3684
3685_export({
3686 target: 'Object',
3687 stat: true,
3688 sham: !descriptors
3689}, {
3690 create: objectCreate
3691});
3692
3693var Object$2 = path.Object;
3694
3695var create$4 = function create(P, D) {
3696 return Object$2.create(P, D);
3697};
3698
3699var create$3 = create$4;
3700
3701var create$2 = create$3;
3702
3703var $stringify = getBuiltIn('JSON', 'stringify');
3704var re = /[\uD800-\uDFFF]/g;
3705var low = /^[\uD800-\uDBFF]$/;
3706var hi = /^[\uDC00-\uDFFF]$/;
3707
3708var fix = function (match, offset, string) {
3709 var prev = string.charAt(offset - 1);
3710 var next = string.charAt(offset + 1);
3711
3712 if (low.test(match) && !hi.test(next) || hi.test(match) && !low.test(prev)) {
3713 return '\\u' + match.charCodeAt(0).toString(16);
3714 }
3715
3716 return match;
3717};
3718
3719var FORCED$3 = fails(function () {
3720 return $stringify('\uDF06\uD834') !== '"\\udf06\\ud834"' || $stringify('\uDEAD') !== '"\\udead"';
3721});
3722
3723if ($stringify) {
3724 // `JSON.stringify` method
3725 // https://tc39.es/ecma262/#sec-json.stringify
3726 // https://github.com/tc39/proposal-well-formed-stringify
3727 _export({
3728 target: 'JSON',
3729 stat: true,
3730 forced: FORCED$3
3731 }, {
3732 // eslint-disable-next-line no-unused-vars -- required for `.length`
3733 stringify: function stringify(it, replacer, space) {
3734 var result = $stringify.apply(null, arguments);
3735 return typeof result == 'string' ? result.replace(re, fix) : result;
3736 }
3737 });
3738}
3739
3740if (!path.JSON) path.JSON = {
3741 stringify: JSON.stringify
3742}; // eslint-disable-next-line no-unused-vars -- required for `.length`
3743
3744var stringify$3 = function stringify(it, replacer, space) {
3745 return path.JSON.stringify.apply(null, arguments);
3746};
3747
3748var stringify$2 = stringify$3;
3749
3750var stringify$1 = stringify$2;
3751
3752var slice = [].slice;
3753var MSIE = /MSIE .\./.test(engineUserAgent); // <- dirty ie9- check
3754
3755var wrap = function (scheduler) {
3756 return function (handler, timeout
3757 /* , ...arguments */
3758 ) {
3759 var boundArgs = arguments.length > 2;
3760 var args = boundArgs ? slice.call(arguments, 2) : undefined;
3761 return scheduler(boundArgs ? function () {
3762 // eslint-disable-next-line no-new-func -- spec requirement
3763 (typeof handler == 'function' ? handler : Function(handler)).apply(this, args);
3764 } : handler, timeout);
3765 };
3766}; // ie9- setTimeout & setInterval additional parameters fix
3767// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
3768
3769
3770_export({
3771 global: true,
3772 bind: true,
3773 forced: MSIE
3774}, {
3775 // `setTimeout` method
3776 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout
3777 setTimeout: wrap(global_1.setTimeout),
3778 // `setInterval` method
3779 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
3780 setInterval: wrap(global_1.setInterval)
3781});
3782
3783var setTimeout$2 = path.setTimeout;
3784
3785var setTimeout$1 = setTimeout$2;
3786
3787// https://tc39.es/ecma262/#sec-array.prototype.fill
3788
3789
3790var arrayFill = function fill(value
3791/* , start = 0, end = @length */
3792) {
3793 var O = toObject(this);
3794 var length = toLength(O.length);
3795 var argumentsLength = arguments.length;
3796 var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);
3797 var end = argumentsLength > 2 ? arguments[2] : undefined;
3798 var endPos = end === undefined ? length : toAbsoluteIndex(end, length);
3799
3800 while (endPos > index) O[index++] = value;
3801
3802 return O;
3803};
3804
3805// https://tc39.es/ecma262/#sec-array.prototype.fill
3806
3807_export({
3808 target: 'Array',
3809 proto: true
3810}, {
3811 fill: arrayFill
3812}); // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
3813
3814var fill$2 = entryVirtual('Array').fill;
3815
3816var ArrayPrototype$8 = Array.prototype;
3817
3818var fill_1 = function (it) {
3819 var own = it.fill;
3820 return it === ArrayPrototype$8 || it instanceof Array && own === ArrayPrototype$8.fill ? fill$2 : own;
3821};
3822
3823var fill$1 = fill_1;
3824
3825var fill = fill$1;
3826
3827/*! Hammer.JS - v2.0.17-rc - 2019-12-16
3828 * http://naver.github.io/egjs
3829 *
3830 * Forked By Naver egjs
3831 * Copyright (c) hammerjs
3832 * Licensed under the MIT license */
3833function _extends() {
3834 _extends = Object.assign || function (target) {
3835 for (var i = 1; i < arguments.length; i++) {
3836 var source = arguments[i];
3837
3838 for (var key in source) {
3839 if (Object.prototype.hasOwnProperty.call(source, key)) {
3840 target[key] = source[key];
3841 }
3842 }
3843 }
3844
3845 return target;
3846 };
3847
3848 return _extends.apply(this, arguments);
3849}
3850
3851function _inheritsLoose(subClass, superClass) {
3852 subClass.prototype = Object.create(superClass.prototype);
3853 subClass.prototype.constructor = subClass;
3854 subClass.__proto__ = superClass;
3855}
3856
3857function _assertThisInitialized$1(self) {
3858 if (self === void 0) {
3859 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
3860 }
3861
3862 return self;
3863}
3864/**
3865 * @private
3866 * extend object.
3867 * means that properties in dest will be overwritten by the ones in src.
3868 * @param {Object} target
3869 * @param {...Object} objects_to_assign
3870 * @returns {Object} target
3871 */
3872
3873
3874var assign;
3875
3876if (typeof Object.assign !== 'function') {
3877 assign = function assign(target) {
3878 if (target === undefined || target === null) {
3879 throw new TypeError('Cannot convert undefined or null to object');
3880 }
3881
3882 var output = Object(target);
3883
3884 for (var index = 1; index < arguments.length; index++) {
3885 var source = arguments[index];
3886
3887 if (source !== undefined && source !== null) {
3888 for (var nextKey in source) {
3889 if (source.hasOwnProperty(nextKey)) {
3890 output[nextKey] = source[nextKey];
3891 }
3892 }
3893 }
3894 }
3895
3896 return output;
3897 };
3898} else {
3899 assign = Object.assign;
3900}
3901
3902var assign$1 = assign;
3903var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
3904var TEST_ELEMENT = typeof document === "undefined" ? {
3905 style: {}
3906} : document.createElement('div');
3907var TYPE_FUNCTION = 'function';
3908var round = Math.round,
3909 abs$1 = Math.abs;
3910var now = Date.now;
3911/**
3912 * @private
3913 * get the prefixed property
3914 * @param {Object} obj
3915 * @param {String} property
3916 * @returns {String|Undefined} prefixed
3917 */
3918
3919function prefixed(obj, property) {
3920 var prefix;
3921 var prop;
3922 var camelProp = property[0].toUpperCase() + property.slice(1);
3923 var i = 0;
3924
3925 while (i < VENDOR_PREFIXES.length) {
3926 prefix = VENDOR_PREFIXES[i];
3927 prop = prefix ? prefix + camelProp : property;
3928
3929 if (prop in obj) {
3930 return prop;
3931 }
3932
3933 i++;
3934 }
3935
3936 return undefined;
3937}
3938/* eslint-disable no-new-func, no-nested-ternary */
3939
3940
3941var win;
3942
3943if (typeof window === "undefined") {
3944 // window is undefined in node.js
3945 win = {};
3946} else {
3947 win = window;
3948}
3949
3950var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
3951var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
3952
3953function getTouchActionProps() {
3954 if (!NATIVE_TOUCH_ACTION) {
3955 return false;
3956 }
3957
3958 var touchMap = {};
3959 var cssSupports = win.CSS && win.CSS.supports;
3960 ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function (val) {
3961 // If css.supports is not supported but there is native touch-action assume it supports
3962 // all values. This is the case for IE 10 and 11.
3963 return touchMap[val] = cssSupports ? win.CSS.supports('touch-action', val) : true;
3964 });
3965 return touchMap;
3966}
3967
3968var TOUCH_ACTION_COMPUTE = 'compute';
3969var TOUCH_ACTION_AUTO = 'auto';
3970var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
3971
3972var TOUCH_ACTION_NONE = 'none';
3973var TOUCH_ACTION_PAN_X = 'pan-x';
3974var TOUCH_ACTION_PAN_Y = 'pan-y';
3975var TOUCH_ACTION_MAP = getTouchActionProps();
3976var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
3977var SUPPORT_TOUCH = ('ontouchstart' in win);
3978var SUPPORT_POINTER_EVENTS = prefixed(win, 'PointerEvent') !== undefined;
3979var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
3980var INPUT_TYPE_TOUCH = 'touch';
3981var INPUT_TYPE_PEN = 'pen';
3982var INPUT_TYPE_MOUSE = 'mouse';
3983var INPUT_TYPE_KINECT = 'kinect';
3984var COMPUTE_INTERVAL = 25;
3985var INPUT_START = 1;
3986var INPUT_MOVE = 2;
3987var INPUT_END = 4;
3988var INPUT_CANCEL = 8;
3989var DIRECTION_NONE = 1;
3990var DIRECTION_LEFT = 2;
3991var DIRECTION_RIGHT = 4;
3992var DIRECTION_UP = 8;
3993var DIRECTION_DOWN = 16;
3994var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
3995var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
3996var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
3997var PROPS_XY = ['x', 'y'];
3998var PROPS_CLIENT_XY = ['clientX', 'clientY'];
3999/**
4000 * @private
4001 * walk objects and arrays
4002 * @param {Object} obj
4003 * @param {Function} iterator
4004 * @param {Object} context
4005 */
4006
4007function each(obj, iterator, context) {
4008 var i;
4009
4010 if (!obj) {
4011 return;
4012 }
4013
4014 if (obj.forEach) {
4015 obj.forEach(iterator, context);
4016 } else if (obj.length !== undefined) {
4017 i = 0;
4018
4019 while (i < obj.length) {
4020 iterator.call(context, obj[i], i, obj);
4021 i++;
4022 }
4023 } else {
4024 for (i in obj) {
4025 obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
4026 }
4027 }
4028}
4029/**
4030 * @private
4031 * let a boolean value also be a function that must return a boolean
4032 * this first item in args will be used as the context
4033 * @param {Boolean|Function} val
4034 * @param {Array} [args]
4035 * @returns {Boolean}
4036 */
4037
4038
4039function boolOrFn(val, args) {
4040 if (typeof val === TYPE_FUNCTION) {
4041 return val.apply(args ? args[0] || undefined : undefined, args);
4042 }
4043
4044 return val;
4045}
4046/**
4047 * @private
4048 * small indexOf wrapper
4049 * @param {String} str
4050 * @param {String} find
4051 * @returns {Boolean} found
4052 */
4053
4054
4055function inStr(str, find) {
4056 return str.indexOf(find) > -1;
4057}
4058/**
4059 * @private
4060 * when the touchActions are collected they are not a valid value, so we need to clean things up. *
4061 * @param {String} actions
4062 * @returns {*}
4063 */
4064
4065
4066function cleanTouchActions(actions) {
4067 // none
4068 if (inStr(actions, TOUCH_ACTION_NONE)) {
4069 return TOUCH_ACTION_NONE;
4070 }
4071
4072 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
4073 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); // if both pan-x and pan-y are set (different recognizers
4074 // for different directions, e.g. horizontal pan but vertical swipe?)
4075 // we need none (as otherwise with pan-x pan-y combined none of these
4076 // recognizers will work, since the browser would handle all panning
4077
4078 if (hasPanX && hasPanY) {
4079 return TOUCH_ACTION_NONE;
4080 } // pan-x OR pan-y
4081
4082
4083 if (hasPanX || hasPanY) {
4084 return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
4085 } // manipulation
4086
4087
4088 if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
4089 return TOUCH_ACTION_MANIPULATION;
4090 }
4091
4092 return TOUCH_ACTION_AUTO;
4093}
4094/**
4095 * @private
4096 * Touch Action
4097 * sets the touchAction property or uses the js alternative
4098 * @param {Manager} manager
4099 * @param {String} value
4100 * @constructor
4101 */
4102
4103
4104var TouchAction = /*#__PURE__*/function () {
4105 function TouchAction(manager, value) {
4106 this.manager = manager;
4107 this.set(value);
4108 }
4109 /**
4110 * @private
4111 * set the touchAction value on the element or enable the polyfill
4112 * @param {String} value
4113 */
4114
4115
4116 var _proto = TouchAction.prototype;
4117
4118 _proto.set = function set(value) {
4119 // find out the touch-action by the event handlers
4120 if (value === TOUCH_ACTION_COMPUTE) {
4121 value = this.compute();
4122 }
4123
4124 if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
4125 this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
4126 }
4127
4128 this.actions = value.toLowerCase().trim();
4129 };
4130 /**
4131 * @private
4132 * just re-set the touchAction value
4133 */
4134
4135
4136 _proto.update = function update() {
4137 this.set(this.manager.options.touchAction);
4138 };
4139 /**
4140 * @private
4141 * compute the value for the touchAction property based on the recognizer's settings
4142 * @returns {String} value
4143 */
4144
4145
4146 _proto.compute = function compute() {
4147 var actions = [];
4148 each(this.manager.recognizers, function (recognizer) {
4149 if (boolOrFn(recognizer.options.enable, [recognizer])) {
4150 actions = actions.concat(recognizer.getTouchAction());
4151 }
4152 });
4153 return cleanTouchActions(actions.join(' '));
4154 };
4155 /**
4156 * @private
4157 * this method is called on each input cycle and provides the preventing of the browser behavior
4158 * @param {Object} input
4159 */
4160
4161
4162 _proto.preventDefaults = function preventDefaults(input) {
4163 var srcEvent = input.srcEvent;
4164 var direction = input.offsetDirection; // if the touch action did prevented once this session
4165
4166 if (this.manager.session.prevented) {
4167 srcEvent.preventDefault();
4168 return;
4169 }
4170
4171 var actions = this.actions;
4172 var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
4173 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
4174 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
4175
4176 if (hasNone) {
4177 // do not prevent defaults if this is a tap gesture
4178 var isTapPointer = input.pointers.length === 1;
4179 var isTapMovement = input.distance < 2;
4180 var isTapTouchTime = input.deltaTime < 250;
4181
4182 if (isTapPointer && isTapMovement && isTapTouchTime) {
4183 return;
4184 }
4185 }
4186
4187 if (hasPanX && hasPanY) {
4188 // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
4189 return;
4190 }
4191
4192 if (hasNone || hasPanY && direction & DIRECTION_HORIZONTAL || hasPanX && direction & DIRECTION_VERTICAL) {
4193 return this.preventSrc(srcEvent);
4194 }
4195 };
4196 /**
4197 * @private
4198 * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
4199 * @param {Object} srcEvent
4200 */
4201
4202
4203 _proto.preventSrc = function preventSrc(srcEvent) {
4204 this.manager.session.prevented = true;
4205 srcEvent.preventDefault();
4206 };
4207
4208 return TouchAction;
4209}();
4210/**
4211 * @private
4212 * find if a node is in the given parent
4213 * @method hasParent
4214 * @param {HTMLElement} node
4215 * @param {HTMLElement} parent
4216 * @return {Boolean} found
4217 */
4218
4219
4220function hasParent$1(node, parent) {
4221 while (node) {
4222 if (node === parent) {
4223 return true;
4224 }
4225
4226 node = node.parentNode;
4227 }
4228
4229 return false;
4230}
4231/**
4232 * @private
4233 * get the center of all the pointers
4234 * @param {Array} pointers
4235 * @return {Object} center contains `x` and `y` properties
4236 */
4237
4238
4239function getCenter(pointers) {
4240 var pointersLength = pointers.length; // no need to loop when only one touch
4241
4242 if (pointersLength === 1) {
4243 return {
4244 x: round(pointers[0].clientX),
4245 y: round(pointers[0].clientY)
4246 };
4247 }
4248
4249 var x = 0;
4250 var y = 0;
4251 var i = 0;
4252
4253 while (i < pointersLength) {
4254 x += pointers[i].clientX;
4255 y += pointers[i].clientY;
4256 i++;
4257 }
4258
4259 return {
4260 x: round(x / pointersLength),
4261 y: round(y / pointersLength)
4262 };
4263}
4264/**
4265 * @private
4266 * create a simple clone from the input used for storage of firstInput and firstMultiple
4267 * @param {Object} input
4268 * @returns {Object} clonedInputData
4269 */
4270
4271
4272function simpleCloneInputData(input) {
4273 // make a simple copy of the pointers because we will get a reference if we don't
4274 // we only need clientXY for the calculations
4275 var pointers = [];
4276 var i = 0;
4277
4278 while (i < input.pointers.length) {
4279 pointers[i] = {
4280 clientX: round(input.pointers[i].clientX),
4281 clientY: round(input.pointers[i].clientY)
4282 };
4283 i++;
4284 }
4285
4286 return {
4287 timeStamp: now(),
4288 pointers: pointers,
4289 center: getCenter(pointers),
4290 deltaX: input.deltaX,
4291 deltaY: input.deltaY
4292 };
4293}
4294/**
4295 * @private
4296 * calculate the absolute distance between two points
4297 * @param {Object} p1 {x, y}
4298 * @param {Object} p2 {x, y}
4299 * @param {Array} [props] containing x and y keys
4300 * @return {Number} distance
4301 */
4302
4303
4304function getDistance(p1, p2, props) {
4305 if (!props) {
4306 props = PROPS_XY;
4307 }
4308
4309 var x = p2[props[0]] - p1[props[0]];
4310 var y = p2[props[1]] - p1[props[1]];
4311 return Math.sqrt(x * x + y * y);
4312}
4313/**
4314 * @private
4315 * calculate the angle between two coordinates
4316 * @param {Object} p1
4317 * @param {Object} p2
4318 * @param {Array} [props] containing x and y keys
4319 * @return {Number} angle
4320 */
4321
4322
4323function getAngle(p1, p2, props) {
4324 if (!props) {
4325 props = PROPS_XY;
4326 }
4327
4328 var x = p2[props[0]] - p1[props[0]];
4329 var y = p2[props[1]] - p1[props[1]];
4330 return Math.atan2(y, x) * 180 / Math.PI;
4331}
4332/**
4333 * @private
4334 * get the direction between two points
4335 * @param {Number} x
4336 * @param {Number} y
4337 * @return {Number} direction
4338 */
4339
4340
4341function getDirection(x, y) {
4342 if (x === y) {
4343 return DIRECTION_NONE;
4344 }
4345
4346 if (abs$1(x) >= abs$1(y)) {
4347 return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
4348 }
4349
4350 return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
4351}
4352
4353function computeDeltaXY(session, input) {
4354 var center = input.center; // let { offsetDelta:offset = {}, prevDelta = {}, prevInput = {} } = session;
4355 // jscs throwing error on defalut destructured values and without defaults tests fail
4356
4357 var offset = session.offsetDelta || {};
4358 var prevDelta = session.prevDelta || {};
4359 var prevInput = session.prevInput || {};
4360
4361 if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
4362 prevDelta = session.prevDelta = {
4363 x: prevInput.deltaX || 0,
4364 y: prevInput.deltaY || 0
4365 };
4366 offset = session.offsetDelta = {
4367 x: center.x,
4368 y: center.y
4369 };
4370 }
4371
4372 input.deltaX = prevDelta.x + (center.x - offset.x);
4373 input.deltaY = prevDelta.y + (center.y - offset.y);
4374}
4375/**
4376 * @private
4377 * calculate the velocity between two points. unit is in px per ms.
4378 * @param {Number} deltaTime
4379 * @param {Number} x
4380 * @param {Number} y
4381 * @return {Object} velocity `x` and `y`
4382 */
4383
4384
4385function getVelocity(deltaTime, x, y) {
4386 return {
4387 x: x / deltaTime || 0,
4388 y: y / deltaTime || 0
4389 };
4390}
4391/**
4392 * @private
4393 * calculate the scale factor between two pointersets
4394 * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
4395 * @param {Array} start array of pointers
4396 * @param {Array} end array of pointers
4397 * @return {Number} scale
4398 */
4399
4400
4401function getScale(start, end) {
4402 return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
4403}
4404/**
4405 * @private
4406 * calculate the rotation degrees between two pointersets
4407 * @param {Array} start array of pointers
4408 * @param {Array} end array of pointers
4409 * @return {Number} rotation
4410 */
4411
4412
4413function getRotation(start, end) {
4414 return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
4415}
4416/**
4417 * @private
4418 * velocity is calculated every x ms
4419 * @param {Object} session
4420 * @param {Object} input
4421 */
4422
4423
4424function computeIntervalInputData(session, input) {
4425 var last = session.lastInterval || input;
4426 var deltaTime = input.timeStamp - last.timeStamp;
4427 var velocity;
4428 var velocityX;
4429 var velocityY;
4430 var direction;
4431
4432 if (input.eventType !== INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
4433 var deltaX = input.deltaX - last.deltaX;
4434 var deltaY = input.deltaY - last.deltaY;
4435 var v = getVelocity(deltaTime, deltaX, deltaY);
4436 velocityX = v.x;
4437 velocityY = v.y;
4438 velocity = abs$1(v.x) > abs$1(v.y) ? v.x : v.y;
4439 direction = getDirection(deltaX, deltaY);
4440 session.lastInterval = input;
4441 } else {
4442 // use latest velocity info if it doesn't overtake a minimum period
4443 velocity = last.velocity;
4444 velocityX = last.velocityX;
4445 velocityY = last.velocityY;
4446 direction = last.direction;
4447 }
4448
4449 input.velocity = velocity;
4450 input.velocityX = velocityX;
4451 input.velocityY = velocityY;
4452 input.direction = direction;
4453}
4454/**
4455* @private
4456 * extend the data with some usable properties like scale, rotate, velocity etc
4457 * @param {Object} manager
4458 * @param {Object} input
4459 */
4460
4461
4462function computeInputData(manager, input) {
4463 var session = manager.session;
4464 var pointers = input.pointers;
4465 var pointersLength = pointers.length; // store the first input to calculate the distance and direction
4466
4467 if (!session.firstInput) {
4468 session.firstInput = simpleCloneInputData(input);
4469 } // to compute scale and rotation we need to store the multiple touches
4470
4471
4472 if (pointersLength > 1 && !session.firstMultiple) {
4473 session.firstMultiple = simpleCloneInputData(input);
4474 } else if (pointersLength === 1) {
4475 session.firstMultiple = false;
4476 }
4477
4478 var firstInput = session.firstInput,
4479 firstMultiple = session.firstMultiple;
4480 var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
4481 var center = input.center = getCenter(pointers);
4482 input.timeStamp = now();
4483 input.deltaTime = input.timeStamp - firstInput.timeStamp;
4484 input.angle = getAngle(offsetCenter, center);
4485 input.distance = getDistance(offsetCenter, center);
4486 computeDeltaXY(session, input);
4487 input.offsetDirection = getDirection(input.deltaX, input.deltaY);
4488 var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
4489 input.overallVelocityX = overallVelocity.x;
4490 input.overallVelocityY = overallVelocity.y;
4491 input.overallVelocity = abs$1(overallVelocity.x) > abs$1(overallVelocity.y) ? overallVelocity.x : overallVelocity.y;
4492 input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
4493 input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
4494 input.maxPointers = !session.prevInput ? input.pointers.length : input.pointers.length > session.prevInput.maxPointers ? input.pointers.length : session.prevInput.maxPointers;
4495 computeIntervalInputData(session, input); // find the correct target
4496
4497 var target = manager.element;
4498 var srcEvent = input.srcEvent;
4499 var srcEventTarget;
4500
4501 if (srcEvent.composedPath) {
4502 srcEventTarget = srcEvent.composedPath()[0];
4503 } else if (srcEvent.path) {
4504 srcEventTarget = srcEvent.path[0];
4505 } else {
4506 srcEventTarget = srcEvent.target;
4507 }
4508
4509 if (hasParent$1(srcEventTarget, target)) {
4510 target = srcEventTarget;
4511 }
4512
4513 input.target = target;
4514}
4515/**
4516 * @private
4517 * handle input events
4518 * @param {Manager} manager
4519 * @param {String} eventType
4520 * @param {Object} input
4521 */
4522
4523
4524function inputHandler(manager, eventType, input) {
4525 var pointersLen = input.pointers.length;
4526 var changedPointersLen = input.changedPointers.length;
4527 var isFirst = eventType & INPUT_START && pointersLen - changedPointersLen === 0;
4528 var isFinal = eventType & (INPUT_END | INPUT_CANCEL) && pointersLen - changedPointersLen === 0;
4529 input.isFirst = !!isFirst;
4530 input.isFinal = !!isFinal;
4531
4532 if (isFirst) {
4533 manager.session = {};
4534 } // source event is the normalized value of the domEvents
4535 // like 'touchstart, mouseup, pointerdown'
4536
4537
4538 input.eventType = eventType; // compute scale, rotation etc
4539
4540 computeInputData(manager, input); // emit secret event
4541
4542 manager.emit('hammer.input', input);
4543 manager.recognize(input);
4544 manager.session.prevInput = input;
4545}
4546/**
4547 * @private
4548 * split string on whitespace
4549 * @param {String} str
4550 * @returns {Array} words
4551 */
4552
4553
4554function splitStr(str) {
4555 return str.trim().split(/\s+/g);
4556}
4557/**
4558 * @private
4559 * addEventListener with multiple events at once
4560 * @param {EventTarget} target
4561 * @param {String} types
4562 * @param {Function} handler
4563 */
4564
4565
4566function addEventListeners(target, types, handler) {
4567 each(splitStr(types), function (type) {
4568 target.addEventListener(type, handler, false);
4569 });
4570}
4571/**
4572 * @private
4573 * removeEventListener with multiple events at once
4574 * @param {EventTarget} target
4575 * @param {String} types
4576 * @param {Function} handler
4577 */
4578
4579
4580function removeEventListeners(target, types, handler) {
4581 each(splitStr(types), function (type) {
4582 target.removeEventListener(type, handler, false);
4583 });
4584}
4585/**
4586 * @private
4587 * get the window object of an element
4588 * @param {HTMLElement} element
4589 * @returns {DocumentView|Window}
4590 */
4591
4592
4593function getWindowForElement(element) {
4594 var doc = element.ownerDocument || element;
4595 return doc.defaultView || doc.parentWindow || window;
4596}
4597/**
4598 * @private
4599 * create new input type manager
4600 * @param {Manager} manager
4601 * @param {Function} callback
4602 * @returns {Input}
4603 * @constructor
4604 */
4605
4606
4607var Input = /*#__PURE__*/function () {
4608 function Input(manager, callback) {
4609 var self = this;
4610 this.manager = manager;
4611 this.callback = callback;
4612 this.element = manager.element;
4613 this.target = manager.options.inputTarget; // smaller wrapper around the handler, for the scope and the enabled state of the manager,
4614 // so when disabled the input events are completely bypassed.
4615
4616 this.domHandler = function (ev) {
4617 if (boolOrFn(manager.options.enable, [manager])) {
4618 self.handler(ev);
4619 }
4620 };
4621
4622 this.init();
4623 }
4624 /**
4625 * @private
4626 * should handle the inputEvent data and trigger the callback
4627 * @virtual
4628 */
4629
4630
4631 var _proto = Input.prototype;
4632
4633 _proto.handler = function handler() {};
4634 /**
4635 * @private
4636 * bind the events
4637 */
4638
4639
4640 _proto.init = function init() {
4641 this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
4642 this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
4643 this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
4644 };
4645 /**
4646 * @private
4647 * unbind the events
4648 */
4649
4650
4651 _proto.destroy = function destroy() {
4652 this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
4653 this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
4654 this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
4655 };
4656
4657 return Input;
4658}();
4659/**
4660 * @private
4661 * find if a array contains the object using indexOf or a simple polyFill
4662 * @param {Array} src
4663 * @param {String} find
4664 * @param {String} [findByKey]
4665 * @return {Boolean|Number} false when not found, or the index
4666 */
4667
4668
4669function inArray(src, find, findByKey) {
4670 if (src.indexOf && !findByKey) {
4671 return src.indexOf(find);
4672 } else {
4673 var i = 0;
4674
4675 while (i < src.length) {
4676 if (findByKey && src[i][findByKey] == find || !findByKey && src[i] === find) {
4677 // do not use === here, test fails
4678 return i;
4679 }
4680
4681 i++;
4682 }
4683
4684 return -1;
4685 }
4686}
4687
4688var POINTER_INPUT_MAP = {
4689 pointerdown: INPUT_START,
4690 pointermove: INPUT_MOVE,
4691 pointerup: INPUT_END,
4692 pointercancel: INPUT_CANCEL,
4693 pointerout: INPUT_CANCEL
4694}; // in IE10 the pointer types is defined as an enum
4695
4696var IE10_POINTER_TYPE_ENUM = {
4697 2: INPUT_TYPE_TOUCH,
4698 3: INPUT_TYPE_PEN,
4699 4: INPUT_TYPE_MOUSE,
4700 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
4701
4702};
4703var POINTER_ELEMENT_EVENTS = 'pointerdown';
4704var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; // IE10 has prefixed support, and case-sensitive
4705
4706if (win.MSPointerEvent && !win.PointerEvent) {
4707 POINTER_ELEMENT_EVENTS = 'MSPointerDown';
4708 POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
4709}
4710/**
4711 * @private
4712 * Pointer events input
4713 * @constructor
4714 * @extends Input
4715 */
4716
4717
4718var PointerEventInput = /*#__PURE__*/function (_Input) {
4719 _inheritsLoose(PointerEventInput, _Input);
4720
4721 function PointerEventInput() {
4722 var _this;
4723
4724 var proto = PointerEventInput.prototype;
4725 proto.evEl = POINTER_ELEMENT_EVENTS;
4726 proto.evWin = POINTER_WINDOW_EVENTS;
4727 _this = _Input.apply(this, arguments) || this;
4728 _this.store = _this.manager.session.pointerEvents = [];
4729 return _this;
4730 }
4731 /**
4732 * @private
4733 * handle mouse events
4734 * @param {Object} ev
4735 */
4736
4737
4738 var _proto = PointerEventInput.prototype;
4739
4740 _proto.handler = function handler(ev) {
4741 var store = this.store;
4742 var removePointer = false;
4743 var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
4744 var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
4745 var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
4746 var isTouch = pointerType === INPUT_TYPE_TOUCH; // get index of the event in the store
4747
4748 var storeIndex = inArray(store, ev.pointerId, 'pointerId'); // start and mouse must be down
4749
4750 if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
4751 if (storeIndex < 0) {
4752 store.push(ev);
4753 storeIndex = store.length - 1;
4754 }
4755 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
4756 removePointer = true;
4757 } // it not found, so the pointer hasn't been down (so it's probably a hover)
4758
4759
4760 if (storeIndex < 0) {
4761 return;
4762 } // update the event in the store
4763
4764
4765 store[storeIndex] = ev;
4766 this.callback(this.manager, eventType, {
4767 pointers: store,
4768 changedPointers: [ev],
4769 pointerType: pointerType,
4770 srcEvent: ev
4771 });
4772
4773 if (removePointer) {
4774 // remove from the store
4775 store.splice(storeIndex, 1);
4776 }
4777 };
4778
4779 return PointerEventInput;
4780}(Input);
4781/**
4782 * @private
4783 * convert array-like objects to real arrays
4784 * @param {Object} obj
4785 * @returns {Array}
4786 */
4787
4788
4789function toArray$1(obj) {
4790 return Array.prototype.slice.call(obj, 0);
4791}
4792/**
4793 * @private
4794 * unique array with objects based on a key (like 'id') or just by the array's value
4795 * @param {Array} src [{id:1},{id:2},{id:1}]
4796 * @param {String} [key]
4797 * @param {Boolean} [sort=False]
4798 * @returns {Array} [{id:1},{id:2}]
4799 */
4800
4801
4802function uniqueArray(src, key, sort) {
4803 var results = [];
4804 var values = [];
4805 var i = 0;
4806
4807 while (i < src.length) {
4808 var val = key ? src[i][key] : src[i];
4809
4810 if (inArray(values, val) < 0) {
4811 results.push(src[i]);
4812 }
4813
4814 values[i] = val;
4815 i++;
4816 }
4817
4818 if (sort) {
4819 if (!key) {
4820 results = results.sort();
4821 } else {
4822 results = results.sort(function (a, b) {
4823 return a[key] > b[key];
4824 });
4825 }
4826 }
4827
4828 return results;
4829}
4830
4831var TOUCH_INPUT_MAP = {
4832 touchstart: INPUT_START,
4833 touchmove: INPUT_MOVE,
4834 touchend: INPUT_END,
4835 touchcancel: INPUT_CANCEL
4836};
4837var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
4838/**
4839 * @private
4840 * Multi-user touch events input
4841 * @constructor
4842 * @extends Input
4843 */
4844
4845var TouchInput = /*#__PURE__*/function (_Input) {
4846 _inheritsLoose(TouchInput, _Input);
4847
4848 function TouchInput() {
4849 var _this;
4850
4851 TouchInput.prototype.evTarget = TOUCH_TARGET_EVENTS;
4852 _this = _Input.apply(this, arguments) || this;
4853 _this.targetIds = {}; // this.evTarget = TOUCH_TARGET_EVENTS;
4854
4855 return _this;
4856 }
4857
4858 var _proto = TouchInput.prototype;
4859
4860 _proto.handler = function handler(ev) {
4861 var type = TOUCH_INPUT_MAP[ev.type];
4862 var touches = getTouches.call(this, ev, type);
4863
4864 if (!touches) {
4865 return;
4866 }
4867
4868 this.callback(this.manager, type, {
4869 pointers: touches[0],
4870 changedPointers: touches[1],
4871 pointerType: INPUT_TYPE_TOUCH,
4872 srcEvent: ev
4873 });
4874 };
4875
4876 return TouchInput;
4877}(Input);
4878
4879function getTouches(ev, type) {
4880 var allTouches = toArray$1(ev.touches);
4881 var targetIds = this.targetIds; // when there is only one touch, the process can be simplified
4882
4883 if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
4884 targetIds[allTouches[0].identifier] = true;
4885 return [allTouches, allTouches];
4886 }
4887
4888 var i;
4889 var targetTouches;
4890 var changedTouches = toArray$1(ev.changedTouches);
4891 var changedTargetTouches = [];
4892 var target = this.target; // get target touches from touches
4893
4894 targetTouches = allTouches.filter(function (touch) {
4895 return hasParent$1(touch.target, target);
4896 }); // collect touches
4897
4898 if (type === INPUT_START) {
4899 i = 0;
4900
4901 while (i < targetTouches.length) {
4902 targetIds[targetTouches[i].identifier] = true;
4903 i++;
4904 }
4905 } // filter changed touches to only contain touches that exist in the collected target ids
4906
4907
4908 i = 0;
4909
4910 while (i < changedTouches.length) {
4911 if (targetIds[changedTouches[i].identifier]) {
4912 changedTargetTouches.push(changedTouches[i]);
4913 } // cleanup removed touches
4914
4915
4916 if (type & (INPUT_END | INPUT_CANCEL)) {
4917 delete targetIds[changedTouches[i].identifier];
4918 }
4919
4920 i++;
4921 }
4922
4923 if (!changedTargetTouches.length) {
4924 return;
4925 }
4926
4927 return [// merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
4928 uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), changedTargetTouches];
4929}
4930
4931var MOUSE_INPUT_MAP = {
4932 mousedown: INPUT_START,
4933 mousemove: INPUT_MOVE,
4934 mouseup: INPUT_END
4935};
4936var MOUSE_ELEMENT_EVENTS = 'mousedown';
4937var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
4938/**
4939 * @private
4940 * Mouse events input
4941 * @constructor
4942 * @extends Input
4943 */
4944
4945var MouseInput = /*#__PURE__*/function (_Input) {
4946 _inheritsLoose(MouseInput, _Input);
4947
4948 function MouseInput() {
4949 var _this;
4950
4951 var proto = MouseInput.prototype;
4952 proto.evEl = MOUSE_ELEMENT_EVENTS;
4953 proto.evWin = MOUSE_WINDOW_EVENTS;
4954 _this = _Input.apply(this, arguments) || this;
4955 _this.pressed = false; // mousedown state
4956
4957 return _this;
4958 }
4959 /**
4960 * @private
4961 * handle mouse events
4962 * @param {Object} ev
4963 */
4964
4965
4966 var _proto = MouseInput.prototype;
4967
4968 _proto.handler = function handler(ev) {
4969 var eventType = MOUSE_INPUT_MAP[ev.type]; // on start we want to have the left mouse button down
4970
4971 if (eventType & INPUT_START && ev.button === 0) {
4972 this.pressed = true;
4973 }
4974
4975 if (eventType & INPUT_MOVE && ev.which !== 1) {
4976 eventType = INPUT_END;
4977 } // mouse must be down
4978
4979
4980 if (!this.pressed) {
4981 return;
4982 }
4983
4984 if (eventType & INPUT_END) {
4985 this.pressed = false;
4986 }
4987
4988 this.callback(this.manager, eventType, {
4989 pointers: [ev],
4990 changedPointers: [ev],
4991 pointerType: INPUT_TYPE_MOUSE,
4992 srcEvent: ev
4993 });
4994 };
4995
4996 return MouseInput;
4997}(Input);
4998/**
4999 * @private
5000 * Combined touch and mouse input
5001 *
5002 * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
5003 * This because touch devices also emit mouse events while doing a touch.
5004 *
5005 * @constructor
5006 * @extends Input
5007 */
5008
5009
5010var DEDUP_TIMEOUT = 2500;
5011var DEDUP_DISTANCE = 25;
5012
5013function setLastTouch(eventData) {
5014 var _eventData$changedPoi = eventData.changedPointers,
5015 touch = _eventData$changedPoi[0];
5016
5017 if (touch.identifier === this.primaryTouch) {
5018 var lastTouch = {
5019 x: touch.clientX,
5020 y: touch.clientY
5021 };
5022 var lts = this.lastTouches;
5023 this.lastTouches.push(lastTouch);
5024
5025 var removeLastTouch = function removeLastTouch() {
5026 var i = lts.indexOf(lastTouch);
5027
5028 if (i > -1) {
5029 lts.splice(i, 1);
5030 }
5031 };
5032
5033 setTimeout(removeLastTouch, DEDUP_TIMEOUT);
5034 }
5035}
5036
5037function recordTouches(eventType, eventData) {
5038 if (eventType & INPUT_START) {
5039 this.primaryTouch = eventData.changedPointers[0].identifier;
5040 setLastTouch.call(this, eventData);
5041 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
5042 setLastTouch.call(this, eventData);
5043 }
5044}
5045
5046function isSyntheticEvent(eventData) {
5047 var x = eventData.srcEvent.clientX;
5048 var y = eventData.srcEvent.clientY;
5049
5050 for (var i = 0; i < this.lastTouches.length; i++) {
5051 var t = this.lastTouches[i];
5052 var dx = Math.abs(x - t.x);
5053 var dy = Math.abs(y - t.y);
5054
5055 if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
5056 return true;
5057 }
5058 }
5059
5060 return false;
5061}
5062
5063var TouchMouseInput = /*#__PURE__*/function () {
5064 var TouchMouseInput = /*#__PURE__*/function (_Input) {
5065 _inheritsLoose(TouchMouseInput, _Input);
5066
5067 function TouchMouseInput(_manager, callback) {
5068 var _this;
5069
5070 _this = _Input.call(this, _manager, callback) || this;
5071
5072 _this.handler = function (manager, inputEvent, inputData) {
5073 var isTouch = inputData.pointerType === INPUT_TYPE_TOUCH;
5074 var isMouse = inputData.pointerType === INPUT_TYPE_MOUSE;
5075
5076 if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
5077 return;
5078 } // when we're in a touch event, record touches to de-dupe synthetic mouse event
5079
5080
5081 if (isTouch) {
5082 recordTouches.call(_assertThisInitialized$1(_assertThisInitialized$1(_this)), inputEvent, inputData);
5083 } else if (isMouse && isSyntheticEvent.call(_assertThisInitialized$1(_assertThisInitialized$1(_this)), inputData)) {
5084 return;
5085 }
5086
5087 _this.callback(manager, inputEvent, inputData);
5088 };
5089
5090 _this.touch = new TouchInput(_this.manager, _this.handler);
5091 _this.mouse = new MouseInput(_this.manager, _this.handler);
5092 _this.primaryTouch = null;
5093 _this.lastTouches = [];
5094 return _this;
5095 }
5096 /**
5097 * @private
5098 * handle mouse and touch events
5099 * @param {Hammer} manager
5100 * @param {String} inputEvent
5101 * @param {Object} inputData
5102 */
5103
5104
5105 var _proto = TouchMouseInput.prototype;
5106 /**
5107 * @private
5108 * remove the event listeners
5109 */
5110
5111 _proto.destroy = function destroy() {
5112 this.touch.destroy();
5113 this.mouse.destroy();
5114 };
5115
5116 return TouchMouseInput;
5117 }(Input);
5118
5119 return TouchMouseInput;
5120}();
5121/**
5122 * @private
5123 * create new input type manager
5124 * called by the Manager constructor
5125 * @param {Hammer} manager
5126 * @returns {Input}
5127 */
5128
5129
5130function createInputInstance(manager) {
5131 var Type; // let inputClass = manager.options.inputClass;
5132
5133 var inputClass = manager.options.inputClass;
5134
5135 if (inputClass) {
5136 Type = inputClass;
5137 } else if (SUPPORT_POINTER_EVENTS) {
5138 Type = PointerEventInput;
5139 } else if (SUPPORT_ONLY_TOUCH) {
5140 Type = TouchInput;
5141 } else if (!SUPPORT_TOUCH) {
5142 Type = MouseInput;
5143 } else {
5144 Type = TouchMouseInput;
5145 }
5146
5147 return new Type(manager, inputHandler);
5148}
5149/**
5150 * @private
5151 * if the argument is an array, we want to execute the fn on each entry
5152 * if it aint an array we don't want to do a thing.
5153 * this is used by all the methods that accept a single and array argument.
5154 * @param {*|Array} arg
5155 * @param {String} fn
5156 * @param {Object} [context]
5157 * @returns {Boolean}
5158 */
5159
5160
5161function invokeArrayArg(arg, fn, context) {
5162 if (Array.isArray(arg)) {
5163 each(arg, context[fn], context);
5164 return true;
5165 }
5166
5167 return false;
5168}
5169
5170var STATE_POSSIBLE = 1;
5171var STATE_BEGAN = 2;
5172var STATE_CHANGED = 4;
5173var STATE_ENDED = 8;
5174var STATE_RECOGNIZED = STATE_ENDED;
5175var STATE_CANCELLED = 16;
5176var STATE_FAILED = 32;
5177/**
5178 * @private
5179 * get a unique id
5180 * @returns {number} uniqueId
5181 */
5182
5183var _uniqueId = 1;
5184
5185function uniqueId() {
5186 return _uniqueId++;
5187}
5188/**
5189 * @private
5190 * get a recognizer by name if it is bound to a manager
5191 * @param {Recognizer|String} otherRecognizer
5192 * @param {Recognizer} recognizer
5193 * @returns {Recognizer}
5194 */
5195
5196
5197function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
5198 var manager = recognizer.manager;
5199
5200 if (manager) {
5201 return manager.get(otherRecognizer);
5202 }
5203
5204 return otherRecognizer;
5205}
5206/**
5207 * @private
5208 * get a usable string, used as event postfix
5209 * @param {constant} state
5210 * @returns {String} state
5211 */
5212
5213
5214function stateStr(state) {
5215 if (state & STATE_CANCELLED) {
5216 return 'cancel';
5217 } else if (state & STATE_ENDED) {
5218 return 'end';
5219 } else if (state & STATE_CHANGED) {
5220 return 'move';
5221 } else if (state & STATE_BEGAN) {
5222 return 'start';
5223 }
5224
5225 return '';
5226}
5227/**
5228 * @private
5229 * Recognizer flow explained; *
5230 * All recognizers have the initial state of POSSIBLE when a input session starts.
5231 * The definition of a input session is from the first input until the last input, with all it's movement in it. *
5232 * Example session for mouse-input: mousedown -> mousemove -> mouseup
5233 *
5234 * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
5235 * which determines with state it should be.
5236 *
5237 * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
5238 * POSSIBLE to give it another change on the next cycle.
5239 *
5240 * Possible
5241 * |
5242 * +-----+---------------+
5243 * | |
5244 * +-----+-----+ |
5245 * | | |
5246 * Failed Cancelled |
5247 * +-------+------+
5248 * | |
5249 * Recognized Began
5250 * |
5251 * Changed
5252 * |
5253 * Ended/Recognized
5254 */
5255
5256/**
5257 * @private
5258 * Recognizer
5259 * Every recognizer needs to extend from this class.
5260 * @constructor
5261 * @param {Object} options
5262 */
5263
5264
5265var Recognizer = /*#__PURE__*/function () {
5266 function Recognizer(options) {
5267 if (options === void 0) {
5268 options = {};
5269 }
5270
5271 this.options = _extends({
5272 enable: true
5273 }, options);
5274 this.id = uniqueId();
5275 this.manager = null; // default is enable true
5276
5277 this.state = STATE_POSSIBLE;
5278 this.simultaneous = {};
5279 this.requireFail = [];
5280 }
5281 /**
5282 * @private
5283 * set options
5284 * @param {Object} options
5285 * @return {Recognizer}
5286 */
5287
5288
5289 var _proto = Recognizer.prototype;
5290
5291 _proto.set = function set(options) {
5292 assign$1(this.options, options); // also update the touchAction, in case something changed about the directions/enabled state
5293
5294 this.manager && this.manager.touchAction.update();
5295 return this;
5296 };
5297 /**
5298 * @private
5299 * recognize simultaneous with an other recognizer.
5300 * @param {Recognizer} otherRecognizer
5301 * @returns {Recognizer} this
5302 */
5303
5304
5305 _proto.recognizeWith = function recognizeWith(otherRecognizer) {
5306 if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
5307 return this;
5308 }
5309
5310 var simultaneous = this.simultaneous;
5311 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
5312
5313 if (!simultaneous[otherRecognizer.id]) {
5314 simultaneous[otherRecognizer.id] = otherRecognizer;
5315 otherRecognizer.recognizeWith(this);
5316 }
5317
5318 return this;
5319 };
5320 /**
5321 * @private
5322 * drop the simultaneous link. it doesnt remove the link on the other recognizer.
5323 * @param {Recognizer} otherRecognizer
5324 * @returns {Recognizer} this
5325 */
5326
5327
5328 _proto.dropRecognizeWith = function dropRecognizeWith(otherRecognizer) {
5329 if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
5330 return this;
5331 }
5332
5333 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
5334 delete this.simultaneous[otherRecognizer.id];
5335 return this;
5336 };
5337 /**
5338 * @private
5339 * recognizer can only run when an other is failing
5340 * @param {Recognizer} otherRecognizer
5341 * @returns {Recognizer} this
5342 */
5343
5344
5345 _proto.requireFailure = function requireFailure(otherRecognizer) {
5346 if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
5347 return this;
5348 }
5349
5350 var requireFail = this.requireFail;
5351 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
5352
5353 if (inArray(requireFail, otherRecognizer) === -1) {
5354 requireFail.push(otherRecognizer);
5355 otherRecognizer.requireFailure(this);
5356 }
5357
5358 return this;
5359 };
5360 /**
5361 * @private
5362 * drop the requireFailure link. it does not remove the link on the other recognizer.
5363 * @param {Recognizer} otherRecognizer
5364 * @returns {Recognizer} this
5365 */
5366
5367
5368 _proto.dropRequireFailure = function dropRequireFailure(otherRecognizer) {
5369 if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
5370 return this;
5371 }
5372
5373 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
5374 var index = inArray(this.requireFail, otherRecognizer);
5375
5376 if (index > -1) {
5377 this.requireFail.splice(index, 1);
5378 }
5379
5380 return this;
5381 };
5382 /**
5383 * @private
5384 * has require failures boolean
5385 * @returns {boolean}
5386 */
5387
5388
5389 _proto.hasRequireFailures = function hasRequireFailures() {
5390 return this.requireFail.length > 0;
5391 };
5392 /**
5393 * @private
5394 * if the recognizer can recognize simultaneous with an other recognizer
5395 * @param {Recognizer} otherRecognizer
5396 * @returns {Boolean}
5397 */
5398
5399
5400 _proto.canRecognizeWith = function canRecognizeWith(otherRecognizer) {
5401 return !!this.simultaneous[otherRecognizer.id];
5402 };
5403 /**
5404 * @private
5405 * You should use `tryEmit` instead of `emit` directly to check
5406 * that all the needed recognizers has failed before emitting.
5407 * @param {Object} input
5408 */
5409
5410
5411 _proto.emit = function emit(input) {
5412 var self = this;
5413 var state = this.state;
5414
5415 function emit(event) {
5416 self.manager.emit(event, input);
5417 } // 'panstart' and 'panmove'
5418
5419
5420 if (state < STATE_ENDED) {
5421 emit(self.options.event + stateStr(state));
5422 }
5423
5424 emit(self.options.event); // simple 'eventName' events
5425
5426 if (input.additionalEvent) {
5427 // additional event(panleft, panright, pinchin, pinchout...)
5428 emit(input.additionalEvent);
5429 } // panend and pancancel
5430
5431
5432 if (state >= STATE_ENDED) {
5433 emit(self.options.event + stateStr(state));
5434 }
5435 };
5436 /**
5437 * @private
5438 * Check that all the require failure recognizers has failed,
5439 * if true, it emits a gesture event,
5440 * otherwise, setup the state to FAILED.
5441 * @param {Object} input
5442 */
5443
5444
5445 _proto.tryEmit = function tryEmit(input) {
5446 if (this.canEmit()) {
5447 return this.emit(input);
5448 } // it's failing anyway
5449
5450
5451 this.state = STATE_FAILED;
5452 };
5453 /**
5454 * @private
5455 * can we emit?
5456 * @returns {boolean}
5457 */
5458
5459
5460 _proto.canEmit = function canEmit() {
5461 var i = 0;
5462
5463 while (i < this.requireFail.length) {
5464 if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
5465 return false;
5466 }
5467
5468 i++;
5469 }
5470
5471 return true;
5472 };
5473 /**
5474 * @private
5475 * update the recognizer
5476 * @param {Object} inputData
5477 */
5478
5479
5480 _proto.recognize = function recognize(inputData) {
5481 // make a new copy of the inputData
5482 // so we can change the inputData without messing up the other recognizers
5483 var inputDataClone = assign$1({}, inputData); // is is enabled and allow recognizing?
5484
5485 if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
5486 this.reset();
5487 this.state = STATE_FAILED;
5488 return;
5489 } // reset when we've reached the end
5490
5491
5492 if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
5493 this.state = STATE_POSSIBLE;
5494 }
5495
5496 this.state = this.process(inputDataClone); // the recognizer has recognized a gesture
5497 // so trigger an event
5498
5499 if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
5500 this.tryEmit(inputDataClone);
5501 }
5502 };
5503 /**
5504 * @private
5505 * return the state of the recognizer
5506 * the actual recognizing happens in this method
5507 * @virtual
5508 * @param {Object} inputData
5509 * @returns {constant} STATE
5510 */
5511
5512 /* jshint ignore:start */
5513
5514
5515 _proto.process = function process(inputData) {};
5516 /* jshint ignore:end */
5517
5518 /**
5519 * @private
5520 * return the preferred touch-action
5521 * @virtual
5522 * @returns {Array}
5523 */
5524
5525
5526 _proto.getTouchAction = function getTouchAction() {};
5527 /**
5528 * @private
5529 * called when the gesture isn't allowed to recognize
5530 * like when another is being recognized or it is disabled
5531 * @virtual
5532 */
5533
5534
5535 _proto.reset = function reset() {};
5536
5537 return Recognizer;
5538}();
5539/**
5540 * @private
5541 * A tap is recognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
5542 * between the given interval and position. The delay option can be used to recognize multi-taps without firing
5543 * a single tap.
5544 *
5545 * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
5546 * multi-taps being recognized.
5547 * @constructor
5548 * @extends Recognizer
5549 */
5550
5551
5552var TapRecognizer = /*#__PURE__*/function (_Recognizer) {
5553 _inheritsLoose(TapRecognizer, _Recognizer);
5554
5555 function TapRecognizer(options) {
5556 var _this;
5557
5558 if (options === void 0) {
5559 options = {};
5560 }
5561
5562 _this = _Recognizer.call(this, _extends({
5563 event: 'tap',
5564 pointers: 1,
5565 taps: 1,
5566 interval: 300,
5567 // max time between the multi-tap taps
5568 time: 250,
5569 // max time of the pointer to be down (like finger on the screen)
5570 threshold: 9,
5571 // a minimal movement is ok, but keep it low
5572 posThreshold: 10
5573 }, options)) || this; // previous time and center,
5574 // used for tap counting
5575
5576 _this.pTime = false;
5577 _this.pCenter = false;
5578 _this._timer = null;
5579 _this._input = null;
5580 _this.count = 0;
5581 return _this;
5582 }
5583
5584 var _proto = TapRecognizer.prototype;
5585
5586 _proto.getTouchAction = function getTouchAction() {
5587 return [TOUCH_ACTION_MANIPULATION];
5588 };
5589
5590 _proto.process = function process(input) {
5591 var _this2 = this;
5592
5593 var options = this.options;
5594 var validPointers = input.pointers.length === options.pointers;
5595 var validMovement = input.distance < options.threshold;
5596 var validTouchTime = input.deltaTime < options.time;
5597 this.reset();
5598
5599 if (input.eventType & INPUT_START && this.count === 0) {
5600 return this.failTimeout();
5601 } // we only allow little movement
5602 // and we've reached an end event, so a tap is possible
5603
5604
5605 if (validMovement && validTouchTime && validPointers) {
5606 if (input.eventType !== INPUT_END) {
5607 return this.failTimeout();
5608 }
5609
5610 var validInterval = this.pTime ? input.timeStamp - this.pTime < options.interval : true;
5611 var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
5612 this.pTime = input.timeStamp;
5613 this.pCenter = input.center;
5614
5615 if (!validMultiTap || !validInterval) {
5616 this.count = 1;
5617 } else {
5618 this.count += 1;
5619 }
5620
5621 this._input = input; // if tap count matches we have recognized it,
5622 // else it has began recognizing...
5623
5624 var tapCount = this.count % options.taps;
5625
5626 if (tapCount === 0) {
5627 // no failing requirements, immediately trigger the tap event
5628 // or wait as long as the multitap interval to trigger
5629 if (!this.hasRequireFailures()) {
5630 return STATE_RECOGNIZED;
5631 } else {
5632 this._timer = setTimeout(function () {
5633 _this2.state = STATE_RECOGNIZED;
5634
5635 _this2.tryEmit();
5636 }, options.interval);
5637 return STATE_BEGAN;
5638 }
5639 }
5640 }
5641
5642 return STATE_FAILED;
5643 };
5644
5645 _proto.failTimeout = function failTimeout() {
5646 var _this3 = this;
5647
5648 this._timer = setTimeout(function () {
5649 _this3.state = STATE_FAILED;
5650 }, this.options.interval);
5651 return STATE_FAILED;
5652 };
5653
5654 _proto.reset = function reset() {
5655 clearTimeout(this._timer);
5656 };
5657
5658 _proto.emit = function emit() {
5659 if (this.state === STATE_RECOGNIZED) {
5660 this._input.tapCount = this.count;
5661 this.manager.emit(this.options.event, this._input);
5662 }
5663 };
5664
5665 return TapRecognizer;
5666}(Recognizer);
5667/**
5668 * @private
5669 * This recognizer is just used as a base for the simple attribute recognizers.
5670 * @constructor
5671 * @extends Recognizer
5672 */
5673
5674
5675var AttrRecognizer = /*#__PURE__*/function (_Recognizer) {
5676 _inheritsLoose(AttrRecognizer, _Recognizer);
5677
5678 function AttrRecognizer(options) {
5679 if (options === void 0) {
5680 options = {};
5681 }
5682
5683 return _Recognizer.call(this, _extends({
5684 pointers: 1
5685 }, options)) || this;
5686 }
5687 /**
5688 * @private
5689 * Used to check if it the recognizer receives valid input, like input.distance > 10.
5690 * @memberof AttrRecognizer
5691 * @param {Object} input
5692 * @returns {Boolean} recognized
5693 */
5694
5695
5696 var _proto = AttrRecognizer.prototype;
5697
5698 _proto.attrTest = function attrTest(input) {
5699 var optionPointers = this.options.pointers;
5700 return optionPointers === 0 || input.pointers.length === optionPointers;
5701 };
5702 /**
5703 * @private
5704 * Process the input and return the state for the recognizer
5705 * @memberof AttrRecognizer
5706 * @param {Object} input
5707 * @returns {*} State
5708 */
5709
5710
5711 _proto.process = function process(input) {
5712 var state = this.state;
5713 var eventType = input.eventType;
5714 var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
5715 var isValid = this.attrTest(input); // on cancel input and we've recognized before, return STATE_CANCELLED
5716
5717 if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
5718 return state | STATE_CANCELLED;
5719 } else if (isRecognized || isValid) {
5720 if (eventType & INPUT_END) {
5721 return state | STATE_ENDED;
5722 } else if (!(state & STATE_BEGAN)) {
5723 return STATE_BEGAN;
5724 }
5725
5726 return state | STATE_CHANGED;
5727 }
5728
5729 return STATE_FAILED;
5730 };
5731
5732 return AttrRecognizer;
5733}(Recognizer);
5734/**
5735 * @private
5736 * direction cons to string
5737 * @param {constant} direction
5738 * @returns {String}
5739 */
5740
5741
5742function directionStr(direction) {
5743 if (direction === DIRECTION_DOWN) {
5744 return 'down';
5745 } else if (direction === DIRECTION_UP) {
5746 return 'up';
5747 } else if (direction === DIRECTION_LEFT) {
5748 return 'left';
5749 } else if (direction === DIRECTION_RIGHT) {
5750 return 'right';
5751 }
5752
5753 return '';
5754}
5755/**
5756 * @private
5757 * Pan
5758 * Recognized when the pointer is down and moved in the allowed direction.
5759 * @constructor
5760 * @extends AttrRecognizer
5761 */
5762
5763
5764var PanRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
5765 _inheritsLoose(PanRecognizer, _AttrRecognizer);
5766
5767 function PanRecognizer(options) {
5768 var _this;
5769
5770 if (options === void 0) {
5771 options = {};
5772 }
5773
5774 _this = _AttrRecognizer.call(this, _extends({
5775 event: 'pan',
5776 threshold: 10,
5777 pointers: 1,
5778 direction: DIRECTION_ALL
5779 }, options)) || this;
5780 _this.pX = null;
5781 _this.pY = null;
5782 return _this;
5783 }
5784
5785 var _proto = PanRecognizer.prototype;
5786
5787 _proto.getTouchAction = function getTouchAction() {
5788 var direction = this.options.direction;
5789 var actions = [];
5790
5791 if (direction & DIRECTION_HORIZONTAL) {
5792 actions.push(TOUCH_ACTION_PAN_Y);
5793 }
5794
5795 if (direction & DIRECTION_VERTICAL) {
5796 actions.push(TOUCH_ACTION_PAN_X);
5797 }
5798
5799 return actions;
5800 };
5801
5802 _proto.directionTest = function directionTest(input) {
5803 var options = this.options;
5804 var hasMoved = true;
5805 var distance = input.distance;
5806 var direction = input.direction;
5807 var x = input.deltaX;
5808 var y = input.deltaY; // lock to axis?
5809
5810 if (!(direction & options.direction)) {
5811 if (options.direction & DIRECTION_HORIZONTAL) {
5812 direction = x === 0 ? DIRECTION_NONE : x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
5813 hasMoved = x !== this.pX;
5814 distance = Math.abs(input.deltaX);
5815 } else {
5816 direction = y === 0 ? DIRECTION_NONE : y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
5817 hasMoved = y !== this.pY;
5818 distance = Math.abs(input.deltaY);
5819 }
5820 }
5821
5822 input.direction = direction;
5823 return hasMoved && distance > options.threshold && direction & options.direction;
5824 };
5825
5826 _proto.attrTest = function attrTest(input) {
5827 return AttrRecognizer.prototype.attrTest.call(this, input) && ( // replace with a super call
5828 this.state & STATE_BEGAN || !(this.state & STATE_BEGAN) && this.directionTest(input));
5829 };
5830
5831 _proto.emit = function emit(input) {
5832 this.pX = input.deltaX;
5833 this.pY = input.deltaY;
5834 var direction = directionStr(input.direction);
5835
5836 if (direction) {
5837 input.additionalEvent = this.options.event + direction;
5838 }
5839
5840 _AttrRecognizer.prototype.emit.call(this, input);
5841 };
5842
5843 return PanRecognizer;
5844}(AttrRecognizer);
5845/**
5846 * @private
5847 * Swipe
5848 * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
5849 * @constructor
5850 * @extends AttrRecognizer
5851 */
5852
5853
5854var SwipeRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
5855 _inheritsLoose(SwipeRecognizer, _AttrRecognizer);
5856
5857 function SwipeRecognizer(options) {
5858 if (options === void 0) {
5859 options = {};
5860 }
5861
5862 return _AttrRecognizer.call(this, _extends({
5863 event: 'swipe',
5864 threshold: 10,
5865 velocity: 0.3,
5866 direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
5867 pointers: 1
5868 }, options)) || this;
5869 }
5870
5871 var _proto = SwipeRecognizer.prototype;
5872
5873 _proto.getTouchAction = function getTouchAction() {
5874 return PanRecognizer.prototype.getTouchAction.call(this);
5875 };
5876
5877 _proto.attrTest = function attrTest(input) {
5878 var direction = this.options.direction;
5879 var velocity;
5880
5881 if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
5882 velocity = input.overallVelocity;
5883 } else if (direction & DIRECTION_HORIZONTAL) {
5884 velocity = input.overallVelocityX;
5885 } else if (direction & DIRECTION_VERTICAL) {
5886 velocity = input.overallVelocityY;
5887 }
5888
5889 return _AttrRecognizer.prototype.attrTest.call(this, input) && direction & input.offsetDirection && input.distance > this.options.threshold && input.maxPointers === this.options.pointers && abs$1(velocity) > this.options.velocity && input.eventType & INPUT_END;
5890 };
5891
5892 _proto.emit = function emit(input) {
5893 var direction = directionStr(input.offsetDirection);
5894
5895 if (direction) {
5896 this.manager.emit(this.options.event + direction, input);
5897 }
5898
5899 this.manager.emit(this.options.event, input);
5900 };
5901
5902 return SwipeRecognizer;
5903}(AttrRecognizer);
5904/**
5905 * @private
5906 * Pinch
5907 * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
5908 * @constructor
5909 * @extends AttrRecognizer
5910 */
5911
5912
5913var PinchRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
5914 _inheritsLoose(PinchRecognizer, _AttrRecognizer);
5915
5916 function PinchRecognizer(options) {
5917 if (options === void 0) {
5918 options = {};
5919 }
5920
5921 return _AttrRecognizer.call(this, _extends({
5922 event: 'pinch',
5923 threshold: 0,
5924 pointers: 2
5925 }, options)) || this;
5926 }
5927
5928 var _proto = PinchRecognizer.prototype;
5929
5930 _proto.getTouchAction = function getTouchAction() {
5931 return [TOUCH_ACTION_NONE];
5932 };
5933
5934 _proto.attrTest = function attrTest(input) {
5935 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
5936 };
5937
5938 _proto.emit = function emit(input) {
5939 if (input.scale !== 1) {
5940 var inOut = input.scale < 1 ? 'in' : 'out';
5941 input.additionalEvent = this.options.event + inOut;
5942 }
5943
5944 _AttrRecognizer.prototype.emit.call(this, input);
5945 };
5946
5947 return PinchRecognizer;
5948}(AttrRecognizer);
5949/**
5950 * @private
5951 * Rotate
5952 * Recognized when two or more pointer are moving in a circular motion.
5953 * @constructor
5954 * @extends AttrRecognizer
5955 */
5956
5957
5958var RotateRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
5959 _inheritsLoose(RotateRecognizer, _AttrRecognizer);
5960
5961 function RotateRecognizer(options) {
5962 if (options === void 0) {
5963 options = {};
5964 }
5965
5966 return _AttrRecognizer.call(this, _extends({
5967 event: 'rotate',
5968 threshold: 0,
5969 pointers: 2
5970 }, options)) || this;
5971 }
5972
5973 var _proto = RotateRecognizer.prototype;
5974
5975 _proto.getTouchAction = function getTouchAction() {
5976 return [TOUCH_ACTION_NONE];
5977 };
5978
5979 _proto.attrTest = function attrTest(input) {
5980 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
5981 };
5982
5983 return RotateRecognizer;
5984}(AttrRecognizer);
5985/**
5986 * @private
5987 * Press
5988 * Recognized when the pointer is down for x ms without any movement.
5989 * @constructor
5990 * @extends Recognizer
5991 */
5992
5993
5994var PressRecognizer = /*#__PURE__*/function (_Recognizer) {
5995 _inheritsLoose(PressRecognizer, _Recognizer);
5996
5997 function PressRecognizer(options) {
5998 var _this;
5999
6000 if (options === void 0) {
6001 options = {};
6002 }
6003
6004 _this = _Recognizer.call(this, _extends({
6005 event: 'press',
6006 pointers: 1,
6007 time: 251,
6008 // minimal time of the pointer to be pressed
6009 threshold: 9
6010 }, options)) || this;
6011 _this._timer = null;
6012 _this._input = null;
6013 return _this;
6014 }
6015
6016 var _proto = PressRecognizer.prototype;
6017
6018 _proto.getTouchAction = function getTouchAction() {
6019 return [TOUCH_ACTION_AUTO];
6020 };
6021
6022 _proto.process = function process(input) {
6023 var _this2 = this;
6024
6025 var options = this.options;
6026 var validPointers = input.pointers.length === options.pointers;
6027 var validMovement = input.distance < options.threshold;
6028 var validTime = input.deltaTime > options.time;
6029 this._input = input; // we only allow little movement
6030 // and we've reached an end event, so a tap is possible
6031
6032 if (!validMovement || !validPointers || input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime) {
6033 this.reset();
6034 } else if (input.eventType & INPUT_START) {
6035 this.reset();
6036 this._timer = setTimeout(function () {
6037 _this2.state = STATE_RECOGNIZED;
6038
6039 _this2.tryEmit();
6040 }, options.time);
6041 } else if (input.eventType & INPUT_END) {
6042 return STATE_RECOGNIZED;
6043 }
6044
6045 return STATE_FAILED;
6046 };
6047
6048 _proto.reset = function reset() {
6049 clearTimeout(this._timer);
6050 };
6051
6052 _proto.emit = function emit(input) {
6053 if (this.state !== STATE_RECOGNIZED) {
6054 return;
6055 }
6056
6057 if (input && input.eventType & INPUT_END) {
6058 this.manager.emit(this.options.event + "up", input);
6059 } else {
6060 this._input.timeStamp = now();
6061 this.manager.emit(this.options.event, this._input);
6062 }
6063 };
6064
6065 return PressRecognizer;
6066}(Recognizer);
6067
6068var defaults = {
6069 /**
6070 * @private
6071 * set if DOM events are being triggered.
6072 * But this is slower and unused by simple implementations, so disabled by default.
6073 * @type {Boolean}
6074 * @default false
6075 */
6076 domEvents: false,
6077
6078 /**
6079 * @private
6080 * The value for the touchAction property/fallback.
6081 * When set to `compute` it will magically set the correct value based on the added recognizers.
6082 * @type {String}
6083 * @default compute
6084 */
6085 touchAction: TOUCH_ACTION_COMPUTE,
6086
6087 /**
6088 * @private
6089 * @type {Boolean}
6090 * @default true
6091 */
6092 enable: true,
6093
6094 /**
6095 * @private
6096 * EXPERIMENTAL FEATURE -- can be removed/changed
6097 * Change the parent input target element.
6098 * If Null, then it is being set the to main element.
6099 * @type {Null|EventTarget}
6100 * @default null
6101 */
6102 inputTarget: null,
6103
6104 /**
6105 * @private
6106 * force an input class
6107 * @type {Null|Function}
6108 * @default null
6109 */
6110 inputClass: null,
6111
6112 /**
6113 * @private
6114 * Some CSS properties can be used to improve the working of Hammer.
6115 * Add them to this method and they will be set when creating a new Manager.
6116 * @namespace
6117 */
6118 cssProps: {
6119 /**
6120 * @private
6121 * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
6122 * @type {String}
6123 * @default 'none'
6124 */
6125 userSelect: "none",
6126
6127 /**
6128 * @private
6129 * Disable the Windows Phone grippers when pressing an element.
6130 * @type {String}
6131 * @default 'none'
6132 */
6133 touchSelect: "none",
6134
6135 /**
6136 * @private
6137 * Disables the default callout shown when you touch and hold a touch target.
6138 * On iOS, when you touch and hold a touch target such as a link, Safari displays
6139 * a callout containing information about the link. This property allows you to disable that callout.
6140 * @type {String}
6141 * @default 'none'
6142 */
6143 touchCallout: "none",
6144
6145 /**
6146 * @private
6147 * Specifies whether zooming is enabled. Used by IE10>
6148 * @type {String}
6149 * @default 'none'
6150 */
6151 contentZooming: "none",
6152
6153 /**
6154 * @private
6155 * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
6156 * @type {String}
6157 * @default 'none'
6158 */
6159 userDrag: "none",
6160
6161 /**
6162 * @private
6163 * Overrides the highlight color shown when the user taps a link or a JavaScript
6164 * clickable element in iOS. This property obeys the alpha value, if specified.
6165 * @type {String}
6166 * @default 'rgba(0,0,0,0)'
6167 */
6168 tapHighlightColor: "rgba(0,0,0,0)"
6169 }
6170};
6171/**
6172 * @private
6173 * Default recognizer setup when calling `Hammer()`
6174 * When creating a new Manager these will be skipped.
6175 * This is separated with other defaults because of tree-shaking.
6176 * @type {Array}
6177 */
6178
6179var preset = [[RotateRecognizer, {
6180 enable: false
6181}], [PinchRecognizer, {
6182 enable: false
6183}, ['rotate']], [SwipeRecognizer, {
6184 direction: DIRECTION_HORIZONTAL
6185}], [PanRecognizer, {
6186 direction: DIRECTION_HORIZONTAL
6187}, ['swipe']], [TapRecognizer], [TapRecognizer, {
6188 event: 'doubletap',
6189 taps: 2
6190}, ['tap']], [PressRecognizer]];
6191var STOP = 1;
6192var FORCED_STOP = 2;
6193/**
6194 * @private
6195 * add/remove the css properties as defined in manager.options.cssProps
6196 * @param {Manager} manager
6197 * @param {Boolean} add
6198 */
6199
6200function toggleCssProps(manager, add) {
6201 var element = manager.element;
6202
6203 if (!element.style) {
6204 return;
6205 }
6206
6207 var prop;
6208 each(manager.options.cssProps, function (value, name) {
6209 prop = prefixed(element.style, name);
6210
6211 if (add) {
6212 manager.oldCssProps[prop] = element.style[prop];
6213 element.style[prop] = value;
6214 } else {
6215 element.style[prop] = manager.oldCssProps[prop] || "";
6216 }
6217 });
6218
6219 if (!add) {
6220 manager.oldCssProps = {};
6221 }
6222}
6223/**
6224 * @private
6225 * trigger dom event
6226 * @param {String} event
6227 * @param {Object} data
6228 */
6229
6230
6231function triggerDomEvent(event, data) {
6232 var gestureEvent = document.createEvent("Event");
6233 gestureEvent.initEvent(event, true, true);
6234 gestureEvent.gesture = data;
6235 data.target.dispatchEvent(gestureEvent);
6236}
6237/**
6238* @private
6239 * Manager
6240 * @param {HTMLElement} element
6241 * @param {Object} [options]
6242 * @constructor
6243 */
6244
6245
6246var Manager = /*#__PURE__*/function () {
6247 function Manager(element, options) {
6248 var _this = this;
6249
6250 this.options = assign$1({}, defaults, options || {});
6251 this.options.inputTarget = this.options.inputTarget || element;
6252 this.handlers = {};
6253 this.session = {};
6254 this.recognizers = [];
6255 this.oldCssProps = {};
6256 this.element = element;
6257 this.input = createInputInstance(this);
6258 this.touchAction = new TouchAction(this, this.options.touchAction);
6259 toggleCssProps(this, true);
6260 each(this.options.recognizers, function (item) {
6261 var recognizer = _this.add(new item[0](item[1]));
6262
6263 item[2] && recognizer.recognizeWith(item[2]);
6264 item[3] && recognizer.requireFailure(item[3]);
6265 }, this);
6266 }
6267 /**
6268 * @private
6269 * set options
6270 * @param {Object} options
6271 * @returns {Manager}
6272 */
6273
6274
6275 var _proto = Manager.prototype;
6276
6277 _proto.set = function set(options) {
6278 assign$1(this.options, options); // Options that need a little more setup
6279
6280 if (options.touchAction) {
6281 this.touchAction.update();
6282 }
6283
6284 if (options.inputTarget) {
6285 // Clean up existing event listeners and reinitialize
6286 this.input.destroy();
6287 this.input.target = options.inputTarget;
6288 this.input.init();
6289 }
6290
6291 return this;
6292 };
6293 /**
6294 * @private
6295 * stop recognizing for this session.
6296 * This session will be discarded, when a new [input]start event is fired.
6297 * When forced, the recognizer cycle is stopped immediately.
6298 * @param {Boolean} [force]
6299 */
6300
6301
6302 _proto.stop = function stop(force) {
6303 this.session.stopped = force ? FORCED_STOP : STOP;
6304 };
6305 /**
6306 * @private
6307 * run the recognizers!
6308 * called by the inputHandler function on every movement of the pointers (touches)
6309 * it walks through all the recognizers and tries to detect the gesture that is being made
6310 * @param {Object} inputData
6311 */
6312
6313
6314 _proto.recognize = function recognize(inputData) {
6315 var session = this.session;
6316
6317 if (session.stopped) {
6318 return;
6319 } // run the touch-action polyfill
6320
6321
6322 this.touchAction.preventDefaults(inputData);
6323 var recognizer;
6324 var recognizers = this.recognizers; // this holds the recognizer that is being recognized.
6325 // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
6326 // if no recognizer is detecting a thing, it is set to `null`
6327
6328 var curRecognizer = session.curRecognizer; // reset when the last recognizer is recognized
6329 // or when we're in a new session
6330
6331 if (!curRecognizer || curRecognizer && curRecognizer.state & STATE_RECOGNIZED) {
6332 session.curRecognizer = null;
6333 curRecognizer = null;
6334 }
6335
6336 var i = 0;
6337
6338 while (i < recognizers.length) {
6339 recognizer = recognizers[i]; // find out if we are allowed try to recognize the input for this one.
6340 // 1. allow if the session is NOT forced stopped (see the .stop() method)
6341 // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
6342 // that is being recognized.
6343 // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
6344 // this can be setup with the `recognizeWith()` method on the recognizer.
6345
6346 if (session.stopped !== FORCED_STOP && ( // 1
6347 !curRecognizer || recognizer === curRecognizer || // 2
6348 recognizer.canRecognizeWith(curRecognizer))) {
6349 // 3
6350 recognizer.recognize(inputData);
6351 } else {
6352 recognizer.reset();
6353 } // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
6354 // current active recognizer. but only if we don't already have an active recognizer
6355
6356
6357 if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
6358 session.curRecognizer = recognizer;
6359 curRecognizer = recognizer;
6360 }
6361
6362 i++;
6363 }
6364 };
6365 /**
6366 * @private
6367 * get a recognizer by its event name.
6368 * @param {Recognizer|String} recognizer
6369 * @returns {Recognizer|Null}
6370 */
6371
6372
6373 _proto.get = function get(recognizer) {
6374 if (recognizer instanceof Recognizer) {
6375 return recognizer;
6376 }
6377
6378 var recognizers = this.recognizers;
6379
6380 for (var i = 0; i < recognizers.length; i++) {
6381 if (recognizers[i].options.event === recognizer) {
6382 return recognizers[i];
6383 }
6384 }
6385
6386 return null;
6387 };
6388 /**
6389 * @private add a recognizer to the manager
6390 * existing recognizers with the same event name will be removed
6391 * @param {Recognizer} recognizer
6392 * @returns {Recognizer|Manager}
6393 */
6394
6395
6396 _proto.add = function add(recognizer) {
6397 if (invokeArrayArg(recognizer, "add", this)) {
6398 return this;
6399 } // remove existing
6400
6401
6402 var existing = this.get(recognizer.options.event);
6403
6404 if (existing) {
6405 this.remove(existing);
6406 }
6407
6408 this.recognizers.push(recognizer);
6409 recognizer.manager = this;
6410 this.touchAction.update();
6411 return recognizer;
6412 };
6413 /**
6414 * @private
6415 * remove a recognizer by name or instance
6416 * @param {Recognizer|String} recognizer
6417 * @returns {Manager}
6418 */
6419
6420
6421 _proto.remove = function remove(recognizer) {
6422 if (invokeArrayArg(recognizer, "remove", this)) {
6423 return this;
6424 }
6425
6426 var targetRecognizer = this.get(recognizer); // let's make sure this recognizer exists
6427
6428 if (recognizer) {
6429 var recognizers = this.recognizers;
6430 var index = inArray(recognizers, targetRecognizer);
6431
6432 if (index !== -1) {
6433 recognizers.splice(index, 1);
6434 this.touchAction.update();
6435 }
6436 }
6437
6438 return this;
6439 };
6440 /**
6441 * @private
6442 * bind event
6443 * @param {String} events
6444 * @param {Function} handler
6445 * @returns {EventEmitter} this
6446 */
6447
6448
6449 _proto.on = function on(events, handler) {
6450 if (events === undefined || handler === undefined) {
6451 return this;
6452 }
6453
6454 var handlers = this.handlers;
6455 each(splitStr(events), function (event) {
6456 handlers[event] = handlers[event] || [];
6457 handlers[event].push(handler);
6458 });
6459 return this;
6460 };
6461 /**
6462 * @private unbind event, leave emit blank to remove all handlers
6463 * @param {String} events
6464 * @param {Function} [handler]
6465 * @returns {EventEmitter} this
6466 */
6467
6468
6469 _proto.off = function off(events, handler) {
6470 if (events === undefined) {
6471 return this;
6472 }
6473
6474 var handlers = this.handlers;
6475 each(splitStr(events), function (event) {
6476 if (!handler) {
6477 delete handlers[event];
6478 } else {
6479 handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
6480 }
6481 });
6482 return this;
6483 };
6484 /**
6485 * @private emit event to the listeners
6486 * @param {String} event
6487 * @param {Object} data
6488 */
6489
6490
6491 _proto.emit = function emit(event, data) {
6492 // we also want to trigger dom events
6493 if (this.options.domEvents) {
6494 triggerDomEvent(event, data);
6495 } // no handlers, so skip it all
6496
6497
6498 var handlers = this.handlers[event] && this.handlers[event].slice();
6499
6500 if (!handlers || !handlers.length) {
6501 return;
6502 }
6503
6504 data.type = event;
6505
6506 data.preventDefault = function () {
6507 data.srcEvent.preventDefault();
6508 };
6509
6510 var i = 0;
6511
6512 while (i < handlers.length) {
6513 handlers[i](data);
6514 i++;
6515 }
6516 };
6517 /**
6518 * @private
6519 * destroy the manager and unbinds all events
6520 * it doesn't unbind dom events, that is the user own responsibility
6521 */
6522
6523
6524 _proto.destroy = function destroy() {
6525 this.element && toggleCssProps(this, false);
6526 this.handlers = {};
6527 this.session = {};
6528 this.input.destroy();
6529 this.element = null;
6530 };
6531
6532 return Manager;
6533}();
6534
6535var SINGLE_TOUCH_INPUT_MAP = {
6536 touchstart: INPUT_START,
6537 touchmove: INPUT_MOVE,
6538 touchend: INPUT_END,
6539 touchcancel: INPUT_CANCEL
6540};
6541var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
6542var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
6543/**
6544 * @private
6545 * Touch events input
6546 * @constructor
6547 * @extends Input
6548 */
6549
6550var SingleTouchInput = /*#__PURE__*/function (_Input) {
6551 _inheritsLoose(SingleTouchInput, _Input);
6552
6553 function SingleTouchInput() {
6554 var _this;
6555
6556 var proto = SingleTouchInput.prototype;
6557 proto.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
6558 proto.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
6559 _this = _Input.apply(this, arguments) || this;
6560 _this.started = false;
6561 return _this;
6562 }
6563
6564 var _proto = SingleTouchInput.prototype;
6565
6566 _proto.handler = function handler(ev) {
6567 var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; // should we handle the touch events?
6568
6569 if (type === INPUT_START) {
6570 this.started = true;
6571 }
6572
6573 if (!this.started) {
6574 return;
6575 }
6576
6577 var touches = normalizeSingleTouches.call(this, ev, type); // when done, reset the started state
6578
6579 if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
6580 this.started = false;
6581 }
6582
6583 this.callback(this.manager, type, {
6584 pointers: touches[0],
6585 changedPointers: touches[1],
6586 pointerType: INPUT_TYPE_TOUCH,
6587 srcEvent: ev
6588 });
6589 };
6590
6591 return SingleTouchInput;
6592}(Input);
6593
6594function normalizeSingleTouches(ev, type) {
6595 var all = toArray$1(ev.touches);
6596 var changed = toArray$1(ev.changedTouches);
6597
6598 if (type & (INPUT_END | INPUT_CANCEL)) {
6599 all = uniqueArray(all.concat(changed), 'identifier', true);
6600 }
6601
6602 return [all, changed];
6603}
6604/**
6605 * @private
6606 * wrap a method with a deprecation warning and stack trace
6607 * @param {Function} method
6608 * @param {String} name
6609 * @param {String} message
6610 * @returns {Function} A new function wrapping the supplied method.
6611 */
6612
6613
6614function deprecate(method, name, message) {
6615 var deprecationMessage = "DEPRECATED METHOD: " + name + "\n" + message + " AT \n";
6616 return function () {
6617 var e = new Error('get-stack-trace');
6618 var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '').replace(/^\s+at\s+/gm, '').replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
6619 var log = window.console && (window.console.warn || window.console.log);
6620
6621 if (log) {
6622 log.call(window.console, deprecationMessage, stack);
6623 }
6624
6625 return method.apply(this, arguments);
6626 };
6627}
6628/**
6629 * @private
6630 * extend object.
6631 * means that properties in dest will be overwritten by the ones in src.
6632 * @param {Object} dest
6633 * @param {Object} src
6634 * @param {Boolean} [merge=false]
6635 * @returns {Object} dest
6636 */
6637
6638
6639var extend$1 = deprecate(function (dest, src, merge) {
6640 var keys = Object.keys(src);
6641 var i = 0;
6642
6643 while (i < keys.length) {
6644 if (!merge || merge && dest[keys[i]] === undefined) {
6645 dest[keys[i]] = src[keys[i]];
6646 }
6647
6648 i++;
6649 }
6650
6651 return dest;
6652}, 'extend', 'Use `assign`.');
6653/**
6654 * @private
6655 * merge the values from src in the dest.
6656 * means that properties that exist in dest will not be overwritten by src
6657 * @param {Object} dest
6658 * @param {Object} src
6659 * @returns {Object} dest
6660 */
6661
6662var merge$2 = deprecate(function (dest, src) {
6663 return extend$1(dest, src, true);
6664}, 'merge', 'Use `assign`.');
6665/**
6666 * @private
6667 * simple class inheritance
6668 * @param {Function} child
6669 * @param {Function} base
6670 * @param {Object} [properties]
6671 */
6672
6673function inherit(child, base, properties) {
6674 var baseP = base.prototype;
6675 var childP;
6676 childP = child.prototype = Object.create(baseP);
6677 childP.constructor = child;
6678 childP._super = baseP;
6679
6680 if (properties) {
6681 assign$1(childP, properties);
6682 }
6683}
6684/**
6685 * @private
6686 * simple function bind
6687 * @param {Function} fn
6688 * @param {Object} context
6689 * @returns {Function}
6690 */
6691
6692
6693function bindFn(fn, context) {
6694 return function boundFn() {
6695 return fn.apply(context, arguments);
6696 };
6697}
6698/**
6699 * @private
6700 * Simple way to create a manager with a default set of recognizers.
6701 * @param {HTMLElement} element
6702 * @param {Object} [options]
6703 * @constructor
6704 */
6705
6706
6707var Hammer$2 = /*#__PURE__*/function () {
6708 var Hammer =
6709 /**
6710 * @private
6711 * @const {string}
6712 */
6713 function Hammer(element, options) {
6714 if (options === void 0) {
6715 options = {};
6716 }
6717
6718 return new Manager(element, _extends({
6719 recognizers: preset.concat()
6720 }, options));
6721 };
6722
6723 Hammer.VERSION = "2.0.17-rc";
6724 Hammer.DIRECTION_ALL = DIRECTION_ALL;
6725 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
6726 Hammer.DIRECTION_LEFT = DIRECTION_LEFT;
6727 Hammer.DIRECTION_RIGHT = DIRECTION_RIGHT;
6728 Hammer.DIRECTION_UP = DIRECTION_UP;
6729 Hammer.DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL;
6730 Hammer.DIRECTION_VERTICAL = DIRECTION_VERTICAL;
6731 Hammer.DIRECTION_NONE = DIRECTION_NONE;
6732 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
6733 Hammer.INPUT_START = INPUT_START;
6734 Hammer.INPUT_MOVE = INPUT_MOVE;
6735 Hammer.INPUT_END = INPUT_END;
6736 Hammer.INPUT_CANCEL = INPUT_CANCEL;
6737 Hammer.STATE_POSSIBLE = STATE_POSSIBLE;
6738 Hammer.STATE_BEGAN = STATE_BEGAN;
6739 Hammer.STATE_CHANGED = STATE_CHANGED;
6740 Hammer.STATE_ENDED = STATE_ENDED;
6741 Hammer.STATE_RECOGNIZED = STATE_RECOGNIZED;
6742 Hammer.STATE_CANCELLED = STATE_CANCELLED;
6743 Hammer.STATE_FAILED = STATE_FAILED;
6744 Hammer.Manager = Manager;
6745 Hammer.Input = Input;
6746 Hammer.TouchAction = TouchAction;
6747 Hammer.TouchInput = TouchInput;
6748 Hammer.MouseInput = MouseInput;
6749 Hammer.PointerEventInput = PointerEventInput;
6750 Hammer.TouchMouseInput = TouchMouseInput;
6751 Hammer.SingleTouchInput = SingleTouchInput;
6752 Hammer.Recognizer = Recognizer;
6753 Hammer.AttrRecognizer = AttrRecognizer;
6754 Hammer.Tap = TapRecognizer;
6755 Hammer.Pan = PanRecognizer;
6756 Hammer.Swipe = SwipeRecognizer;
6757 Hammer.Pinch = PinchRecognizer;
6758 Hammer.Rotate = RotateRecognizer;
6759 Hammer.Press = PressRecognizer;
6760 Hammer.on = addEventListeners;
6761 Hammer.off = removeEventListeners;
6762 Hammer.each = each;
6763 Hammer.merge = merge$2;
6764 Hammer.extend = extend$1;
6765 Hammer.bindFn = bindFn;
6766 Hammer.assign = assign$1;
6767 Hammer.inherit = inherit;
6768 Hammer.bindFn = bindFn;
6769 Hammer.prefixed = prefixed;
6770 Hammer.toArray = toArray$1;
6771 Hammer.inArray = inArray;
6772 Hammer.uniqueArray = uniqueArray;
6773 Hammer.splitStr = splitStr;
6774 Hammer.boolOrFn = boolOrFn;
6775 Hammer.hasParent = hasParent$1;
6776 Hammer.addEventListeners = addEventListeners;
6777 Hammer.removeEventListeners = removeEventListeners;
6778 Hammer.defaults = assign$1({}, defaults, {
6779 preset: preset
6780 });
6781 return Hammer;
6782}(); // style loader but by script tag, not by the loader.
6783var RealHammer = Hammer$2;
6784
6785function ownKeys$5(object, enumerableOnly) { var keys = keys$3(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
6786
6787function _objectSpread$5(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context22; forEach$2(_context22 = ownKeys$5(Object(source), true)).call(_context22, function (key) { _defineProperty(target, key, source[key]); }); } else if (getOwnPropertyDescriptors) { defineProperties(target, getOwnPropertyDescriptors(source)); } else { var _context23; forEach$2(_context23 = ownKeys$5(Object(source))).call(_context23, function (key) { defineProperty$5(target, key, getOwnPropertyDescriptor$2(source, key)); }); } } return target; }
6788
6789function _createForOfIteratorHelper$8(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (isArray(o) || (it = _unsupportedIterableToArray$8(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
6790
6791function _unsupportedIterableToArray$8(o, minLen) { var _context21; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$8(o, minLen); var n = slice$1(_context21 = Object.prototype.toString.call(o)).call(_context21, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from_1$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$8(o, minLen); }
6792
6793function _arrayLikeToArray$8(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
6794/**
6795 * Use this symbol to delete properies in deepObjectAssign.
6796 */
6797
6798var DELETE = symbol("DELETE");
6799/**
6800 * Pure version of deepObjectAssign, it doesn't modify any of it's arguments.
6801 *
6802 * @param base - The base object that fullfils the whole interface T.
6803 * @param updates - Updates that may change or delete props.
6804 *
6805 * @returns A brand new instance with all the supplied objects deeply merged.
6806 */
6807
6808
6809function pureDeepObjectAssign(base) {
6810 var _context;
6811
6812 for (var _len = arguments.length, updates = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
6813 updates[_key - 1] = arguments[_key];
6814 }
6815
6816 return deepObjectAssign.apply(void 0, concat(_context = [{}, base]).call(_context, updates));
6817}
6818/**
6819 * Deep version of object assign with additional deleting by the DELETE symbol.
6820 *
6821 * @param values - Objects to be deeply merged.
6822 *
6823 * @returns The first object from values.
6824 */
6825
6826
6827function deepObjectAssign() {
6828 var merged = deepObjectAssignNonentry.apply(void 0, arguments);
6829 stripDelete(merged);
6830 return merged;
6831}
6832/**
6833 * Deep version of object assign with additional deleting by the DELETE symbol.
6834 *
6835 * @remarks
6836 * This doesn't strip the DELETE symbols so they may end up in the final object.
6837 *
6838 * @param values - Objects to be deeply merged.
6839 *
6840 * @returns The first object from values.
6841 */
6842
6843
6844function deepObjectAssignNonentry() {
6845 for (var _len2 = arguments.length, values = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
6846 values[_key2] = arguments[_key2];
6847 }
6848
6849 if (values.length < 2) {
6850 return values[0];
6851 } else if (values.length > 2) {
6852 var _context2;
6853
6854 return deepObjectAssignNonentry.apply(void 0, concat(_context2 = [deepObjectAssign(values[0], values[1])]).call(_context2, _toConsumableArray(slice$1(values).call(values, 2))));
6855 }
6856
6857 var a = values[0];
6858 var b = values[1];
6859
6860 var _iterator = _createForOfIteratorHelper$8(ownKeys$6(b)),
6861 _step;
6862
6863 try {
6864 for (_iterator.s(); !(_step = _iterator.n()).done;) {
6865 var prop = _step.value;
6866 if (!Object.prototype.propertyIsEnumerable.call(b, prop)) ;else if (b[prop] === DELETE) {
6867 delete a[prop];
6868 } else if (a[prop] !== null && b[prop] !== null && _typeof(a[prop]) === "object" && _typeof(b[prop]) === "object" && !isArray(a[prop]) && !isArray(b[prop])) {
6869 a[prop] = deepObjectAssignNonentry(a[prop], b[prop]);
6870 } else {
6871 a[prop] = clone(b[prop]);
6872 }
6873 }
6874 } catch (err) {
6875 _iterator.e(err);
6876 } finally {
6877 _iterator.f();
6878 }
6879
6880 return a;
6881}
6882/**
6883 * Deep clone given object or array. In case of primitive simply return.
6884 *
6885 * @param a - Anything.
6886 *
6887 * @returns Deep cloned object/array or unchanged a.
6888 */
6889
6890
6891function clone(a) {
6892 if (isArray(a)) {
6893 return map$3(a).call(a, function (value) {
6894 return clone(value);
6895 });
6896 } else if (_typeof(a) === "object" && a !== null) {
6897 return deepObjectAssignNonentry({}, a);
6898 } else {
6899 return a;
6900 }
6901}
6902/**
6903 * Strip DELETE from given object.
6904 *
6905 * @param a - Object which may contain DELETE but won't after this is executed.
6906 */
6907
6908
6909function stripDelete(a) {
6910 for (var _i = 0, _Object$keys = keys$3(a); _i < _Object$keys.length; _i++) {
6911 var prop = _Object$keys[_i];
6912
6913 if (a[prop] === DELETE) {
6914 delete a[prop];
6915 } else if (_typeof(a[prop]) === "object" && a[prop] !== null) {
6916 stripDelete(a[prop]);
6917 }
6918 }
6919}
6920/**
6921 * Seedable, fast and reasonably good (not crypto but more than okay for our
6922 * needs) random number generator.
6923 *
6924 * @remarks
6925 * Adapted from {@link https://web.archive.org/web/20110429100736/http://baagoe.com:80/en/RandomMusings/javascript}.
6926 * Original algorithm created by Johannes Baagøe \<baagoe\@baagoe.com\> in 2010.
6927 */
6928
6929/**
6930 * Create a seeded pseudo random generator based on Alea by Johannes Baagøe.
6931 *
6932 * @param seed - All supplied arguments will be used as a seed. In case nothing
6933 * is supplied the current time will be used to seed the generator.
6934 *
6935 * @returns A ready to use seeded generator.
6936 */
6937
6938
6939function Alea() {
6940 for (var _len3 = arguments.length, seed = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
6941 seed[_key3] = arguments[_key3];
6942 }
6943
6944 return AleaImplementation(seed.length ? seed : [now$1()]);
6945}
6946/**
6947 * An implementation of [[Alea]] without user input validation.
6948 *
6949 * @param seed - The data that will be used to seed the generator.
6950 *
6951 * @returns A ready to use seeded generator.
6952 */
6953
6954
6955function AleaImplementation(seed) {
6956 var _mashSeed = mashSeed(seed),
6957 _mashSeed2 = _slicedToArray(_mashSeed, 3),
6958 s0 = _mashSeed2[0],
6959 s1 = _mashSeed2[1],
6960 s2 = _mashSeed2[2];
6961
6962 var c = 1;
6963
6964 var random = function random() {
6965 var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
6966
6967 s0 = s1;
6968 s1 = s2;
6969 return s2 = t - (c = t | 0);
6970 };
6971
6972 random.uint32 = function () {
6973 return random() * 0x100000000;
6974 }; // 2^32
6975
6976
6977 random.fract53 = function () {
6978 return random() + (random() * 0x200000 | 0) * 1.1102230246251565e-16;
6979 }; // 2^-53
6980
6981
6982 random.algorithm = "Alea";
6983 random.seed = seed;
6984 random.version = "0.9";
6985 return random;
6986}
6987/**
6988 * Turn arbitrary data into values [[AleaImplementation]] can use to generate
6989 * random numbers.
6990 *
6991 * @param seed - Arbitrary data that will be used as the seed.
6992 *
6993 * @returns Three numbers to use as initial values for [[AleaImplementation]].
6994 */
6995
6996
6997function mashSeed() {
6998 var mash = Mash();
6999 var s0 = mash(" ");
7000 var s1 = mash(" ");
7001 var s2 = mash(" ");
7002
7003 for (var i = 0; i < arguments.length; i++) {
7004 s0 -= mash(i < 0 || arguments.length <= i ? undefined : arguments[i]);
7005
7006 if (s0 < 0) {
7007 s0 += 1;
7008 }
7009
7010 s1 -= mash(i < 0 || arguments.length <= i ? undefined : arguments[i]);
7011
7012 if (s1 < 0) {
7013 s1 += 1;
7014 }
7015
7016 s2 -= mash(i < 0 || arguments.length <= i ? undefined : arguments[i]);
7017
7018 if (s2 < 0) {
7019 s2 += 1;
7020 }
7021 }
7022
7023 return [s0, s1, s2];
7024}
7025/**
7026 * Create a new mash function.
7027 *
7028 * @returns A nonpure function that takes arbitrary [[Mashable]] data and turns
7029 * them into numbers.
7030 */
7031
7032
7033function Mash() {
7034 var n = 0xefc8249d;
7035 return function (data) {
7036 var string = data.toString();
7037
7038 for (var i = 0; i < string.length; i++) {
7039 n += string.charCodeAt(i);
7040 var h = 0.02519603282416938 * n;
7041 n = h >>> 0;
7042 h -= n;
7043 h *= n;
7044 n = h >>> 0;
7045 h -= n;
7046 n += h * 0x100000000; // 2^32
7047 }
7048
7049 return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
7050 };
7051}
7052/**
7053 * Setup a mock hammer.js object, for unit testing.
7054 *
7055 * Inspiration: https://github.com/uber/deck.gl/pull/658
7056 *
7057 * @returns {{on: noop, off: noop, destroy: noop, emit: noop, get: get}}
7058 */
7059
7060
7061function hammerMock() {
7062 var noop = function noop() {};
7063
7064 return {
7065 on: noop,
7066 off: noop,
7067 destroy: noop,
7068 emit: noop,
7069 get: function get() {
7070 return {
7071 set: noop
7072 };
7073 }
7074 };
7075}
7076
7077var Hammer = typeof window !== "undefined" ? window.Hammer || RealHammer : function () {
7078 // hammer.js is only available in a browser, not in node.js. Replacing it with a mock object.
7079 return hammerMock();
7080};
7081/**
7082 * Turn an element into an clickToUse element.
7083 * When not active, the element has a transparent overlay. When the overlay is
7084 * clicked, the mode is changed to active.
7085 * When active, the element is displayed with a blue border around it, and
7086 * the interactive contents of the element can be used. When clicked outside
7087 * the element, the elements mode is changed to inactive.
7088 *
7089 * @param {Element} container
7090 * @class Activator
7091 */
7092
7093function Activator(container) {
7094 var _this = this,
7095 _context3;
7096
7097 this._cleanupQueue = [];
7098 this.active = false;
7099 this._dom = {
7100 container: container,
7101 overlay: document.createElement("div")
7102 };
7103
7104 this._dom.overlay.classList.add("vis-overlay");
7105
7106 this._dom.container.appendChild(this._dom.overlay);
7107
7108 this._cleanupQueue.push(function () {
7109 _this._dom.overlay.parentNode.removeChild(_this._dom.overlay);
7110 });
7111
7112 var hammer = Hammer(this._dom.overlay);
7113 hammer.on("tap", bind(_context3 = this._onTapOverlay).call(_context3, this));
7114
7115 this._cleanupQueue.push(function () {
7116 hammer.destroy(); // FIXME: cleaning up hammer instances doesn't work (Timeline not removed
7117 // from memory)
7118 }); // block all touch events (except tap)
7119
7120
7121 var events = ["tap", "doubletap", "press", "pinch", "pan", "panstart", "panmove", "panend"];
7122
7123 forEach$2(events).call(events, function (event) {
7124 hammer.on(event, function (event) {
7125 event.srcEvent.stopPropagation();
7126 });
7127 }); // attach a click event to the window, in order to deactivate when clicking outside the timeline
7128
7129
7130 if (document && document.body) {
7131 this._onClick = function (event) {
7132 if (!_hasParent(event.target, container)) {
7133 _this.deactivate();
7134 }
7135 };
7136
7137 document.body.addEventListener("click", this._onClick);
7138
7139 this._cleanupQueue.push(function () {
7140 document.body.removeEventListener("click", _this._onClick);
7141 });
7142 } // prepare escape key listener for deactivating when active
7143
7144
7145 this._escListener = function (event) {
7146 if ("key" in event ? event.key === "Escape" : event.keyCode === 27
7147 /* the keyCode is for IE11 */
7148 ) {
7149 _this.deactivate();
7150 }
7151 };
7152} // turn into an event emitter
7153
7154
7155componentEmitter(Activator.prototype); // The currently active activator
7156
7157Activator.current = null;
7158/**
7159 * Destroy the activator. Cleans up all created DOM and event listeners
7160 */
7161
7162Activator.prototype.destroy = function () {
7163 var _context4, _context5;
7164
7165 this.deactivate();
7166
7167 var _iterator2 = _createForOfIteratorHelper$8(reverse(_context4 = splice(_context5 = this._cleanupQueue).call(_context5, 0)).call(_context4)),
7168 _step2;
7169
7170 try {
7171 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
7172 var callback = _step2.value;
7173 callback();
7174 }
7175 } catch (err) {
7176 _iterator2.e(err);
7177 } finally {
7178 _iterator2.f();
7179 }
7180};
7181/**
7182 * Activate the element
7183 * Overlay is hidden, element is decorated with a blue shadow border
7184 */
7185
7186
7187Activator.prototype.activate = function () {
7188 // we allow only one active activator at a time
7189 if (Activator.current) {
7190 Activator.current.deactivate();
7191 }
7192
7193 Activator.current = this;
7194 this.active = true;
7195 this._dom.overlay.style.display = "none";
7196
7197 this._dom.container.classList.add("vis-active");
7198
7199 this.emit("change");
7200 this.emit("activate"); // ugly hack: bind ESC after emitting the events, as the Network rebinds all
7201 // keyboard events on a 'change' event
7202
7203 document.body.addEventListener("keydown", this._escListener);
7204};
7205/**
7206 * Deactivate the element
7207 * Overlay is displayed on top of the element
7208 */
7209
7210
7211Activator.prototype.deactivate = function () {
7212 this.active = false;
7213 this._dom.overlay.style.display = "block";
7214
7215 this._dom.container.classList.remove("vis-active");
7216
7217 document.body.removeEventListener("keydown", this._escListener);
7218 this.emit("change");
7219 this.emit("deactivate");
7220};
7221/**
7222 * Handle a tap event: activate the container
7223 *
7224 * @param {Event} event The event
7225 * @private
7226 */
7227
7228
7229Activator.prototype._onTapOverlay = function (event) {
7230 // activate the container
7231 this.activate();
7232 event.srcEvent.stopPropagation();
7233};
7234/**
7235 * Test whether the element has the requested parent element somewhere in
7236 * its chain of parent nodes.
7237 *
7238 * @param {HTMLElement} element
7239 * @param {HTMLElement} parent
7240 * @returns {boolean} Returns true when the parent is found somewhere in the
7241 * chain of parent nodes.
7242 * @private
7243 */
7244
7245
7246function _hasParent(element, parent) {
7247 while (element) {
7248 if (element === parent) {
7249 return true;
7250 }
7251
7252 element = element.parentNode;
7253 }
7254
7255 return false;
7256} // utility functions
7257// parse ASP.Net Date pattern,
7258// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/'
7259// code from http://momentjs.com/
7260
7261
7262var ASPDateRegex = /^\/?Date\((-?\d+)/i; // Color REs
7263
7264var fullHexRE = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
7265var shortHexRE = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
7266var rgbRE = /^rgb\( *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *\)$/i;
7267var rgbaRE = /^rgba\( *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *(1?\d{1,2}|2[0-4]\d|25[0-5]) *, *([01]|0?\.\d+) *\)$/i;
7268/**
7269 * Test whether given object is a number.
7270 *
7271 * @param value - Input value of unknown type.
7272 *
7273 * @returns True if number, false otherwise.
7274 */
7275
7276function isNumber(value) {
7277 return value instanceof Number || typeof value === "number";
7278}
7279/**
7280 * Remove everything in the DOM object.
7281 *
7282 * @param DOMobject - Node whose child nodes will be recursively deleted.
7283 */
7284
7285
7286function recursiveDOMDelete(DOMobject) {
7287 if (DOMobject) {
7288 while (DOMobject.hasChildNodes() === true) {
7289 var child = DOMobject.firstChild;
7290
7291 if (child) {
7292 recursiveDOMDelete(child);
7293 DOMobject.removeChild(child);
7294 }
7295 }
7296 }
7297}
7298/**
7299 * Test whether given object is a string.
7300 *
7301 * @param value - Input value of unknown type.
7302 *
7303 * @returns True if string, false otherwise.
7304 */
7305
7306
7307function isString(value) {
7308 return value instanceof String || typeof value === "string";
7309}
7310/**
7311 * Test whether given object is a object (not primitive or null).
7312 *
7313 * @param value - Input value of unknown type.
7314 *
7315 * @returns True if not null object, false otherwise.
7316 */
7317
7318
7319function isObject(value) {
7320 return _typeof(value) === "object" && value !== null;
7321}
7322/**
7323 * Test whether given object is a Date, or a String containing a Date.
7324 *
7325 * @param value - Input value of unknown type.
7326 *
7327 * @returns True if Date instance or string date representation, false otherwise.
7328 */
7329
7330
7331function isDate(value) {
7332 if (value instanceof Date) {
7333 return true;
7334 } else if (isString(value)) {
7335 // test whether this string contains a date
7336 var match = ASPDateRegex.exec(value);
7337
7338 if (match) {
7339 return true;
7340 } else if (!isNaN(Date.parse(value))) {
7341 return true;
7342 }
7343 }
7344
7345 return false;
7346}
7347/**
7348 * Copy property from b to a if property present in a.
7349 * If property in b explicitly set to null, delete it if `allowDeletion` set.
7350 *
7351 * Internal helper routine, should not be exported. Not added to `exports` for that reason.
7352 *
7353 * @param a - Target object.
7354 * @param b - Source object.
7355 * @param prop - Name of property to copy from b to a.
7356 * @param allowDeletion - If true, delete property in a if explicitly set to null in b.
7357 */
7358
7359
7360function copyOrDelete(a, b, prop, allowDeletion) {
7361 var doDeletion = false;
7362
7363 if (allowDeletion === true) {
7364 doDeletion = b[prop] === null && a[prop] !== undefined;
7365 }
7366
7367 if (doDeletion) {
7368 delete a[prop];
7369 } else {
7370 a[prop] = b[prop]; // Remember, this is a reference copy!
7371 }
7372}
7373/**
7374 * Fill an object with a possibly partially defined other object.
7375 *
7376 * Only copies values for the properties already present in a.
7377 * That means an object is not created on a property if only the b object has it.
7378 *
7379 * @param a - The object that will have it's properties updated.
7380 * @param b - The object with property updates.
7381 * @param allowDeletion - If true, delete properties in a that are explicitly set to null in b.
7382 */
7383
7384
7385function fillIfDefined(a, b) {
7386 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
7387
7388 // NOTE: iteration of properties of a
7389 // NOTE: prototype properties iterated over as well
7390 for (var prop in a) {
7391 if (b[prop] !== undefined) {
7392 if (b[prop] === null || _typeof(b[prop]) !== "object") {
7393 // Note: typeof null === 'object'
7394 copyOrDelete(a, b, prop, allowDeletion);
7395 } else {
7396 var aProp = a[prop];
7397 var bProp = b[prop];
7398
7399 if (isObject(aProp) && isObject(bProp)) {
7400 fillIfDefined(aProp, bProp, allowDeletion);
7401 }
7402 }
7403 }
7404 }
7405}
7406/**
7407 * Copy the values of all of the enumerable own properties from one or more source objects to a
7408 * target object. Returns the target object.
7409 *
7410 * @param target - The target object to copy to.
7411 * @param source - The source object from which to copy properties.
7412 *
7413 * @returns The target object.
7414 */
7415
7416
7417var extend = assign$2;
7418/**
7419 * Extend object a with selected properties of object b or a series of objects.
7420 *
7421 * @remarks
7422 * Only properties with defined values are copied.
7423 *
7424 * @param props - Properties to be copied to a.
7425 * @param a - The target.
7426 * @param others - The sources.
7427 *
7428 * @returns Argument a.
7429 */
7430
7431function selectiveExtend(props, a) {
7432 if (!isArray(props)) {
7433 throw new Error("Array with property names expected as first argument");
7434 }
7435
7436 for (var _len4 = arguments.length, others = new Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) {
7437 others[_key4 - 2] = arguments[_key4];
7438 }
7439
7440 for (var _i2 = 0, _others = others; _i2 < _others.length; _i2++) {
7441 var other = _others[_i2];
7442
7443 for (var p = 0; p < props.length; p++) {
7444 var prop = props[p];
7445
7446 if (other && Object.prototype.hasOwnProperty.call(other, prop)) {
7447 a[prop] = other[prop];
7448 }
7449 }
7450 }
7451
7452 return a;
7453}
7454/**
7455 * Extend object a with selected properties of object b.
7456 * Only properties with defined values are copied.
7457 *
7458 * @remarks
7459 * Previous version of this routine implied that multiple source objects could
7460 * be used; however, the implementation was **wrong**. Since multiple (\>1)
7461 * sources weren't used anywhere in the `vis.js` code, this has been removed
7462 *
7463 * @param props - Names of first-level properties to copy over.
7464 * @param a - Target object.
7465 * @param b - Source object.
7466 * @param allowDeletion - If true, delete property in a if explicitly set to null in b.
7467 *
7468 * @returns Argument a.
7469 */
7470
7471
7472function selectiveDeepExtend(props, a, b) {
7473 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
7474
7475 // TODO: add support for Arrays to deepExtend
7476 if (isArray(b)) {
7477 throw new TypeError("Arrays are not supported by deepExtend");
7478 }
7479
7480 for (var p = 0; p < props.length; p++) {
7481 var prop = props[p];
7482
7483 if (Object.prototype.hasOwnProperty.call(b, prop)) {
7484 if (b[prop] && b[prop].constructor === Object) {
7485 if (a[prop] === undefined) {
7486 a[prop] = {};
7487 }
7488
7489 if (a[prop].constructor === Object) {
7490 deepExtend(a[prop], b[prop], false, allowDeletion);
7491 } else {
7492 copyOrDelete(a, b, prop, allowDeletion);
7493 }
7494 } else if (isArray(b[prop])) {
7495 throw new TypeError("Arrays are not supported by deepExtend");
7496 } else {
7497 copyOrDelete(a, b, prop, allowDeletion);
7498 }
7499 }
7500 }
7501
7502 return a;
7503}
7504/**
7505 * Extend object `a` with properties of object `b`, ignoring properties which
7506 * are explicitly specified to be excluded.
7507 *
7508 * @remarks
7509 * The properties of `b` are considered for copying. Properties which are
7510 * themselves objects are are also extended. Only properties with defined
7511 * values are copied.
7512 *
7513 * @param propsToExclude - Names of properties which should *not* be copied.
7514 * @param a - Object to extend.
7515 * @param b - Object to take properties from for extension.
7516 * @param allowDeletion - If true, delete properties in a that are explicitly
7517 * set to null in b.
7518 *
7519 * @returns Argument a.
7520 */
7521
7522
7523function selectiveNotDeepExtend(propsToExclude, a, b) {
7524 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
7525
7526 // TODO: add support for Arrays to deepExtend
7527 // NOTE: array properties have an else-below; apparently, there is a problem here.
7528 if (isArray(b)) {
7529 throw new TypeError("Arrays are not supported by deepExtend");
7530 }
7531
7532 for (var prop in b) {
7533 if (!Object.prototype.hasOwnProperty.call(b, prop)) {
7534 continue;
7535 } // Handle local properties only
7536
7537
7538 if (includes(propsToExclude).call(propsToExclude, prop)) {
7539 continue;
7540 } // In exclusion list, skip
7541
7542
7543 if (b[prop] && b[prop].constructor === Object) {
7544 if (a[prop] === undefined) {
7545 a[prop] = {};
7546 }
7547
7548 if (a[prop].constructor === Object) {
7549 deepExtend(a[prop], b[prop]); // NOTE: allowDeletion not propagated!
7550 } else {
7551 copyOrDelete(a, b, prop, allowDeletion);
7552 }
7553 } else if (isArray(b[prop])) {
7554 a[prop] = [];
7555
7556 for (var i = 0; i < b[prop].length; i++) {
7557 a[prop].push(b[prop][i]);
7558 }
7559 } else {
7560 copyOrDelete(a, b, prop, allowDeletion);
7561 }
7562 }
7563
7564 return a;
7565}
7566/**
7567 * Deep extend an object a with the properties of object b.
7568 *
7569 * @param a - Target object.
7570 * @param b - Source object.
7571 * @param protoExtend - If true, the prototype values will also be extended.
7572 * (That is the options objects that inherit from others will also get the
7573 * inherited options).
7574 * @param allowDeletion - If true, the values of fields that are null will be deleted.
7575 *
7576 * @returns Argument a.
7577 */
7578
7579
7580function deepExtend(a, b) {
7581 var protoExtend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
7582 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
7583
7584 for (var prop in b) {
7585 if (Object.prototype.hasOwnProperty.call(b, prop) || protoExtend === true) {
7586 if (_typeof(b[prop]) === "object" && b[prop] !== null && getPrototypeOf$3(b[prop]) === Object.prototype) {
7587 if (a[prop] === undefined) {
7588 a[prop] = deepExtend({}, b[prop], protoExtend); // NOTE: allowDeletion not propagated!
7589 } else if (_typeof(a[prop]) === "object" && a[prop] !== null && getPrototypeOf$3(a[prop]) === Object.prototype) {
7590 deepExtend(a[prop], b[prop], protoExtend); // NOTE: allowDeletion not propagated!
7591 } else {
7592 copyOrDelete(a, b, prop, allowDeletion);
7593 }
7594 } else if (isArray(b[prop])) {
7595 var _context6;
7596
7597 a[prop] = slice$1(_context6 = b[prop]).call(_context6);
7598 } else {
7599 copyOrDelete(a, b, prop, allowDeletion);
7600 }
7601 }
7602 }
7603
7604 return a;
7605}
7606/**
7607 * Test whether all elements in two arrays are equal.
7608 *
7609 * @param a - First array.
7610 * @param b - Second array.
7611 *
7612 * @returns True if both arrays have the same length and same elements (1 = '1').
7613 */
7614
7615
7616function equalArray(a, b) {
7617 if (a.length !== b.length) {
7618 return false;
7619 }
7620
7621 for (var i = 0, len = a.length; i < len; i++) {
7622 if (a[i] != b[i]) {
7623 return false;
7624 }
7625 }
7626
7627 return true;
7628}
7629/**
7630 * Get the type of an object, for example exports.getType([]) returns 'Array'.
7631 *
7632 * @param object - Input value of unknown type.
7633 *
7634 * @returns Detected type.
7635 */
7636
7637
7638function getType(object) {
7639 var type = _typeof(object);
7640
7641 if (type === "object") {
7642 if (object === null) {
7643 return "null";
7644 }
7645
7646 if (object instanceof Boolean) {
7647 return "Boolean";
7648 }
7649
7650 if (object instanceof Number) {
7651 return "Number";
7652 }
7653
7654 if (object instanceof String) {
7655 return "String";
7656 }
7657
7658 if (isArray(object)) {
7659 return "Array";
7660 }
7661
7662 if (object instanceof Date) {
7663 return "Date";
7664 }
7665
7666 return "Object";
7667 }
7668
7669 if (type === "number") {
7670 return "Number";
7671 }
7672
7673 if (type === "boolean") {
7674 return "Boolean";
7675 }
7676
7677 if (type === "string") {
7678 return "String";
7679 }
7680
7681 if (type === undefined) {
7682 return "undefined";
7683 }
7684
7685 return type;
7686}
7687/**
7688 * Used to extend an array and copy it. This is used to propagate paths recursively.
7689 *
7690 * @param arr - First part.
7691 * @param newValue - The value to be aadded into the array.
7692 *
7693 * @returns A new array with all items from arr and newValue (which is last).
7694 */
7695
7696
7697function copyAndExtendArray(arr, newValue) {
7698 var _context7;
7699
7700 return concat(_context7 = []).call(_context7, _toConsumableArray(arr), [newValue]);
7701}
7702/**
7703 * Used to extend an array and copy it. This is used to propagate paths recursively.
7704 *
7705 * @param arr - The array to be copied.
7706 *
7707 * @returns Shallow copy of arr.
7708 */
7709
7710
7711function copyArray(arr) {
7712 return slice$1(arr).call(arr);
7713}
7714/**
7715 * Retrieve the absolute left value of a DOM element.
7716 *
7717 * @param elem - A dom element, for example a div.
7718 *
7719 * @returns The absolute left position of this element in the browser page.
7720 */
7721
7722
7723function getAbsoluteLeft(elem) {
7724 return elem.getBoundingClientRect().left;
7725}
7726/**
7727 * Retrieve the absolute right value of a DOM element.
7728 *
7729 * @param elem - A dom element, for example a div.
7730 *
7731 * @returns The absolute right position of this element in the browser page.
7732 */
7733
7734
7735function getAbsoluteRight(elem) {
7736 return elem.getBoundingClientRect().right;
7737}
7738/**
7739 * Retrieve the absolute top value of a DOM element.
7740 *
7741 * @param elem - A dom element, for example a div.
7742 *
7743 * @returns The absolute top position of this element in the browser page.
7744 */
7745
7746
7747function getAbsoluteTop(elem) {
7748 return elem.getBoundingClientRect().top;
7749}
7750/**
7751 * Add a className to the given elements style.
7752 *
7753 * @param elem - The element to which the classes will be added.
7754 * @param classNames - Space separated list of classes.
7755 */
7756
7757
7758function addClassName(elem, classNames) {
7759 var classes = elem.className.split(" ");
7760 var newClasses = classNames.split(" ");
7761 classes = concat(classes).call(classes, filter(newClasses).call(newClasses, function (className) {
7762 return !includes(classes).call(classes, className);
7763 }));
7764 elem.className = classes.join(" ");
7765}
7766/**
7767 * Remove a className from the given elements style.
7768 *
7769 * @param elem - The element from which the classes will be removed.
7770 * @param classNames - Space separated list of classes.
7771 */
7772
7773
7774function removeClassName(elem, classNames) {
7775 var classes = elem.className.split(" ");
7776 var oldClasses = classNames.split(" ");
7777 classes = filter(classes).call(classes, function (className) {
7778 return !includes(oldClasses).call(oldClasses, className);
7779 });
7780 elem.className = classes.join(" ");
7781}
7782/**
7783 * For each method for both arrays and objects.
7784 * In case of an array, the built-in Array.forEach() is applied (**No, it's not!**).
7785 * In case of an Object, the method loops over all properties of the object.
7786 *
7787 * @param object - An Object or Array to be iterated over.
7788 * @param callback - Array.forEach-like callback.
7789 */
7790
7791
7792function forEach$1(object, callback) {
7793 if (isArray(object)) {
7794 // array
7795 var len = object.length;
7796
7797 for (var i = 0; i < len; i++) {
7798 callback(object[i], i, object);
7799 }
7800 } else {
7801 // object
7802 for (var key in object) {
7803 if (Object.prototype.hasOwnProperty.call(object, key)) {
7804 callback(object[key], key, object);
7805 }
7806 }
7807 }
7808}
7809/**
7810 * Convert an object into an array: all objects properties are put into the array. The resulting array is unordered.
7811 *
7812 * @param o - Object that contains the properties and methods.
7813 *
7814 * @returns An array of unordered values.
7815 */
7816
7817
7818var toArray = values$3;
7819/**
7820 * Update a property in an object.
7821 *
7822 * @param object - The object whose property will be updated.
7823 * @param key - Name of the property to be updated.
7824 * @param value - The new value to be assigned.
7825 *
7826 * @returns Whether the value was updated (true) or already strictly the same in the original object (false).
7827 */
7828
7829function updateProperty(object, key, value) {
7830 if (object[key] !== value) {
7831 object[key] = value;
7832 return true;
7833 } else {
7834 return false;
7835 }
7836}
7837/**
7838 * Throttle the given function to be only executed once per animation frame.
7839 *
7840 * @param fn - The original function.
7841 *
7842 * @returns The throttled function.
7843 */
7844
7845
7846function throttle(fn) {
7847 var scheduled = false;
7848 return function () {
7849 if (!scheduled) {
7850 scheduled = true;
7851 requestAnimationFrame(function () {
7852 scheduled = false;
7853 fn();
7854 });
7855 }
7856 };
7857}
7858/**
7859 * Add and event listener. Works for all browsers.
7860 *
7861 * @param element - The element to bind the event listener to.
7862 * @param action - Same as Element.addEventListener(action, —, —).
7863 * @param listener - Same as Element.addEventListener(—, listener, —).
7864 * @param useCapture - Same as Element.addEventListener(—, —, useCapture).
7865 */
7866
7867
7868function addEventListener(element, action, listener, useCapture) {
7869 if (element.addEventListener) {
7870 var _context8;
7871
7872 if (useCapture === undefined) {
7873 useCapture = false;
7874 }
7875
7876 if (action === "mousewheel" && includes(_context8 = navigator.userAgent).call(_context8, "Firefox")) {
7877 action = "DOMMouseScroll"; // For Firefox
7878 }
7879
7880 element.addEventListener(action, listener, useCapture);
7881 } else {
7882 // @TODO: IE types? Does anyone care?
7883 element.attachEvent("on" + action, listener); // IE browsers
7884 }
7885}
7886/**
7887 * Remove an event listener from an element.
7888 *
7889 * @param element - The element to bind the event listener to.
7890 * @param action - Same as Element.removeEventListener(action, —, —).
7891 * @param listener - Same as Element.removeEventListener(—, listener, —).
7892 * @param useCapture - Same as Element.removeEventListener(—, —, useCapture).
7893 */
7894
7895
7896function removeEventListener(element, action, listener, useCapture) {
7897 if (element.removeEventListener) {
7898 var _context9;
7899
7900 // non-IE browsers
7901 if (useCapture === undefined) {
7902 useCapture = false;
7903 }
7904
7905 if (action === "mousewheel" && includes(_context9 = navigator.userAgent).call(_context9, "Firefox")) {
7906 action = "DOMMouseScroll"; // For Firefox
7907 }
7908
7909 element.removeEventListener(action, listener, useCapture);
7910 } else {
7911 // @TODO: IE types? Does anyone care?
7912 element.detachEvent("on" + action, listener); // IE browsers
7913 }
7914}
7915/**
7916 * Cancels the event's default action if it is cancelable, without stopping further propagation of the event.
7917 *
7918 * @param event - The event whose default action should be prevented.
7919 */
7920
7921
7922function preventDefault(event) {
7923 if (!event) {
7924 event = window.event;
7925 }
7926
7927 if (!event) ;else if (event.preventDefault) {
7928 event.preventDefault(); // non-IE browsers
7929 } else {
7930 // @TODO: IE types? Does anyone care?
7931 event.returnValue = false; // IE browsers
7932 }
7933}
7934/**
7935 * Get HTML element which is the target of the event.
7936 *
7937 * @param event - The event.
7938 *
7939 * @returns The element or null if not obtainable.
7940 */
7941
7942
7943function getTarget() {
7944 var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.event;
7945 // code from http://www.quirksmode.org/js/events_properties.html
7946 // @TODO: EventTarget can be almost anything, is it okay to return only Elements?
7947 var target = null;
7948 if (!event) ;else if (event.target) {
7949 target = event.target;
7950 } else if (event.srcElement) {
7951 target = event.srcElement;
7952 }
7953
7954 if (!(target instanceof Element)) {
7955 return null;
7956 }
7957
7958 if (target.nodeType != null && target.nodeType == 3) {
7959 // defeat Safari bug
7960 target = target.parentNode;
7961
7962 if (!(target instanceof Element)) {
7963 return null;
7964 }
7965 }
7966
7967 return target;
7968}
7969/**
7970 * Check if given element contains given parent somewhere in the DOM tree.
7971 *
7972 * @param element - The element to be tested.
7973 * @param parent - The ancestor (not necessarily parent) of the element.
7974 *
7975 * @returns True if parent is an ancestor of the element, false otherwise.
7976 */
7977
7978
7979function hasParent(element, parent) {
7980 var elem = element;
7981
7982 while (elem) {
7983 if (elem === parent) {
7984 return true;
7985 } else if (elem.parentNode) {
7986 elem = elem.parentNode;
7987 } else {
7988 return false;
7989 }
7990 }
7991
7992 return false;
7993}
7994
7995var option = {
7996 /**
7997 * Convert a value into a boolean.
7998 *
7999 * @param value - Value to be converted intoboolean, a function will be executed as `(() => unknown)`.
8000 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8001 *
8002 * @returns Corresponding boolean value, if none then the default value, if none then null.
8003 */
8004 asBoolean: function asBoolean(value, defaultValue) {
8005 if (typeof value == "function") {
8006 value = value();
8007 }
8008
8009 if (value != null) {
8010 return value != false;
8011 }
8012
8013 return defaultValue || null;
8014 },
8015
8016 /**
8017 * Convert a value into a number.
8018 *
8019 * @param value - Value to be converted intonumber, a function will be executed as `(() => unknown)`.
8020 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8021 *
8022 * @returns Corresponding **boxed** number value, if none then the default value, if none then null.
8023 */
8024 asNumber: function asNumber(value, defaultValue) {
8025 if (typeof value == "function") {
8026 value = value();
8027 }
8028
8029 if (value != null) {
8030 return Number(value) || defaultValue || null;
8031 }
8032
8033 return defaultValue || null;
8034 },
8035
8036 /**
8037 * Convert a value into a string.
8038 *
8039 * @param value - Value to be converted intostring, a function will be executed as `(() => unknown)`.
8040 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8041 *
8042 * @returns Corresponding **boxed** string value, if none then the default value, if none then null.
8043 */
8044 asString: function asString(value, defaultValue) {
8045 if (typeof value == "function") {
8046 value = value();
8047 }
8048
8049 if (value != null) {
8050 return String(value);
8051 }
8052
8053 return defaultValue || null;
8054 },
8055
8056 /**
8057 * Convert a value into a size.
8058 *
8059 * @param value - Value to be converted intosize, a function will be executed as `(() => unknown)`.
8060 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8061 *
8062 * @returns Corresponding string value (number + 'px'), if none then the default value, if none then null.
8063 */
8064 asSize: function asSize(value, defaultValue) {
8065 if (typeof value == "function") {
8066 value = value();
8067 }
8068
8069 if (isString(value)) {
8070 return value;
8071 } else if (isNumber(value)) {
8072 return value + "px";
8073 } else {
8074 return defaultValue || null;
8075 }
8076 },
8077
8078 /**
8079 * Convert a value into a DOM Element.
8080 *
8081 * @param value - Value to be converted into DOM Element, a function will be executed as `(() => unknown)`.
8082 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8083 *
8084 * @returns The DOM Element, if none then the default value, if none then null.
8085 */
8086 asElement: function asElement(value, defaultValue) {
8087 if (typeof value == "function") {
8088 value = value();
8089 }
8090
8091 return value || defaultValue || null;
8092 }
8093};
8094/**
8095 * Convert hex color string into RGB color object.
8096 *
8097 * @remarks
8098 * {@link http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb}
8099 *
8100 * @param hex - Hex color string (3 or 6 digits, with or without #).
8101 *
8102 * @returns RGB color object.
8103 */
8104
8105function hexToRGB(hex) {
8106 var result;
8107
8108 switch (hex.length) {
8109 case 3:
8110 case 4:
8111 result = shortHexRE.exec(hex);
8112 return result ? {
8113 r: _parseInt(result[1] + result[1], 16),
8114 g: _parseInt(result[2] + result[2], 16),
8115 b: _parseInt(result[3] + result[3], 16)
8116 } : null;
8117
8118 case 6:
8119 case 7:
8120 result = fullHexRE.exec(hex);
8121 return result ? {
8122 r: _parseInt(result[1], 16),
8123 g: _parseInt(result[2], 16),
8124 b: _parseInt(result[3], 16)
8125 } : null;
8126
8127 default:
8128 return null;
8129 }
8130}
8131/**
8132 * This function takes string color in hex or RGB format and adds the opacity, RGBA is passed through unchanged.
8133 *
8134 * @param color - The color string (hex, RGB, RGBA).
8135 * @param opacity - The new opacity.
8136 *
8137 * @returns RGBA string, for example 'rgba(255, 0, 127, 0.3)'.
8138 */
8139
8140
8141function overrideOpacity(color, opacity) {
8142 if (includes(color).call(color, "rgba")) {
8143 return color;
8144 } else if (includes(color).call(color, "rgb")) {
8145 var rgb = color.substr(indexOf(color).call(color, "(") + 1).replace(")", "").split(",");
8146 return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + opacity + ")";
8147 } else {
8148 var _rgb = hexToRGB(color);
8149
8150 if (_rgb == null) {
8151 return color;
8152 } else {
8153 return "rgba(" + _rgb.r + "," + _rgb.g + "," + _rgb.b + "," + opacity + ")";
8154 }
8155 }
8156}
8157/**
8158 * Convert RGB \<0, 255\> into hex color string.
8159 *
8160 * @param red - Red channel.
8161 * @param green - Green channel.
8162 * @param blue - Blue channel.
8163 *
8164 * @returns Hex color string (for example: '#0acdc0').
8165 */
8166
8167
8168function RGBToHex(red, green, blue) {
8169 var _context10;
8170
8171 return "#" + slice$1(_context10 = ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16)).call(_context10, 1);
8172}
8173/**
8174 * Parse a color property into an object with border, background, and highlight colors.
8175 *
8176 * @param inputColor - Shorthand color string or input color object.
8177 * @param defaultColor - Full color object to fill in missing values in inputColor.
8178 *
8179 * @returns Color object.
8180 */
8181
8182
8183function parseColor(inputColor, defaultColor) {
8184 if (isString(inputColor)) {
8185 var colorStr = inputColor;
8186
8187 if (isValidRGB(colorStr)) {
8188 var _context11;
8189
8190 var rgb = map$3(_context11 = colorStr.substr(4).substr(0, colorStr.length - 5).split(",")).call(_context11, function (value) {
8191 return _parseInt(value);
8192 });
8193
8194 colorStr = RGBToHex(rgb[0], rgb[1], rgb[2]);
8195 }
8196
8197 if (isValidHex(colorStr) === true) {
8198 var hsv = hexToHSV(colorStr);
8199 var lighterColorHSV = {
8200 h: hsv.h,
8201 s: hsv.s * 0.8,
8202 v: Math.min(1, hsv.v * 1.02)
8203 };
8204 var darkerColorHSV = {
8205 h: hsv.h,
8206 s: Math.min(1, hsv.s * 1.25),
8207 v: hsv.v * 0.8
8208 };
8209 var darkerColorHex = HSVToHex(darkerColorHSV.h, darkerColorHSV.s, darkerColorHSV.v);
8210 var lighterColorHex = HSVToHex(lighterColorHSV.h, lighterColorHSV.s, lighterColorHSV.v);
8211 return {
8212 background: colorStr,
8213 border: darkerColorHex,
8214 highlight: {
8215 background: lighterColorHex,
8216 border: darkerColorHex
8217 },
8218 hover: {
8219 background: lighterColorHex,
8220 border: darkerColorHex
8221 }
8222 };
8223 } else {
8224 return {
8225 background: colorStr,
8226 border: colorStr,
8227 highlight: {
8228 background: colorStr,
8229 border: colorStr
8230 },
8231 hover: {
8232 background: colorStr,
8233 border: colorStr
8234 }
8235 };
8236 }
8237 } else {
8238 if (defaultColor) {
8239 var color = {
8240 background: inputColor.background || defaultColor.background,
8241 border: inputColor.border || defaultColor.border,
8242 highlight: isString(inputColor.highlight) ? {
8243 border: inputColor.highlight,
8244 background: inputColor.highlight
8245 } : {
8246 background: inputColor.highlight && inputColor.highlight.background || defaultColor.highlight.background,
8247 border: inputColor.highlight && inputColor.highlight.border || defaultColor.highlight.border
8248 },
8249 hover: isString(inputColor.hover) ? {
8250 border: inputColor.hover,
8251 background: inputColor.hover
8252 } : {
8253 border: inputColor.hover && inputColor.hover.border || defaultColor.hover.border,
8254 background: inputColor.hover && inputColor.hover.background || defaultColor.hover.background
8255 }
8256 };
8257 return color;
8258 } else {
8259 var _color = {
8260 background: inputColor.background || undefined,
8261 border: inputColor.border || undefined,
8262 highlight: isString(inputColor.highlight) ? {
8263 border: inputColor.highlight,
8264 background: inputColor.highlight
8265 } : {
8266 background: inputColor.highlight && inputColor.highlight.background || undefined,
8267 border: inputColor.highlight && inputColor.highlight.border || undefined
8268 },
8269 hover: isString(inputColor.hover) ? {
8270 border: inputColor.hover,
8271 background: inputColor.hover
8272 } : {
8273 border: inputColor.hover && inputColor.hover.border || undefined,
8274 background: inputColor.hover && inputColor.hover.background || undefined
8275 }
8276 };
8277 return _color;
8278 }
8279 }
8280}
8281/**
8282 * Convert RGB \<0, 255\> into HSV object.
8283 *
8284 * @remarks
8285 * {@link http://www.javascripter.net/faq/rgb2hsv.htm}
8286 *
8287 * @param red - Red channel.
8288 * @param green - Green channel.
8289 * @param blue - Blue channel.
8290 *
8291 * @returns HSV color object.
8292 */
8293
8294
8295function RGBToHSV(red, green, blue) {
8296 red = red / 255;
8297 green = green / 255;
8298 blue = blue / 255;
8299 var minRGB = Math.min(red, Math.min(green, blue));
8300 var maxRGB = Math.max(red, Math.max(green, blue)); // Black-gray-white
8301
8302 if (minRGB === maxRGB) {
8303 return {
8304 h: 0,
8305 s: 0,
8306 v: minRGB
8307 };
8308 } // Colors other than black-gray-white:
8309
8310
8311 var d = red === minRGB ? green - blue : blue === minRGB ? red - green : blue - red;
8312 var h = red === minRGB ? 3 : blue === minRGB ? 1 : 5;
8313 var hue = 60 * (h - d / (maxRGB - minRGB)) / 360;
8314 var saturation = (maxRGB - minRGB) / maxRGB;
8315 var value = maxRGB;
8316 return {
8317 h: hue,
8318 s: saturation,
8319 v: value
8320 };
8321}
8322
8323var cssUtil = {
8324 // split a string with css styles into an object with key/values
8325 split: function split(cssText) {
8326 var _context12;
8327
8328 var styles = {};
8329
8330 forEach$2(_context12 = cssText.split(";")).call(_context12, function (style) {
8331 if (trim$1(style).call(style) != "") {
8332 var _context13, _context14;
8333
8334 var parts = style.split(":");
8335
8336 var key = trim$1(_context13 = parts[0]).call(_context13);
8337
8338 var value = trim$1(_context14 = parts[1]).call(_context14);
8339
8340 styles[key] = value;
8341 }
8342 });
8343
8344 return styles;
8345 },
8346 // build a css text string from an object with key/values
8347 join: function join(styles) {
8348 var _context15;
8349
8350 return map$3(_context15 = keys$3(styles)).call(_context15, function (key) {
8351 return key + ": " + styles[key];
8352 }).join("; ");
8353 }
8354};
8355/**
8356 * Append a string with css styles to an element.
8357 *
8358 * @param element - The element that will receive new styles.
8359 * @param cssText - The styles to be appended.
8360 */
8361
8362function addCssText(element, cssText) {
8363 var currentStyles = cssUtil.split(element.style.cssText);
8364 var newStyles = cssUtil.split(cssText);
8365
8366 var styles = _objectSpread$5(_objectSpread$5({}, currentStyles), newStyles);
8367
8368 element.style.cssText = cssUtil.join(styles);
8369}
8370/**
8371 * Remove a string with css styles from an element.
8372 *
8373 * @param element - The element from which styles should be removed.
8374 * @param cssText - The styles to be removed.
8375 */
8376
8377
8378function removeCssText(element, cssText) {
8379 var styles = cssUtil.split(element.style.cssText);
8380 var removeStyles = cssUtil.split(cssText);
8381
8382 for (var key in removeStyles) {
8383 if (Object.prototype.hasOwnProperty.call(removeStyles, key)) {
8384 delete styles[key];
8385 }
8386 }
8387
8388 element.style.cssText = cssUtil.join(styles);
8389}
8390/**
8391 * Convert HSV \<0, 1\> into RGB color object.
8392 *
8393 * @remarks
8394 * {@link https://gist.github.com/mjijackson/5311256}
8395 *
8396 * @param h - Hue.
8397 * @param s - Saturation.
8398 * @param v - Value.
8399 *
8400 * @returns RGB color object.
8401 */
8402
8403
8404function HSVToRGB(h, s, v) {
8405 var r;
8406 var g;
8407 var b;
8408 var i = Math.floor(h * 6);
8409 var f = h * 6 - i;
8410 var p = v * (1 - s);
8411 var q = v * (1 - f * s);
8412 var t = v * (1 - (1 - f) * s);
8413
8414 switch (i % 6) {
8415 case 0:
8416 r = v, g = t, b = p;
8417 break;
8418
8419 case 1:
8420 r = q, g = v, b = p;
8421 break;
8422
8423 case 2:
8424 r = p, g = v, b = t;
8425 break;
8426
8427 case 3:
8428 r = p, g = q, b = v;
8429 break;
8430
8431 case 4:
8432 r = t, g = p, b = v;
8433 break;
8434
8435 case 5:
8436 r = v, g = p, b = q;
8437 break;
8438 }
8439
8440 return {
8441 r: Math.floor(r * 255),
8442 g: Math.floor(g * 255),
8443 b: Math.floor(b * 255)
8444 };
8445}
8446/**
8447 * Convert HSV \<0, 1\> into hex color string.
8448 *
8449 * @param h - Hue.
8450 * @param s - Saturation.
8451 * @param v - Value.
8452 *
8453 * @returns Hex color string.
8454 */
8455
8456
8457function HSVToHex(h, s, v) {
8458 var rgb = HSVToRGB(h, s, v);
8459 return RGBToHex(rgb.r, rgb.g, rgb.b);
8460}
8461/**
8462 * Convert hex color string into HSV \<0, 1\>.
8463 *
8464 * @param hex - Hex color string.
8465 *
8466 * @returns HSV color object.
8467 */
8468
8469
8470function hexToHSV(hex) {
8471 var rgb = hexToRGB(hex);
8472
8473 if (!rgb) {
8474 throw new TypeError("'".concat(hex, "' is not a valid color."));
8475 }
8476
8477 return RGBToHSV(rgb.r, rgb.g, rgb.b);
8478}
8479/**
8480 * Validate hex color string.
8481 *
8482 * @param hex - Unknown string that may contain a color.
8483 *
8484 * @returns True if the string is valid, false otherwise.
8485 */
8486
8487
8488function isValidHex(hex) {
8489 var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex);
8490 return isOk;
8491}
8492/**
8493 * Validate RGB color string.
8494 *
8495 * @param rgb - Unknown string that may contain a color.
8496 *
8497 * @returns True if the string is valid, false otherwise.
8498 */
8499
8500
8501function isValidRGB(rgb) {
8502 return rgbRE.test(rgb);
8503}
8504/**
8505 * Validate RGBA color string.
8506 *
8507 * @param rgba - Unknown string that may contain a color.
8508 *
8509 * @returns True if the string is valid, false otherwise.
8510 */
8511
8512
8513function isValidRGBA(rgba) {
8514 return rgbaRE.test(rgba);
8515}
8516/**
8517 * This recursively redirects the prototype of JSON objects to the referenceObject.
8518 * This is used for default options.
8519 *
8520 * @param fields - Names of properties to be bridged.
8521 * @param referenceObject - The original object.
8522 *
8523 * @returns A new object inheriting from the referenceObject.
8524 */
8525
8526
8527function selectiveBridgeObject(fields, referenceObject) {
8528 if (referenceObject !== null && _typeof(referenceObject) === "object") {
8529 // !!! typeof null === 'object'
8530 var objectTo = create$2(referenceObject);
8531
8532 for (var i = 0; i < fields.length; i++) {
8533 if (Object.prototype.hasOwnProperty.call(referenceObject, fields[i])) {
8534 if (_typeof(referenceObject[fields[i]]) == "object") {
8535 objectTo[fields[i]] = bridgeObject(referenceObject[fields[i]]);
8536 }
8537 }
8538 }
8539
8540 return objectTo;
8541 } else {
8542 return null;
8543 }
8544}
8545/**
8546 * This recursively redirects the prototype of JSON objects to the referenceObject.
8547 * This is used for default options.
8548 *
8549 * @param referenceObject - The original object.
8550 *
8551 * @returns The Element if the referenceObject is an Element, or a new object inheriting from the referenceObject.
8552 */
8553
8554
8555function bridgeObject(referenceObject) {
8556 if (referenceObject === null || _typeof(referenceObject) !== "object") {
8557 return null;
8558 }
8559
8560 if (referenceObject instanceof Element) {
8561 // Avoid bridging DOM objects
8562 return referenceObject;
8563 }
8564
8565 var objectTo = create$2(referenceObject);
8566
8567 for (var i in referenceObject) {
8568 if (Object.prototype.hasOwnProperty.call(referenceObject, i)) {
8569 if (_typeof(referenceObject[i]) == "object") {
8570 objectTo[i] = bridgeObject(referenceObject[i]);
8571 }
8572 }
8573 }
8574
8575 return objectTo;
8576}
8577/**
8578 * This method provides a stable sort implementation, very fast for presorted data.
8579 *
8580 * @param a - The array to be sorted (in-place).
8581 * @param compare - An order comparator.
8582 *
8583 * @returns The argument a.
8584 */
8585
8586
8587function insertSort(a, compare) {
8588 for (var i = 0; i < a.length; i++) {
8589 var k = a[i];
8590 var j = void 0;
8591
8592 for (j = i; j > 0 && compare(k, a[j - 1]) < 0; j--) {
8593 a[j] = a[j - 1];
8594 }
8595
8596 a[j] = k;
8597 }
8598
8599 return a;
8600}
8601/**
8602 * This is used to set the options of subobjects in the options object.
8603 *
8604 * A requirement of these subobjects is that they have an 'enabled' element
8605 * which is optional for the user but mandatory for the program.
8606 *
8607 * The added value here of the merge is that option 'enabled' is set as required.
8608 *
8609 * @param mergeTarget - Either this.options or the options used for the groups.
8610 * @param options - Options.
8611 * @param option - Option key in the options argument.
8612 * @param globalOptions - Global options, passed in to determine value of option 'enabled'.
8613 */
8614
8615
8616function mergeOptions(mergeTarget, options, option) {
8617 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
8618
8619 // Local helpers
8620 var isPresent = function isPresent(obj) {
8621 return obj !== null && obj !== undefined;
8622 };
8623
8624 var isObject = function isObject(obj) {
8625 return obj !== null && _typeof(obj) === "object";
8626 }; // https://stackoverflow.com/a/34491287/1223531
8627
8628
8629 var isEmpty = function isEmpty(obj) {
8630 for (var x in obj) {
8631 if (Object.prototype.hasOwnProperty.call(obj, x)) {
8632 return false;
8633 }
8634 }
8635
8636 return true;
8637 }; // Guards
8638
8639
8640 if (!isObject(mergeTarget)) {
8641 throw new Error("Parameter mergeTarget must be an object");
8642 }
8643
8644 if (!isObject(options)) {
8645 throw new Error("Parameter options must be an object");
8646 }
8647
8648 if (!isPresent(option)) {
8649 throw new Error("Parameter option must have a value");
8650 }
8651
8652 if (!isObject(globalOptions)) {
8653 throw new Error("Parameter globalOptions must be an object");
8654 } //
8655 // Actual merge routine, separated from main logic
8656 // Only a single level of options is merged. Deeper levels are ref'd. This may actually be an issue.
8657 //
8658
8659
8660 var doMerge = function doMerge(target, options, option) {
8661 if (!isObject(target[option])) {
8662 target[option] = {};
8663 }
8664
8665 var src = options[option];
8666 var dst = target[option];
8667
8668 for (var prop in src) {
8669 if (Object.prototype.hasOwnProperty.call(src, prop)) {
8670 dst[prop] = src[prop];
8671 }
8672 }
8673 }; // Local initialization
8674
8675
8676 var srcOption = options[option];
8677 var globalPassed = isObject(globalOptions) && !isEmpty(globalOptions);
8678 var globalOption = globalPassed ? globalOptions[option] : undefined;
8679 var globalEnabled = globalOption ? globalOption.enabled : undefined; /////////////////////////////////////////
8680 // Main routine
8681 /////////////////////////////////////////
8682
8683 if (srcOption === undefined) {
8684 return; // Nothing to do
8685 }
8686
8687 if (typeof srcOption === "boolean") {
8688 if (!isObject(mergeTarget[option])) {
8689 mergeTarget[option] = {};
8690 }
8691
8692 mergeTarget[option].enabled = srcOption;
8693 return;
8694 }
8695
8696 if (srcOption === null && !isObject(mergeTarget[option])) {
8697 // If possible, explicit copy from globals
8698 if (isPresent(globalOption)) {
8699 mergeTarget[option] = create$2(globalOption);
8700 } else {
8701 return; // Nothing to do
8702 }
8703 }
8704
8705 if (!isObject(srcOption)) {
8706 return;
8707 } //
8708 // Ensure that 'enabled' is properly set. It is required internally
8709 // Note that the value from options will always overwrite the existing value
8710 //
8711
8712
8713 var enabled = true; // default value
8714
8715 if (srcOption.enabled !== undefined) {
8716 enabled = srcOption.enabled;
8717 } else {
8718 // Take from globals, if present
8719 if (globalEnabled !== undefined) {
8720 enabled = globalOption.enabled;
8721 }
8722 }
8723
8724 doMerge(mergeTarget, options, option);
8725 mergeTarget[option].enabled = enabled;
8726}
8727/**
8728 * This function does a binary search for a visible item in a sorted list. If we find a visible item, the code that uses
8729 * this function will then iterate in both directions over this sorted list to find all visible items.
8730 *
8731 * @param orderedItems - Items ordered by start.
8732 * @param comparator - -1 is lower, 0 is equal, 1 is higher.
8733 * @param field - Property name on an item (That is item[field]).
8734 * @param field2 - Second property name on an item (That is item[field][field2]).
8735 *
8736 * @returns Index of the found item or -1 if nothing was found.
8737 */
8738
8739
8740function binarySearchCustom(orderedItems, comparator, field, field2) {
8741 var maxIterations = 10000;
8742 var iteration = 0;
8743 var low = 0;
8744 var high = orderedItems.length - 1;
8745
8746 while (low <= high && iteration < maxIterations) {
8747 var middle = Math.floor((low + high) / 2);
8748 var item = orderedItems[middle];
8749 var value = field2 === undefined ? item[field] : item[field][field2];
8750 var searchResult = comparator(value);
8751
8752 if (searchResult == 0) {
8753 // jihaa, found a visible item!
8754 return middle;
8755 } else if (searchResult == -1) {
8756 // it is too small --> increase low
8757 low = middle + 1;
8758 } else {
8759 // it is too big --> decrease high
8760 high = middle - 1;
8761 }
8762
8763 iteration++;
8764 }
8765
8766 return -1;
8767}
8768/**
8769 * This function does a binary search for a specific value in a sorted array.
8770 * If it does not exist but is in between of two values, we return either the
8771 * one before or the one after, depending on user input If it is found, we
8772 * return the index, else -1.
8773 *
8774 * @param orderedItems - Sorted array.
8775 * @param target - The searched value.
8776 * @param field - Name of the property in items to be searched.
8777 * @param sidePreference - If the target is between two values, should the index of the before or the after be returned?
8778 * @param comparator - An optional comparator, returning -1, 0, 1 for \<, ===, \>.
8779 *
8780 * @returns The index of found value or -1 if nothing was found.
8781 */
8782
8783
8784function binarySearchValue(orderedItems, target, field, sidePreference, comparator) {
8785 var maxIterations = 10000;
8786 var iteration = 0;
8787 var low = 0;
8788 var high = orderedItems.length - 1;
8789 var prevValue;
8790 var value;
8791 var nextValue;
8792 var middle;
8793 comparator = comparator != undefined ? comparator : function (a, b) {
8794 return a == b ? 0 : a < b ? -1 : 1;
8795 };
8796
8797 while (low <= high && iteration < maxIterations) {
8798 // get a new guess
8799 middle = Math.floor(0.5 * (high + low));
8800 prevValue = orderedItems[Math.max(0, middle - 1)][field];
8801 value = orderedItems[middle][field];
8802 nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field];
8803
8804 if (comparator(value, target) == 0) {
8805 // we found the target
8806 return middle;
8807 } else if (comparator(prevValue, target) < 0 && comparator(value, target) > 0) {
8808 // target is in between of the previous and the current
8809 return sidePreference == "before" ? Math.max(0, middle - 1) : middle;
8810 } else if (comparator(value, target) < 0 && comparator(nextValue, target) > 0) {
8811 // target is in between of the current and the next
8812 return sidePreference == "before" ? middle : Math.min(orderedItems.length - 1, middle + 1);
8813 } else {
8814 // didnt find the target, we need to change our boundaries.
8815 if (comparator(value, target) < 0) {
8816 // it is too small --> increase low
8817 low = middle + 1;
8818 } else {
8819 // it is too big --> decrease high
8820 high = middle - 1;
8821 }
8822 }
8823
8824 iteration++;
8825 } // didnt find anything. Return -1.
8826
8827
8828 return -1;
8829}
8830/*
8831 * Easing Functions.
8832 * Only considering the t value for the range [0, 1] => [0, 1].
8833 *
8834 * Inspiration: from http://gizma.com/easing/
8835 * https://gist.github.com/gre/1650294
8836 */
8837
8838
8839var easingFunctions = {
8840 /**
8841 * Provides no easing and no acceleration.
8842 *
8843 * @param t - Time.
8844 *
8845 * @returns Value at time t.
8846 */
8847 linear: function linear(t) {
8848 return t;
8849 },
8850
8851 /**
8852 * Accelerate from zero velocity.
8853 *
8854 * @param t - Time.
8855 *
8856 * @returns Value at time t.
8857 */
8858 easeInQuad: function easeInQuad(t) {
8859 return t * t;
8860 },
8861
8862 /**
8863 * Decelerate to zero velocity.
8864 *
8865 * @param t - Time.
8866 *
8867 * @returns Value at time t.
8868 */
8869 easeOutQuad: function easeOutQuad(t) {
8870 return t * (2 - t);
8871 },
8872
8873 /**
8874 * Accelerate until halfway, then decelerate.
8875 *
8876 * @param t - Time.
8877 *
8878 * @returns Value at time t.
8879 */
8880 easeInOutQuad: function easeInOutQuad(t) {
8881 return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
8882 },
8883
8884 /**
8885 * Accelerate from zero velocity.
8886 *
8887 * @param t - Time.
8888 *
8889 * @returns Value at time t.
8890 */
8891 easeInCubic: function easeInCubic(t) {
8892 return t * t * t;
8893 },
8894
8895 /**
8896 * Decelerate to zero velocity.
8897 *
8898 * @param t - Time.
8899 *
8900 * @returns Value at time t.
8901 */
8902 easeOutCubic: function easeOutCubic(t) {
8903 return --t * t * t + 1;
8904 },
8905
8906 /**
8907 * Accelerate until halfway, then decelerate.
8908 *
8909 * @param t - Time.
8910 *
8911 * @returns Value at time t.
8912 */
8913 easeInOutCubic: function easeInOutCubic(t) {
8914 return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
8915 },
8916
8917 /**
8918 * Accelerate from zero velocity.
8919 *
8920 * @param t - Time.
8921 *
8922 * @returns Value at time t.
8923 */
8924 easeInQuart: function easeInQuart(t) {
8925 return t * t * t * t;
8926 },
8927
8928 /**
8929 * Decelerate to zero velocity.
8930 *
8931 * @param t - Time.
8932 *
8933 * @returns Value at time t.
8934 */
8935 easeOutQuart: function easeOutQuart(t) {
8936 return 1 - --t * t * t * t;
8937 },
8938
8939 /**
8940 * Accelerate until halfway, then decelerate.
8941 *
8942 * @param t - Time.
8943 *
8944 * @returns Value at time t.
8945 */
8946 easeInOutQuart: function easeInOutQuart(t) {
8947 return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
8948 },
8949
8950 /**
8951 * Accelerate from zero velocity.
8952 *
8953 * @param t - Time.
8954 *
8955 * @returns Value at time t.
8956 */
8957 easeInQuint: function easeInQuint(t) {
8958 return t * t * t * t * t;
8959 },
8960
8961 /**
8962 * Decelerate to zero velocity.
8963 *
8964 * @param t - Time.
8965 *
8966 * @returns Value at time t.
8967 */
8968 easeOutQuint: function easeOutQuint(t) {
8969 return 1 + --t * t * t * t * t;
8970 },
8971
8972 /**
8973 * Accelerate until halfway, then decelerate.
8974 *
8975 * @param t - Time.
8976 *
8977 * @returns Value at time t.
8978 */
8979 easeInOutQuint: function easeInOutQuint(t) {
8980 return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
8981 }
8982};
8983/**
8984 * Experimentaly compute the width of the scrollbar for this browser.
8985 *
8986 * @returns The width in pixels.
8987 */
8988
8989function getScrollBarWidth() {
8990 var inner = document.createElement("p");
8991 inner.style.width = "100%";
8992 inner.style.height = "200px";
8993 var outer = document.createElement("div");
8994 outer.style.position = "absolute";
8995 outer.style.top = "0px";
8996 outer.style.left = "0px";
8997 outer.style.visibility = "hidden";
8998 outer.style.width = "200px";
8999 outer.style.height = "150px";
9000 outer.style.overflow = "hidden";
9001 outer.appendChild(inner);
9002 document.body.appendChild(outer);
9003 var w1 = inner.offsetWidth;
9004 outer.style.overflow = "scroll";
9005 var w2 = inner.offsetWidth;
9006
9007 if (w1 == w2) {
9008 w2 = outer.clientWidth;
9009 }
9010
9011 document.body.removeChild(outer);
9012 return w1 - w2;
9013} // @TODO: This doesn't work properly.
9014// It works only for single property objects,
9015// otherwise it combines all of the types in a union.
9016// export function topMost<K1 extends string, V1> (
9017// pile: Record<K1, undefined | V1>[],
9018// accessors: K1 | [K1]
9019// ): undefined | V1
9020// export function topMost<K1 extends string, K2 extends string, V1, V2> (
9021// pile: Record<K1, undefined | V1 | Record<K2, undefined | V2>>[],
9022// accessors: [K1, K2]
9023// ): undefined | V1 | V2
9024// export function topMost<K1 extends string, K2 extends string, K3 extends string, V1, V2, V3> (
9025// pile: Record<K1, undefined | V1 | Record<K2, undefined | V2 | Record<K3, undefined | V3>>>[],
9026// accessors: [K1, K2, K3]
9027// ): undefined | V1 | V2 | V3
9028
9029/**
9030 * Get the top most property value from a pile of objects.
9031 *
9032 * @param pile - Array of objects, no required format.
9033 * @param accessors - Array of property names.
9034 * For example `object['foo']['bar']` → `['foo', 'bar']`.
9035 *
9036 * @returns Value of the property with given accessors path from the first pile item where it's not undefined.
9037 */
9038
9039
9040function topMost(pile, accessors) {
9041 var candidate;
9042
9043 if (!isArray(accessors)) {
9044 accessors = [accessors];
9045 }
9046
9047 var _iterator3 = _createForOfIteratorHelper$8(pile),
9048 _step3;
9049
9050 try {
9051 for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
9052 var member = _step3.value;
9053
9054 if (member) {
9055 candidate = member[accessors[0]];
9056
9057 for (var i = 1; i < accessors.length; i++) {
9058 if (candidate) {
9059 candidate = candidate[accessors[i]];
9060 }
9061 }
9062
9063 if (typeof candidate !== "undefined") {
9064 break;
9065 }
9066 }
9067 }
9068 } catch (err) {
9069 _iterator3.e(err);
9070 } finally {
9071 _iterator3.f();
9072 }
9073
9074 return candidate;
9075}
9076
9077var htmlColors = {
9078 black: "#000000",
9079 navy: "#000080",
9080 darkblue: "#00008B",
9081 mediumblue: "#0000CD",
9082 blue: "#0000FF",
9083 darkgreen: "#006400",
9084 green: "#008000",
9085 teal: "#008080",
9086 darkcyan: "#008B8B",
9087 deepskyblue: "#00BFFF",
9088 darkturquoise: "#00CED1",
9089 mediumspringgreen: "#00FA9A",
9090 lime: "#00FF00",
9091 springgreen: "#00FF7F",
9092 aqua: "#00FFFF",
9093 cyan: "#00FFFF",
9094 midnightblue: "#191970",
9095 dodgerblue: "#1E90FF",
9096 lightseagreen: "#20B2AA",
9097 forestgreen: "#228B22",
9098 seagreen: "#2E8B57",
9099 darkslategray: "#2F4F4F",
9100 limegreen: "#32CD32",
9101 mediumseagreen: "#3CB371",
9102 turquoise: "#40E0D0",
9103 royalblue: "#4169E1",
9104 steelblue: "#4682B4",
9105 darkslateblue: "#483D8B",
9106 mediumturquoise: "#48D1CC",
9107 indigo: "#4B0082",
9108 darkolivegreen: "#556B2F",
9109 cadetblue: "#5F9EA0",
9110 cornflowerblue: "#6495ED",
9111 mediumaquamarine: "#66CDAA",
9112 dimgray: "#696969",
9113 slateblue: "#6A5ACD",
9114 olivedrab: "#6B8E23",
9115 slategray: "#708090",
9116 lightslategray: "#778899",
9117 mediumslateblue: "#7B68EE",
9118 lawngreen: "#7CFC00",
9119 chartreuse: "#7FFF00",
9120 aquamarine: "#7FFFD4",
9121 maroon: "#800000",
9122 purple: "#800080",
9123 olive: "#808000",
9124 gray: "#808080",
9125 skyblue: "#87CEEB",
9126 lightskyblue: "#87CEFA",
9127 blueviolet: "#8A2BE2",
9128 darkred: "#8B0000",
9129 darkmagenta: "#8B008B",
9130 saddlebrown: "#8B4513",
9131 darkseagreen: "#8FBC8F",
9132 lightgreen: "#90EE90",
9133 mediumpurple: "#9370D8",
9134 darkviolet: "#9400D3",
9135 palegreen: "#98FB98",
9136 darkorchid: "#9932CC",
9137 yellowgreen: "#9ACD32",
9138 sienna: "#A0522D",
9139 brown: "#A52A2A",
9140 darkgray: "#A9A9A9",
9141 lightblue: "#ADD8E6",
9142 greenyellow: "#ADFF2F",
9143 paleturquoise: "#AFEEEE",
9144 lightsteelblue: "#B0C4DE",
9145 powderblue: "#B0E0E6",
9146 firebrick: "#B22222",
9147 darkgoldenrod: "#B8860B",
9148 mediumorchid: "#BA55D3",
9149 rosybrown: "#BC8F8F",
9150 darkkhaki: "#BDB76B",
9151 silver: "#C0C0C0",
9152 mediumvioletred: "#C71585",
9153 indianred: "#CD5C5C",
9154 peru: "#CD853F",
9155 chocolate: "#D2691E",
9156 tan: "#D2B48C",
9157 lightgrey: "#D3D3D3",
9158 palevioletred: "#D87093",
9159 thistle: "#D8BFD8",
9160 orchid: "#DA70D6",
9161 goldenrod: "#DAA520",
9162 crimson: "#DC143C",
9163 gainsboro: "#DCDCDC",
9164 plum: "#DDA0DD",
9165 burlywood: "#DEB887",
9166 lightcyan: "#E0FFFF",
9167 lavender: "#E6E6FA",
9168 darksalmon: "#E9967A",
9169 violet: "#EE82EE",
9170 palegoldenrod: "#EEE8AA",
9171 lightcoral: "#F08080",
9172 khaki: "#F0E68C",
9173 aliceblue: "#F0F8FF",
9174 honeydew: "#F0FFF0",
9175 azure: "#F0FFFF",
9176 sandybrown: "#F4A460",
9177 wheat: "#F5DEB3",
9178 beige: "#F5F5DC",
9179 whitesmoke: "#F5F5F5",
9180 mintcream: "#F5FFFA",
9181 ghostwhite: "#F8F8FF",
9182 salmon: "#FA8072",
9183 antiquewhite: "#FAEBD7",
9184 linen: "#FAF0E6",
9185 lightgoldenrodyellow: "#FAFAD2",
9186 oldlace: "#FDF5E6",
9187 red: "#FF0000",
9188 fuchsia: "#FF00FF",
9189 magenta: "#FF00FF",
9190 deeppink: "#FF1493",
9191 orangered: "#FF4500",
9192 tomato: "#FF6347",
9193 hotpink: "#FF69B4",
9194 coral: "#FF7F50",
9195 darkorange: "#FF8C00",
9196 lightsalmon: "#FFA07A",
9197 orange: "#FFA500",
9198 lightpink: "#FFB6C1",
9199 pink: "#FFC0CB",
9200 gold: "#FFD700",
9201 peachpuff: "#FFDAB9",
9202 navajowhite: "#FFDEAD",
9203 moccasin: "#FFE4B5",
9204 bisque: "#FFE4C4",
9205 mistyrose: "#FFE4E1",
9206 blanchedalmond: "#FFEBCD",
9207 papayawhip: "#FFEFD5",
9208 lavenderblush: "#FFF0F5",
9209 seashell: "#FFF5EE",
9210 cornsilk: "#FFF8DC",
9211 lemonchiffon: "#FFFACD",
9212 floralwhite: "#FFFAF0",
9213 snow: "#FFFAFA",
9214 yellow: "#FFFF00",
9215 lightyellow: "#FFFFE0",
9216 ivory: "#FFFFF0",
9217 white: "#FFFFFF"
9218};
9219/**
9220 * @param {number} [pixelRatio=1]
9221 */
9222
9223var ColorPicker = /*#__PURE__*/function () {
9224 /**
9225 * @param {number} [pixelRatio=1]
9226 */
9227 function ColorPicker() {
9228 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
9229
9230 _classCallCheck(this, ColorPicker);
9231
9232 this.pixelRatio = pixelRatio;
9233 this.generated = false;
9234 this.centerCoordinates = {
9235 x: 289 / 2,
9236 y: 289 / 2
9237 };
9238 this.r = 289 * 0.49;
9239 this.color = {
9240 r: 255,
9241 g: 255,
9242 b: 255,
9243 a: 1.0
9244 };
9245 this.hueCircle = undefined;
9246 this.initialColor = {
9247 r: 255,
9248 g: 255,
9249 b: 255,
9250 a: 1.0
9251 };
9252 this.previousColor = undefined;
9253 this.applied = false; // bound by
9254
9255 this.updateCallback = function () {};
9256
9257 this.closeCallback = function () {}; // create all DOM elements
9258
9259
9260 this._create();
9261 }
9262 /**
9263 * this inserts the colorPicker into a div from the DOM
9264 *
9265 * @param {Element} container
9266 */
9267
9268
9269 _createClass(ColorPicker, [{
9270 key: "insertTo",
9271 value: function insertTo(container) {
9272 if (this.hammer !== undefined) {
9273 this.hammer.destroy();
9274 this.hammer = undefined;
9275 }
9276
9277 this.container = container;
9278 this.container.appendChild(this.frame);
9279
9280 this._bindHammer();
9281
9282 this._setSize();
9283 }
9284 /**
9285 * the callback is executed on apply and save. Bind it to the application
9286 *
9287 * @param {Function} callback
9288 */
9289
9290 }, {
9291 key: "setUpdateCallback",
9292 value: function setUpdateCallback(callback) {
9293 if (typeof callback === "function") {
9294 this.updateCallback = callback;
9295 } else {
9296 throw new Error("Function attempted to set as colorPicker update callback is not a function.");
9297 }
9298 }
9299 /**
9300 * the callback is executed on apply and save. Bind it to the application
9301 *
9302 * @param {Function} callback
9303 */
9304
9305 }, {
9306 key: "setCloseCallback",
9307 value: function setCloseCallback(callback) {
9308 if (typeof callback === "function") {
9309 this.closeCallback = callback;
9310 } else {
9311 throw new Error("Function attempted to set as colorPicker closing callback is not a function.");
9312 }
9313 }
9314 /**
9315 *
9316 * @param {string} color
9317 * @returns {string}
9318 * @private
9319 */
9320
9321 }, {
9322 key: "_isColorString",
9323 value: function _isColorString(color) {
9324 if (typeof color === "string") {
9325 return htmlColors[color];
9326 }
9327 }
9328 /**
9329 * Set the color of the colorPicker
9330 * Supported formats:
9331 * 'red' --> HTML color string
9332 * '#ffffff' --> hex string
9333 * 'rgb(255,255,255)' --> rgb string
9334 * 'rgba(255,255,255,1.0)' --> rgba string
9335 * {r:255,g:255,b:255} --> rgb object
9336 * {r:255,g:255,b:255,a:1.0} --> rgba object
9337 *
9338 * @param {string | object} color
9339 * @param {boolean} [setInitial=true]
9340 */
9341
9342 }, {
9343 key: "setColor",
9344 value: function setColor(color) {
9345 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
9346
9347 if (color === "none") {
9348 return;
9349 }
9350
9351 var rgba; // if a html color shorthand is used, convert to hex
9352
9353 var htmlColor = this._isColorString(color);
9354
9355 if (htmlColor !== undefined) {
9356 color = htmlColor;
9357 } // check format
9358
9359
9360 if (isString(color) === true) {
9361 if (isValidRGB(color) === true) {
9362 var rgbaArray = color.substr(4).substr(0, color.length - 5).split(",");
9363 rgba = {
9364 r: rgbaArray[0],
9365 g: rgbaArray[1],
9366 b: rgbaArray[2],
9367 a: 1.0
9368 };
9369 } else if (isValidRGBA(color) === true) {
9370 var _rgbaArray = color.substr(5).substr(0, color.length - 6).split(",");
9371
9372 rgba = {
9373 r: _rgbaArray[0],
9374 g: _rgbaArray[1],
9375 b: _rgbaArray[2],
9376 a: _rgbaArray[3]
9377 };
9378 } else if (isValidHex(color) === true) {
9379 var rgbObj = hexToRGB(color);
9380 rgba = {
9381 r: rgbObj.r,
9382 g: rgbObj.g,
9383 b: rgbObj.b,
9384 a: 1.0
9385 };
9386 }
9387 } else {
9388 if (color instanceof Object) {
9389 if (color.r !== undefined && color.g !== undefined && color.b !== undefined) {
9390 var alpha = color.a !== undefined ? color.a : "1.0";
9391 rgba = {
9392 r: color.r,
9393 g: color.g,
9394 b: color.b,
9395 a: alpha
9396 };
9397 }
9398 }
9399 } // set color
9400
9401
9402 if (rgba === undefined) {
9403 throw new Error("Unknown color passed to the colorPicker. Supported are strings: rgb, hex, rgba. Object: rgb ({r:r,g:g,b:b,[a:a]}). Supplied: " + stringify$1(color));
9404 } else {
9405 this._setColor(rgba, setInitial);
9406 }
9407 }
9408 /**
9409 * this shows the color picker.
9410 * The hue circle is constructed once and stored.
9411 */
9412
9413 }, {
9414 key: "show",
9415 value: function show() {
9416 if (this.closeCallback !== undefined) {
9417 this.closeCallback();
9418 this.closeCallback = undefined;
9419 }
9420
9421 this.applied = false;
9422 this.frame.style.display = "block";
9423
9424 this._generateHueCircle();
9425 } // ------------------------------------------ PRIVATE ----------------------------- //
9426
9427 /**
9428 * Hide the picker. Is called by the cancel button.
9429 * Optional boolean to store the previous color for easy access later on.
9430 *
9431 * @param {boolean} [storePrevious=true]
9432 * @private
9433 */
9434
9435 }, {
9436 key: "_hide",
9437 value: function _hide() {
9438 var _this2 = this;
9439
9440 var storePrevious = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
9441
9442 // store the previous color for next time;
9443 if (storePrevious === true) {
9444 this.previousColor = assign$2({}, this.color);
9445 }
9446
9447 if (this.applied === true) {
9448 this.updateCallback(this.initialColor);
9449 }
9450
9451 this.frame.style.display = "none"; // call the closing callback, restoring the onclick method.
9452 // this is in a setTimeout because it will trigger the show again before the click is done.
9453
9454 setTimeout$1(function () {
9455 if (_this2.closeCallback !== undefined) {
9456 _this2.closeCallback();
9457
9458 _this2.closeCallback = undefined;
9459 }
9460 }, 0);
9461 }
9462 /**
9463 * bound to the save button. Saves and hides.
9464 *
9465 * @private
9466 */
9467
9468 }, {
9469 key: "_save",
9470 value: function _save() {
9471 this.updateCallback(this.color);
9472 this.applied = false;
9473
9474 this._hide();
9475 }
9476 /**
9477 * Bound to apply button. Saves but does not close. Is undone by the cancel button.
9478 *
9479 * @private
9480 */
9481
9482 }, {
9483 key: "_apply",
9484 value: function _apply() {
9485 this.applied = true;
9486 this.updateCallback(this.color);
9487
9488 this._updatePicker(this.color);
9489 }
9490 /**
9491 * load the color from the previous session.
9492 *
9493 * @private
9494 */
9495
9496 }, {
9497 key: "_loadLast",
9498 value: function _loadLast() {
9499 if (this.previousColor !== undefined) {
9500 this.setColor(this.previousColor, false);
9501 } else {
9502 alert("There is no last color to load...");
9503 }
9504 }
9505 /**
9506 * set the color, place the picker
9507 *
9508 * @param {object} rgba
9509 * @param {boolean} [setInitial=true]
9510 * @private
9511 */
9512
9513 }, {
9514 key: "_setColor",
9515 value: function _setColor(rgba) {
9516 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
9517
9518 // store the initial color
9519 if (setInitial === true) {
9520 this.initialColor = assign$2({}, rgba);
9521 }
9522
9523 this.color = rgba;
9524 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
9525 var angleConvert = 2 * Math.PI;
9526 var radius = this.r * hsv.s;
9527 var x = this.centerCoordinates.x + radius * Math.sin(angleConvert * hsv.h);
9528 var y = this.centerCoordinates.y + radius * Math.cos(angleConvert * hsv.h);
9529 this.colorPickerSelector.style.left = x - 0.5 * this.colorPickerSelector.clientWidth + "px";
9530 this.colorPickerSelector.style.top = y - 0.5 * this.colorPickerSelector.clientHeight + "px";
9531
9532 this._updatePicker(rgba);
9533 }
9534 /**
9535 * bound to opacity control
9536 *
9537 * @param {number} value
9538 * @private
9539 */
9540
9541 }, {
9542 key: "_setOpacity",
9543 value: function _setOpacity(value) {
9544 this.color.a = value / 100;
9545
9546 this._updatePicker(this.color);
9547 }
9548 /**
9549 * bound to brightness control
9550 *
9551 * @param {number} value
9552 * @private
9553 */
9554
9555 }, {
9556 key: "_setBrightness",
9557 value: function _setBrightness(value) {
9558 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
9559 hsv.v = value / 100;
9560 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
9561 rgba["a"] = this.color.a;
9562 this.color = rgba;
9563
9564 this._updatePicker();
9565 }
9566 /**
9567 * update the color picker. A black circle overlays the hue circle to mimic the brightness decreasing.
9568 *
9569 * @param {object} rgba
9570 * @private
9571 */
9572
9573 }, {
9574 key: "_updatePicker",
9575 value: function _updatePicker() {
9576 var rgba = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.color;
9577 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
9578 var ctx = this.colorPickerCanvas.getContext("2d");
9579
9580 if (this.pixelRation === undefined) {
9581 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
9582 }
9583
9584 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
9585
9586 var w = this.colorPickerCanvas.clientWidth;
9587 var h = this.colorPickerCanvas.clientHeight;
9588 ctx.clearRect(0, 0, w, h);
9589 ctx.putImageData(this.hueCircle, 0, 0);
9590 ctx.fillStyle = "rgba(0,0,0," + (1 - hsv.v) + ")";
9591 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
9592
9593 fill(ctx).call(ctx);
9594
9595 this.brightnessRange.value = 100 * hsv.v;
9596 this.opacityRange.value = 100 * rgba.a;
9597 this.initialColorDiv.style.backgroundColor = "rgba(" + this.initialColor.r + "," + this.initialColor.g + "," + this.initialColor.b + "," + this.initialColor.a + ")";
9598 this.newColorDiv.style.backgroundColor = "rgba(" + this.color.r + "," + this.color.g + "," + this.color.b + "," + this.color.a + ")";
9599 }
9600 /**
9601 * used by create to set the size of the canvas.
9602 *
9603 * @private
9604 */
9605
9606 }, {
9607 key: "_setSize",
9608 value: function _setSize() {
9609 this.colorPickerCanvas.style.width = "100%";
9610 this.colorPickerCanvas.style.height = "100%";
9611 this.colorPickerCanvas.width = 289 * this.pixelRatio;
9612 this.colorPickerCanvas.height = 289 * this.pixelRatio;
9613 }
9614 /**
9615 * create all dom elements
9616 * TODO: cleanup, lots of similar dom elements
9617 *
9618 * @private
9619 */
9620
9621 }, {
9622 key: "_create",
9623 value: function _create() {
9624 var _context16, _context17, _context18, _context19;
9625
9626 this.frame = document.createElement("div");
9627 this.frame.className = "vis-color-picker";
9628 this.colorPickerDiv = document.createElement("div");
9629 this.colorPickerSelector = document.createElement("div");
9630 this.colorPickerSelector.className = "vis-selector";
9631 this.colorPickerDiv.appendChild(this.colorPickerSelector);
9632 this.colorPickerCanvas = document.createElement("canvas");
9633 this.colorPickerDiv.appendChild(this.colorPickerCanvas);
9634
9635 if (!this.colorPickerCanvas.getContext) {
9636 var noCanvas = document.createElement("DIV");
9637 noCanvas.style.color = "red";
9638 noCanvas.style.fontWeight = "bold";
9639 noCanvas.style.padding = "10px";
9640 noCanvas.innerText = "Error: your browser does not support HTML canvas";
9641 this.colorPickerCanvas.appendChild(noCanvas);
9642 } else {
9643 var ctx = this.colorPickerCanvas.getContext("2d");
9644 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
9645 this.colorPickerCanvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
9646 }
9647
9648 this.colorPickerDiv.className = "vis-color";
9649 this.opacityDiv = document.createElement("div");
9650 this.opacityDiv.className = "vis-opacity";
9651 this.brightnessDiv = document.createElement("div");
9652 this.brightnessDiv.className = "vis-brightness";
9653 this.arrowDiv = document.createElement("div");
9654 this.arrowDiv.className = "vis-arrow";
9655 this.opacityRange = document.createElement("input");
9656
9657 try {
9658 this.opacityRange.type = "range"; // Not supported on IE9
9659
9660 this.opacityRange.min = "0";
9661 this.opacityRange.max = "100";
9662 } catch (err) {// TODO: Add some error handling.
9663 }
9664
9665 this.opacityRange.value = "100";
9666 this.opacityRange.className = "vis-range";
9667 this.brightnessRange = document.createElement("input");
9668
9669 try {
9670 this.brightnessRange.type = "range"; // Not supported on IE9
9671
9672 this.brightnessRange.min = "0";
9673 this.brightnessRange.max = "100";
9674 } catch (err) {// TODO: Add some error handling.
9675 }
9676
9677 this.brightnessRange.value = "100";
9678 this.brightnessRange.className = "vis-range";
9679 this.opacityDiv.appendChild(this.opacityRange);
9680 this.brightnessDiv.appendChild(this.brightnessRange);
9681 var me = this;
9682
9683 this.opacityRange.onchange = function () {
9684 me._setOpacity(this.value);
9685 };
9686
9687 this.opacityRange.oninput = function () {
9688 me._setOpacity(this.value);
9689 };
9690
9691 this.brightnessRange.onchange = function () {
9692 me._setBrightness(this.value);
9693 };
9694
9695 this.brightnessRange.oninput = function () {
9696 me._setBrightness(this.value);
9697 };
9698
9699 this.brightnessLabel = document.createElement("div");
9700 this.brightnessLabel.className = "vis-label vis-brightness";
9701 this.brightnessLabel.innerText = "brightness:";
9702 this.opacityLabel = document.createElement("div");
9703 this.opacityLabel.className = "vis-label vis-opacity";
9704 this.opacityLabel.innerText = "opacity:";
9705 this.newColorDiv = document.createElement("div");
9706 this.newColorDiv.className = "vis-new-color";
9707 this.newColorDiv.innerText = "new";
9708 this.initialColorDiv = document.createElement("div");
9709 this.initialColorDiv.className = "vis-initial-color";
9710 this.initialColorDiv.innerText = "initial";
9711 this.cancelButton = document.createElement("div");
9712 this.cancelButton.className = "vis-button vis-cancel";
9713 this.cancelButton.innerText = "cancel";
9714 this.cancelButton.onclick = bind(_context16 = this._hide).call(_context16, this, false);
9715 this.applyButton = document.createElement("div");
9716 this.applyButton.className = "vis-button vis-apply";
9717 this.applyButton.innerText = "apply";
9718 this.applyButton.onclick = bind(_context17 = this._apply).call(_context17, this);
9719 this.saveButton = document.createElement("div");
9720 this.saveButton.className = "vis-button vis-save";
9721 this.saveButton.innerText = "save";
9722 this.saveButton.onclick = bind(_context18 = this._save).call(_context18, this);
9723 this.loadButton = document.createElement("div");
9724 this.loadButton.className = "vis-button vis-load";
9725 this.loadButton.innerText = "load last";
9726 this.loadButton.onclick = bind(_context19 = this._loadLast).call(_context19, this);
9727 this.frame.appendChild(this.colorPickerDiv);
9728 this.frame.appendChild(this.arrowDiv);
9729 this.frame.appendChild(this.brightnessLabel);
9730 this.frame.appendChild(this.brightnessDiv);
9731 this.frame.appendChild(this.opacityLabel);
9732 this.frame.appendChild(this.opacityDiv);
9733 this.frame.appendChild(this.newColorDiv);
9734 this.frame.appendChild(this.initialColorDiv);
9735 this.frame.appendChild(this.cancelButton);
9736 this.frame.appendChild(this.applyButton);
9737 this.frame.appendChild(this.saveButton);
9738 this.frame.appendChild(this.loadButton);
9739 }
9740 /**
9741 * bind hammer to the color picker
9742 *
9743 * @private
9744 */
9745
9746 }, {
9747 key: "_bindHammer",
9748 value: function _bindHammer() {
9749 var _this3 = this;
9750
9751 this.drag = {};
9752 this.pinch = {};
9753 this.hammer = new Hammer(this.colorPickerCanvas);
9754 this.hammer.get("pinch").set({
9755 enable: true
9756 });
9757 this.hammer.on("hammer.input", function (event) {
9758 if (event.isFirst) {
9759 _this3._moveSelector(event);
9760 }
9761 });
9762 this.hammer.on("tap", function (event) {
9763 _this3._moveSelector(event);
9764 });
9765 this.hammer.on("panstart", function (event) {
9766 _this3._moveSelector(event);
9767 });
9768 this.hammer.on("panmove", function (event) {
9769 _this3._moveSelector(event);
9770 });
9771 this.hammer.on("panend", function (event) {
9772 _this3._moveSelector(event);
9773 });
9774 }
9775 /**
9776 * generate the hue circle. This is relatively heavy (200ms) and is done only once on the first time it is shown.
9777 *
9778 * @private
9779 */
9780
9781 }, {
9782 key: "_generateHueCircle",
9783 value: function _generateHueCircle() {
9784 if (this.generated === false) {
9785 var ctx = this.colorPickerCanvas.getContext("2d");
9786
9787 if (this.pixelRation === undefined) {
9788 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
9789 }
9790
9791 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
9792
9793 var w = this.colorPickerCanvas.clientWidth;
9794 var h = this.colorPickerCanvas.clientHeight;
9795 ctx.clearRect(0, 0, w, h); // draw hue circle
9796
9797 var x, y, hue, sat;
9798 this.centerCoordinates = {
9799 x: w * 0.5,
9800 y: h * 0.5
9801 };
9802 this.r = 0.49 * w;
9803 var angleConvert = 2 * Math.PI / 360;
9804 var hfac = 1 / 360;
9805 var sfac = 1 / this.r;
9806 var rgb;
9807
9808 for (hue = 0; hue < 360; hue++) {
9809 for (sat = 0; sat < this.r; sat++) {
9810 x = this.centerCoordinates.x + sat * Math.sin(angleConvert * hue);
9811 y = this.centerCoordinates.y + sat * Math.cos(angleConvert * hue);
9812 rgb = HSVToRGB(hue * hfac, sat * sfac, 1);
9813 ctx.fillStyle = "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")";
9814 ctx.fillRect(x - 0.5, y - 0.5, 2, 2);
9815 }
9816 }
9817
9818 ctx.strokeStyle = "rgba(0,0,0,1)";
9819 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
9820 ctx.stroke();
9821 this.hueCircle = ctx.getImageData(0, 0, w, h);
9822 }
9823
9824 this.generated = true;
9825 }
9826 /**
9827 * move the selector. This is called by hammer functions.
9828 *
9829 * @param {Event} event The event
9830 * @private
9831 */
9832
9833 }, {
9834 key: "_moveSelector",
9835 value: function _moveSelector(event) {
9836 var rect = this.colorPickerDiv.getBoundingClientRect();
9837 var left = event.center.x - rect.left;
9838 var top = event.center.y - rect.top;
9839 var centerY = 0.5 * this.colorPickerDiv.clientHeight;
9840 var centerX = 0.5 * this.colorPickerDiv.clientWidth;
9841 var x = left - centerX;
9842 var y = top - centerY;
9843 var angle = Math.atan2(x, y);
9844 var radius = 0.98 * Math.min(Math.sqrt(x * x + y * y), centerX);
9845 var newTop = Math.cos(angle) * radius + centerY;
9846 var newLeft = Math.sin(angle) * radius + centerX;
9847 this.colorPickerSelector.style.top = newTop - 0.5 * this.colorPickerSelector.clientHeight + "px";
9848 this.colorPickerSelector.style.left = newLeft - 0.5 * this.colorPickerSelector.clientWidth + "px"; // set color
9849
9850 var h = angle / (2 * Math.PI);
9851 h = h < 0 ? h + 1 : h;
9852 var s = radius / this.r;
9853 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
9854 hsv.h = h;
9855 hsv.s = s;
9856 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
9857 rgba["a"] = this.color.a;
9858 this.color = rgba; // update previews
9859
9860 this.initialColorDiv.style.backgroundColor = "rgba(" + this.initialColor.r + "," + this.initialColor.g + "," + this.initialColor.b + "," + this.initialColor.a + ")";
9861 this.newColorDiv.style.backgroundColor = "rgba(" + this.color.r + "," + this.color.g + "," + this.color.b + "," + this.color.a + ")";
9862 }
9863 }]);
9864
9865 return ColorPicker;
9866}();
9867/**
9868 * Wrap given text (last argument) in HTML elements (all preceding arguments).
9869 *
9870 * @param {...any} rest - List of tag names followed by inner text.
9871 *
9872 * @returns An element or a text node.
9873 */
9874
9875
9876function wrapInTag() {
9877 for (var _len5 = arguments.length, rest = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
9878 rest[_key5] = arguments[_key5];
9879 }
9880
9881 if (rest.length < 1) {
9882 throw new TypeError("Invalid arguments.");
9883 } else if (rest.length === 1) {
9884 return document.createTextNode(rest[0]);
9885 } else {
9886 var element = document.createElement(rest[0]);
9887 element.appendChild(wrapInTag.apply(void 0, _toConsumableArray(slice$1(rest).call(rest, 1))));
9888 return element;
9889 }
9890}
9891/**
9892 * The way this works is for all properties of this.possible options, you can supply the property name in any form to list the options.
9893 * Boolean options are recognised as Boolean
9894 * Number options should be written as array: [default value, min value, max value, stepsize]
9895 * Colors should be written as array: ['color', '#ffffff']
9896 * Strings with should be written as array: [option1, option2, option3, ..]
9897 *
9898 * The options are matched with their counterparts in each of the modules and the values used in the configuration are
9899 */
9900
9901
9902var Configurator = /*#__PURE__*/function () {
9903 /**
9904 * @param {object} parentModule | the location where parentModule.setOptions() can be called
9905 * @param {object} defaultContainer | the default container of the module
9906 * @param {object} configureOptions | the fully configured and predefined options set found in allOptions.js
9907 * @param {number} pixelRatio | canvas pixel ratio
9908 * @param {Function} hideOption | custom logic to dynamically hide options
9909 */
9910 function Configurator(parentModule, defaultContainer, configureOptions) {
9911 var pixelRatio = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
9912 var hideOption = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : function () {
9913 return false;
9914 };
9915
9916 _classCallCheck(this, Configurator);
9917
9918 this.parent = parentModule;
9919 this.changedOptions = [];
9920 this.container = defaultContainer;
9921 this.allowCreation = false;
9922 this.hideOption = hideOption;
9923 this.options = {};
9924 this.initialized = false;
9925 this.popupCounter = 0;
9926 this.defaultOptions = {
9927 enabled: false,
9928 filter: true,
9929 container: undefined,
9930 showButton: true
9931 };
9932
9933 assign$2(this.options, this.defaultOptions);
9934
9935 this.configureOptions = configureOptions;
9936 this.moduleOptions = {};
9937 this.domElements = [];
9938 this.popupDiv = {};
9939 this.popupLimit = 5;
9940 this.popupHistory = {};
9941 this.colorPicker = new ColorPicker(pixelRatio);
9942 this.wrapper = undefined;
9943 }
9944 /**
9945 * refresh all options.
9946 * Because all modules parse their options by themselves, we just use their options. We copy them here.
9947 *
9948 * @param {object} options
9949 */
9950
9951
9952 _createClass(Configurator, [{
9953 key: "setOptions",
9954 value: function setOptions(options) {
9955 if (options !== undefined) {
9956 // reset the popup history because the indices may have been changed.
9957 this.popupHistory = {};
9958
9959 this._removePopup();
9960
9961 var enabled = true;
9962
9963 if (typeof options === "string") {
9964 this.options.filter = options;
9965 } else if (isArray(options)) {
9966 this.options.filter = options.join();
9967 } else if (_typeof(options) === "object") {
9968 if (options == null) {
9969 throw new TypeError("options cannot be null");
9970 }
9971
9972 if (options.container !== undefined) {
9973 this.options.container = options.container;
9974 }
9975
9976 if (filter(options) !== undefined) {
9977 this.options.filter = filter(options);
9978 }
9979
9980 if (options.showButton !== undefined) {
9981 this.options.showButton = options.showButton;
9982 }
9983
9984 if (options.enabled !== undefined) {
9985 enabled = options.enabled;
9986 }
9987 } else if (typeof options === "boolean") {
9988 this.options.filter = true;
9989 enabled = options;
9990 } else if (typeof options === "function") {
9991 this.options.filter = options;
9992 enabled = true;
9993 }
9994
9995 if (filter(this.options) === false) {
9996 enabled = false;
9997 }
9998
9999 this.options.enabled = enabled;
10000 }
10001
10002 this._clean();
10003 }
10004 /**
10005 *
10006 * @param {object} moduleOptions
10007 */
10008
10009 }, {
10010 key: "setModuleOptions",
10011 value: function setModuleOptions(moduleOptions) {
10012 this.moduleOptions = moduleOptions;
10013
10014 if (this.options.enabled === true) {
10015 this._clean();
10016
10017 if (this.options.container !== undefined) {
10018 this.container = this.options.container;
10019 }
10020
10021 this._create();
10022 }
10023 }
10024 /**
10025 * Create all DOM elements
10026 *
10027 * @private
10028 */
10029
10030 }, {
10031 key: "_create",
10032 value: function _create() {
10033 this._clean();
10034
10035 this.changedOptions = [];
10036
10037 var filter$1 = filter(this.options);
10038
10039 var counter = 0;
10040 var show = false;
10041
10042 for (var _option in this.configureOptions) {
10043 if (Object.prototype.hasOwnProperty.call(this.configureOptions, _option)) {
10044 this.allowCreation = false;
10045 show = false;
10046
10047 if (typeof filter$1 === "function") {
10048 show = filter$1(_option, []);
10049 show = show || this._handleObject(this.configureOptions[_option], [_option], true);
10050 } else if (filter$1 === true || indexOf(filter$1).call(filter$1, _option) !== -1) {
10051 show = true;
10052 }
10053
10054 if (show !== false) {
10055 this.allowCreation = true; // linebreak between categories
10056
10057 if (counter > 0) {
10058 this._makeItem([]);
10059 } // a header for the category
10060
10061
10062 this._makeHeader(_option); // get the sub options
10063
10064
10065 this._handleObject(this.configureOptions[_option], [_option]);
10066 }
10067
10068 counter++;
10069 }
10070 }
10071
10072 this._makeButton();
10073
10074 this._push(); //~ this.colorPicker.insertTo(this.container);
10075
10076 }
10077 /**
10078 * draw all DOM elements on the screen
10079 *
10080 * @private
10081 */
10082
10083 }, {
10084 key: "_push",
10085 value: function _push() {
10086 this.wrapper = document.createElement("div");
10087 this.wrapper.className = "vis-configuration-wrapper";
10088 this.container.appendChild(this.wrapper);
10089
10090 for (var i = 0; i < this.domElements.length; i++) {
10091 this.wrapper.appendChild(this.domElements[i]);
10092 }
10093
10094 this._showPopupIfNeeded();
10095 }
10096 /**
10097 * delete all DOM elements
10098 *
10099 * @private
10100 */
10101
10102 }, {
10103 key: "_clean",
10104 value: function _clean() {
10105 for (var i = 0; i < this.domElements.length; i++) {
10106 this.wrapper.removeChild(this.domElements[i]);
10107 }
10108
10109 if (this.wrapper !== undefined) {
10110 this.container.removeChild(this.wrapper);
10111 this.wrapper = undefined;
10112 }
10113
10114 this.domElements = [];
10115
10116 this._removePopup();
10117 }
10118 /**
10119 * get the value from the actualOptions if it exists
10120 *
10121 * @param {Array} path | where to look for the actual option
10122 * @returns {*}
10123 * @private
10124 */
10125
10126 }, {
10127 key: "_getValue",
10128 value: function _getValue(path) {
10129 var base = this.moduleOptions;
10130
10131 for (var i = 0; i < path.length; i++) {
10132 if (base[path[i]] !== undefined) {
10133 base = base[path[i]];
10134 } else {
10135 base = undefined;
10136 break;
10137 }
10138 }
10139
10140 return base;
10141 }
10142 /**
10143 * all option elements are wrapped in an item
10144 *
10145 * @param {Array} path | where to look for the actual option
10146 * @param {Array.<Element>} domElements
10147 * @returns {number}
10148 * @private
10149 */
10150
10151 }, {
10152 key: "_makeItem",
10153 value: function _makeItem(path) {
10154 if (this.allowCreation === true) {
10155 var item = document.createElement("div");
10156 item.className = "vis-configuration vis-config-item vis-config-s" + path.length;
10157
10158 for (var _len6 = arguments.length, domElements = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
10159 domElements[_key6 - 1] = arguments[_key6];
10160 }
10161
10162 forEach$2(domElements).call(domElements, function (element) {
10163 item.appendChild(element);
10164 });
10165
10166 this.domElements.push(item);
10167 return this.domElements.length;
10168 }
10169
10170 return 0;
10171 }
10172 /**
10173 * header for major subjects
10174 *
10175 * @param {string} name
10176 * @private
10177 */
10178
10179 }, {
10180 key: "_makeHeader",
10181 value: function _makeHeader(name) {
10182 var div = document.createElement("div");
10183 div.className = "vis-configuration vis-config-header";
10184 div.innerText = name;
10185
10186 this._makeItem([], div);
10187 }
10188 /**
10189 * make a label, if it is an object label, it gets different styling.
10190 *
10191 * @param {string} name
10192 * @param {Array} path | where to look for the actual option
10193 * @param {string} objectLabel
10194 * @returns {HTMLElement}
10195 * @private
10196 */
10197
10198 }, {
10199 key: "_makeLabel",
10200 value: function _makeLabel(name, path) {
10201 var objectLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
10202 var div = document.createElement("div");
10203 div.className = "vis-configuration vis-config-label vis-config-s" + path.length;
10204
10205 if (objectLabel === true) {
10206 while (div.firstChild) {
10207 div.removeChild(div.firstChild);
10208 }
10209
10210 div.appendChild(wrapInTag("i", "b", name));
10211 } else {
10212 div.innerText = name + ":";
10213 }
10214
10215 return div;
10216 }
10217 /**
10218 * make a dropdown list for multiple possible string optoins
10219 *
10220 * @param {Array.<number>} arr
10221 * @param {number} value
10222 * @param {Array} path | where to look for the actual option
10223 * @private
10224 */
10225
10226 }, {
10227 key: "_makeDropdown",
10228 value: function _makeDropdown(arr, value, path) {
10229 var select = document.createElement("select");
10230 select.className = "vis-configuration vis-config-select";
10231 var selectedValue = 0;
10232
10233 if (value !== undefined) {
10234 if (indexOf(arr).call(arr, value) !== -1) {
10235 selectedValue = indexOf(arr).call(arr, value);
10236 }
10237 }
10238
10239 for (var i = 0; i < arr.length; i++) {
10240 var _option2 = document.createElement("option");
10241
10242 _option2.value = arr[i];
10243
10244 if (i === selectedValue) {
10245 _option2.selected = "selected";
10246 }
10247
10248 _option2.innerText = arr[i];
10249 select.appendChild(_option2);
10250 }
10251
10252 var me = this;
10253
10254 select.onchange = function () {
10255 me._update(this.value, path);
10256 };
10257
10258 var label = this._makeLabel(path[path.length - 1], path);
10259
10260 this._makeItem(path, label, select);
10261 }
10262 /**
10263 * make a range object for numeric options
10264 *
10265 * @param {Array.<number>} arr
10266 * @param {number} value
10267 * @param {Array} path | where to look for the actual option
10268 * @private
10269 */
10270
10271 }, {
10272 key: "_makeRange",
10273 value: function _makeRange(arr, value, path) {
10274 var defaultValue = arr[0];
10275 var min = arr[1];
10276 var max = arr[2];
10277 var step = arr[3];
10278 var range = document.createElement("input");
10279 range.className = "vis-configuration vis-config-range";
10280
10281 try {
10282 range.type = "range"; // not supported on IE9
10283
10284 range.min = min;
10285 range.max = max;
10286 } catch (err) {// TODO: Add some error handling.
10287 }
10288
10289 range.step = step; // set up the popup settings in case they are needed.
10290
10291 var popupString = "";
10292 var popupValue = 0;
10293
10294 if (value !== undefined) {
10295 var factor = 1.2;
10296
10297 if (value < 0 && value * factor < min) {
10298 range.min = Math.ceil(value * factor);
10299 popupValue = range.min;
10300 popupString = "range increased";
10301 } else if (value / factor < min) {
10302 range.min = Math.ceil(value / factor);
10303 popupValue = range.min;
10304 popupString = "range increased";
10305 }
10306
10307 if (value * factor > max && max !== 1) {
10308 range.max = Math.ceil(value * factor);
10309 popupValue = range.max;
10310 popupString = "range increased";
10311 }
10312
10313 range.value = value;
10314 } else {
10315 range.value = defaultValue;
10316 }
10317
10318 var input = document.createElement("input");
10319 input.className = "vis-configuration vis-config-rangeinput";
10320 input.value = range.value;
10321 var me = this;
10322
10323 range.onchange = function () {
10324 input.value = this.value;
10325
10326 me._update(Number(this.value), path);
10327 };
10328
10329 range.oninput = function () {
10330 input.value = this.value;
10331 };
10332
10333 var label = this._makeLabel(path[path.length - 1], path);
10334
10335 var itemIndex = this._makeItem(path, label, range, input); // if a popup is needed AND it has not been shown for this value, show it.
10336
10337
10338 if (popupString !== "" && this.popupHistory[itemIndex] !== popupValue) {
10339 this.popupHistory[itemIndex] = popupValue;
10340
10341 this._setupPopup(popupString, itemIndex);
10342 }
10343 }
10344 /**
10345 * make a button object
10346 *
10347 * @private
10348 */
10349
10350 }, {
10351 key: "_makeButton",
10352 value: function _makeButton() {
10353 var _this4 = this;
10354
10355 if (this.options.showButton === true) {
10356 var generateButton = document.createElement("div");
10357 generateButton.className = "vis-configuration vis-config-button";
10358 generateButton.innerText = "generate options";
10359
10360 generateButton.onclick = function () {
10361 _this4._printOptions();
10362 };
10363
10364 generateButton.onmouseover = function () {
10365 generateButton.className = "vis-configuration vis-config-button hover";
10366 };
10367
10368 generateButton.onmouseout = function () {
10369 generateButton.className = "vis-configuration vis-config-button";
10370 };
10371
10372 this.optionsContainer = document.createElement("div");
10373 this.optionsContainer.className = "vis-configuration vis-config-option-container";
10374 this.domElements.push(this.optionsContainer);
10375 this.domElements.push(generateButton);
10376 }
10377 }
10378 /**
10379 * prepare the popup
10380 *
10381 * @param {string} string
10382 * @param {number} index
10383 * @private
10384 */
10385
10386 }, {
10387 key: "_setupPopup",
10388 value: function _setupPopup(string, index) {
10389 var _this5 = this;
10390
10391 if (this.initialized === true && this.allowCreation === true && this.popupCounter < this.popupLimit) {
10392 var div = document.createElement("div");
10393 div.id = "vis-configuration-popup";
10394 div.className = "vis-configuration-popup";
10395 div.innerText = string;
10396
10397 div.onclick = function () {
10398 _this5._removePopup();
10399 };
10400
10401 this.popupCounter += 1;
10402 this.popupDiv = {
10403 html: div,
10404 index: index
10405 };
10406 }
10407 }
10408 /**
10409 * remove the popup from the dom
10410 *
10411 * @private
10412 */
10413
10414 }, {
10415 key: "_removePopup",
10416 value: function _removePopup() {
10417 if (this.popupDiv.html !== undefined) {
10418 this.popupDiv.html.parentNode.removeChild(this.popupDiv.html);
10419 clearTimeout(this.popupDiv.hideTimeout);
10420 clearTimeout(this.popupDiv.deleteTimeout);
10421 this.popupDiv = {};
10422 }
10423 }
10424 /**
10425 * Show the popup if it is needed.
10426 *
10427 * @private
10428 */
10429
10430 }, {
10431 key: "_showPopupIfNeeded",
10432 value: function _showPopupIfNeeded() {
10433 var _this6 = this;
10434
10435 if (this.popupDiv.html !== undefined) {
10436 var correspondingElement = this.domElements[this.popupDiv.index];
10437 var rect = correspondingElement.getBoundingClientRect();
10438 this.popupDiv.html.style.left = rect.left + "px";
10439 this.popupDiv.html.style.top = rect.top - 30 + "px"; // 30 is the height;
10440
10441 document.body.appendChild(this.popupDiv.html);
10442 this.popupDiv.hideTimeout = setTimeout$1(function () {
10443 _this6.popupDiv.html.style.opacity = 0;
10444 }, 1500);
10445 this.popupDiv.deleteTimeout = setTimeout$1(function () {
10446 _this6._removePopup();
10447 }, 1800);
10448 }
10449 }
10450 /**
10451 * make a checkbox for boolean options.
10452 *
10453 * @param {number} defaultValue
10454 * @param {number} value
10455 * @param {Array} path | where to look for the actual option
10456 * @private
10457 */
10458
10459 }, {
10460 key: "_makeCheckbox",
10461 value: function _makeCheckbox(defaultValue, value, path) {
10462 var checkbox = document.createElement("input");
10463 checkbox.type = "checkbox";
10464 checkbox.className = "vis-configuration vis-config-checkbox";
10465 checkbox.checked = defaultValue;
10466
10467 if (value !== undefined) {
10468 checkbox.checked = value;
10469
10470 if (value !== defaultValue) {
10471 if (_typeof(defaultValue) === "object") {
10472 if (value !== defaultValue.enabled) {
10473 this.changedOptions.push({
10474 path: path,
10475 value: value
10476 });
10477 }
10478 } else {
10479 this.changedOptions.push({
10480 path: path,
10481 value: value
10482 });
10483 }
10484 }
10485 }
10486
10487 var me = this;
10488
10489 checkbox.onchange = function () {
10490 me._update(this.checked, path);
10491 };
10492
10493 var label = this._makeLabel(path[path.length - 1], path);
10494
10495 this._makeItem(path, label, checkbox);
10496 }
10497 /**
10498 * make a text input field for string options.
10499 *
10500 * @param {number} defaultValue
10501 * @param {number} value
10502 * @param {Array} path | where to look for the actual option
10503 * @private
10504 */
10505
10506 }, {
10507 key: "_makeTextInput",
10508 value: function _makeTextInput(defaultValue, value, path) {
10509 var checkbox = document.createElement("input");
10510 checkbox.type = "text";
10511 checkbox.className = "vis-configuration vis-config-text";
10512 checkbox.value = value;
10513
10514 if (value !== defaultValue) {
10515 this.changedOptions.push({
10516 path: path,
10517 value: value
10518 });
10519 }
10520
10521 var me = this;
10522
10523 checkbox.onchange = function () {
10524 me._update(this.value, path);
10525 };
10526
10527 var label = this._makeLabel(path[path.length - 1], path);
10528
10529 this._makeItem(path, label, checkbox);
10530 }
10531 /**
10532 * make a color field with a color picker for color fields
10533 *
10534 * @param {Array.<number>} arr
10535 * @param {number} value
10536 * @param {Array} path | where to look for the actual option
10537 * @private
10538 */
10539
10540 }, {
10541 key: "_makeColorField",
10542 value: function _makeColorField(arr, value, path) {
10543 var _this7 = this;
10544
10545 var defaultColor = arr[1];
10546 var div = document.createElement("div");
10547 value = value === undefined ? defaultColor : value;
10548
10549 if (value !== "none") {
10550 div.className = "vis-configuration vis-config-colorBlock";
10551 div.style.backgroundColor = value;
10552 } else {
10553 div.className = "vis-configuration vis-config-colorBlock none";
10554 }
10555
10556 value = value === undefined ? defaultColor : value;
10557
10558 div.onclick = function () {
10559 _this7._showColorPicker(value, div, path);
10560 };
10561
10562 var label = this._makeLabel(path[path.length - 1], path);
10563
10564 this._makeItem(path, label, div);
10565 }
10566 /**
10567 * used by the color buttons to call the color picker.
10568 *
10569 * @param {number} value
10570 * @param {HTMLElement} div
10571 * @param {Array} path | where to look for the actual option
10572 * @private
10573 */
10574
10575 }, {
10576 key: "_showColorPicker",
10577 value: function _showColorPicker(value, div, path) {
10578 var _this8 = this;
10579
10580 // clear the callback from this div
10581 div.onclick = function () {};
10582
10583 this.colorPicker.insertTo(div);
10584 this.colorPicker.show();
10585 this.colorPicker.setColor(value);
10586 this.colorPicker.setUpdateCallback(function (color) {
10587 var colorString = "rgba(" + color.r + "," + color.g + "," + color.b + "," + color.a + ")";
10588 div.style.backgroundColor = colorString;
10589
10590 _this8._update(colorString, path);
10591 }); // on close of the colorpicker, restore the callback.
10592
10593 this.colorPicker.setCloseCallback(function () {
10594 div.onclick = function () {
10595 _this8._showColorPicker(value, div, path);
10596 };
10597 });
10598 }
10599 /**
10600 * parse an object and draw the correct items
10601 *
10602 * @param {object} obj
10603 * @param {Array} [path=[]] | where to look for the actual option
10604 * @param {boolean} [checkOnly=false]
10605 * @returns {boolean}
10606 * @private
10607 */
10608
10609 }, {
10610 key: "_handleObject",
10611 value: function _handleObject(obj) {
10612 var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
10613 var checkOnly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
10614 var show = false;
10615
10616 var filter$1 = filter(this.options);
10617
10618 var visibleInSet = false;
10619
10620 for (var subObj in obj) {
10621 if (Object.prototype.hasOwnProperty.call(obj, subObj)) {
10622 show = true;
10623 var item = obj[subObj];
10624 var newPath = copyAndExtendArray(path, subObj);
10625
10626 if (typeof filter$1 === "function") {
10627 show = filter$1(subObj, path); // if needed we must go deeper into the object.
10628
10629 if (show === false) {
10630 if (!isArray(item) && typeof item !== "string" && typeof item !== "boolean" && item instanceof Object) {
10631 this.allowCreation = false;
10632 show = this._handleObject(item, newPath, true);
10633 this.allowCreation = checkOnly === false;
10634 }
10635 }
10636 }
10637
10638 if (show !== false) {
10639 visibleInSet = true;
10640
10641 var value = this._getValue(newPath);
10642
10643 if (isArray(item)) {
10644 this._handleArray(item, value, newPath);
10645 } else if (typeof item === "string") {
10646 this._makeTextInput(item, value, newPath);
10647 } else if (typeof item === "boolean") {
10648 this._makeCheckbox(item, value, newPath);
10649 } else if (item instanceof Object) {
10650 // skip the options that are not enabled
10651 if (!this.hideOption(path, subObj, this.moduleOptions)) {
10652 // initially collapse options with an disabled enabled option.
10653 if (item.enabled !== undefined) {
10654 var enabledPath = copyAndExtendArray(newPath, "enabled");
10655
10656 var enabledValue = this._getValue(enabledPath);
10657
10658 if (enabledValue === true) {
10659 var label = this._makeLabel(subObj, newPath, true);
10660
10661 this._makeItem(newPath, label);
10662
10663 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
10664 } else {
10665 this._makeCheckbox(item, enabledValue, newPath);
10666 }
10667 } else {
10668 var _label = this._makeLabel(subObj, newPath, true);
10669
10670 this._makeItem(newPath, _label);
10671
10672 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
10673 }
10674 }
10675 } else {
10676 console.error("dont know how to handle", item, subObj, newPath);
10677 }
10678 }
10679 }
10680 }
10681
10682 return visibleInSet;
10683 }
10684 /**
10685 * handle the array type of option
10686 *
10687 * @param {Array.<number>} arr
10688 * @param {number} value
10689 * @param {Array} path | where to look for the actual option
10690 * @private
10691 */
10692
10693 }, {
10694 key: "_handleArray",
10695 value: function _handleArray(arr, value, path) {
10696 if (typeof arr[0] === "string" && arr[0] === "color") {
10697 this._makeColorField(arr, value, path);
10698
10699 if (arr[1] !== value) {
10700 this.changedOptions.push({
10701 path: path,
10702 value: value
10703 });
10704 }
10705 } else if (typeof arr[0] === "string") {
10706 this._makeDropdown(arr, value, path);
10707
10708 if (arr[0] !== value) {
10709 this.changedOptions.push({
10710 path: path,
10711 value: value
10712 });
10713 }
10714 } else if (typeof arr[0] === "number") {
10715 this._makeRange(arr, value, path);
10716
10717 if (arr[0] !== value) {
10718 this.changedOptions.push({
10719 path: path,
10720 value: Number(value)
10721 });
10722 }
10723 }
10724 }
10725 /**
10726 * called to update the network with the new settings.
10727 *
10728 * @param {number} value
10729 * @param {Array} path | where to look for the actual option
10730 * @private
10731 */
10732
10733 }, {
10734 key: "_update",
10735 value: function _update(value, path) {
10736 var options = this._constructOptions(value, path);
10737
10738 if (this.parent.body && this.parent.body.emitter && this.parent.body.emitter.emit) {
10739 this.parent.body.emitter.emit("configChange", options);
10740 }
10741
10742 this.initialized = true;
10743 this.parent.setOptions(options);
10744 }
10745 /**
10746 *
10747 * @param {string | boolean} value
10748 * @param {Array.<string>} path
10749 * @param {{}} optionsObj
10750 * @returns {{}}
10751 * @private
10752 */
10753
10754 }, {
10755 key: "_constructOptions",
10756 value: function _constructOptions(value, path) {
10757 var optionsObj = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
10758 var pointer = optionsObj; // when dropdown boxes can be string or boolean, we typecast it into correct types
10759
10760 value = value === "true" ? true : value;
10761 value = value === "false" ? false : value;
10762
10763 for (var i = 0; i < path.length; i++) {
10764 if (path[i] !== "global") {
10765 if (pointer[path[i]] === undefined) {
10766 pointer[path[i]] = {};
10767 }
10768
10769 if (i !== path.length - 1) {
10770 pointer = pointer[path[i]];
10771 } else {
10772 pointer[path[i]] = value;
10773 }
10774 }
10775 }
10776
10777 return optionsObj;
10778 }
10779 /**
10780 * @private
10781 */
10782
10783 }, {
10784 key: "_printOptions",
10785 value: function _printOptions() {
10786 var options = this.getOptions();
10787
10788 while (this.optionsContainer.firstChild) {
10789 this.optionsContainer.removeChild(this.optionsContainer.firstChild);
10790 }
10791
10792 this.optionsContainer.appendChild(wrapInTag("pre", "const options = " + stringify$1(options, null, 2)));
10793 }
10794 /**
10795 *
10796 * @returns {{}} options
10797 */
10798
10799 }, {
10800 key: "getOptions",
10801 value: function getOptions() {
10802 var options = {};
10803
10804 for (var i = 0; i < this.changedOptions.length; i++) {
10805 this._constructOptions(this.changedOptions[i].value, this.changedOptions[i].path, options);
10806 }
10807
10808 return options;
10809 }
10810 }]);
10811
10812 return Configurator;
10813}();
10814/**
10815 * Popup is a class to create a popup window with some text
10816 */
10817
10818
10819var Popup = /*#__PURE__*/function () {
10820 /**
10821 * @param {Element} container The container object.
10822 * @param {string} overflowMethod How the popup should act to overflowing ('flip' or 'cap')
10823 */
10824 function Popup(container, overflowMethod) {
10825 _classCallCheck(this, Popup);
10826
10827 this.container = container;
10828 this.overflowMethod = overflowMethod || "cap";
10829 this.x = 0;
10830 this.y = 0;
10831 this.padding = 5;
10832 this.hidden = false; // create the frame
10833
10834 this.frame = document.createElement("div");
10835 this.frame.className = "vis-tooltip";
10836 this.container.appendChild(this.frame);
10837 }
10838 /**
10839 * @param {number} x Horizontal position of the popup window
10840 * @param {number} y Vertical position of the popup window
10841 */
10842
10843
10844 _createClass(Popup, [{
10845 key: "setPosition",
10846 value: function setPosition(x, y) {
10847 this.x = _parseInt(x);
10848 this.y = _parseInt(y);
10849 }
10850 /**
10851 * Set the content for the popup window. This can be HTML code or text.
10852 *
10853 * @param {string | Element} content
10854 */
10855
10856 }, {
10857 key: "setText",
10858 value: function setText(content) {
10859 if (content instanceof Element) {
10860 while (this.frame.firstChild) {
10861 this.frame.removeChild(this.frame.firstChild);
10862 }
10863
10864 this.frame.appendChild(content);
10865 } else {
10866 // String containing literal text, element has to be used for HTML due to
10867 // XSS risks associated with innerHTML (i.e. prevent XSS by accident).
10868 this.frame.innerText = content;
10869 }
10870 }
10871 /**
10872 * Show the popup window
10873 *
10874 * @param {boolean} [doShow] Show or hide the window
10875 */
10876
10877 }, {
10878 key: "show",
10879 value: function show(doShow) {
10880 if (doShow === undefined) {
10881 doShow = true;
10882 }
10883
10884 if (doShow === true) {
10885 var height = this.frame.clientHeight;
10886 var width = this.frame.clientWidth;
10887 var maxHeight = this.frame.parentNode.clientHeight;
10888 var maxWidth = this.frame.parentNode.clientWidth;
10889 var left = 0,
10890 top = 0;
10891
10892 if (this.overflowMethod == "flip") {
10893 var isLeft = false,
10894 isTop = true; // Where around the position it's located
10895
10896 if (this.y - height < this.padding) {
10897 isTop = false;
10898 }
10899
10900 if (this.x + width > maxWidth - this.padding) {
10901 isLeft = true;
10902 }
10903
10904 if (isLeft) {
10905 left = this.x - width;
10906 } else {
10907 left = this.x;
10908 }
10909
10910 if (isTop) {
10911 top = this.y - height;
10912 } else {
10913 top = this.y;
10914 }
10915 } else {
10916 top = this.y - height;
10917
10918 if (top + height + this.padding > maxHeight) {
10919 top = maxHeight - height - this.padding;
10920 }
10921
10922 if (top < this.padding) {
10923 top = this.padding;
10924 }
10925
10926 left = this.x;
10927
10928 if (left + width + this.padding > maxWidth) {
10929 left = maxWidth - width - this.padding;
10930 }
10931
10932 if (left < this.padding) {
10933 left = this.padding;
10934 }
10935 }
10936
10937 this.frame.style.left = left + "px";
10938 this.frame.style.top = top + "px";
10939 this.frame.style.visibility = "visible";
10940 this.hidden = false;
10941 } else {
10942 this.hide();
10943 }
10944 }
10945 /**
10946 * Hide the popup window
10947 */
10948
10949 }, {
10950 key: "hide",
10951 value: function hide() {
10952 this.hidden = true;
10953 this.frame.style.left = "0";
10954 this.frame.style.top = "0";
10955 this.frame.style.visibility = "hidden";
10956 }
10957 /**
10958 * Remove the popup window
10959 */
10960
10961 }, {
10962 key: "destroy",
10963 value: function destroy() {
10964 this.frame.parentNode.removeChild(this.frame); // Remove element from DOM
10965 }
10966 }]);
10967
10968 return Popup;
10969}();
10970
10971var errorFound = false;
10972var allOptions$2;
10973var VALIDATOR_PRINT_STYLE = "background: #FFeeee; color: #dd0000";
10974/**
10975 * Used to validate options.
10976 */
10977
10978var Validator = /*#__PURE__*/function () {
10979 function Validator() {
10980 _classCallCheck(this, Validator);
10981 }
10982
10983 _createClass(Validator, null, [{
10984 key: "validate",
10985 value:
10986 /**
10987 * Main function to be called
10988 *
10989 * @param {object} options
10990 * @param {object} referenceOptions
10991 * @param {object} subObject
10992 * @returns {boolean}
10993 * @static
10994 */
10995 function validate(options, referenceOptions, subObject) {
10996 errorFound = false;
10997 allOptions$2 = referenceOptions;
10998 var usedOptions = referenceOptions;
10999
11000 if (subObject !== undefined) {
11001 usedOptions = referenceOptions[subObject];
11002 }
11003
11004 Validator.parse(options, usedOptions, []);
11005 return errorFound;
11006 }
11007 /**
11008 * Will traverse an object recursively and check every value
11009 *
11010 * @param {object} options
11011 * @param {object} referenceOptions
11012 * @param {Array} path | where to look for the actual option
11013 * @static
11014 */
11015
11016 }, {
11017 key: "parse",
11018 value: function parse(options, referenceOptions, path) {
11019 for (var _option3 in options) {
11020 if (Object.prototype.hasOwnProperty.call(options, _option3)) {
11021 Validator.check(_option3, options, referenceOptions, path);
11022 }
11023 }
11024 }
11025 /**
11026 * Check every value. If the value is an object, call the parse function on that object.
11027 *
11028 * @param {string} option
11029 * @param {object} options
11030 * @param {object} referenceOptions
11031 * @param {Array} path | where to look for the actual option
11032 * @static
11033 */
11034
11035 }, {
11036 key: "check",
11037 value: function check(option, options, referenceOptions, path) {
11038 if (referenceOptions[option] === undefined && referenceOptions.__any__ === undefined) {
11039 Validator.getSuggestion(option, referenceOptions, path);
11040 return;
11041 }
11042
11043 var referenceOption = option;
11044 var is_object = true;
11045
11046 if (referenceOptions[option] === undefined && referenceOptions.__any__ !== undefined) {
11047 // NOTE: This only triggers if the __any__ is in the top level of the options object.
11048 // THAT'S A REALLY BAD PLACE TO ALLOW IT!!!!
11049 // TODO: Examine if needed, remove if possible
11050 // __any__ is a wildcard. Any value is accepted and will be further analysed by reference.
11051 referenceOption = "__any__"; // if the any-subgroup is not a predefined object in the configurator,
11052 // we do not look deeper into the object.
11053
11054 is_object = Validator.getType(options[option]) === "object";
11055 }
11056
11057 var refOptionObj = referenceOptions[referenceOption];
11058
11059 if (is_object && refOptionObj.__type__ !== undefined) {
11060 refOptionObj = refOptionObj.__type__;
11061 }
11062
11063 Validator.checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path);
11064 }
11065 /**
11066 *
11067 * @param {string} option | the option property
11068 * @param {object} options | The supplied options object
11069 * @param {object} referenceOptions | The reference options containing all options and their allowed formats
11070 * @param {string} referenceOption | Usually this is the same as option, except when handling an __any__ tag.
11071 * @param {string} refOptionObj | This is the type object from the reference options
11072 * @param {Array} path | where in the object is the option
11073 * @static
11074 */
11075
11076 }, {
11077 key: "checkFields",
11078 value: function checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path) {
11079 var log = function log(message) {
11080 console.error("%c" + message + Validator.printLocation(path, option), VALIDATOR_PRINT_STYLE);
11081 };
11082
11083 var optionType = Validator.getType(options[option]);
11084 var refOptionType = refOptionObj[optionType];
11085
11086 if (refOptionType !== undefined) {
11087 // if the type is correct, we check if it is supposed to be one of a few select values
11088 if (Validator.getType(refOptionType) === "array" && indexOf(refOptionType).call(refOptionType, options[option]) === -1) {
11089 log('Invalid option detected in "' + option + '".' + " Allowed values are:" + Validator.print(refOptionType) + ' not "' + options[option] + '". ');
11090 errorFound = true;
11091 } else if (optionType === "object" && referenceOption !== "__any__") {
11092 path = copyAndExtendArray(path, option);
11093 Validator.parse(options[option], referenceOptions[referenceOption], path);
11094 }
11095 } else if (refOptionObj["any"] === undefined) {
11096 // type of the field is incorrect and the field cannot be any
11097 log('Invalid type received for "' + option + '". Expected: ' + Validator.print(keys$3(refOptionObj)) + ". Received [" + optionType + '] "' + options[option] + '"');
11098 errorFound = true;
11099 }
11100 }
11101 /**
11102 *
11103 * @param {object | boolean | number | string | Array.<number> | Date | Node | Moment | undefined | null} object
11104 * @returns {string}
11105 * @static
11106 */
11107
11108 }, {
11109 key: "getType",
11110 value: function getType(object) {
11111 var type = _typeof(object);
11112
11113 if (type === "object") {
11114 if (object === null) {
11115 return "null";
11116 }
11117
11118 if (object instanceof Boolean) {
11119 return "boolean";
11120 }
11121
11122 if (object instanceof Number) {
11123 return "number";
11124 }
11125
11126 if (object instanceof String) {
11127 return "string";
11128 }
11129
11130 if (isArray(object)) {
11131 return "array";
11132 }
11133
11134 if (object instanceof Date) {
11135 return "date";
11136 }
11137
11138 if (object.nodeType !== undefined) {
11139 return "dom";
11140 }
11141
11142 if (object._isAMomentObject === true) {
11143 return "moment";
11144 }
11145
11146 return "object";
11147 } else if (type === "number") {
11148 return "number";
11149 } else if (type === "boolean") {
11150 return "boolean";
11151 } else if (type === "string") {
11152 return "string";
11153 } else if (type === undefined) {
11154 return "undefined";
11155 }
11156
11157 return type;
11158 }
11159 /**
11160 * @param {string} option
11161 * @param {object} options
11162 * @param {Array.<string>} path
11163 * @static
11164 */
11165
11166 }, {
11167 key: "getSuggestion",
11168 value: function getSuggestion(option, options, path) {
11169 var localSearch = Validator.findInOptions(option, options, path, false);
11170 var globalSearch = Validator.findInOptions(option, allOptions$2, [], true);
11171 var localSearchThreshold = 8;
11172 var globalSearchThreshold = 4;
11173 var msg;
11174
11175 if (localSearch.indexMatch !== undefined) {
11176 msg = " in " + Validator.printLocation(localSearch.path, option, "") + 'Perhaps it was incomplete? Did you mean: "' + localSearch.indexMatch + '"?\n\n';
11177 } else if (globalSearch.distance <= globalSearchThreshold && localSearch.distance > globalSearch.distance) {
11178 msg = " in " + Validator.printLocation(localSearch.path, option, "") + "Perhaps it was misplaced? Matching option found at: " + Validator.printLocation(globalSearch.path, globalSearch.closestMatch, "");
11179 } else if (localSearch.distance <= localSearchThreshold) {
11180 msg = '. Did you mean "' + localSearch.closestMatch + '"?' + Validator.printLocation(localSearch.path, option);
11181 } else {
11182 msg = ". Did you mean one of these: " + Validator.print(keys$3(options)) + Validator.printLocation(path, option);
11183 }
11184
11185 console.error('%cUnknown option detected: "' + option + '"' + msg, VALIDATOR_PRINT_STYLE);
11186 errorFound = true;
11187 }
11188 /**
11189 * traverse the options in search for a match.
11190 *
11191 * @param {string} option
11192 * @param {object} options
11193 * @param {Array} path | where to look for the actual option
11194 * @param {boolean} [recursive=false]
11195 * @returns {{closestMatch: string, path: Array, distance: number}}
11196 * @static
11197 */
11198
11199 }, {
11200 key: "findInOptions",
11201 value: function findInOptions(option, options, path) {
11202 var recursive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
11203 var min = 1e9;
11204 var closestMatch = "";
11205 var closestMatchPath = [];
11206 var lowerCaseOption = option.toLowerCase();
11207 var indexMatch = undefined;
11208
11209 for (var op in options) {
11210 var distance = void 0;
11211
11212 if (options[op].__type__ !== undefined && recursive === true) {
11213 var result = Validator.findInOptions(option, options[op], copyAndExtendArray(path, op));
11214
11215 if (min > result.distance) {
11216 closestMatch = result.closestMatch;
11217 closestMatchPath = result.path;
11218 min = result.distance;
11219 indexMatch = result.indexMatch;
11220 }
11221 } else {
11222 var _context20;
11223
11224 if (indexOf(_context20 = op.toLowerCase()).call(_context20, lowerCaseOption) !== -1) {
11225 indexMatch = op;
11226 }
11227
11228 distance = Validator.levenshteinDistance(option, op);
11229
11230 if (min > distance) {
11231 closestMatch = op;
11232 closestMatchPath = copyArray(path);
11233 min = distance;
11234 }
11235 }
11236 }
11237
11238 return {
11239 closestMatch: closestMatch,
11240 path: closestMatchPath,
11241 distance: min,
11242 indexMatch: indexMatch
11243 };
11244 }
11245 /**
11246 * @param {Array.<string>} path
11247 * @param {object} option
11248 * @param {string} prefix
11249 * @returns {string}
11250 * @static
11251 */
11252
11253 }, {
11254 key: "printLocation",
11255 value: function printLocation(path, option) {
11256 var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "Problem value found at: \n";
11257 var str = "\n\n" + prefix + "options = {\n";
11258
11259 for (var i = 0; i < path.length; i++) {
11260 for (var j = 0; j < i + 1; j++) {
11261 str += " ";
11262 }
11263
11264 str += path[i] + ": {\n";
11265 }
11266
11267 for (var _j = 0; _j < path.length + 1; _j++) {
11268 str += " ";
11269 }
11270
11271 str += option + "\n";
11272
11273 for (var _i3 = 0; _i3 < path.length + 1; _i3++) {
11274 for (var _j2 = 0; _j2 < path.length - _i3; _j2++) {
11275 str += " ";
11276 }
11277
11278 str += "}\n";
11279 }
11280
11281 return str + "\n\n";
11282 }
11283 /**
11284 * @param {object} options
11285 * @returns {string}
11286 * @static
11287 */
11288
11289 }, {
11290 key: "print",
11291 value: function print(options) {
11292 return stringify$1(options).replace(/(")|(\[)|(\])|(,"__type__")/g, "").replace(/(,)/g, ", ");
11293 }
11294 /**
11295 * Compute the edit distance between the two given strings
11296 * http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
11297 *
11298 * Copyright (c) 2011 Andrei Mackenzie
11299 *
11300 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11301 *
11302 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11303 *
11304 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11305 *
11306 * @param {string} a
11307 * @param {string} b
11308 * @returns {Array.<Array.<number>>}}
11309 * @static
11310 */
11311
11312 }, {
11313 key: "levenshteinDistance",
11314 value: function levenshteinDistance(a, b) {
11315 if (a.length === 0) return b.length;
11316 if (b.length === 0) return a.length;
11317 var matrix = []; // increment along the first column of each row
11318
11319 var i;
11320
11321 for (i = 0; i <= b.length; i++) {
11322 matrix[i] = [i];
11323 } // increment each column in the first row
11324
11325
11326 var j;
11327
11328 for (j = 0; j <= a.length; j++) {
11329 matrix[0][j] = j;
11330 } // Fill in the rest of the matrix
11331
11332
11333 for (i = 1; i <= b.length; i++) {
11334 for (j = 1; j <= a.length; j++) {
11335 if (b.charAt(i - 1) == a.charAt(j - 1)) {
11336 matrix[i][j] = matrix[i - 1][j - 1];
11337 } else {
11338 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
11339 Math.min(matrix[i][j - 1] + 1, // insertion
11340 matrix[i - 1][j] + 1)); // deletion
11341 }
11342 }
11343 }
11344
11345 return matrix[b.length][a.length];
11346 }
11347 }]);
11348
11349 return Validator;
11350}();
11351
11352var Activator$1 = Activator;
11353var ColorPicker$1 = ColorPicker;
11354var Configurator$1 = Configurator;
11355var Hammer$1 = Hammer;
11356var Popup$1 = Popup;
11357var VALIDATOR_PRINT_STYLE$1 = VALIDATOR_PRINT_STYLE;
11358var Validator$1 = Validator;
11359
11360var index$2 = /*#__PURE__*/Object.freeze({
11361 __proto__: null,
11362 Activator: Activator$1,
11363 Alea: Alea,
11364 ColorPicker: ColorPicker$1,
11365 Configurator: Configurator$1,
11366 DELETE: DELETE,
11367 HSVToHex: HSVToHex,
11368 HSVToRGB: HSVToRGB,
11369 Hammer: Hammer$1,
11370 Popup: Popup$1,
11371 RGBToHSV: RGBToHSV,
11372 RGBToHex: RGBToHex,
11373 VALIDATOR_PRINT_STYLE: VALIDATOR_PRINT_STYLE$1,
11374 Validator: Validator$1,
11375 addClassName: addClassName,
11376 addCssText: addCssText,
11377 addEventListener: addEventListener,
11378 binarySearchCustom: binarySearchCustom,
11379 binarySearchValue: binarySearchValue,
11380 bridgeObject: bridgeObject,
11381 copyAndExtendArray: copyAndExtendArray,
11382 copyArray: copyArray,
11383 deepExtend: deepExtend,
11384 deepObjectAssign: deepObjectAssign,
11385 easingFunctions: easingFunctions,
11386 equalArray: equalArray,
11387 extend: extend,
11388 fillIfDefined: fillIfDefined,
11389 forEach: forEach$1,
11390 getAbsoluteLeft: getAbsoluteLeft,
11391 getAbsoluteRight: getAbsoluteRight,
11392 getAbsoluteTop: getAbsoluteTop,
11393 getScrollBarWidth: getScrollBarWidth,
11394 getTarget: getTarget,
11395 getType: getType,
11396 hasParent: hasParent,
11397 hexToHSV: hexToHSV,
11398 hexToRGB: hexToRGB,
11399 insertSort: insertSort,
11400 isDate: isDate,
11401 isNumber: isNumber,
11402 isObject: isObject,
11403 isString: isString,
11404 isValidHex: isValidHex,
11405 isValidRGB: isValidRGB,
11406 isValidRGBA: isValidRGBA,
11407 mergeOptions: mergeOptions,
11408 option: option,
11409 overrideOpacity: overrideOpacity,
11410 parseColor: parseColor,
11411 preventDefault: preventDefault,
11412 pureDeepObjectAssign: pureDeepObjectAssign,
11413 recursiveDOMDelete: recursiveDOMDelete,
11414 removeClassName: removeClassName,
11415 removeCssText: removeCssText,
11416 removeEventListener: removeEventListener,
11417 selectiveBridgeObject: selectiveBridgeObject,
11418 selectiveDeepExtend: selectiveDeepExtend,
11419 selectiveExtend: selectiveExtend,
11420 selectiveNotDeepExtend: selectiveNotDeepExtend,
11421 throttle: throttle,
11422 toArray: toArray,
11423 topMost: topMost,
11424 updateProperty: updateProperty
11425});
11426
11427/* eslint-disable no-prototype-builtins */
11428
11429/* eslint-disable no-unused-vars */
11430
11431/* eslint-disable no-var */
11432
11433/**
11434 * Parse a text source containing data in DOT language into a JSON object.
11435 * The object contains two lists: one with nodes and one with edges.
11436 *
11437 * DOT language reference: http://www.graphviz.org/doc/info/lang.html
11438 *
11439 * DOT language attributes: http://graphviz.org/content/attrs
11440 *
11441 * @param {string} data Text containing a graph in DOT-notation
11442 * @returns {object} graph An object containing two parameters:
11443 * {Object[]} nodes
11444 * {Object[]} edges
11445 *
11446 * -------------------------------------------
11447 * TODO
11448 * ====
11449 *
11450 * For label handling, this is an incomplete implementation. From docs (quote #3015):
11451 *
11452 * > the escape sequences "\n", "\l" and "\r" divide the label into lines, centered,
11453 * > left-justified, and right-justified, respectively.
11454 *
11455 * Source: http://www.graphviz.org/content/attrs#kescString
11456 *
11457 * > As another aid for readability, dot allows double-quoted strings to span multiple physical
11458 * > lines using the standard C convention of a backslash immediately preceding a newline
11459 * > character
11460 * > In addition, double-quoted strings can be concatenated using a '+' operator.
11461 * > As HTML strings can contain newline characters, which are used solely for formatting,
11462 * > the language does not allow escaped newlines or concatenation operators to be used
11463 * > within them.
11464 *
11465 * - Currently, only '\\n' is handled
11466 * - Note that text explicitly says 'labels'; the dot parser currently handles escape
11467 * sequences in **all** strings.
11468 */
11469function parseDOT(data) {
11470 dot = data;
11471 return parseGraph();
11472} // mapping of attributes from DOT (the keys) to vis.js (the values)
11473
11474var NODE_ATTR_MAPPING = {
11475 fontsize: "font.size",
11476 fontcolor: "font.color",
11477 labelfontcolor: "font.color",
11478 fontname: "font.face",
11479 color: ["color.border", "color.background"],
11480 fillcolor: "color.background",
11481 tooltip: "title",
11482 labeltooltip: "title"
11483};
11484
11485var EDGE_ATTR_MAPPING = create$2(NODE_ATTR_MAPPING);
11486
11487EDGE_ATTR_MAPPING.color = "color.color";
11488EDGE_ATTR_MAPPING.style = "dashes"; // token types enumeration
11489
11490var TOKENTYPE = {
11491 NULL: 0,
11492 DELIMITER: 1,
11493 IDENTIFIER: 2,
11494 UNKNOWN: 3
11495}; // map with all delimiters
11496
11497var DELIMITERS = {
11498 "{": true,
11499 "}": true,
11500 "[": true,
11501 "]": true,
11502 ";": true,
11503 "=": true,
11504 ",": true,
11505 "->": true,
11506 "--": true
11507};
11508var dot = ""; // current dot file
11509
11510var index$1 = 0; // current index in dot file
11511
11512var c = ""; // current token character in expr
11513
11514var token = ""; // current token
11515
11516var tokenType = TOKENTYPE.NULL; // type of the token
11517
11518/**
11519 * Get the first character from the dot file.
11520 * The character is stored into the char c. If the end of the dot file is
11521 * reached, the function puts an empty string in c.
11522 */
11523
11524function first() {
11525 index$1 = 0;
11526 c = dot.charAt(0);
11527}
11528/**
11529 * Get the next character from the dot file.
11530 * The character is stored into the char c. If the end of the dot file is
11531 * reached, the function puts an empty string in c.
11532 */
11533
11534
11535function next() {
11536 index$1++;
11537 c = dot.charAt(index$1);
11538}
11539/**
11540 * Preview the next character from the dot file.
11541 *
11542 * @returns {string} cNext
11543 */
11544
11545
11546function nextPreview() {
11547 return dot.charAt(index$1 + 1);
11548}
11549/**
11550 * Test whether given character is alphabetic or numeric ( a-zA-Z_0-9.:# )
11551 *
11552 * @param {string} c
11553 * @returns {boolean} isAlphaNumeric
11554 */
11555
11556
11557function isAlphaNumeric(c) {
11558 var charCode = c.charCodeAt(0);
11559
11560 if (charCode < 47) {
11561 // #.
11562 return charCode === 35 || charCode === 46;
11563 }
11564
11565 if (charCode < 59) {
11566 // 0-9 and :
11567 return charCode > 47;
11568 }
11569
11570 if (charCode < 91) {
11571 // A-Z
11572 return charCode > 64;
11573 }
11574
11575 if (charCode < 96) {
11576 // _
11577 return charCode === 95;
11578 }
11579
11580 if (charCode < 123) {
11581 // a-z
11582 return charCode > 96;
11583 }
11584
11585 return false;
11586}
11587/**
11588 * Merge all options of object b into object b
11589 *
11590 * @param {object} a
11591 * @param {object} b
11592 * @returns {object} a
11593 */
11594
11595
11596function merge$1(a, b) {
11597 if (!a) {
11598 a = {};
11599 }
11600
11601 if (b) {
11602 for (var name in b) {
11603 if (b.hasOwnProperty(name)) {
11604 a[name] = b[name];
11605 }
11606 }
11607 }
11608
11609 return a;
11610}
11611/**
11612 * Set a value in an object, where the provided parameter name can be a
11613 * path with nested parameters. For example:
11614 *
11615 * var obj = {a: 2};
11616 * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}}
11617 *
11618 * @param {object} obj
11619 * @param {string} path A parameter name or dot-separated parameter path,
11620 * like "color.highlight.border".
11621 * @param {*} value
11622 */
11623
11624
11625function setValue(obj, path, value) {
11626 var keys = path.split(".");
11627 var o = obj;
11628
11629 while (keys.length) {
11630 var key = keys.shift();
11631
11632 if (keys.length) {
11633 // this isn't the end point
11634 if (!o[key]) {
11635 o[key] = {};
11636 }
11637
11638 o = o[key];
11639 } else {
11640 // this is the end point
11641 o[key] = value;
11642 }
11643 }
11644}
11645/**
11646 * Add a node to a graph object. If there is already a node with
11647 * the same id, their attributes will be merged.
11648 *
11649 * @param {object} graph
11650 * @param {object} node
11651 */
11652
11653
11654function addNode(graph, node) {
11655 var i, len;
11656 var current = null; // find root graph (in case of subgraph)
11657
11658 var graphs = [graph]; // list with all graphs from current graph to root graph
11659
11660 var root = graph;
11661
11662 while (root.parent) {
11663 graphs.push(root.parent);
11664 root = root.parent;
11665 } // find existing node (at root level) by its id
11666
11667
11668 if (root.nodes) {
11669 for (i = 0, len = root.nodes.length; i < len; i++) {
11670 if (node.id === root.nodes[i].id) {
11671 current = root.nodes[i];
11672 break;
11673 }
11674 }
11675 }
11676
11677 if (!current) {
11678 // this is a new node
11679 current = {
11680 id: node.id
11681 };
11682
11683 if (graph.node) {
11684 // clone default attributes
11685 current.attr = merge$1(current.attr, graph.node);
11686 }
11687 } // add node to this (sub)graph and all its parent graphs
11688
11689
11690 for (i = graphs.length - 1; i >= 0; i--) {
11691 var _context;
11692
11693 var g = graphs[i];
11694
11695 if (!g.nodes) {
11696 g.nodes = [];
11697 }
11698
11699 if (indexOf(_context = g.nodes).call(_context, current) === -1) {
11700 g.nodes.push(current);
11701 }
11702 } // merge attributes
11703
11704
11705 if (node.attr) {
11706 current.attr = merge$1(current.attr, node.attr);
11707 }
11708}
11709/**
11710 * Add an edge to a graph object
11711 *
11712 * @param {object} graph
11713 * @param {object} edge
11714 */
11715
11716
11717function addEdge(graph, edge) {
11718 if (!graph.edges) {
11719 graph.edges = [];
11720 }
11721
11722 graph.edges.push(edge);
11723
11724 if (graph.edge) {
11725 var attr = merge$1({}, graph.edge); // clone default attributes
11726
11727 edge.attr = merge$1(attr, edge.attr); // merge attributes
11728 }
11729}
11730/**
11731 * Create an edge to a graph object
11732 *
11733 * @param {object} graph
11734 * @param {string | number | object} from
11735 * @param {string | number | object} to
11736 * @param {string} type
11737 * @param {object | null} attr
11738 * @returns {object} edge
11739 */
11740
11741
11742function createEdge(graph, from, to, type, attr) {
11743 var edge = {
11744 from: from,
11745 to: to,
11746 type: type
11747 };
11748
11749 if (graph.edge) {
11750 edge.attr = merge$1({}, graph.edge); // clone default attributes
11751 }
11752
11753 edge.attr = merge$1(edge.attr || {}, attr); // merge attributes
11754 // Move arrows attribute from attr to edge temporally created in
11755 // parseAttributeList().
11756
11757 if (attr != null) {
11758 if (attr.hasOwnProperty("arrows") && attr["arrows"] != null) {
11759 edge["arrows"] = {
11760 to: {
11761 enabled: true,
11762 type: attr.arrows.type
11763 }
11764 };
11765 attr["arrows"] = null;
11766 }
11767 }
11768
11769 return edge;
11770}
11771/**
11772 * Get next token in the current dot file.
11773 * The token and token type are available as token and tokenType
11774 */
11775
11776
11777function getToken() {
11778 tokenType = TOKENTYPE.NULL;
11779 token = ""; // skip over whitespaces
11780
11781 while (c === " " || c === "\t" || c === "\n" || c === "\r") {
11782 // space, tab, enter
11783 next();
11784 }
11785
11786 do {
11787 var isComment = false; // skip comment
11788
11789 if (c === "#") {
11790 // find the previous non-space character
11791 var i = index$1 - 1;
11792
11793 while (dot.charAt(i) === " " || dot.charAt(i) === "\t") {
11794 i--;
11795 }
11796
11797 if (dot.charAt(i) === "\n" || dot.charAt(i) === "") {
11798 // the # is at the start of a line, this is indeed a line comment
11799 while (c != "" && c != "\n") {
11800 next();
11801 }
11802
11803 isComment = true;
11804 }
11805 }
11806
11807 if (c === "/" && nextPreview() === "/") {
11808 // skip line comment
11809 while (c != "" && c != "\n") {
11810 next();
11811 }
11812
11813 isComment = true;
11814 }
11815
11816 if (c === "/" && nextPreview() === "*") {
11817 // skip block comment
11818 while (c != "") {
11819 if (c === "*" && nextPreview() === "/") {
11820 // end of block comment found. skip these last two characters
11821 next();
11822 next();
11823 break;
11824 } else {
11825 next();
11826 }
11827 }
11828
11829 isComment = true;
11830 } // skip over whitespaces
11831
11832
11833 while (c === " " || c === "\t" || c === "\n" || c === "\r") {
11834 // space, tab, enter
11835 next();
11836 }
11837 } while (isComment); // check for end of dot file
11838
11839
11840 if (c === "") {
11841 // token is still empty
11842 tokenType = TOKENTYPE.DELIMITER;
11843 return;
11844 } // check for delimiters consisting of 2 characters
11845
11846
11847 var c2 = c + nextPreview();
11848
11849 if (DELIMITERS[c2]) {
11850 tokenType = TOKENTYPE.DELIMITER;
11851 token = c2;
11852 next();
11853 next();
11854 return;
11855 } // check for delimiters consisting of 1 character
11856
11857
11858 if (DELIMITERS[c]) {
11859 tokenType = TOKENTYPE.DELIMITER;
11860 token = c;
11861 next();
11862 return;
11863 } // check for an identifier (number or string)
11864 // TODO: more precise parsing of numbers/strings (and the port separator ':')
11865
11866
11867 if (isAlphaNumeric(c) || c === "-") {
11868 token += c;
11869 next();
11870
11871 while (isAlphaNumeric(c)) {
11872 token += c;
11873 next();
11874 }
11875
11876 if (token === "false") {
11877 token = false; // convert to boolean
11878 } else if (token === "true") {
11879 token = true; // convert to boolean
11880 } else if (!isNaN(Number(token))) {
11881 token = Number(token); // convert to number
11882 }
11883
11884 tokenType = TOKENTYPE.IDENTIFIER;
11885 return;
11886 } // check for a string enclosed by double quotes
11887
11888
11889 if (c === '"') {
11890 next();
11891
11892 while (c != "" && (c != '"' || c === '"' && nextPreview() === '"')) {
11893 if (c === '"') {
11894 // skip the escape character
11895 token += c;
11896 next();
11897 } else if (c === "\\" && nextPreview() === "n") {
11898 // Honor a newline escape sequence
11899 token += "\n";
11900 next();
11901 } else {
11902 token += c;
11903 }
11904
11905 next();
11906 }
11907
11908 if (c != '"') {
11909 throw newSyntaxError('End of string " expected');
11910 }
11911
11912 next();
11913 tokenType = TOKENTYPE.IDENTIFIER;
11914 return;
11915 } // something unknown is found, wrong characters, a syntax error
11916
11917
11918 tokenType = TOKENTYPE.UNKNOWN;
11919
11920 while (c != "") {
11921 token += c;
11922 next();
11923 }
11924
11925 throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"');
11926}
11927/**
11928 * Parse a graph.
11929 *
11930 * @returns {object} graph
11931 */
11932
11933
11934function parseGraph() {
11935 var graph = {};
11936 first();
11937 getToken(); // optional strict keyword
11938
11939 if (token === "strict") {
11940 graph.strict = true;
11941 getToken();
11942 } // graph or digraph keyword
11943
11944
11945 if (token === "graph" || token === "digraph") {
11946 graph.type = token;
11947 getToken();
11948 } // optional graph id
11949
11950
11951 if (tokenType === TOKENTYPE.IDENTIFIER) {
11952 graph.id = token;
11953 getToken();
11954 } // open angle bracket
11955
11956
11957 if (token != "{") {
11958 throw newSyntaxError("Angle bracket { expected");
11959 }
11960
11961 getToken(); // statements
11962
11963 parseStatements(graph); // close angle bracket
11964
11965 if (token != "}") {
11966 throw newSyntaxError("Angle bracket } expected");
11967 }
11968
11969 getToken(); // end of file
11970
11971 if (token !== "") {
11972 throw newSyntaxError("End of file expected");
11973 }
11974
11975 getToken(); // remove temporary default options
11976
11977 delete graph.node;
11978 delete graph.edge;
11979 delete graph.graph;
11980 return graph;
11981}
11982/**
11983 * Parse a list with statements.
11984 *
11985 * @param {object} graph
11986 */
11987
11988
11989function parseStatements(graph) {
11990 while (token !== "" && token != "}") {
11991 parseStatement(graph);
11992
11993 if (token === ";") {
11994 getToken();
11995 }
11996 }
11997}
11998/**
11999 * Parse a single statement. Can be a an attribute statement, node
12000 * statement, a series of node statements and edge statements, or a
12001 * parameter.
12002 *
12003 * @param {object} graph
12004 */
12005
12006
12007function parseStatement(graph) {
12008 // parse subgraph
12009 var subgraph = parseSubgraph(graph);
12010
12011 if (subgraph) {
12012 // edge statements
12013 parseEdge(graph, subgraph);
12014 return;
12015 } // parse an attribute statement
12016
12017
12018 var attr = parseAttributeStatement(graph);
12019
12020 if (attr) {
12021 return;
12022 } // parse node
12023
12024
12025 if (tokenType != TOKENTYPE.IDENTIFIER) {
12026 throw newSyntaxError("Identifier expected");
12027 }
12028
12029 var id = token; // id can be a string or a number
12030
12031 getToken();
12032
12033 if (token === "=") {
12034 // id statement
12035 getToken();
12036
12037 if (tokenType != TOKENTYPE.IDENTIFIER) {
12038 throw newSyntaxError("Identifier expected");
12039 }
12040
12041 graph[id] = token;
12042 getToken(); // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] "
12043 } else {
12044 parseNodeStatement(graph, id);
12045 }
12046}
12047/**
12048 * Parse a subgraph
12049 *
12050 * @param {object} graph parent graph object
12051 * @returns {object | null} subgraph
12052 */
12053
12054
12055function parseSubgraph(graph) {
12056 var subgraph = null; // optional subgraph keyword
12057
12058 if (token === "subgraph") {
12059 subgraph = {};
12060 subgraph.type = "subgraph";
12061 getToken(); // optional graph id
12062
12063 if (tokenType === TOKENTYPE.IDENTIFIER) {
12064 subgraph.id = token;
12065 getToken();
12066 }
12067 } // open angle bracket
12068
12069
12070 if (token === "{") {
12071 getToken();
12072
12073 if (!subgraph) {
12074 subgraph = {};
12075 }
12076
12077 subgraph.parent = graph;
12078 subgraph.node = graph.node;
12079 subgraph.edge = graph.edge;
12080 subgraph.graph = graph.graph; // statements
12081
12082 parseStatements(subgraph); // close angle bracket
12083
12084 if (token != "}") {
12085 throw newSyntaxError("Angle bracket } expected");
12086 }
12087
12088 getToken(); // remove temporary default options
12089
12090 delete subgraph.node;
12091 delete subgraph.edge;
12092 delete subgraph.graph;
12093 delete subgraph.parent; // register at the parent graph
12094
12095 if (!graph.subgraphs) {
12096 graph.subgraphs = [];
12097 }
12098
12099 graph.subgraphs.push(subgraph);
12100 }
12101
12102 return subgraph;
12103}
12104/**
12105 * parse an attribute statement like "node [shape=circle fontSize=16]".
12106 * Available keywords are 'node', 'edge', 'graph'.
12107 * The previous list with default attributes will be replaced
12108 *
12109 * @param {object} graph
12110 * @returns {string | null} keyword Returns the name of the parsed attribute
12111 * (node, edge, graph), or null if nothing
12112 * is parsed.
12113 */
12114
12115
12116function parseAttributeStatement(graph) {
12117 // attribute statements
12118 if (token === "node") {
12119 getToken(); // node attributes
12120
12121 graph.node = parseAttributeList();
12122 return "node";
12123 } else if (token === "edge") {
12124 getToken(); // edge attributes
12125
12126 graph.edge = parseAttributeList();
12127 return "edge";
12128 } else if (token === "graph") {
12129 getToken(); // graph attributes
12130
12131 graph.graph = parseAttributeList();
12132 return "graph";
12133 }
12134
12135 return null;
12136}
12137/**
12138 * parse a node statement
12139 *
12140 * @param {object} graph
12141 * @param {string | number} id
12142 */
12143
12144
12145function parseNodeStatement(graph, id) {
12146 // node statement
12147 var node = {
12148 id: id
12149 };
12150 var attr = parseAttributeList();
12151
12152 if (attr) {
12153 node.attr = attr;
12154 }
12155
12156 addNode(graph, node); // edge statements
12157
12158 parseEdge(graph, id);
12159}
12160/**
12161 * Parse an edge or a series of edges
12162 *
12163 * @param {object} graph
12164 * @param {string | number} from Id of the from node
12165 */
12166
12167
12168function parseEdge(graph, from) {
12169 while (token === "->" || token === "--") {
12170 var to;
12171 var type = token;
12172 getToken();
12173 var subgraph = parseSubgraph(graph);
12174
12175 if (subgraph) {
12176 to = subgraph;
12177 } else {
12178 if (tokenType != TOKENTYPE.IDENTIFIER) {
12179 throw newSyntaxError("Identifier or subgraph expected");
12180 }
12181
12182 to = token;
12183 addNode(graph, {
12184 id: to
12185 });
12186 getToken();
12187 } // parse edge attributes
12188
12189
12190 var attr = parseAttributeList(); // create edge
12191
12192 var edge = createEdge(graph, from, to, type, attr);
12193 addEdge(graph, edge);
12194 from = to;
12195 }
12196}
12197/**
12198 * Parse a set with attributes,
12199 * for example [label="1.000", shape=solid]
12200 *
12201 * @returns {object | null} attr
12202 */
12203
12204
12205function parseAttributeList() {
12206 var i;
12207 var attr = null; // edge styles of dot and vis
12208
12209 var edgeStyles = {
12210 dashed: true,
12211 solid: false,
12212 dotted: [1, 5]
12213 };
12214 /**
12215 * Define arrow types.
12216 * vis currently supports types defined in 'arrowTypes'.
12217 * Details of arrow shapes are described in
12218 * http://www.graphviz.org/content/arrow-shapes
12219 */
12220
12221 var arrowTypes = {
12222 dot: "circle",
12223 box: "box",
12224 crow: "crow",
12225 curve: "curve",
12226 icurve: "inv_curve",
12227 normal: "triangle",
12228 inv: "inv_triangle",
12229 diamond: "diamond",
12230 tee: "bar",
12231 vee: "vee"
12232 };
12233 /**
12234 * 'attr_list' contains attributes for checking if some of them are affected
12235 * later. For instance, both of 'arrowhead' and 'dir' (edge style defined
12236 * in DOT) make changes to 'arrows' attribute in vis.
12237 */
12238
12239 var attr_list = new Array();
12240 var attr_names = new Array(); // used for checking the case.
12241 // parse attributes
12242
12243 while (token === "[") {
12244 getToken();
12245 attr = {};
12246
12247 while (token !== "" && token != "]") {
12248 if (tokenType != TOKENTYPE.IDENTIFIER) {
12249 throw newSyntaxError("Attribute name expected");
12250 }
12251
12252 var name = token;
12253 getToken();
12254
12255 if (token != "=") {
12256 throw newSyntaxError("Equal sign = expected");
12257 }
12258
12259 getToken();
12260
12261 if (tokenType != TOKENTYPE.IDENTIFIER) {
12262 throw newSyntaxError("Attribute value expected");
12263 }
12264
12265 var value = token; // convert from dot style to vis
12266
12267 if (name === "style") {
12268 value = edgeStyles[value];
12269 }
12270
12271 var arrowType;
12272
12273 if (name === "arrowhead") {
12274 arrowType = arrowTypes[value];
12275 name = "arrows";
12276 value = {
12277 to: {
12278 enabled: true,
12279 type: arrowType
12280 }
12281 };
12282 }
12283
12284 if (name === "arrowtail") {
12285 arrowType = arrowTypes[value];
12286 name = "arrows";
12287 value = {
12288 from: {
12289 enabled: true,
12290 type: arrowType
12291 }
12292 };
12293 }
12294
12295 attr_list.push({
12296 attr: attr,
12297 name: name,
12298 value: value
12299 });
12300 attr_names.push(name);
12301 getToken();
12302
12303 if (token == ",") {
12304 getToken();
12305 }
12306 }
12307
12308 if (token != "]") {
12309 throw newSyntaxError("Bracket ] expected");
12310 }
12311
12312 getToken();
12313 }
12314 /**
12315 * As explained in [1], graphviz has limitations for combination of
12316 * arrow[head|tail] and dir. If attribute list includes 'dir',
12317 * following cases just be supported.
12318 * 1. both or none + arrowhead, arrowtail
12319 * 2. forward + arrowhead (arrowtail is not affedted)
12320 * 3. back + arrowtail (arrowhead is not affected)
12321 * [1] https://www.graphviz.org/doc/info/attrs.html#h:undir_note
12322 */
12323
12324
12325 if (includes(attr_names).call(attr_names, "dir")) {
12326 var idx = {}; // get index of 'arrows' and 'dir'
12327
12328 idx.arrows = {};
12329
12330 for (i = 0; i < attr_list.length; i++) {
12331 if (attr_list[i].name === "arrows") {
12332 if (attr_list[i].value.to != null) {
12333 idx.arrows.to = i;
12334 } else if (attr_list[i].value.from != null) {
12335 idx.arrows.from = i;
12336 } else {
12337 throw newSyntaxError("Invalid value of arrows");
12338 }
12339 } else if (attr_list[i].name === "dir") {
12340 idx.dir = i;
12341 }
12342 } // first, add default arrow shape if it is not assigned to avoid error
12343
12344
12345 var dir_type = attr_list[idx.dir].value;
12346
12347 if (!includes(attr_names).call(attr_names, "arrows")) {
12348 if (dir_type === "both") {
12349 attr_list.push({
12350 attr: attr_list[idx.dir].attr,
12351 name: "arrows",
12352 value: {
12353 to: {
12354 enabled: true
12355 }
12356 }
12357 });
12358 idx.arrows.to = attr_list.length - 1;
12359 attr_list.push({
12360 attr: attr_list[idx.dir].attr,
12361 name: "arrows",
12362 value: {
12363 from: {
12364 enabled: true
12365 }
12366 }
12367 });
12368 idx.arrows.from = attr_list.length - 1;
12369 } else if (dir_type === "forward") {
12370 attr_list.push({
12371 attr: attr_list[idx.dir].attr,
12372 name: "arrows",
12373 value: {
12374 to: {
12375 enabled: true
12376 }
12377 }
12378 });
12379 idx.arrows.to = attr_list.length - 1;
12380 } else if (dir_type === "back") {
12381 attr_list.push({
12382 attr: attr_list[idx.dir].attr,
12383 name: "arrows",
12384 value: {
12385 from: {
12386 enabled: true
12387 }
12388 }
12389 });
12390 idx.arrows.from = attr_list.length - 1;
12391 } else if (dir_type === "none") {
12392 attr_list.push({
12393 attr: attr_list[idx.dir].attr,
12394 name: "arrows",
12395 value: ""
12396 });
12397 idx.arrows.to = attr_list.length - 1;
12398 } else {
12399 throw newSyntaxError('Invalid dir type "' + dir_type + '"');
12400 }
12401 }
12402
12403 var from_type;
12404 var to_type; // update 'arrows' attribute from 'dir'.
12405
12406 if (dir_type === "both") {
12407 // both of shapes of 'from' and 'to' are given
12408 if (idx.arrows.to && idx.arrows.from) {
12409 to_type = attr_list[idx.arrows.to].value.to.type;
12410 from_type = attr_list[idx.arrows.from].value.from.type;
12411 attr_list[idx.arrows.to] = {
12412 attr: attr_list[idx.arrows.to].attr,
12413 name: attr_list[idx.arrows.to].name,
12414 value: {
12415 to: {
12416 enabled: true,
12417 type: to_type
12418 },
12419 from: {
12420 enabled: true,
12421 type: from_type
12422 }
12423 }
12424 };
12425
12426 splice(attr_list).call(attr_list, idx.arrows.from, 1); // shape of 'to' is assigned and use default to 'from'
12427
12428 } else if (idx.arrows.to) {
12429 to_type = attr_list[idx.arrows.to].value.to.type;
12430 from_type = "arrow";
12431 attr_list[idx.arrows.to] = {
12432 attr: attr_list[idx.arrows.to].attr,
12433 name: attr_list[idx.arrows.to].name,
12434 value: {
12435 to: {
12436 enabled: true,
12437 type: to_type
12438 },
12439 from: {
12440 enabled: true,
12441 type: from_type
12442 }
12443 }
12444 }; // only shape of 'from' is assigned and use default for 'to'
12445 } else if (idx.arrows.from) {
12446 to_type = "arrow";
12447 from_type = attr_list[idx.arrows.from].value.from.type;
12448 attr_list[idx.arrows.from] = {
12449 attr: attr_list[idx.arrows.from].attr,
12450 name: attr_list[idx.arrows.from].name,
12451 value: {
12452 to: {
12453 enabled: true,
12454 type: to_type
12455 },
12456 from: {
12457 enabled: true,
12458 type: from_type
12459 }
12460 }
12461 };
12462 }
12463 } else if (dir_type === "back") {
12464 // given both of shapes, but use only 'from'
12465 if (idx.arrows.to && idx.arrows.from) {
12466 to_type = "";
12467 from_type = attr_list[idx.arrows.from].value.from.type;
12468 attr_list[idx.arrows.from] = {
12469 attr: attr_list[idx.arrows.from].attr,
12470 name: attr_list[idx.arrows.from].name,
12471 value: {
12472 to: {
12473 enabled: true,
12474 type: to_type
12475 },
12476 from: {
12477 enabled: true,
12478 type: from_type
12479 }
12480 }
12481 }; // given shape of 'to', but does not use it
12482 } else if (idx.arrows.to) {
12483 to_type = "";
12484 from_type = "arrow";
12485 idx.arrows.from = idx.arrows.to;
12486 attr_list[idx.arrows.from] = {
12487 attr: attr_list[idx.arrows.from].attr,
12488 name: attr_list[idx.arrows.from].name,
12489 value: {
12490 to: {
12491 enabled: true,
12492 type: to_type
12493 },
12494 from: {
12495 enabled: true,
12496 type: from_type
12497 }
12498 }
12499 }; // assign given 'from' shape
12500 } else if (idx.arrows.from) {
12501 to_type = "";
12502 from_type = attr_list[idx.arrows.from].value.from.type;
12503 attr_list[idx.arrows.to] = {
12504 attr: attr_list[idx.arrows.from].attr,
12505 name: attr_list[idx.arrows.from].name,
12506 value: {
12507 to: {
12508 enabled: true,
12509 type: to_type
12510 },
12511 from: {
12512 enabled: true,
12513 type: from_type
12514 }
12515 }
12516 };
12517 }
12518
12519 attr_list[idx.arrows.from] = {
12520 attr: attr_list[idx.arrows.from].attr,
12521 name: attr_list[idx.arrows.from].name,
12522 value: {
12523 from: {
12524 enabled: true,
12525 type: attr_list[idx.arrows.from].value.from.type
12526 }
12527 }
12528 };
12529 } else if (dir_type === "none") {
12530 var idx_arrow;
12531
12532 if (idx.arrows.to) {
12533 idx_arrow = idx.arrows.to;
12534 } else {
12535 idx_arrow = idx.arrows.from;
12536 }
12537
12538 attr_list[idx_arrow] = {
12539 attr: attr_list[idx_arrow].attr,
12540 name: attr_list[idx_arrow].name,
12541 value: ""
12542 };
12543 } else if (dir_type === "forward") {
12544 // given both of shapes, but use only 'to'
12545 if (idx.arrows.to && idx.arrows.from) {
12546 to_type = attr_list[idx.arrows.to].value.to.type;
12547 from_type = "";
12548 attr_list[idx.arrows.to] = {
12549 attr: attr_list[idx.arrows.to].attr,
12550 name: attr_list[idx.arrows.to].name,
12551 value: {
12552 to: {
12553 enabled: true,
12554 type: to_type
12555 },
12556 from: {
12557 enabled: true,
12558 type: from_type
12559 }
12560 }
12561 }; // assign given 'to' shape
12562 } else if (idx.arrows.to) {
12563 to_type = attr_list[idx.arrows.to].value.to.type;
12564 from_type = "";
12565 attr_list[idx.arrows.to] = {
12566 attr: attr_list[idx.arrows.to].attr,
12567 name: attr_list[idx.arrows.to].name,
12568 value: {
12569 to: {
12570 enabled: true,
12571 type: to_type
12572 },
12573 from: {
12574 enabled: true,
12575 type: from_type
12576 }
12577 }
12578 }; // given shape of 'from', but does not use it
12579 } else if (idx.arrows.from) {
12580 to_type = "arrow";
12581 from_type = "";
12582 idx.arrows.to = idx.arrows.from;
12583 attr_list[idx.arrows.to] = {
12584 attr: attr_list[idx.arrows.to].attr,
12585 name: attr_list[idx.arrows.to].name,
12586 value: {
12587 to: {
12588 enabled: true,
12589 type: to_type
12590 },
12591 from: {
12592 enabled: true,
12593 type: from_type
12594 }
12595 }
12596 };
12597 }
12598
12599 attr_list[idx.arrows.to] = {
12600 attr: attr_list[idx.arrows.to].attr,
12601 name: attr_list[idx.arrows.to].name,
12602 value: {
12603 to: {
12604 enabled: true,
12605 type: attr_list[idx.arrows.to].value.to.type
12606 }
12607 }
12608 };
12609 } else {
12610 throw newSyntaxError('Invalid dir type "' + dir_type + '"');
12611 } // remove 'dir' attribute no need anymore
12612
12613
12614 splice(attr_list).call(attr_list, idx.dir, 1);
12615 } // parse 'penwidth'
12616
12617
12618 var nof_attr_list;
12619
12620 if (includes(attr_names).call(attr_names, "penwidth")) {
12621 var tmp_attr_list = [];
12622 nof_attr_list = attr_list.length;
12623
12624 for (i = 0; i < nof_attr_list; i++) {
12625 // exclude 'width' from attr_list if 'penwidth' exists
12626 if (attr_list[i].name !== "width") {
12627 if (attr_list[i].name === "penwidth") {
12628 attr_list[i].name = "width";
12629 }
12630
12631 tmp_attr_list.push(attr_list[i]);
12632 }
12633 }
12634
12635 attr_list = tmp_attr_list;
12636 }
12637
12638 nof_attr_list = attr_list.length;
12639
12640 for (i = 0; i < nof_attr_list; i++) {
12641 setValue(attr_list[i].attr, attr_list[i].name, attr_list[i].value);
12642 }
12643
12644 return attr;
12645}
12646/**
12647 * Create a syntax error with extra information on current token and index.
12648 *
12649 * @param {string} message
12650 * @returns {SyntaxError} err
12651 */
12652
12653
12654function newSyntaxError(message) {
12655 return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index$1 + ")");
12656}
12657/**
12658 * Chop off text after a maximum length
12659 *
12660 * @param {string} text
12661 * @param {number} maxLength
12662 * @returns {string}
12663 */
12664
12665
12666function chop(text, maxLength) {
12667 return text.length <= maxLength ? text : text.substr(0, 27) + "...";
12668}
12669/**
12670 * Execute a function fn for each pair of elements in two arrays
12671 *
12672 * @param {Array | *} array1
12673 * @param {Array | *} array2
12674 * @param {Function} fn
12675 */
12676
12677
12678function forEach2(array1, array2, fn) {
12679 if (isArray(array1)) {
12680 forEach$2(array1).call(array1, function (elem1) {
12681 if (isArray(array2)) {
12682 forEach$2(array2).call(array2, function (elem2) {
12683 fn(elem1, elem2);
12684 });
12685 } else {
12686 fn(elem1, array2);
12687 }
12688 });
12689 } else {
12690 if (isArray(array2)) {
12691 forEach$2(array2).call(array2, function (elem2) {
12692 fn(array1, elem2);
12693 });
12694 } else {
12695 fn(array1, array2);
12696 }
12697 }
12698}
12699/**
12700 * Set a nested property on an object
12701 * When nested objects are missing, they will be created.
12702 * For example setProp({}, 'font.color', 'red') will return {font: {color: 'red'}}
12703 *
12704 * @param {object} object
12705 * @param {string} path A dot separated string like 'font.color'
12706 * @param {*} value Value for the property
12707 * @returns {object} Returns the original object, allows for chaining.
12708 */
12709
12710
12711function setProp(object, path, value) {
12712 var names = path.split(".");
12713 var prop = names.pop(); // traverse over the nested objects
12714
12715 var obj = object;
12716
12717 for (var i = 0; i < names.length; i++) {
12718 var name = names[i];
12719
12720 if (!(name in obj)) {
12721 obj[name] = {};
12722 }
12723
12724 obj = obj[name];
12725 } // set the property value
12726
12727
12728 obj[prop] = value;
12729 return object;
12730}
12731/**
12732 * Convert an object with DOT attributes to their vis.js equivalents.
12733 *
12734 * @param {object} attr Object with DOT attributes
12735 * @param {object} mapping
12736 * @returns {object} Returns an object with vis.js attributes
12737 */
12738
12739
12740function convertAttr(attr, mapping) {
12741 var converted = {};
12742
12743 for (var prop in attr) {
12744 if (attr.hasOwnProperty(prop)) {
12745 var visProp = mapping[prop];
12746
12747 if (isArray(visProp)) {
12748 forEach$2(visProp).call(visProp, function (visPropI) {
12749 setProp(converted, visPropI, attr[prop]);
12750 });
12751 } else if (typeof visProp === "string") {
12752 setProp(converted, visProp, attr[prop]);
12753 } else {
12754 setProp(converted, prop, attr[prop]);
12755 }
12756 }
12757 }
12758
12759 return converted;
12760}
12761/**
12762 * Convert a string containing a graph in DOT language into a map containing
12763 * with nodes and edges in the format of graph.
12764 *
12765 * @param {string} data Text containing a graph in DOT-notation
12766 * @returns {object} graphData
12767 */
12768
12769
12770function DOTToGraph(data) {
12771 // parse the DOT file
12772 var dotData = parseDOT(data);
12773 var graphData = {
12774 nodes: [],
12775 edges: [],
12776 options: {}
12777 }; // copy the nodes
12778
12779 if (dotData.nodes) {
12780 var _context2;
12781
12782 forEach$2(_context2 = dotData.nodes).call(_context2, function (dotNode) {
12783 var graphNode = {
12784 id: dotNode.id,
12785 label: String(dotNode.label || dotNode.id)
12786 };
12787 merge$1(graphNode, convertAttr(dotNode.attr, NODE_ATTR_MAPPING));
12788
12789 if (graphNode.image) {
12790 graphNode.shape = "image";
12791 }
12792
12793 graphData.nodes.push(graphNode);
12794 });
12795 } // copy the edges
12796
12797
12798 if (dotData.edges) {
12799 var _context3;
12800
12801 /**
12802 * Convert an edge in DOT format to an edge with VisGraph format
12803 *
12804 * @param {object} dotEdge
12805 * @returns {object} graphEdge
12806 */
12807 var convertEdge = function convertEdge(dotEdge) {
12808 var graphEdge = {
12809 from: dotEdge.from,
12810 to: dotEdge.to
12811 };
12812 merge$1(graphEdge, convertAttr(dotEdge.attr, EDGE_ATTR_MAPPING)); // Add arrows attribute to default styled arrow.
12813 // The reason why default style is not added in parseAttributeList() is
12814 // because only default is cleared before here.
12815
12816 if (graphEdge.arrows == null && dotEdge.type === "->") {
12817 graphEdge.arrows = "to";
12818 }
12819
12820 return graphEdge;
12821 };
12822
12823 forEach$2(_context3 = dotData.edges).call(_context3, function (dotEdge) {
12824 var from, to;
12825
12826 if (dotEdge.from instanceof Object) {
12827 from = dotEdge.from.nodes;
12828 } else {
12829 from = {
12830 id: dotEdge.from
12831 };
12832 }
12833
12834 if (dotEdge.to instanceof Object) {
12835 to = dotEdge.to.nodes;
12836 } else {
12837 to = {
12838 id: dotEdge.to
12839 };
12840 }
12841
12842 if (dotEdge.from instanceof Object && dotEdge.from.edges) {
12843 var _context4;
12844
12845 forEach$2(_context4 = dotEdge.from.edges).call(_context4, function (subEdge) {
12846 var graphEdge = convertEdge(subEdge);
12847 graphData.edges.push(graphEdge);
12848 });
12849 }
12850
12851 forEach2(from, to, function (from, to) {
12852 var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr);
12853 var graphEdge = convertEdge(subEdge);
12854 graphData.edges.push(graphEdge);
12855 });
12856
12857 if (dotEdge.to instanceof Object && dotEdge.to.edges) {
12858 var _context5;
12859
12860 forEach$2(_context5 = dotEdge.to.edges).call(_context5, function (subEdge) {
12861 var graphEdge = convertEdge(subEdge);
12862 graphData.edges.push(graphEdge);
12863 });
12864 }
12865 });
12866 } // copy the options
12867
12868
12869 if (dotData.attr) {
12870 graphData.options = dotData.attr;
12871 }
12872
12873 return graphData;
12874}
12875/* eslint-enable no-var */
12876
12877/* eslint-enable no-unused-vars */
12878
12879/* eslint-enable no-prototype-builtins */
12880
12881var dotparser = /*#__PURE__*/Object.freeze({
12882 __proto__: null,
12883 parseDOT: parseDOT,
12884 DOTToGraph: DOTToGraph
12885});
12886
12887/**
12888 * Convert Gephi to Vis.
12889 *
12890 * @param gephiJSON - The parsed JSON data in Gephi format.
12891 * @param optionsObj - Additional options.
12892 *
12893 * @returns The converted data ready to be used in Vis.
12894 */
12895function parseGephi(gephiJSON, optionsObj) {
12896 var _context;
12897
12898 var options = {
12899 edges: {
12900 inheritColor: false
12901 },
12902 nodes: {
12903 fixed: false,
12904 parseColor: false
12905 }
12906 };
12907
12908 if (optionsObj != null) {
12909 if (optionsObj.fixed != null) {
12910 options.nodes.fixed = optionsObj.fixed;
12911 }
12912
12913 if (optionsObj.parseColor != null) {
12914 options.nodes.parseColor = optionsObj.parseColor;
12915 }
12916
12917 if (optionsObj.inheritColor != null) {
12918 options.edges.inheritColor = optionsObj.inheritColor;
12919 }
12920 }
12921
12922 var gEdges = gephiJSON.edges;
12923
12924 var vEdges = map$3(gEdges).call(gEdges, function (gEdge) {
12925 var vEdge = {
12926 from: gEdge.source,
12927 id: gEdge.id,
12928 to: gEdge.target
12929 };
12930
12931 if (gEdge.attributes != null) {
12932 vEdge.attributes = gEdge.attributes;
12933 }
12934
12935 if (gEdge.label != null) {
12936 vEdge.label = gEdge.label;
12937 }
12938
12939 if (gEdge.attributes != null && gEdge.attributes.title != null) {
12940 vEdge.title = gEdge.attributes.title;
12941 }
12942
12943 if (gEdge.type === "Directed") {
12944 vEdge.arrows = "to";
12945 } // edge['value'] = gEdge.attributes != null ? gEdge.attributes.Weight : undefined;
12946 // edge['width'] = edge['value'] != null ? undefined : edgegEdge.size;
12947
12948
12949 if (gEdge.color && options.edges.inheritColor === false) {
12950 vEdge.color = gEdge.color;
12951 }
12952
12953 return vEdge;
12954 });
12955
12956 var vNodes = map$3(_context = gephiJSON.nodes).call(_context, function (gNode) {
12957 var vNode = {
12958 id: gNode.id,
12959 fixed: options.nodes.fixed && gNode.x != null && gNode.y != null
12960 };
12961
12962 if (gNode.attributes != null) {
12963 vNode.attributes = gNode.attributes;
12964 }
12965
12966 if (gNode.label != null) {
12967 vNode.label = gNode.label;
12968 }
12969
12970 if (gNode.size != null) {
12971 vNode.size = gNode.size;
12972 }
12973
12974 if (gNode.attributes != null && gNode.attributes.title != null) {
12975 vNode.title = gNode.attributes.title;
12976 }
12977
12978 if (gNode.title != null) {
12979 vNode.title = gNode.title;
12980 }
12981
12982 if (gNode.x != null) {
12983 vNode.x = gNode.x;
12984 }
12985
12986 if (gNode.y != null) {
12987 vNode.y = gNode.y;
12988 }
12989
12990 if (gNode.color != null) {
12991 if (options.nodes.parseColor === true) {
12992 vNode.color = gNode.color;
12993 } else {
12994 vNode.color = {
12995 background: gNode.color,
12996 border: gNode.color,
12997 highlight: {
12998 background: gNode.color,
12999 border: gNode.color
13000 },
13001 hover: {
13002 background: gNode.color,
13003 border: gNode.color
13004 }
13005 };
13006 }
13007 }
13008
13009 return vNode;
13010 });
13011
13012 return {
13013 nodes: vNodes,
13014 edges: vEdges
13015 };
13016}
13017
13018var gephiParser = /*#__PURE__*/Object.freeze({
13019 __proto__: null,
13020 parseGephi: parseGephi
13021});
13022
13023// English
13024var en = {
13025 addDescription: "Click in an empty space to place a new node.",
13026 addEdge: "Add Edge",
13027 addNode: "Add Node",
13028 back: "Back",
13029 close: "Close",
13030 createEdgeError: "Cannot link edges to a cluster.",
13031 del: "Delete selected",
13032 deleteClusterError: "Clusters cannot be deleted.",
13033 edgeDescription: "Click on a node and drag the edge to another node to connect them.",
13034 edit: "Edit",
13035 editClusterError: "Clusters cannot be edited.",
13036 editEdge: "Edit Edge",
13037 editEdgeDescription: "Click on the control points and drag them to a node to connect to it.",
13038 editNode: "Edit Node"
13039}; // German
13040
13041var de = {
13042 addDescription: "Klicke auf eine freie Stelle, um einen neuen Knoten zu plazieren.",
13043 addEdge: "Kante hinzuf\xFCgen",
13044 addNode: "Knoten hinzuf\xFCgen",
13045 back: "Zur\xFCck",
13046 close: "Schließen",
13047 createEdgeError: "Es ist nicht m\xF6glich, Kanten mit Clustern zu verbinden.",
13048 del: "L\xF6sche Auswahl",
13049 deleteClusterError: "Cluster k\xF6nnen nicht gel\xF6scht werden.",
13050 edgeDescription: "Klicke auf einen Knoten und ziehe die Kante zu einem anderen Knoten, um diese zu verbinden.",
13051 edit: "Editieren",
13052 editClusterError: "Cluster k\xF6nnen nicht editiert werden.",
13053 editEdge: "Kante editieren",
13054 editEdgeDescription: "Klicke auf die Verbindungspunkte und ziehe diese auf einen Knoten, um sie zu verbinden.",
13055 editNode: "Knoten editieren"
13056}; // Spanish
13057
13058var es = {
13059 addDescription: "Haga clic en un lugar vac\xEDo para colocar un nuevo nodo.",
13060 addEdge: "A\xF1adir arista",
13061 addNode: "A\xF1adir nodo",
13062 back: "Atr\xE1s",
13063 close: "Cerrar",
13064 createEdgeError: "No se puede conectar una arista a un grupo.",
13065 del: "Eliminar selecci\xF3n",
13066 deleteClusterError: "No es posible eliminar grupos.",
13067 edgeDescription: "Haga clic en un nodo y arrastre la arista hacia otro nodo para conectarlos.",
13068 edit: "Editar",
13069 editClusterError: "No es posible editar grupos.",
13070 editEdge: "Editar arista",
13071 editEdgeDescription: "Haga clic en un punto de control y arrastrelo a un nodo para conectarlo.",
13072 editNode: "Editar nodo"
13073}; //Italiano
13074
13075var it = {
13076 addDescription: "Clicca per aggiungere un nuovo nodo",
13077 addEdge: "Aggiungi un vertice",
13078 addNode: "Aggiungi un nodo",
13079 back: "Indietro",
13080 close: "Chiudere",
13081 createEdgeError: "Non si possono collegare vertici ad un cluster",
13082 del: "Cancella la selezione",
13083 deleteClusterError: "I cluster non possono essere cancellati",
13084 edgeDescription: "Clicca su un nodo e trascinalo ad un altro nodo per connetterli.",
13085 edit: "Modifica",
13086 editClusterError: "I clusters non possono essere modificati.",
13087 editEdge: "Modifica il vertice",
13088 editEdgeDescription: "Clicca sui Punti di controllo e trascinali ad un nodo per connetterli.",
13089 editNode: "Modifica il nodo"
13090}; // Dutch
13091
13092var nl = {
13093 addDescription: "Klik op een leeg gebied om een nieuwe node te maken.",
13094 addEdge: "Link toevoegen",
13095 addNode: "Node toevoegen",
13096 back: "Terug",
13097 close: "Sluiten",
13098 createEdgeError: "Kan geen link maken naar een cluster.",
13099 del: "Selectie verwijderen",
13100 deleteClusterError: "Clusters kunnen niet worden verwijderd.",
13101 edgeDescription: "Klik op een node en sleep de link naar een andere node om ze te verbinden.",
13102 edit: "Wijzigen",
13103 editClusterError: "Clusters kunnen niet worden aangepast.",
13104 editEdge: "Link wijzigen",
13105 editEdgeDescription: "Klik op de verbindingspunten en sleep ze naar een node om daarmee te verbinden.",
13106 editNode: "Node wijzigen"
13107}; // Portuguese Brazil
13108
13109var pt = {
13110 addDescription: "Clique em um espaço em branco para adicionar um novo nó",
13111 addEdge: "Adicionar aresta",
13112 addNode: "Adicionar nó",
13113 back: "Voltar",
13114 close: "Fechar",
13115 createEdgeError: "Não foi possível linkar arestas a um cluster.",
13116 del: "Remover selecionado",
13117 deleteClusterError: "Clusters não puderam ser removidos.",
13118 edgeDescription: "Clique em um nó e arraste a aresta até outro nó para conectá-los",
13119 edit: "Editar",
13120 editClusterError: "Clusters não puderam ser editados.",
13121 editEdge: "Editar aresta",
13122 editEdgeDescription: "Clique nos pontos de controle e os arraste para um nó para conectá-los",
13123 editNode: "Editar nó"
13124}; // Russian
13125
13126var ru = {
13127 addDescription: "Кликните в свободное место, чтобы добавить новый узел.",
13128 addEdge: "Добавить ребро",
13129 addNode: "Добавить узел",
13130 back: "Назад",
13131 close: "Закрывать",
13132 createEdgeError: "Невозможно соединить ребра в кластер.",
13133 del: "Удалить выбранное",
13134 deleteClusterError: "Кластеры не могут быть удалены",
13135 edgeDescription: "Кликните на узел и протяните ребро к другому узлу, чтобы соединить их.",
13136 edit: "Редактировать",
13137 editClusterError: "Кластеры недоступны для редактирования.",
13138 editEdge: "Редактировать ребро",
13139 editEdgeDescription: "Кликните на контрольные точки и перетащите их в узел, чтобы подключиться к нему.",
13140 editNode: "Редактировать узел"
13141}; // Chinese
13142
13143var cn = {
13144 addDescription: "单击空白处放置新节点。",
13145 addEdge: "添加连接线",
13146 addNode: "添加节点",
13147 back: "返回",
13148 close: "關閉",
13149 createEdgeError: "无法将连接线连接到群集。",
13150 del: "删除选定",
13151 deleteClusterError: "无法删除群集。",
13152 edgeDescription: "单击某个节点并将该连接线拖动到另一个节点以连接它们。",
13153 edit: "编辑",
13154 editClusterError: "无法编辑群集。",
13155 editEdge: "编辑连接线",
13156 editEdgeDescription: "单击控制节点并将它们拖到节点上连接。",
13157 editNode: "编辑节点"
13158}; // Ukrainian
13159
13160var uk = {
13161 addDescription: "Kлікніть на вільне місце, щоб додати новий вузол.",
13162 addEdge: "Додати край",
13163 addNode: "Додати вузол",
13164 back: "Назад",
13165 close: "Закрити",
13166 createEdgeError: "Не можливо об'єднати краї в групу.",
13167 del: "Видалити обране",
13168 deleteClusterError: "Групи не можуть бути видалені.",
13169 edgeDescription: "Клікніть на вузол і перетягніть край до іншого вузла, щоб їх з'єднати.",
13170 edit: "Редагувати",
13171 editClusterError: "Групи недоступні для редагування.",
13172 editEdge: "Редагувати край",
13173 editEdgeDescription: "Клікніть на контрольні точки і перетягніть їх у вузол, щоб підключитися до нього.",
13174 editNode: "Редагувати вузол"
13175}; // French
13176
13177var fr = {
13178 addDescription: "Cliquez dans un endroit vide pour placer un nœud.",
13179 addEdge: "Ajouter un lien",
13180 addNode: "Ajouter un nœud",
13181 back: "Retour",
13182 close: "Fermer",
13183 createEdgeError: "Impossible de créer un lien vers un cluster.",
13184 del: "Effacer la sélection",
13185 deleteClusterError: "Les clusters ne peuvent pas être effacés.",
13186 edgeDescription: "Cliquez sur un nœud et glissez le lien vers un autre nœud pour les connecter.",
13187 edit: "Éditer",
13188 editClusterError: "Les clusters ne peuvent pas être édités.",
13189 editEdge: "Éditer le lien",
13190 editEdgeDescription: "Cliquez sur les points de contrôle et glissez-les pour connecter un nœud.",
13191 editNode: "Éditer le nœud"
13192}; // Czech
13193
13194var cs = {
13195 addDescription: "Kluknutím do prázdného prostoru můžete přidat nový vrchol.",
13196 addEdge: "Přidat hranu",
13197 addNode: "Přidat vrchol",
13198 back: "Zpět",
13199 close: "Zavřít",
13200 createEdgeError: "Nelze připojit hranu ke shluku.",
13201 del: "Smazat výběr",
13202 deleteClusterError: "Nelze mazat shluky.",
13203 edgeDescription: "Přetažením z jednoho vrcholu do druhého můžete spojit tyto vrcholy novou hranou.",
13204 edit: "Upravit",
13205 editClusterError: "Nelze upravovat shluky.",
13206 editEdge: "Upravit hranu",
13207 editEdgeDescription: "Přetažením kontrolního vrcholu hrany ji můžete připojit k jinému vrcholu.",
13208 editNode: "Upravit vrchol"
13209};
13210
13211var locales = /*#__PURE__*/Object.freeze({
13212 __proto__: null,
13213 en: en,
13214 de: de,
13215 es: es,
13216 it: it,
13217 nl: nl,
13218 pt: pt,
13219 ru: ru,
13220 cn: cn,
13221 uk: uk,
13222 fr: fr,
13223 cs: cs
13224});
13225
13226/**
13227 * Normalizes language code into the format used internally.
13228 *
13229 * @param locales - All the available locales.
13230 * @param rawCode - The original code as supplied by the user.
13231 *
13232 * @returns Language code in the format language-COUNTRY or language, eventually
13233 * fallbacks to en.
13234 */
13235function normalizeLanguageCode(locales, rawCode) {
13236 try {
13237 var _rawCode$split = rawCode.split(/[-_ /]/, 2),
13238 _rawCode$split2 = _slicedToArray(_rawCode$split, 2),
13239 rawLanguage = _rawCode$split2[0],
13240 rawCountry = _rawCode$split2[1];
13241
13242 var language = rawLanguage != null ? rawLanguage.toLowerCase() : null;
13243 var country = rawCountry != null ? rawCountry.toUpperCase() : null;
13244
13245 if (language && country) {
13246 var code = language + "-" + country;
13247
13248 if (Object.prototype.hasOwnProperty.call(locales, code)) {
13249 return code;
13250 } else {
13251 var _context;
13252
13253 console.warn(concat(_context = "Unknown variant ".concat(country, " of language ")).call(_context, language, "."));
13254 }
13255 }
13256
13257 if (language) {
13258 var _code = language;
13259
13260 if (Object.prototype.hasOwnProperty.call(locales, _code)) {
13261 return _code;
13262 } else {
13263 console.warn("Unknown language ".concat(language));
13264 }
13265 }
13266
13267 console.warn("Unknown locale ".concat(rawCode, ", falling back to English."));
13268 return "en";
13269 } catch (error) {
13270 console.error(error);
13271 console.warn("Unexpected error while normalizing locale ".concat(rawCode, ", falling back to English."));
13272 return "en";
13273 }
13274}
13275
13276/**
13277 * Associates a canvas to a given image, containing a number of renderings
13278 * of the image at various sizes.
13279 *
13280 * This technique is known as 'mipmapping'.
13281 *
13282 * NOTE: Images can also be of type 'data:svg+xml`. This code also works
13283 * for svg, but the mipmapping may not be necessary.
13284 *
13285 * @param {Image} image
13286 */
13287var CachedImage = /*#__PURE__*/function () {
13288 /**
13289 * @ignore
13290 */
13291 function CachedImage() {
13292 _classCallCheck(this, CachedImage);
13293
13294 this.NUM_ITERATIONS = 4; // Number of items in the coordinates array
13295
13296 this.image = new Image();
13297 this.canvas = document.createElement("canvas");
13298 }
13299 /**
13300 * Called when the image has been successfully loaded.
13301 */
13302
13303
13304 _createClass(CachedImage, [{
13305 key: "init",
13306 value: function init() {
13307 if (this.initialized()) return;
13308 this.src = this.image.src; // For same interface with Image
13309
13310 var w = this.image.width;
13311 var h = this.image.height; // Ease external access
13312
13313 this.width = w;
13314 this.height = h;
13315 var h2 = Math.floor(h / 2);
13316 var h4 = Math.floor(h / 4);
13317 var h8 = Math.floor(h / 8);
13318 var h16 = Math.floor(h / 16);
13319 var w2 = Math.floor(w / 2);
13320 var w4 = Math.floor(w / 4);
13321 var w8 = Math.floor(w / 8);
13322 var w16 = Math.floor(w / 16); // Make canvas as small as possible
13323
13324 this.canvas.width = 3 * w4;
13325 this.canvas.height = h2; // Coordinates and sizes of images contained in the canvas
13326 // Values per row: [top x, left y, width, height]
13327
13328 this.coordinates = [[0, 0, w2, h2], [w2, 0, w4, h4], [w2, h4, w8, h8], [5 * w8, h4, w16, h16]];
13329
13330 this._fillMipMap();
13331 }
13332 /**
13333 * @returns {boolean} true if init() has been called, false otherwise.
13334 */
13335
13336 }, {
13337 key: "initialized",
13338 value: function initialized() {
13339 return this.coordinates !== undefined;
13340 }
13341 /**
13342 * Redraw main image in various sizes to the context.
13343 *
13344 * The rationale behind this is to reduce artefacts due to interpolation
13345 * at differing zoom levels.
13346 *
13347 * Source: http://stackoverflow.com/q/18761404/1223531
13348 *
13349 * This methods takes the resizing out of the drawing loop, in order to
13350 * reduce performance overhead.
13351 *
13352 * TODO: The code assumes that a 2D context can always be gotten. This is
13353 * not necessarily true! OTOH, if not true then usage of this class
13354 * is senseless.
13355 *
13356 * @private
13357 */
13358
13359 }, {
13360 key: "_fillMipMap",
13361 value: function _fillMipMap() {
13362 var ctx = this.canvas.getContext("2d"); // First zoom-level comes from the image
13363
13364 var to = this.coordinates[0];
13365 ctx.drawImage(this.image, to[0], to[1], to[2], to[3]); // The rest are copy actions internal to the canvas/context
13366
13367 for (var iterations = 1; iterations < this.NUM_ITERATIONS; iterations++) {
13368 var from = this.coordinates[iterations - 1];
13369 var _to = this.coordinates[iterations];
13370 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], _to[0], _to[1], _to[2], _to[3]);
13371 }
13372 }
13373 /**
13374 * Draw the image, using the mipmap if necessary.
13375 *
13376 * MipMap is only used if param factor > 2; otherwise, original bitmap
13377 * is resized. This is also used to skip mipmap usage, e.g. by setting factor = 1
13378 *
13379 * Credits to 'Alex de Mulder' for original implementation.
13380 *
13381 * @param {CanvasRenderingContext2D} ctx context on which to draw zoomed image
13382 * @param {Float} factor scale factor at which to draw
13383 * @param {number} left
13384 * @param {number} top
13385 * @param {number} width
13386 * @param {number} height
13387 */
13388
13389 }, {
13390 key: "drawImageAtPosition",
13391 value: function drawImageAtPosition(ctx, factor, left, top, width, height) {
13392 if (!this.initialized()) return; //can't draw image yet not intialized
13393
13394 if (factor > 2) {
13395 // Determine which zoomed image to use
13396 factor *= 0.5;
13397 var iterations = 0;
13398
13399 while (factor > 2 && iterations < this.NUM_ITERATIONS) {
13400 factor *= 0.5;
13401 iterations += 1;
13402 }
13403
13404 if (iterations >= this.NUM_ITERATIONS) {
13405 iterations = this.NUM_ITERATIONS - 1;
13406 } //console.log("iterations: " + iterations);
13407
13408
13409 var from = this.coordinates[iterations];
13410 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], left, top, width, height);
13411 } else {
13412 // Draw image directly
13413 ctx.drawImage(this.image, left, top, width, height);
13414 }
13415 }
13416 }]);
13417
13418 return CachedImage;
13419}();
13420
13421/**
13422 * This callback is a callback that accepts an Image.
13423 *
13424 * @callback ImageCallback
13425 * @param {Image} image
13426 */
13427
13428/**
13429 * This class loads images and keeps them stored.
13430 *
13431 * @param {ImageCallback} callback
13432 */
13433
13434var Images = /*#__PURE__*/function () {
13435 /**
13436 * @param {ImageCallback} callback
13437 */
13438 function Images(callback) {
13439 _classCallCheck(this, Images);
13440
13441 this.images = {};
13442 this.imageBroken = {};
13443 this.callback = callback;
13444 }
13445 /**
13446 * @param {string} url The original Url that failed to load, if the broken image is successfully loaded it will be added to the cache using this Url as the key so that subsequent requests for this Url will return the broken image
13447 * @param {string} brokenUrl Url the broken image to try and load
13448 * @param {Image} imageToLoadBrokenUrlOn The image object
13449 */
13450
13451
13452 _createClass(Images, [{
13453 key: "_tryloadBrokenUrl",
13454 value: function _tryloadBrokenUrl(url, brokenUrl, imageToLoadBrokenUrlOn) {
13455 //If these parameters aren't specified then exit the function because nothing constructive can be done
13456 if (url === undefined || imageToLoadBrokenUrlOn === undefined) return;
13457
13458 if (brokenUrl === undefined) {
13459 console.warn("No broken url image defined");
13460 return;
13461 } //Clear the old subscription to the error event and put a new in place that only handle errors in loading the brokenImageUrl
13462
13463
13464 imageToLoadBrokenUrlOn.image.onerror = function () {
13465 console.error("Could not load brokenImage:", brokenUrl); // cache item will contain empty image, this should be OK for default
13466 }; //Set the source of the image to the brokenUrl, this is actually what kicks off the loading of the broken image
13467
13468
13469 imageToLoadBrokenUrlOn.image.src = brokenUrl;
13470 }
13471 /**
13472 *
13473 * @param {vis.Image} imageToRedrawWith
13474 * @private
13475 */
13476
13477 }, {
13478 key: "_redrawWithImage",
13479 value: function _redrawWithImage(imageToRedrawWith) {
13480 if (this.callback) {
13481 this.callback(imageToRedrawWith);
13482 }
13483 }
13484 /**
13485 * @param {string} url Url of the image
13486 * @param {string} brokenUrl Url of an image to use if the url image is not found
13487 * @returns {Image} img The image object
13488 */
13489
13490 }, {
13491 key: "load",
13492 value: function load(url, brokenUrl) {
13493 var _this = this;
13494
13495 //Try and get the image from the cache, if successful then return the cached image
13496 var cachedImage = this.images[url];
13497 if (cachedImage) return cachedImage; //Create a new image
13498
13499 var img = new CachedImage(); // Need to add to cache here, otherwise final return will spawn different copies of the same image,
13500 // Also, there will be multiple loads of the same image.
13501
13502 this.images[url] = img; //Subscribe to the event that is raised if the image loads successfully
13503
13504 img.image.onload = function () {
13505 // Properly init the cached item and then request a redraw
13506 _this._fixImageCoordinates(img.image);
13507
13508 img.init();
13509
13510 _this._redrawWithImage(img);
13511 }; //Subscribe to the event that is raised if the image fails to load
13512
13513
13514 img.image.onerror = function () {
13515 console.error("Could not load image:", url); //Try and load the image specified by the brokenUrl using
13516
13517 _this._tryloadBrokenUrl(url, brokenUrl, img);
13518 }; //Set the source of the image to the url, this is what actually kicks off the loading of the image
13519
13520
13521 img.image.src = url; //Return the new image
13522
13523 return img;
13524 }
13525 /**
13526 * IE11 fix -- thanks dponch!
13527 *
13528 * Local helper function
13529 *
13530 * @param {vis.Image} imageToCache
13531 * @private
13532 */
13533
13534 }, {
13535 key: "_fixImageCoordinates",
13536 value: function _fixImageCoordinates(imageToCache) {
13537 if (imageToCache.width === 0) {
13538 document.body.appendChild(imageToCache);
13539 imageToCache.width = imageToCache.offsetWidth;
13540 imageToCache.height = imageToCache.offsetHeight;
13541 document.body.removeChild(imageToCache);
13542 }
13543 }
13544 }]);
13545
13546 return Images;
13547}();
13548
13549var freezing = !fails(function () {
13550 // eslint-disable-next-line es/no-object-isextensible, es/no-object-preventextensions -- required for testing
13551 return Object.isExtensible(Object.preventExtensions({}));
13552});
13553
13554var internalMetadata = createCommonjsModule(function (module) {
13555 var defineProperty = objectDefineProperty.f;
13556 var REQUIRED = false;
13557 var METADATA = uid('meta');
13558 var id = 0; // eslint-disable-next-line es/no-object-isextensible -- safe
13559
13560 var isExtensible = Object.isExtensible || function () {
13561 return true;
13562 };
13563
13564 var setMetadata = function (it) {
13565 defineProperty(it, METADATA, {
13566 value: {
13567 objectID: 'O' + id++,
13568 // object ID
13569 weakData: {} // weak collections IDs
13570
13571 }
13572 });
13573 };
13574
13575 var fastKey = function (it, create) {
13576 // return a primitive with prefix
13577 if (!isObject$1(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
13578
13579 if (!has$1(it, METADATA)) {
13580 // can't set metadata to uncaught frozen object
13581 if (!isExtensible(it)) return 'F'; // not necessary to add metadata
13582
13583 if (!create) return 'E'; // add missing metadata
13584
13585 setMetadata(it); // return object ID
13586 }
13587
13588 return it[METADATA].objectID;
13589 };
13590
13591 var getWeakData = function (it, create) {
13592 if (!has$1(it, METADATA)) {
13593 // can't set metadata to uncaught frozen object
13594 if (!isExtensible(it)) return true; // not necessary to add metadata
13595
13596 if (!create) return false; // add missing metadata
13597
13598 setMetadata(it); // return the store of weak collections IDs
13599 }
13600
13601 return it[METADATA].weakData;
13602 }; // add metadata on freeze-family methods calling
13603
13604
13605 var onFreeze = function (it) {
13606 if (freezing && REQUIRED && isExtensible(it) && !has$1(it, METADATA)) setMetadata(it);
13607 return it;
13608 };
13609
13610 var enable = function () {
13611 meta.enable = function () {
13612 /* empty */
13613 };
13614
13615 REQUIRED = true;
13616 var getOwnPropertyNames = objectGetOwnPropertyNames.f;
13617 var splice = [].splice;
13618 var test = {};
13619 test[METADATA] = 1; // prevent exposing of metadata key
13620
13621 if (getOwnPropertyNames(test).length) {
13622 objectGetOwnPropertyNames.f = function (it) {
13623 var result = getOwnPropertyNames(it);
13624
13625 for (var i = 0, length = result.length; i < length; i++) {
13626 if (result[i] === METADATA) {
13627 splice.call(result, i, 1);
13628 break;
13629 }
13630 }
13631
13632 return result;
13633 };
13634
13635 _export({
13636 target: 'Object',
13637 stat: true,
13638 forced: true
13639 }, {
13640 getOwnPropertyNames: objectGetOwnPropertyNamesExternal.f
13641 });
13642 }
13643 };
13644
13645 var meta = module.exports = {
13646 enable: enable,
13647 fastKey: fastKey,
13648 getWeakData: getWeakData,
13649 onFreeze: onFreeze
13650 };
13651 hiddenKeys$1[METADATA] = true;
13652});
13653internalMetadata.enable;
13654internalMetadata.fastKey;
13655internalMetadata.getWeakData;
13656internalMetadata.onFreeze;
13657
13658var Result = function (stopped, result) {
13659 this.stopped = stopped;
13660 this.result = result;
13661};
13662
13663var iterate = function (iterable, unboundFunction, options) {
13664 var that = options && options.that;
13665 var AS_ENTRIES = !!(options && options.AS_ENTRIES);
13666 var IS_ITERATOR = !!(options && options.IS_ITERATOR);
13667 var INTERRUPTED = !!(options && options.INTERRUPTED);
13668 var fn = functionBindContext(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
13669 var iterator, iterFn, index, length, result, next, step;
13670
13671 var stop = function (condition) {
13672 if (iterator) iteratorClose(iterator);
13673 return new Result(true, condition);
13674 };
13675
13676 var callFn = function (value) {
13677 if (AS_ENTRIES) {
13678 anObject(value);
13679 return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
13680 }
13681
13682 return INTERRUPTED ? fn(value, stop) : fn(value);
13683 };
13684
13685 if (IS_ITERATOR) {
13686 iterator = iterable;
13687 } else {
13688 iterFn = getIteratorMethod$3(iterable);
13689 if (typeof iterFn != 'function') throw TypeError('Target is not iterable'); // optimisation for array iterators
13690
13691 if (isArrayIteratorMethod(iterFn)) {
13692 for (index = 0, length = toLength(iterable.length); length > index; index++) {
13693 result = callFn(iterable[index]);
13694 if (result && result instanceof Result) return result;
13695 }
13696
13697 return new Result(false);
13698 }
13699
13700 iterator = iterFn.call(iterable);
13701 }
13702
13703 next = iterator.next;
13704
13705 while (!(step = next.call(iterator)).done) {
13706 try {
13707 result = callFn(step.value);
13708 } catch (error) {
13709 iteratorClose(iterator);
13710 throw error;
13711 }
13712
13713 if (typeof result == 'object' && result && result instanceof Result) return result;
13714 }
13715
13716 return new Result(false);
13717};
13718
13719var anInstance = function (it, Constructor, name) {
13720 if (!(it instanceof Constructor)) {
13721 throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
13722 }
13723
13724 return it;
13725};
13726
13727var defineProperty$1 = objectDefineProperty.f;
13728var forEach = arrayIteration.forEach;
13729var setInternalState$2 = internalState.set;
13730var internalStateGetterFor$2 = internalState.getterFor;
13731
13732var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
13733 var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
13734 var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
13735 var ADDER = IS_MAP ? 'set' : 'add';
13736 var NativeConstructor = global_1[CONSTRUCTOR_NAME];
13737 var NativePrototype = NativeConstructor && NativeConstructor.prototype;
13738 var exported = {};
13739 var Constructor;
13740
13741 if (!descriptors || typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
13742 new NativeConstructor().entries().next();
13743 }))) {
13744 // create collection constructor
13745 Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
13746 internalMetadata.enable();
13747 } else {
13748 Constructor = wrapper(function (target, iterable) {
13749 setInternalState$2(anInstance(target, Constructor, CONSTRUCTOR_NAME), {
13750 type: CONSTRUCTOR_NAME,
13751 collection: new NativeConstructor()
13752 });
13753 if (iterable != undefined) iterate(iterable, target[ADDER], {
13754 that: target,
13755 AS_ENTRIES: IS_MAP
13756 });
13757 });
13758 var getInternalState = internalStateGetterFor$2(CONSTRUCTOR_NAME);
13759 forEach(['add', 'clear', 'delete', 'forEach', 'get', 'has', 'set', 'keys', 'values', 'entries'], function (KEY) {
13760 var IS_ADDER = KEY == 'add' || KEY == 'set';
13761
13762 if (KEY in NativePrototype && !(IS_WEAK && KEY == 'clear')) {
13763 createNonEnumerableProperty(Constructor.prototype, KEY, function (a, b) {
13764 var collection = getInternalState(this).collection;
13765 if (!IS_ADDER && IS_WEAK && !isObject$1(a)) return KEY == 'get' ? undefined : false;
13766 var result = collection[KEY](a === 0 ? 0 : a, b);
13767 return IS_ADDER ? this : result;
13768 });
13769 }
13770 });
13771 IS_WEAK || defineProperty$1(Constructor.prototype, 'size', {
13772 configurable: true,
13773 get: function () {
13774 return getInternalState(this).collection.size;
13775 }
13776 });
13777 }
13778
13779 setToStringTag(Constructor, CONSTRUCTOR_NAME, false, true);
13780 exported[CONSTRUCTOR_NAME] = Constructor;
13781 _export({
13782 global: true,
13783 forced: true
13784 }, exported);
13785 if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
13786 return Constructor;
13787};
13788
13789var redefineAll = function (target, src, options) {
13790 for (var key in src) {
13791 if (options && options.unsafe && target[key]) target[key] = src[key];else redefine(target, key, src[key], options);
13792 }
13793
13794 return target;
13795};
13796
13797var SPECIES = wellKnownSymbol('species');
13798
13799var setSpecies = function (CONSTRUCTOR_NAME) {
13800 var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
13801 var defineProperty = objectDefineProperty.f;
13802
13803 if (descriptors && Constructor && !Constructor[SPECIES]) {
13804 defineProperty(Constructor, SPECIES, {
13805 configurable: true,
13806 get: function () {
13807 return this;
13808 }
13809 });
13810 }
13811};
13812
13813var defineProperty = objectDefineProperty.f;
13814var fastKey = internalMetadata.fastKey;
13815var setInternalState$1 = internalState.set;
13816var internalStateGetterFor$1 = internalState.getterFor;
13817var collectionStrong = {
13818 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
13819 var C = wrapper(function (that, iterable) {
13820 anInstance(that, C, CONSTRUCTOR_NAME);
13821 setInternalState$1(that, {
13822 type: CONSTRUCTOR_NAME,
13823 index: objectCreate(null),
13824 first: undefined,
13825 last: undefined,
13826 size: 0
13827 });
13828 if (!descriptors) that.size = 0;
13829 if (iterable != undefined) iterate(iterable, that[ADDER], {
13830 that: that,
13831 AS_ENTRIES: IS_MAP
13832 });
13833 });
13834 var getInternalState = internalStateGetterFor$1(CONSTRUCTOR_NAME);
13835
13836 var define = function (that, key, value) {
13837 var state = getInternalState(that);
13838 var entry = getEntry(that, key);
13839 var previous, index; // change existing entry
13840
13841 if (entry) {
13842 entry.value = value; // create new entry
13843 } else {
13844 state.last = entry = {
13845 index: index = fastKey(key, true),
13846 key: key,
13847 value: value,
13848 previous: previous = state.last,
13849 next: undefined,
13850 removed: false
13851 };
13852 if (!state.first) state.first = entry;
13853 if (previous) previous.next = entry;
13854 if (descriptors) state.size++;else that.size++; // add to index
13855
13856 if (index !== 'F') state.index[index] = entry;
13857 }
13858
13859 return that;
13860 };
13861
13862 var getEntry = function (that, key) {
13863 var state = getInternalState(that); // fast case
13864
13865 var index = fastKey(key);
13866 var entry;
13867 if (index !== 'F') return state.index[index]; // frozen object case
13868
13869 for (entry = state.first; entry; entry = entry.next) {
13870 if (entry.key == key) return entry;
13871 }
13872 };
13873
13874 redefineAll(C.prototype, {
13875 // `{ Map, Set }.prototype.clear()` methods
13876 // https://tc39.es/ecma262/#sec-map.prototype.clear
13877 // https://tc39.es/ecma262/#sec-set.prototype.clear
13878 clear: function clear() {
13879 var that = this;
13880 var state = getInternalState(that);
13881 var data = state.index;
13882 var entry = state.first;
13883
13884 while (entry) {
13885 entry.removed = true;
13886 if (entry.previous) entry.previous = entry.previous.next = undefined;
13887 delete data[entry.index];
13888 entry = entry.next;
13889 }
13890
13891 state.first = state.last = undefined;
13892 if (descriptors) state.size = 0;else that.size = 0;
13893 },
13894 // `{ Map, Set }.prototype.delete(key)` methods
13895 // https://tc39.es/ecma262/#sec-map.prototype.delete
13896 // https://tc39.es/ecma262/#sec-set.prototype.delete
13897 'delete': function (key) {
13898 var that = this;
13899 var state = getInternalState(that);
13900 var entry = getEntry(that, key);
13901
13902 if (entry) {
13903 var next = entry.next;
13904 var prev = entry.previous;
13905 delete state.index[entry.index];
13906 entry.removed = true;
13907 if (prev) prev.next = next;
13908 if (next) next.previous = prev;
13909 if (state.first == entry) state.first = next;
13910 if (state.last == entry) state.last = prev;
13911 if (descriptors) state.size--;else that.size--;
13912 }
13913
13914 return !!entry;
13915 },
13916 // `{ Map, Set }.prototype.forEach(callbackfn, thisArg = undefined)` methods
13917 // https://tc39.es/ecma262/#sec-map.prototype.foreach
13918 // https://tc39.es/ecma262/#sec-set.prototype.foreach
13919 forEach: function forEach(callbackfn
13920 /* , that = undefined */
13921 ) {
13922 var state = getInternalState(this);
13923 var boundFunction = functionBindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
13924 var entry;
13925
13926 while (entry = entry ? entry.next : state.first) {
13927 boundFunction(entry.value, entry.key, this); // revert to the last existing entry
13928
13929 while (entry && entry.removed) entry = entry.previous;
13930 }
13931 },
13932 // `{ Map, Set}.prototype.has(key)` methods
13933 // https://tc39.es/ecma262/#sec-map.prototype.has
13934 // https://tc39.es/ecma262/#sec-set.prototype.has
13935 has: function has(key) {
13936 return !!getEntry(this, key);
13937 }
13938 });
13939 redefineAll(C.prototype, IS_MAP ? {
13940 // `Map.prototype.get(key)` method
13941 // https://tc39.es/ecma262/#sec-map.prototype.get
13942 get: function get(key) {
13943 var entry = getEntry(this, key);
13944 return entry && entry.value;
13945 },
13946 // `Map.prototype.set(key, value)` method
13947 // https://tc39.es/ecma262/#sec-map.prototype.set
13948 set: function set(key, value) {
13949 return define(this, key === 0 ? 0 : key, value);
13950 }
13951 } : {
13952 // `Set.prototype.add(value)` method
13953 // https://tc39.es/ecma262/#sec-set.prototype.add
13954 add: function add(value) {
13955 return define(this, value = value === 0 ? 0 : value, value);
13956 }
13957 });
13958 if (descriptors) defineProperty(C.prototype, 'size', {
13959 get: function () {
13960 return getInternalState(this).size;
13961 }
13962 });
13963 return C;
13964 },
13965 setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
13966 var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
13967 var getInternalCollectionState = internalStateGetterFor$1(CONSTRUCTOR_NAME);
13968 var getInternalIteratorState = internalStateGetterFor$1(ITERATOR_NAME); // `{ Map, Set }.prototype.{ keys, values, entries, @@iterator }()` methods
13969 // https://tc39.es/ecma262/#sec-map.prototype.entries
13970 // https://tc39.es/ecma262/#sec-map.prototype.keys
13971 // https://tc39.es/ecma262/#sec-map.prototype.values
13972 // https://tc39.es/ecma262/#sec-map.prototype-@@iterator
13973 // https://tc39.es/ecma262/#sec-set.prototype.entries
13974 // https://tc39.es/ecma262/#sec-set.prototype.keys
13975 // https://tc39.es/ecma262/#sec-set.prototype.values
13976 // https://tc39.es/ecma262/#sec-set.prototype-@@iterator
13977
13978 defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
13979 setInternalState$1(this, {
13980 type: ITERATOR_NAME,
13981 target: iterated,
13982 state: getInternalCollectionState(iterated),
13983 kind: kind,
13984 last: undefined
13985 });
13986 }, function () {
13987 var state = getInternalIteratorState(this);
13988 var kind = state.kind;
13989 var entry = state.last; // revert to the last existing entry
13990
13991 while (entry && entry.removed) entry = entry.previous; // get next entry
13992
13993
13994 if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
13995 // or finish the iteration
13996 state.target = undefined;
13997 return {
13998 value: undefined,
13999 done: true
14000 };
14001 } // return step by kind
14002
14003
14004 if (kind == 'keys') return {
14005 value: entry.key,
14006 done: false
14007 };
14008 if (kind == 'values') return {
14009 value: entry.value,
14010 done: false
14011 };
14012 return {
14013 value: [entry.key, entry.value],
14014 done: false
14015 };
14016 }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); // `{ Map, Set }.prototype[@@species]` accessors
14017 // https://tc39.es/ecma262/#sec-get-map-@@species
14018 // https://tc39.es/ecma262/#sec-get-set-@@species
14019
14020 setSpecies(CONSTRUCTOR_NAME);
14021 }
14022};
14023collectionStrong.getConstructor;
14024collectionStrong.setStrong;
14025
14026// https://tc39.es/ecma262/#sec-map-objects
14027
14028
14029collection('Map', function (init) {
14030 return function Map() {
14031 return init(this, arguments.length ? arguments[0] : undefined);
14032 };
14033}, collectionStrong);
14034
14035var map$2 = path.Map;
14036
14037var map$1 = map$2;
14038
14039var map = map$1;
14040
14041/**
14042 * This class can store groups and options specific for groups.
14043 */
14044var Groups = /*#__PURE__*/function () {
14045 /**
14046 * @ignore
14047 */
14048 function Groups() {
14049 _classCallCheck(this, Groups);
14050
14051 this.clear();
14052 this._defaultIndex = 0;
14053 this._groupIndex = 0;
14054 this._defaultGroups = [{
14055 border: "#2B7CE9",
14056 background: "#97C2FC",
14057 highlight: {
14058 border: "#2B7CE9",
14059 background: "#D2E5FF"
14060 },
14061 hover: {
14062 border: "#2B7CE9",
14063 background: "#D2E5FF"
14064 }
14065 }, // 0: blue
14066 {
14067 border: "#FFA500",
14068 background: "#FFFF00",
14069 highlight: {
14070 border: "#FFA500",
14071 background: "#FFFFA3"
14072 },
14073 hover: {
14074 border: "#FFA500",
14075 background: "#FFFFA3"
14076 }
14077 }, // 1: yellow
14078 {
14079 border: "#FA0A10",
14080 background: "#FB7E81",
14081 highlight: {
14082 border: "#FA0A10",
14083 background: "#FFAFB1"
14084 },
14085 hover: {
14086 border: "#FA0A10",
14087 background: "#FFAFB1"
14088 }
14089 }, // 2: red
14090 {
14091 border: "#41A906",
14092 background: "#7BE141",
14093 highlight: {
14094 border: "#41A906",
14095 background: "#A1EC76"
14096 },
14097 hover: {
14098 border: "#41A906",
14099 background: "#A1EC76"
14100 }
14101 }, // 3: green
14102 {
14103 border: "#E129F0",
14104 background: "#EB7DF4",
14105 highlight: {
14106 border: "#E129F0",
14107 background: "#F0B3F5"
14108 },
14109 hover: {
14110 border: "#E129F0",
14111 background: "#F0B3F5"
14112 }
14113 }, // 4: magenta
14114 {
14115 border: "#7C29F0",
14116 background: "#AD85E4",
14117 highlight: {
14118 border: "#7C29F0",
14119 background: "#D3BDF0"
14120 },
14121 hover: {
14122 border: "#7C29F0",
14123 background: "#D3BDF0"
14124 }
14125 }, // 5: purple
14126 {
14127 border: "#C37F00",
14128 background: "#FFA807",
14129 highlight: {
14130 border: "#C37F00",
14131 background: "#FFCA66"
14132 },
14133 hover: {
14134 border: "#C37F00",
14135 background: "#FFCA66"
14136 }
14137 }, // 6: orange
14138 {
14139 border: "#4220FB",
14140 background: "#6E6EFD",
14141 highlight: {
14142 border: "#4220FB",
14143 background: "#9B9BFD"
14144 },
14145 hover: {
14146 border: "#4220FB",
14147 background: "#9B9BFD"
14148 }
14149 }, // 7: darkblue
14150 {
14151 border: "#FD5A77",
14152 background: "#FFC0CB",
14153 highlight: {
14154 border: "#FD5A77",
14155 background: "#FFD1D9"
14156 },
14157 hover: {
14158 border: "#FD5A77",
14159 background: "#FFD1D9"
14160 }
14161 }, // 8: pink
14162 {
14163 border: "#4AD63A",
14164 background: "#C2FABC",
14165 highlight: {
14166 border: "#4AD63A",
14167 background: "#E6FFE3"
14168 },
14169 hover: {
14170 border: "#4AD63A",
14171 background: "#E6FFE3"
14172 }
14173 }, // 9: mint
14174 {
14175 border: "#990000",
14176 background: "#EE0000",
14177 highlight: {
14178 border: "#BB0000",
14179 background: "#FF3333"
14180 },
14181 hover: {
14182 border: "#BB0000",
14183 background: "#FF3333"
14184 }
14185 }, // 10:bright red
14186 {
14187 border: "#FF6000",
14188 background: "#FF6000",
14189 highlight: {
14190 border: "#FF6000",
14191 background: "#FF6000"
14192 },
14193 hover: {
14194 border: "#FF6000",
14195 background: "#FF6000"
14196 }
14197 }, // 12: real orange
14198 {
14199 border: "#97C2FC",
14200 background: "#2B7CE9",
14201 highlight: {
14202 border: "#D2E5FF",
14203 background: "#2B7CE9"
14204 },
14205 hover: {
14206 border: "#D2E5FF",
14207 background: "#2B7CE9"
14208 }
14209 }, // 13: blue
14210 {
14211 border: "#399605",
14212 background: "#255C03",
14213 highlight: {
14214 border: "#399605",
14215 background: "#255C03"
14216 },
14217 hover: {
14218 border: "#399605",
14219 background: "#255C03"
14220 }
14221 }, // 14: green
14222 {
14223 border: "#B70054",
14224 background: "#FF007E",
14225 highlight: {
14226 border: "#B70054",
14227 background: "#FF007E"
14228 },
14229 hover: {
14230 border: "#B70054",
14231 background: "#FF007E"
14232 }
14233 }, // 15: magenta
14234 {
14235 border: "#AD85E4",
14236 background: "#7C29F0",
14237 highlight: {
14238 border: "#D3BDF0",
14239 background: "#7C29F0"
14240 },
14241 hover: {
14242 border: "#D3BDF0",
14243 background: "#7C29F0"
14244 }
14245 }, // 16: purple
14246 {
14247 border: "#4557FA",
14248 background: "#000EA1",
14249 highlight: {
14250 border: "#6E6EFD",
14251 background: "#000EA1"
14252 },
14253 hover: {
14254 border: "#6E6EFD",
14255 background: "#000EA1"
14256 }
14257 }, // 17: darkblue
14258 {
14259 border: "#FFC0CB",
14260 background: "#FD5A77",
14261 highlight: {
14262 border: "#FFD1D9",
14263 background: "#FD5A77"
14264 },
14265 hover: {
14266 border: "#FFD1D9",
14267 background: "#FD5A77"
14268 }
14269 }, // 18: pink
14270 {
14271 border: "#C2FABC",
14272 background: "#74D66A",
14273 highlight: {
14274 border: "#E6FFE3",
14275 background: "#74D66A"
14276 },
14277 hover: {
14278 border: "#E6FFE3",
14279 background: "#74D66A"
14280 }
14281 }, // 19: mint
14282 {
14283 border: "#EE0000",
14284 background: "#990000",
14285 highlight: {
14286 border: "#FF3333",
14287 background: "#BB0000"
14288 },
14289 hover: {
14290 border: "#FF3333",
14291 background: "#BB0000"
14292 }
14293 } // 20:bright red
14294 ];
14295 this.options = {};
14296 this.defaultOptions = {
14297 useDefaultGroups: true
14298 };
14299
14300 assign$2(this.options, this.defaultOptions);
14301 }
14302 /**
14303 *
14304 * @param {object} options
14305 */
14306
14307
14308 _createClass(Groups, [{
14309 key: "setOptions",
14310 value: function setOptions(options) {
14311 var optionFields = ["useDefaultGroups"];
14312
14313 if (options !== undefined) {
14314 for (var groupName in options) {
14315 if (Object.prototype.hasOwnProperty.call(options, groupName)) {
14316 if (indexOf(optionFields).call(optionFields, groupName) === -1) {
14317 var group = options[groupName];
14318 this.add(groupName, group);
14319 }
14320 }
14321 }
14322 }
14323 }
14324 /**
14325 * Clear all groups
14326 */
14327
14328 }, {
14329 key: "clear",
14330 value: function clear() {
14331 this._groups = new map();
14332 this._groupNames = [];
14333 }
14334 /**
14335 * Get group options of a groupname.
14336 * If groupname is not found, a new group may be created.
14337 *
14338 * @param {*} groupname Can be a number, string, Date, etc.
14339 * @param {boolean} [shouldCreate=true] If true, create a new group
14340 * @returns {object} The found or created group
14341 */
14342
14343 }, {
14344 key: "get",
14345 value: function get(groupname) {
14346 var shouldCreate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
14347
14348 var group = this._groups.get(groupname);
14349
14350 if (group === undefined && shouldCreate) {
14351 if (this.options.useDefaultGroups === false && this._groupNames.length > 0) {
14352 // create new group
14353 var index = this._groupIndex % this._groupNames.length;
14354 ++this._groupIndex;
14355 group = {};
14356 group.color = this._groups.get(this._groupNames[index]);
14357
14358 this._groups.set(groupname, group);
14359 } else {
14360 // create new group
14361 var _index = this._defaultIndex % this._defaultGroups.length;
14362
14363 this._defaultIndex++;
14364 group = {};
14365 group.color = this._defaultGroups[_index];
14366
14367 this._groups.set(groupname, group);
14368 }
14369 }
14370
14371 return group;
14372 }
14373 /**
14374 * Add custom group style.
14375 *
14376 * @param {string} groupName - The name of the group, a new group will be
14377 * created if a group with the same name doesn't exist, otherwise the old
14378 * groups style will be overwritten.
14379 * @param {object} style - An object containing borderColor, backgroundColor,
14380 * etc.
14381 * @returns {object} The created group object.
14382 */
14383
14384 }, {
14385 key: "add",
14386 value: function add(groupName, style) {
14387 // Only push group name once to prevent duplicates which would consume more
14388 // RAM and also skew the distribution towards more often updated groups,
14389 // neither of which is desirable.
14390 if (!this._groups.has(groupName)) {
14391 this._groupNames.push(groupName);
14392 }
14393
14394 this._groups.set(groupName, style);
14395
14396 return style;
14397 }
14398 }]);
14399
14400 return Groups;
14401}();
14402
14403// https://tc39.es/ecma262/#sec-number.isnan
14404
14405_export({
14406 target: 'Number',
14407 stat: true
14408}, {
14409 isNaN: function isNaN(number) {
14410 // eslint-disable-next-line no-self-compare -- NaN check
14411 return number != number;
14412 }
14413});
14414
14415var isNan$2 = path.Number.isNaN;
14416
14417var isNan$1 = isNan$2;
14418
14419var isNan = isNan$1;
14420
14421var globalIsFinite = global_1.isFinite; // `Number.isFinite` method
14422// https://tc39.es/ecma262/#sec-number.isfinite
14423// eslint-disable-next-line es/no-number-isfinite -- safe
14424
14425var numberIsFinite = Number.isFinite || function isFinite(it) {
14426 return typeof it == 'number' && globalIsFinite(it);
14427};
14428
14429// https://tc39.es/ecma262/#sec-number.isfinite
14430
14431_export({
14432 target: 'Number',
14433 stat: true
14434}, {
14435 isFinite: numberIsFinite
14436});
14437
14438var _isFinite$2 = path.Number.isFinite;
14439
14440var _isFinite$1 = _isFinite$2;
14441
14442var _isFinite = _isFinite$1;
14443
14444var $some = arrayIteration.some;
14445var STRICT_METHOD$3 = arrayMethodIsStrict('some'); // `Array.prototype.some` method
14446// https://tc39.es/ecma262/#sec-array.prototype.some
14447
14448_export({
14449 target: 'Array',
14450 proto: true,
14451 forced: !STRICT_METHOD$3
14452}, {
14453 some: function some(callbackfn
14454 /* , thisArg */
14455 ) {
14456 return $some(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
14457 }
14458});
14459
14460var some$2 = entryVirtual('Array').some;
14461
14462var ArrayPrototype$7 = Array.prototype;
14463
14464var some_1 = function (it) {
14465 var own = it.some;
14466 return it === ArrayPrototype$7 || it instanceof Array && own === ArrayPrototype$7.some ? some$2 : own;
14467};
14468
14469var some$1 = some_1;
14470
14471var some = some$1;
14472
14473var nativeConstruct = getBuiltIn('Reflect', 'construct'); // `Reflect.construct` method
14474// https://tc39.es/ecma262/#sec-reflect.construct
14475// MS Edge supports only 2 arguments and argumentsList argument is optional
14476// FF Nightly sets third argument as `new.target`, but does not create `this` from it
14477
14478var NEW_TARGET_BUG = fails(function () {
14479 function F() {
14480 /* empty */
14481 }
14482
14483 return !(nativeConstruct(function () {
14484 /* empty */
14485 }, [], F) instanceof F);
14486});
14487var ARGS_BUG = !fails(function () {
14488 nativeConstruct(function () {
14489 /* empty */
14490 });
14491});
14492var FORCED$2 = NEW_TARGET_BUG || ARGS_BUG;
14493_export({
14494 target: 'Reflect',
14495 stat: true,
14496 forced: FORCED$2,
14497 sham: FORCED$2
14498}, {
14499 construct: function construct(Target, args
14500 /* , newTarget */
14501 ) {
14502 aFunction(Target);
14503 anObject(args);
14504 var newTarget = arguments.length < 3 ? Target : aFunction(arguments[2]);
14505 if (ARGS_BUG && !NEW_TARGET_BUG) return nativeConstruct(Target, args, newTarget);
14506
14507 if (Target == newTarget) {
14508 // w/o altered newTarget, optimization for 0-4 arguments
14509 switch (args.length) {
14510 case 0:
14511 return new Target();
14512
14513 case 1:
14514 return new Target(args[0]);
14515
14516 case 2:
14517 return new Target(args[0], args[1]);
14518
14519 case 3:
14520 return new Target(args[0], args[1], args[2]);
14521
14522 case 4:
14523 return new Target(args[0], args[1], args[2], args[3]);
14524 } // w/o altered newTarget, lot of arguments case
14525
14526
14527 var $args = [null];
14528 $args.push.apply($args, args);
14529 return new (functionBind.apply(Target, $args))();
14530 } // with altered newTarget, not support built-in constructors
14531
14532
14533 var proto = newTarget.prototype;
14534 var instance = objectCreate(isObject$1(proto) ? proto : Object.prototype);
14535 var result = Function.apply.call(Target, instance, args);
14536 return isObject$1(result) ? result : instance;
14537 }
14538});
14539
14540var construct$2 = path.Reflect.construct;
14541
14542var construct$1 = construct$2;
14543
14544var construct = construct$1;
14545
14546var assertThisInitialized = createCommonjsModule(function (module) {
14547 function _assertThisInitialized(self) {
14548 if (self === void 0) {
14549 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
14550 }
14551
14552 return self;
14553 }
14554
14555 module.exports = _assertThisInitialized;
14556 module.exports["default"] = module.exports, module.exports.__esModule = true;
14557});
14558var _assertThisInitialized = unwrapExports(assertThisInitialized);
14559
14560var create$1 = create$3;
14561
14562var create = create$1;
14563
14564// https://tc39.es/ecma262/#sec-object.setprototypeof
14565
14566_export({
14567 target: 'Object',
14568 stat: true
14569}, {
14570 setPrototypeOf: objectSetPrototypeOf
14571});
14572
14573var setPrototypeOf$4 = path.Object.setPrototypeOf;
14574
14575var setPrototypeOf$3 = setPrototypeOf$4;
14576
14577var setPrototypeOf$2 = setPrototypeOf$3;
14578
14579var setPrototypeOf$1 = setPrototypeOf$2;
14580
14581var setPrototypeOf = createCommonjsModule(function (module) {
14582 function _setPrototypeOf(o, p) {
14583 module.exports = _setPrototypeOf = setPrototypeOf$1 || function _setPrototypeOf(o, p) {
14584 o.__proto__ = p;
14585 return o;
14586 };
14587
14588 module.exports["default"] = module.exports, module.exports.__esModule = true;
14589 return _setPrototypeOf(o, p);
14590 }
14591
14592 module.exports = _setPrototypeOf;
14593 module.exports["default"] = module.exports, module.exports.__esModule = true;
14594});
14595unwrapExports(setPrototypeOf);
14596
14597var inherits = createCommonjsModule(function (module) {
14598 function _inherits(subClass, superClass) {
14599 if (typeof superClass !== "function" && superClass !== null) {
14600 throw new TypeError("Super expression must either be null or a function");
14601 }
14602
14603 subClass.prototype = create(superClass && superClass.prototype, {
14604 constructor: {
14605 value: subClass,
14606 writable: true,
14607 configurable: true
14608 }
14609 });
14610 if (superClass) setPrototypeOf(subClass, superClass);
14611 }
14612
14613 module.exports = _inherits;
14614 module.exports["default"] = module.exports, module.exports.__esModule = true;
14615});
14616var _inherits = unwrapExports(inherits);
14617
14618var possibleConstructorReturn = createCommonjsModule(function (module) {
14619 var _typeof = _typeof_1["default"];
14620
14621 function _possibleConstructorReturn(self, call) {
14622 if (call && (_typeof(call) === "object" || typeof call === "function")) {
14623 return call;
14624 } else if (call !== void 0) {
14625 throw new TypeError("Derived constructors may only return object or undefined");
14626 }
14627
14628 return assertThisInitialized(self);
14629 }
14630
14631 module.exports = _possibleConstructorReturn;
14632 module.exports["default"] = module.exports, module.exports.__esModule = true;
14633});
14634var _possibleConstructorReturn = unwrapExports(possibleConstructorReturn);
14635
14636var getPrototypeOf$2 = getPrototypeOf$4;
14637
14638var getPrototypeOf$1 = getPrototypeOf$2;
14639
14640var getPrototypeOf = createCommonjsModule(function (module) {
14641 function _getPrototypeOf(o) {
14642 module.exports = _getPrototypeOf = setPrototypeOf$1 ? getPrototypeOf$1 : function _getPrototypeOf(o) {
14643 return o.__proto__ || getPrototypeOf$1(o);
14644 };
14645 module.exports["default"] = module.exports, module.exports.__esModule = true;
14646 return _getPrototypeOf(o);
14647 }
14648
14649 module.exports = _getPrototypeOf;
14650 module.exports["default"] = module.exports, module.exports.__esModule = true;
14651});
14652var _getPrototypeOf = unwrapExports(getPrototypeOf);
14653
14654var runtime_1 = createCommonjsModule(function (module) {
14655 /**
14656 * Copyright (c) 2014-present, Facebook, Inc.
14657 *
14658 * This source code is licensed under the MIT license found in the
14659 * LICENSE file in the root directory of this source tree.
14660 */
14661 var runtime = function (exports) {
14662
14663 var Op = Object.prototype;
14664 var hasOwn = Op.hasOwnProperty;
14665 var undefined$1; // More compressible than void 0.
14666
14667 var $Symbol = typeof Symbol === "function" ? Symbol : {};
14668 var iteratorSymbol = $Symbol.iterator || "@@iterator";
14669 var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
14670 var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
14671
14672 function define(obj, key, value) {
14673 Object.defineProperty(obj, key, {
14674 value: value,
14675 enumerable: true,
14676 configurable: true,
14677 writable: true
14678 });
14679 return obj[key];
14680 }
14681
14682 try {
14683 // IE 8 has a broken Object.defineProperty that only works on DOM objects.
14684 define({}, "");
14685 } catch (err) {
14686 define = function (obj, key, value) {
14687 return obj[key] = value;
14688 };
14689 }
14690
14691 function wrap(innerFn, outerFn, self, tryLocsList) {
14692 // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
14693 var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
14694 var generator = Object.create(protoGenerator.prototype);
14695 var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
14696 // .throw, and .return methods.
14697
14698 generator._invoke = makeInvokeMethod(innerFn, self, context);
14699 return generator;
14700 }
14701
14702 exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
14703 // record like context.tryEntries[i].completion. This interface could
14704 // have been (and was previously) designed to take a closure to be
14705 // invoked without arguments, but in all the cases we care about we
14706 // already have an existing method we want to call, so there's no need
14707 // to create a new function object. We can even get away with assuming
14708 // the method takes exactly one argument, since that happens to be true
14709 // in every case, so we don't have to touch the arguments object. The
14710 // only additional allocation required is the completion record, which
14711 // has a stable shape and so hopefully should be cheap to allocate.
14712
14713 function tryCatch(fn, obj, arg) {
14714 try {
14715 return {
14716 type: "normal",
14717 arg: fn.call(obj, arg)
14718 };
14719 } catch (err) {
14720 return {
14721 type: "throw",
14722 arg: err
14723 };
14724 }
14725 }
14726
14727 var GenStateSuspendedStart = "suspendedStart";
14728 var GenStateSuspendedYield = "suspendedYield";
14729 var GenStateExecuting = "executing";
14730 var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
14731 // breaking out of the dispatch switch statement.
14732
14733 var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
14734 // .constructor.prototype properties for functions that return Generator
14735 // objects. For full spec compliance, you may wish to configure your
14736 // minifier not to mangle the names of these two functions.
14737
14738 function Generator() {}
14739
14740 function GeneratorFunction() {}
14741
14742 function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
14743 // don't natively support it.
14744
14745
14746 var IteratorPrototype = {};
14747
14748 IteratorPrototype[iteratorSymbol] = function () {
14749 return this;
14750 };
14751
14752 var getProto = Object.getPrototypeOf;
14753 var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
14754
14755 if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
14756 // This environment has a native %IteratorPrototype%; use it instead
14757 // of the polyfill.
14758 IteratorPrototype = NativeIteratorPrototype;
14759 }
14760
14761 var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
14762 GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
14763 GeneratorFunctionPrototype.constructor = GeneratorFunction;
14764 GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
14765 // Iterator interface in terms of a single ._invoke method.
14766
14767 function defineIteratorMethods(prototype) {
14768 ["next", "throw", "return"].forEach(function (method) {
14769 define(prototype, method, function (arg) {
14770 return this._invoke(method, arg);
14771 });
14772 });
14773 }
14774
14775 exports.isGeneratorFunction = function (genFun) {
14776 var ctor = typeof genFun === "function" && genFun.constructor;
14777 return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
14778 // do is to check its .name property.
14779 (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
14780 };
14781
14782 exports.mark = function (genFun) {
14783 if (Object.setPrototypeOf) {
14784 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
14785 } else {
14786 genFun.__proto__ = GeneratorFunctionPrototype;
14787 define(genFun, toStringTagSymbol, "GeneratorFunction");
14788 }
14789
14790 genFun.prototype = Object.create(Gp);
14791 return genFun;
14792 }; // Within the body of any async function, `await x` is transformed to
14793 // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
14794 // `hasOwn.call(value, "__await")` to determine if the yielded value is
14795 // meant to be awaited.
14796
14797
14798 exports.awrap = function (arg) {
14799 return {
14800 __await: arg
14801 };
14802 };
14803
14804 function AsyncIterator(generator, PromiseImpl) {
14805 function invoke(method, arg, resolve, reject) {
14806 var record = tryCatch(generator[method], generator, arg);
14807
14808 if (record.type === "throw") {
14809 reject(record.arg);
14810 } else {
14811 var result = record.arg;
14812 var value = result.value;
14813
14814 if (value && typeof value === "object" && hasOwn.call(value, "__await")) {
14815 return PromiseImpl.resolve(value.__await).then(function (value) {
14816 invoke("next", value, resolve, reject);
14817 }, function (err) {
14818 invoke("throw", err, resolve, reject);
14819 });
14820 }
14821
14822 return PromiseImpl.resolve(value).then(function (unwrapped) {
14823 // When a yielded Promise is resolved, its final value becomes
14824 // the .value of the Promise<{value,done}> result for the
14825 // current iteration.
14826 result.value = unwrapped;
14827 resolve(result);
14828 }, function (error) {
14829 // If a rejected Promise was yielded, throw the rejection back
14830 // into the async generator function so it can be handled there.
14831 return invoke("throw", error, resolve, reject);
14832 });
14833 }
14834 }
14835
14836 var previousPromise;
14837
14838 function enqueue(method, arg) {
14839 function callInvokeWithMethodAndArg() {
14840 return new PromiseImpl(function (resolve, reject) {
14841 invoke(method, arg, resolve, reject);
14842 });
14843 }
14844
14845 return previousPromise = // If enqueue has been called before, then we want to wait until
14846 // all previous Promises have been resolved before calling invoke,
14847 // so that results are always delivered in the correct order. If
14848 // enqueue has not been called before, then it is important to
14849 // call invoke immediately, without waiting on a callback to fire,
14850 // so that the async generator function has the opportunity to do
14851 // any necessary setup in a predictable way. This predictability
14852 // is why the Promise constructor synchronously invokes its
14853 // executor callback, and why async functions synchronously
14854 // execute code before the first await. Since we implement simple
14855 // async functions in terms of async generators, it is especially
14856 // important to get this right, even though it requires care.
14857 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
14858 // invocations of the iterator.
14859 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
14860 } // Define the unified helper method that is used to implement .next,
14861 // .throw, and .return (see defineIteratorMethods).
14862
14863
14864 this._invoke = enqueue;
14865 }
14866
14867 defineIteratorMethods(AsyncIterator.prototype);
14868
14869 AsyncIterator.prototype[asyncIteratorSymbol] = function () {
14870 return this;
14871 };
14872
14873 exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
14874 // AsyncIterator objects; they just return a Promise for the value of
14875 // the final result produced by the iterator.
14876
14877 exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
14878 if (PromiseImpl === void 0) PromiseImpl = Promise;
14879 var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
14880 return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
14881 : iter.next().then(function (result) {
14882 return result.done ? result.value : iter.next();
14883 });
14884 };
14885
14886 function makeInvokeMethod(innerFn, self, context) {
14887 var state = GenStateSuspendedStart;
14888 return function invoke(method, arg) {
14889 if (state === GenStateExecuting) {
14890 throw new Error("Generator is already running");
14891 }
14892
14893 if (state === GenStateCompleted) {
14894 if (method === "throw") {
14895 throw arg;
14896 } // Be forgiving, per 25.3.3.3.3 of the spec:
14897 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
14898
14899
14900 return doneResult();
14901 }
14902
14903 context.method = method;
14904 context.arg = arg;
14905
14906 while (true) {
14907 var delegate = context.delegate;
14908
14909 if (delegate) {
14910 var delegateResult = maybeInvokeDelegate(delegate, context);
14911
14912 if (delegateResult) {
14913 if (delegateResult === ContinueSentinel) continue;
14914 return delegateResult;
14915 }
14916 }
14917
14918 if (context.method === "next") {
14919 // Setting context._sent for legacy support of Babel's
14920 // function.sent implementation.
14921 context.sent = context._sent = context.arg;
14922 } else if (context.method === "throw") {
14923 if (state === GenStateSuspendedStart) {
14924 state = GenStateCompleted;
14925 throw context.arg;
14926 }
14927
14928 context.dispatchException(context.arg);
14929 } else if (context.method === "return") {
14930 context.abrupt("return", context.arg);
14931 }
14932
14933 state = GenStateExecuting;
14934 var record = tryCatch(innerFn, self, context);
14935
14936 if (record.type === "normal") {
14937 // If an exception is thrown from innerFn, we leave state ===
14938 // GenStateExecuting and loop back for another invocation.
14939 state = context.done ? GenStateCompleted : GenStateSuspendedYield;
14940
14941 if (record.arg === ContinueSentinel) {
14942 continue;
14943 }
14944
14945 return {
14946 value: record.arg,
14947 done: context.done
14948 };
14949 } else if (record.type === "throw") {
14950 state = GenStateCompleted; // Dispatch the exception by looping back around to the
14951 // context.dispatchException(context.arg) call above.
14952
14953 context.method = "throw";
14954 context.arg = record.arg;
14955 }
14956 }
14957 };
14958 } // Call delegate.iterator[context.method](context.arg) and handle the
14959 // result, either by returning a { value, done } result from the
14960 // delegate iterator, or by modifying context.method and context.arg,
14961 // setting context.delegate to null, and returning the ContinueSentinel.
14962
14963
14964 function maybeInvokeDelegate(delegate, context) {
14965 var method = delegate.iterator[context.method];
14966
14967 if (method === undefined$1) {
14968 // A .throw or .return when the delegate iterator has no .throw
14969 // method always terminates the yield* loop.
14970 context.delegate = null;
14971
14972 if (context.method === "throw") {
14973 // Note: ["return"] must be used for ES3 parsing compatibility.
14974 if (delegate.iterator["return"]) {
14975 // If the delegate iterator has a return method, give it a
14976 // chance to clean up.
14977 context.method = "return";
14978 context.arg = undefined$1;
14979 maybeInvokeDelegate(delegate, context);
14980
14981 if (context.method === "throw") {
14982 // If maybeInvokeDelegate(context) changed context.method from
14983 // "return" to "throw", let that override the TypeError below.
14984 return ContinueSentinel;
14985 }
14986 }
14987
14988 context.method = "throw";
14989 context.arg = new TypeError("The iterator does not provide a 'throw' method");
14990 }
14991
14992 return ContinueSentinel;
14993 }
14994
14995 var record = tryCatch(method, delegate.iterator, context.arg);
14996
14997 if (record.type === "throw") {
14998 context.method = "throw";
14999 context.arg = record.arg;
15000 context.delegate = null;
15001 return ContinueSentinel;
15002 }
15003
15004 var info = record.arg;
15005
15006 if (!info) {
15007 context.method = "throw";
15008 context.arg = new TypeError("iterator result is not an object");
15009 context.delegate = null;
15010 return ContinueSentinel;
15011 }
15012
15013 if (info.done) {
15014 // Assign the result of the finished delegate to the temporary
15015 // variable specified by delegate.resultName (see delegateYield).
15016 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
15017
15018 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
15019 // exception, let the outer generator proceed normally. If
15020 // context.method was "next", forget context.arg since it has been
15021 // "consumed" by the delegate iterator. If context.method was
15022 // "return", allow the original .return call to continue in the
15023 // outer generator.
15024
15025 if (context.method !== "return") {
15026 context.method = "next";
15027 context.arg = undefined$1;
15028 }
15029 } else {
15030 // Re-yield the result returned by the delegate method.
15031 return info;
15032 } // The delegate iterator is finished, so forget it and continue with
15033 // the outer generator.
15034
15035
15036 context.delegate = null;
15037 return ContinueSentinel;
15038 } // Define Generator.prototype.{next,throw,return} in terms of the
15039 // unified ._invoke helper method.
15040
15041
15042 defineIteratorMethods(Gp);
15043 define(Gp, toStringTagSymbol, "Generator"); // A Generator should always return itself as the iterator object when the
15044 // @@iterator function is called on it. Some browsers' implementations of the
15045 // iterator prototype chain incorrectly implement this, causing the Generator
15046 // object to not be returned from this call. This ensures that doesn't happen.
15047 // See https://github.com/facebook/regenerator/issues/274 for more details.
15048
15049 Gp[iteratorSymbol] = function () {
15050 return this;
15051 };
15052
15053 Gp.toString = function () {
15054 return "[object Generator]";
15055 };
15056
15057 function pushTryEntry(locs) {
15058 var entry = {
15059 tryLoc: locs[0]
15060 };
15061
15062 if (1 in locs) {
15063 entry.catchLoc = locs[1];
15064 }
15065
15066 if (2 in locs) {
15067 entry.finallyLoc = locs[2];
15068 entry.afterLoc = locs[3];
15069 }
15070
15071 this.tryEntries.push(entry);
15072 }
15073
15074 function resetTryEntry(entry) {
15075 var record = entry.completion || {};
15076 record.type = "normal";
15077 delete record.arg;
15078 entry.completion = record;
15079 }
15080
15081 function Context(tryLocsList) {
15082 // The root entry object (effectively a try statement without a catch
15083 // or a finally block) gives us a place to store values thrown from
15084 // locations where there is no enclosing try statement.
15085 this.tryEntries = [{
15086 tryLoc: "root"
15087 }];
15088 tryLocsList.forEach(pushTryEntry, this);
15089 this.reset(true);
15090 }
15091
15092 exports.keys = function (object) {
15093 var keys = [];
15094
15095 for (var key in object) {
15096 keys.push(key);
15097 }
15098
15099 keys.reverse(); // Rather than returning an object with a next method, we keep
15100 // things simple and return the next function itself.
15101
15102 return function next() {
15103 while (keys.length) {
15104 var key = keys.pop();
15105
15106 if (key in object) {
15107 next.value = key;
15108 next.done = false;
15109 return next;
15110 }
15111 } // To avoid creating an additional object, we just hang the .value
15112 // and .done properties off the next function object itself. This
15113 // also ensures that the minifier will not anonymize the function.
15114
15115
15116 next.done = true;
15117 return next;
15118 };
15119 };
15120
15121 function values(iterable) {
15122 if (iterable) {
15123 var iteratorMethod = iterable[iteratorSymbol];
15124
15125 if (iteratorMethod) {
15126 return iteratorMethod.call(iterable);
15127 }
15128
15129 if (typeof iterable.next === "function") {
15130 return iterable;
15131 }
15132
15133 if (!isNaN(iterable.length)) {
15134 var i = -1,
15135 next = function next() {
15136 while (++i < iterable.length) {
15137 if (hasOwn.call(iterable, i)) {
15138 next.value = iterable[i];
15139 next.done = false;
15140 return next;
15141 }
15142 }
15143
15144 next.value = undefined$1;
15145 next.done = true;
15146 return next;
15147 };
15148
15149 return next.next = next;
15150 }
15151 } // Return an iterator with no values.
15152
15153
15154 return {
15155 next: doneResult
15156 };
15157 }
15158
15159 exports.values = values;
15160
15161 function doneResult() {
15162 return {
15163 value: undefined$1,
15164 done: true
15165 };
15166 }
15167
15168 Context.prototype = {
15169 constructor: Context,
15170 reset: function (skipTempReset) {
15171 this.prev = 0;
15172 this.next = 0; // Resetting context._sent for legacy support of Babel's
15173 // function.sent implementation.
15174
15175 this.sent = this._sent = undefined$1;
15176 this.done = false;
15177 this.delegate = null;
15178 this.method = "next";
15179 this.arg = undefined$1;
15180 this.tryEntries.forEach(resetTryEntry);
15181
15182 if (!skipTempReset) {
15183 for (var name in this) {
15184 // Not sure about the optimal order of these conditions:
15185 if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
15186 this[name] = undefined$1;
15187 }
15188 }
15189 }
15190 },
15191 stop: function () {
15192 this.done = true;
15193 var rootEntry = this.tryEntries[0];
15194 var rootRecord = rootEntry.completion;
15195
15196 if (rootRecord.type === "throw") {
15197 throw rootRecord.arg;
15198 }
15199
15200 return this.rval;
15201 },
15202 dispatchException: function (exception) {
15203 if (this.done) {
15204 throw exception;
15205 }
15206
15207 var context = this;
15208
15209 function handle(loc, caught) {
15210 record.type = "throw";
15211 record.arg = exception;
15212 context.next = loc;
15213
15214 if (caught) {
15215 // If the dispatched exception was caught by a catch block,
15216 // then let that catch block handle the exception normally.
15217 context.method = "next";
15218 context.arg = undefined$1;
15219 }
15220
15221 return !!caught;
15222 }
15223
15224 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
15225 var entry = this.tryEntries[i];
15226 var record = entry.completion;
15227
15228 if (entry.tryLoc === "root") {
15229 // Exception thrown outside of any try block that could handle
15230 // it, so set the completion value of the entire function to
15231 // throw the exception.
15232 return handle("end");
15233 }
15234
15235 if (entry.tryLoc <= this.prev) {
15236 var hasCatch = hasOwn.call(entry, "catchLoc");
15237 var hasFinally = hasOwn.call(entry, "finallyLoc");
15238
15239 if (hasCatch && hasFinally) {
15240 if (this.prev < entry.catchLoc) {
15241 return handle(entry.catchLoc, true);
15242 } else if (this.prev < entry.finallyLoc) {
15243 return handle(entry.finallyLoc);
15244 }
15245 } else if (hasCatch) {
15246 if (this.prev < entry.catchLoc) {
15247 return handle(entry.catchLoc, true);
15248 }
15249 } else if (hasFinally) {
15250 if (this.prev < entry.finallyLoc) {
15251 return handle(entry.finallyLoc);
15252 }
15253 } else {
15254 throw new Error("try statement without catch or finally");
15255 }
15256 }
15257 }
15258 },
15259 abrupt: function (type, arg) {
15260 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
15261 var entry = this.tryEntries[i];
15262
15263 if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
15264 var finallyEntry = entry;
15265 break;
15266 }
15267 }
15268
15269 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
15270 // Ignore the finally entry if control is not jumping to a
15271 // location outside the try/catch block.
15272 finallyEntry = null;
15273 }
15274
15275 var record = finallyEntry ? finallyEntry.completion : {};
15276 record.type = type;
15277 record.arg = arg;
15278
15279 if (finallyEntry) {
15280 this.method = "next";
15281 this.next = finallyEntry.finallyLoc;
15282 return ContinueSentinel;
15283 }
15284
15285 return this.complete(record);
15286 },
15287 complete: function (record, afterLoc) {
15288 if (record.type === "throw") {
15289 throw record.arg;
15290 }
15291
15292 if (record.type === "break" || record.type === "continue") {
15293 this.next = record.arg;
15294 } else if (record.type === "return") {
15295 this.rval = this.arg = record.arg;
15296 this.method = "return";
15297 this.next = "end";
15298 } else if (record.type === "normal" && afterLoc) {
15299 this.next = afterLoc;
15300 }
15301
15302 return ContinueSentinel;
15303 },
15304 finish: function (finallyLoc) {
15305 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
15306 var entry = this.tryEntries[i];
15307
15308 if (entry.finallyLoc === finallyLoc) {
15309 this.complete(entry.completion, entry.afterLoc);
15310 resetTryEntry(entry);
15311 return ContinueSentinel;
15312 }
15313 }
15314 },
15315 "catch": function (tryLoc) {
15316 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
15317 var entry = this.tryEntries[i];
15318
15319 if (entry.tryLoc === tryLoc) {
15320 var record = entry.completion;
15321
15322 if (record.type === "throw") {
15323 var thrown = record.arg;
15324 resetTryEntry(entry);
15325 }
15326
15327 return thrown;
15328 }
15329 } // The context.catch method must only be called with a location
15330 // argument that corresponds to a known catch block.
15331
15332
15333 throw new Error("illegal catch attempt");
15334 },
15335 delegateYield: function (iterable, resultName, nextLoc) {
15336 this.delegate = {
15337 iterator: values(iterable),
15338 resultName: resultName,
15339 nextLoc: nextLoc
15340 };
15341
15342 if (this.method === "next") {
15343 // Deliberately forget the last sent value so that we don't
15344 // accidentally pass it on to the delegate.
15345 this.arg = undefined$1;
15346 }
15347
15348 return ContinueSentinel;
15349 }
15350 }; // Regardless of whether this script is executing as a CommonJS module
15351 // or not, return the runtime object so that we can declare the variable
15352 // regeneratorRuntime in the outer scope, which allows this module to be
15353 // injected easily by `bin/regenerator --include-runtime script.js`.
15354
15355 return exports;
15356 }( // If this script is executing as a CommonJS module, use module.exports
15357 // as the regeneratorRuntime namespace. Otherwise create a new empty
15358 // object. Either way, the resulting object will be used to initialize
15359 // the regeneratorRuntime variable at the top of this file.
15360 module.exports );
15361
15362 try {
15363 regeneratorRuntime = runtime;
15364 } catch (accidentalStrictMode) {
15365 // This module should not be running in strict mode, so the above
15366 // assignment should always work unless something is misconfigured. Just
15367 // in case runtime.js accidentally runs in strict mode, we can escape
15368 // strict mode using a global Function call. This could conceivably fail
15369 // if a Content Security Policy forbids using Function, but in that case
15370 // the proper solution is to fix the accidental strict mode problem. If
15371 // you've misconfigured your bundler to force strict mode and applied a
15372 // CSP to forbid Function, and you're not willing to fix either of those
15373 // problems, please detail your unique predicament in a GitHub issue.
15374 Function("r", "regeneratorRuntime = r")(runtime);
15375 }
15376});
15377
15378var regenerator = runtime_1;
15379
15380var createMethod = function (IS_RIGHT) {
15381 return function (that, callbackfn, argumentsLength, memo) {
15382 aFunction(callbackfn);
15383 var O = toObject(that);
15384 var self = indexedObject(O);
15385 var length = toLength(O.length);
15386 var index = IS_RIGHT ? length - 1 : 0;
15387 var i = IS_RIGHT ? -1 : 1;
15388 if (argumentsLength < 2) while (true) {
15389 if (index in self) {
15390 memo = self[index];
15391 index += i;
15392 break;
15393 }
15394
15395 index += i;
15396
15397 if (IS_RIGHT ? index < 0 : length <= index) {
15398 throw TypeError('Reduce of empty array with no initial value');
15399 }
15400 }
15401
15402 for (; IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
15403 memo = callbackfn(memo, self[index], index, O);
15404 }
15405
15406 return memo;
15407 };
15408};
15409
15410var arrayReduce = {
15411 // `Array.prototype.reduce` method
15412 // https://tc39.es/ecma262/#sec-array.prototype.reduce
15413 left: createMethod(false),
15414 // `Array.prototype.reduceRight` method
15415 // https://tc39.es/ecma262/#sec-array.prototype.reduceright
15416 right: createMethod(true)
15417};
15418
15419var engineIsNode = classofRaw(global_1.process) == 'process';
15420
15421var $reduce = arrayReduce.left;
15422var STRICT_METHOD$2 = arrayMethodIsStrict('reduce'); // Chrome 80-82 has a critical bug
15423// https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
15424
15425var CHROME_BUG = !engineIsNode && engineV8Version > 79 && engineV8Version < 83; // `Array.prototype.reduce` method
15426// https://tc39.es/ecma262/#sec-array.prototype.reduce
15427
15428_export({
15429 target: 'Array',
15430 proto: true,
15431 forced: !STRICT_METHOD$2 || CHROME_BUG
15432}, {
15433 reduce: function reduce(callbackfn
15434 /* , initialValue */
15435 ) {
15436 return $reduce(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
15437 }
15438});
15439
15440var reduce$2 = entryVirtual('Array').reduce;
15441
15442var ArrayPrototype$6 = Array.prototype;
15443
15444var reduce_1 = function (it) {
15445 var own = it.reduce;
15446 return it === ArrayPrototype$6 || it instanceof Array && own === ArrayPrototype$6.reduce ? reduce$2 : own;
15447};
15448
15449var reduce$1 = reduce_1;
15450
15451var reduce = reduce$1;
15452
15453// https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
15454
15455
15456var flattenIntoArray = function (target, original, source, sourceLen, start, depth, mapper, thisArg) {
15457 var targetIndex = start;
15458 var sourceIndex = 0;
15459 var mapFn = mapper ? functionBindContext(mapper, thisArg, 3) : false;
15460 var element;
15461
15462 while (sourceIndex < sourceLen) {
15463 if (sourceIndex in source) {
15464 element = mapFn ? mapFn(source[sourceIndex], sourceIndex, original) : source[sourceIndex];
15465
15466 if (depth > 0 && isArray$5(element)) {
15467 targetIndex = flattenIntoArray(target, original, element, toLength(element.length), targetIndex, depth - 1) - 1;
15468 } else {
15469 if (targetIndex >= 0x1FFFFFFFFFFFFF) throw TypeError('Exceed the acceptable array length');
15470 target[targetIndex] = element;
15471 }
15472
15473 targetIndex++;
15474 }
15475
15476 sourceIndex++;
15477 }
15478
15479 return targetIndex;
15480};
15481
15482var flattenIntoArray_1 = flattenIntoArray;
15483
15484// https://tc39.es/ecma262/#sec-array.prototype.flatmap
15485
15486
15487_export({
15488 target: 'Array',
15489 proto: true
15490}, {
15491 flatMap: function flatMap(callbackfn
15492 /* , thisArg */
15493 ) {
15494 var O = toObject(this);
15495 var sourceLen = toLength(O.length);
15496 var A;
15497 aFunction(callbackfn);
15498 A = arraySpeciesCreate(O, 0);
15499 A.length = flattenIntoArray_1(A, O, O, sourceLen, 0, 1, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
15500 return A;
15501 }
15502});
15503
15504var flatMap$2 = entryVirtual('Array').flatMap;
15505
15506var ArrayPrototype$5 = Array.prototype;
15507
15508var flatMap_1 = function (it) {
15509 var own = it.flatMap;
15510 return it === ArrayPrototype$5 || it instanceof Array && own === ArrayPrototype$5.flatMap ? flatMap$2 : own;
15511};
15512
15513var flatMap$1 = flatMap_1;
15514
15515var flatMap = flatMap$1;
15516
15517// https://tc39.es/ecma262/#sec-set-objects
15518
15519
15520collection('Set', function (init) {
15521 return function Set() {
15522 return init(this, arguments.length ? arguments[0] : undefined);
15523 };
15524}, collectionStrong);
15525
15526var set$2 = path.Set;
15527
15528var set$1 = set$2;
15529
15530var set = set$1;
15531
15532var iterator = iterator$3;
15533
15534var getIterator$3 = function (it) {
15535 var iteratorMethod = getIteratorMethod$3(it);
15536
15537 if (typeof iteratorMethod != 'function') {
15538 throw TypeError(String(it) + ' is not iterable');
15539 }
15540
15541 return anObject(iteratorMethod.call(it));
15542};
15543
15544var getIterator_1 = getIterator$3;
15545
15546var getIterator$2 = getIterator_1;
15547
15548var getIterator$1 = getIterator$2;
15549
15550var getIterator = getIterator$1;
15551
15552// TODO: use something more complex like timsort?
15553var floor = Math.floor;
15554
15555var mergeSort = function (array, comparefn) {
15556 var length = array.length;
15557 var middle = floor(length / 2);
15558 return length < 8 ? insertionSort(array, comparefn) : merge(mergeSort(array.slice(0, middle), comparefn), mergeSort(array.slice(middle), comparefn), comparefn);
15559};
15560
15561var insertionSort = function (array, comparefn) {
15562 var length = array.length;
15563 var i = 1;
15564 var element, j;
15565
15566 while (i < length) {
15567 j = i;
15568 element = array[i];
15569
15570 while (j && comparefn(array[j - 1], element) > 0) {
15571 array[j] = array[--j];
15572 }
15573
15574 if (j !== i++) array[j] = element;
15575 }
15576
15577 return array;
15578};
15579
15580var merge = function (left, right, comparefn) {
15581 var llength = left.length;
15582 var rlength = right.length;
15583 var lindex = 0;
15584 var rindex = 0;
15585 var result = [];
15586
15587 while (lindex < llength || rindex < rlength) {
15588 if (lindex < llength && rindex < rlength) {
15589 result.push(comparefn(left[lindex], right[rindex]) <= 0 ? left[lindex++] : right[rindex++]);
15590 } else {
15591 result.push(lindex < llength ? left[lindex++] : right[rindex++]);
15592 }
15593 }
15594
15595 return result;
15596};
15597
15598var arraySort = mergeSort;
15599
15600var firefox = engineUserAgent.match(/firefox\/(\d+)/i);
15601var engineFfVersion = !!firefox && +firefox[1];
15602
15603var engineIsIeOrEdge = /MSIE|Trident/.test(engineUserAgent);
15604
15605var webkit = engineUserAgent.match(/AppleWebKit\/(\d+)\./);
15606var engineWebkitVersion = !!webkit && +webkit[1];
15607
15608var test = [];
15609var nativeSort = test.sort; // IE8-
15610
15611var FAILS_ON_UNDEFINED = fails(function () {
15612 test.sort(undefined);
15613}); // V8 bug
15614
15615var FAILS_ON_NULL = fails(function () {
15616 test.sort(null);
15617}); // Old WebKit
15618
15619var STRICT_METHOD$1 = arrayMethodIsStrict('sort');
15620var STABLE_SORT = !fails(function () {
15621 // feature detection can be too slow, so check engines versions
15622 if (engineV8Version) return engineV8Version < 70;
15623 if (engineFfVersion && engineFfVersion > 3) return;
15624 if (engineIsIeOrEdge) return true;
15625 if (engineWebkitVersion) return engineWebkitVersion < 603;
15626 var result = '';
15627 var code, chr, value, index; // generate an array with more 512 elements (Chakra and old V8 fails only in this case)
15628
15629 for (code = 65; code < 76; code++) {
15630 chr = String.fromCharCode(code);
15631
15632 switch (code) {
15633 case 66:
15634 case 69:
15635 case 70:
15636 case 72:
15637 value = 3;
15638 break;
15639
15640 case 68:
15641 case 71:
15642 value = 4;
15643 break;
15644
15645 default:
15646 value = 2;
15647 }
15648
15649 for (index = 0; index < 47; index++) {
15650 test.push({
15651 k: chr + index,
15652 v: value
15653 });
15654 }
15655 }
15656
15657 test.sort(function (a, b) {
15658 return b.v - a.v;
15659 });
15660
15661 for (index = 0; index < test.length; index++) {
15662 chr = test[index].k.charAt(0);
15663 if (result.charAt(result.length - 1) !== chr) result += chr;
15664 }
15665
15666 return result !== 'DGBEFHACIJK';
15667});
15668var FORCED$1 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$1 || !STABLE_SORT;
15669
15670var getSortCompare = function (comparefn) {
15671 return function (x, y) {
15672 if (y === undefined) return -1;
15673 if (x === undefined) return 1;
15674 if (comparefn !== undefined) return +comparefn(x, y) || 0;
15675 return toString_1(x) > toString_1(y) ? 1 : -1;
15676 };
15677}; // `Array.prototype.sort` method
15678// https://tc39.es/ecma262/#sec-array.prototype.sort
15679
15680
15681_export({
15682 target: 'Array',
15683 proto: true,
15684 forced: FORCED$1
15685}, {
15686 sort: function sort(comparefn) {
15687 if (comparefn !== undefined) aFunction(comparefn);
15688 var array = toObject(this);
15689 if (STABLE_SORT) return comparefn === undefined ? nativeSort.call(array) : nativeSort.call(array, comparefn);
15690 var items = [];
15691 var arrayLength = toLength(array.length);
15692 var itemsLength, index;
15693
15694 for (index = 0; index < arrayLength; index++) {
15695 if (index in array) items.push(array[index]);
15696 }
15697
15698 items = arraySort(items, getSortCompare(comparefn));
15699 itemsLength = items.length;
15700 index = 0;
15701
15702 while (index < itemsLength) array[index] = items[index++];
15703
15704 while (index < arrayLength) delete array[index++];
15705
15706 return array;
15707 }
15708});
15709
15710var sort$2 = entryVirtual('Array').sort;
15711
15712var ArrayPrototype$4 = Array.prototype;
15713
15714var sort_1 = function (it) {
15715 var own = it.sort;
15716 return it === ArrayPrototype$4 || it instanceof Array && own === ArrayPrototype$4.sort ? sort$2 : own;
15717};
15718
15719var sort$1 = sort_1;
15720
15721var sort = sort$1;
15722
15723var keys$2 = entryVirtual('Array').keys;
15724
15725var keys$1 = keys$2;
15726
15727var ArrayPrototype$3 = Array.prototype;
15728var DOMIterables$2 = {
15729 DOMTokenList: true,
15730 NodeList: true
15731};
15732
15733var keys_1 = function (it) {
15734 var own = it.keys;
15735 return it === ArrayPrototype$3 || it instanceof Array && own === ArrayPrototype$3.keys // eslint-disable-next-line no-prototype-builtins -- safe
15736 || DOMIterables$2.hasOwnProperty(classof(it)) ? keys$1 : own;
15737};
15738
15739var keys = keys_1;
15740
15741var values$2 = entryVirtual('Array').values;
15742
15743var values$1 = values$2;
15744
15745var ArrayPrototype$2 = Array.prototype;
15746var DOMIterables$1 = {
15747 DOMTokenList: true,
15748 NodeList: true
15749};
15750
15751var values_1 = function (it) {
15752 var own = it.values;
15753 return it === ArrayPrototype$2 || it instanceof Array && own === ArrayPrototype$2.values // eslint-disable-next-line no-prototype-builtins -- safe
15754 || DOMIterables$1.hasOwnProperty(classof(it)) ? values$1 : own;
15755};
15756
15757var values = values_1;
15758
15759var entries$2 = entryVirtual('Array').entries;
15760
15761var entries$1 = entries$2;
15762
15763var ArrayPrototype$1 = Array.prototype;
15764var DOMIterables = {
15765 DOMTokenList: true,
15766 NodeList: true
15767};
15768
15769var entries_1 = function (it) {
15770 var own = it.entries;
15771 return it === ArrayPrototype$1 || it instanceof Array && own === ArrayPrototype$1.entries // eslint-disable-next-line no-prototype-builtins -- safe
15772 || DOMIterables.hasOwnProperty(classof(it)) ? entries$1 : own;
15773};
15774
15775var entries = entries_1;
15776
15777// Unique ID creation requires a high quality random # generator. In the browser we therefore
15778// require the crypto API and do not support built-in fallback to lower quality random number
15779// generators (like Math.random()).
15780var getRandomValues;
15781var rnds8 = new Uint8Array(16);
15782function rng() {
15783 // lazy load so that environments that need to polyfill have a chance to do so
15784 if (!getRandomValues) {
15785 // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also,
15786 // find the complete implementation of crypto (msCrypto) on IE11.
15787 getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);
15788
15789 if (!getRandomValues) {
15790 throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
15791 }
15792 }
15793
15794 return getRandomValues(rnds8);
15795}
15796
15797var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;
15798
15799function validate(uuid) {
15800 return typeof uuid === 'string' && REGEX.test(uuid);
15801}
15802
15803/**
15804 * Convert array of 16 byte values to UUID string format of the form:
15805 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
15806 */
15807
15808var byteToHex = [];
15809
15810for (var i = 0; i < 256; ++i) {
15811 byteToHex.push((i + 0x100).toString(16).substr(1));
15812}
15813
15814function stringify(arr) {
15815 var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; // Note: Be careful editing this code! It's been tuned for performance
15816 // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
15817
15818 var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one
15819 // of the following:
15820 // - One or more input array values don't map to a hex octet (leading to
15821 // "undefined" in the uuid)
15822 // - Invalid input values for the RFC `version` or `variant` fields
15823
15824 if (!validate(uuid)) {
15825 throw TypeError('Stringified UUID is invalid');
15826 }
15827
15828 return uuid;
15829}
15830
15831function v4(options, buf, offset) {
15832 options = options || {};
15833 var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
15834
15835 rnds[6] = rnds[6] & 0x0f | 0x40;
15836 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
15837
15838 if (buf) {
15839 offset = offset || 0;
15840
15841 for (var i = 0; i < 16; ++i) {
15842 buf[offset + i] = rnds[i];
15843 }
15844
15845 return buf;
15846 }
15847
15848 return stringify(rnds);
15849}
15850
15851function ownKeys$4(object, enumerableOnly) { var keys = keys$3(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
15852
15853function _objectSpread$4(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context32; forEach$2(_context32 = ownKeys$4(Object(source), true)).call(_context32, function (key) { _defineProperty(target, key, source[key]); }); } else if (getOwnPropertyDescriptors) { defineProperties(target, getOwnPropertyDescriptors(source)); } else { var _context33; forEach$2(_context33 = ownKeys$4(Object(source))).call(_context33, function (key) { defineProperty$5(target, key, getOwnPropertyDescriptor$2(source, key)); }); } } return target; }
15854
15855function _createSuper$t(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$t(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
15856
15857function _isNativeReflectConstruct$t() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
15858
15859function _createForOfIteratorHelper$7(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (isArray(o) || (it = _unsupportedIterableToArray$7(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
15860
15861function _unsupportedIterableToArray$7(o, minLen) { var _context31; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$7(o, minLen); var n = slice$1(_context31 = Object.prototype.toString.call(o)).call(_context31, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from_1$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$7(o, minLen); }
15862
15863function _arrayLikeToArray$7(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
15864/**
15865 * Create new data pipe.
15866 *
15867 * @param from - The source data set or data view.
15868 *
15869 * @remarks
15870 * Example usage:
15871 * ```typescript
15872 * interface AppItem {
15873 * whoami: string;
15874 * appData: unknown;
15875 * visData: VisItem;
15876 * }
15877 * interface VisItem {
15878 * id: number;
15879 * label: string;
15880 * color: string;
15881 * x: number;
15882 * y: number;
15883 * }
15884 *
15885 * const ds1 = new DataSet<AppItem, "whoami">([], { fieldId: "whoami" });
15886 * const ds2 = new DataSet<VisItem, "id">();
15887 *
15888 * const pipe = createNewDataPipeFrom(ds1)
15889 * .filter((item): boolean => item.enabled === true)
15890 * .map<VisItem, "id">((item): VisItem => item.visData)
15891 * .to(ds2);
15892 *
15893 * pipe.start();
15894 * ```
15895 *
15896 * @returns A factory whose methods can be used to configure the pipe.
15897 */
15898
15899function createNewDataPipeFrom(from) {
15900 return new DataPipeUnderConstruction(from);
15901}
15902/**
15903 * Internal implementation of the pipe. This should be accessible only through
15904 * `createNewDataPipeFrom` from the outside.
15905 *
15906 * @typeParam SI - Source item type.
15907 * @typeParam SP - Source item type's id property name.
15908 * @typeParam TI - Target item type.
15909 * @typeParam TP - Target item type's id property name.
15910 */
15911
15912
15913var SimpleDataPipe = /*#__PURE__*/function () {
15914 /**
15915 * Create a new data pipe.
15916 *
15917 * @param _source - The data set or data view that will be observed.
15918 * @param _transformers - An array of transforming functions to be used to
15919 * filter or transform the items in the pipe.
15920 * @param _target - The data set or data view that will receive the items.
15921 */
15922 function SimpleDataPipe(_source, _transformers, _target) {
15923 var _context, _context2, _context3;
15924
15925 _classCallCheck(this, SimpleDataPipe);
15926
15927 this._source = _source;
15928 this._transformers = _transformers;
15929 this._target = _target;
15930 /**
15931 * Bound listeners for use with `DataInterface['on' | 'off']`.
15932 */
15933
15934 this._listeners = {
15935 add: bind(_context = this._add).call(_context, this),
15936 remove: bind(_context2 = this._remove).call(_context2, this),
15937 update: bind(_context3 = this._update).call(_context3, this)
15938 };
15939 }
15940 /** @inheritDoc */
15941
15942
15943 _createClass(SimpleDataPipe, [{
15944 key: "all",
15945 value: function all() {
15946 this._target.update(this._transformItems(this._source.get()));
15947
15948 return this;
15949 }
15950 /** @inheritDoc */
15951
15952 }, {
15953 key: "start",
15954 value: function start() {
15955 this._source.on("add", this._listeners.add);
15956
15957 this._source.on("remove", this._listeners.remove);
15958
15959 this._source.on("update", this._listeners.update);
15960
15961 return this;
15962 }
15963 /** @inheritDoc */
15964
15965 }, {
15966 key: "stop",
15967 value: function stop() {
15968 this._source.off("add", this._listeners.add);
15969
15970 this._source.off("remove", this._listeners.remove);
15971
15972 this._source.off("update", this._listeners.update);
15973
15974 return this;
15975 }
15976 /**
15977 * Apply the transformers to the items.
15978 *
15979 * @param items - The items to be transformed.
15980 *
15981 * @returns The transformed items.
15982 */
15983
15984 }, {
15985 key: "_transformItems",
15986 value: function _transformItems(items) {
15987 var _context4;
15988
15989 return reduce(_context4 = this._transformers).call(_context4, function (items, transform) {
15990 return transform(items);
15991 }, items);
15992 }
15993 /**
15994 * Handle an add event.
15995 *
15996 * @param _name - Ignored.
15997 * @param payload - The payload containing the ids of the added items.
15998 */
15999
16000 }, {
16001 key: "_add",
16002 value: function _add(_name, payload) {
16003 if (payload == null) {
16004 return;
16005 }
16006
16007 this._target.add(this._transformItems(this._source.get(payload.items)));
16008 }
16009 /**
16010 * Handle an update event.
16011 *
16012 * @param _name - Ignored.
16013 * @param payload - The payload containing the ids of the updated items.
16014 */
16015
16016 }, {
16017 key: "_update",
16018 value: function _update(_name, payload) {
16019 if (payload == null) {
16020 return;
16021 }
16022
16023 this._target.update(this._transformItems(this._source.get(payload.items)));
16024 }
16025 /**
16026 * Handle a remove event.
16027 *
16028 * @param _name - Ignored.
16029 * @param payload - The payload containing the data of the removed items.
16030 */
16031
16032 }, {
16033 key: "_remove",
16034 value: function _remove(_name, payload) {
16035 if (payload == null) {
16036 return;
16037 }
16038
16039 this._target.remove(this._transformItems(payload.oldData));
16040 }
16041 }]);
16042
16043 return SimpleDataPipe;
16044}();
16045/**
16046 * Internal implementation of the pipe factory. This should be accessible
16047 * only through `createNewDataPipeFrom` from the outside.
16048 *
16049 * @typeParam TI - Target item type.
16050 * @typeParam TP - Target item type's id property name.
16051 */
16052
16053
16054var DataPipeUnderConstruction = /*#__PURE__*/function () {
16055 /**
16056 * Create a new data pipe factory. This is an internal constructor that
16057 * should never be called from outside of this file.
16058 *
16059 * @param _source - The source data set or data view for this pipe.
16060 */
16061 function DataPipeUnderConstruction(_source) {
16062 _classCallCheck(this, DataPipeUnderConstruction);
16063
16064 this._source = _source;
16065 /**
16066 * Array transformers used to transform items within the pipe. This is typed
16067 * as any for the sake of simplicity.
16068 */
16069
16070 this._transformers = [];
16071 }
16072 /**
16073 * Filter the items.
16074 *
16075 * @param callback - A filtering function that returns true if given item
16076 * should be piped and false if not.
16077 *
16078 * @returns This factory for further configuration.
16079 */
16080
16081
16082 _createClass(DataPipeUnderConstruction, [{
16083 key: "filter",
16084 value: function filter$1(callback) {
16085 this._transformers.push(function (input) {
16086 return filter(input).call(input, callback);
16087 });
16088
16089 return this;
16090 }
16091 /**
16092 * Map each source item to a new type.
16093 *
16094 * @param callback - A mapping function that takes a source item and returns
16095 * corresponding mapped item.
16096 *
16097 * @typeParam TI - Target item type.
16098 * @typeParam TP - Target item type's id property name.
16099 *
16100 * @returns This factory for further configuration.
16101 */
16102
16103 }, {
16104 key: "map",
16105 value: function map(callback) {
16106 this._transformers.push(function (input) {
16107 return map$3(input).call(input, callback);
16108 });
16109
16110 return this;
16111 }
16112 /**
16113 * Map each source item to zero or more items of a new type.
16114 *
16115 * @param callback - A mapping function that takes a source item and returns
16116 * an array of corresponding mapped items.
16117 *
16118 * @typeParam TI - Target item type.
16119 * @typeParam TP - Target item type's id property name.
16120 *
16121 * @returns This factory for further configuration.
16122 */
16123
16124 }, {
16125 key: "flatMap",
16126 value: function flatMap$1(callback) {
16127 this._transformers.push(function (input) {
16128 return flatMap(input).call(input, callback);
16129 });
16130
16131 return this;
16132 }
16133 /**
16134 * Connect this pipe to given data set.
16135 *
16136 * @param target - The data set that will receive the items from this pipe.
16137 *
16138 * @returns The pipe connected between given data sets and performing
16139 * configured transformation on the processed items.
16140 */
16141
16142 }, {
16143 key: "to",
16144 value: function to(target) {
16145 return new SimpleDataPipe(this._source, this._transformers, target);
16146 }
16147 }]);
16148
16149 return DataPipeUnderConstruction;
16150}();
16151/**
16152 * Determine whether a value can be used as an id.
16153 *
16154 * @param value - Input value of unknown type.
16155 *
16156 * @returns True if the value is valid id, false otherwise.
16157 */
16158
16159
16160function isId(value) {
16161 return typeof value === "string" || typeof value === "number";
16162}
16163/**
16164 * A queue.
16165 *
16166 * @typeParam T - The type of method names to be replaced by queued versions.
16167 */
16168
16169
16170var Queue = /*#__PURE__*/function () {
16171 /**
16172 * Construct a new Queue.
16173 *
16174 * @param options - Queue configuration.
16175 */
16176 function Queue(options) {
16177 _classCallCheck(this, Queue);
16178
16179 this._queue = [];
16180 this._timeout = null;
16181 this._extended = null; // options
16182
16183 this.delay = null;
16184 this.max = Infinity;
16185 this.setOptions(options);
16186 }
16187 /**
16188 * Update the configuration of the queue.
16189 *
16190 * @param options - Queue configuration.
16191 */
16192
16193
16194 _createClass(Queue, [{
16195 key: "setOptions",
16196 value: function setOptions(options) {
16197 if (options && typeof options.delay !== "undefined") {
16198 this.delay = options.delay;
16199 }
16200
16201 if (options && typeof options.max !== "undefined") {
16202 this.max = options.max;
16203 }
16204
16205 this._flushIfNeeded();
16206 }
16207 /**
16208 * Extend an object with queuing functionality.
16209 * The object will be extended with a function flush, and the methods provided in options.replace will be replaced with queued ones.
16210 *
16211 * @param object - The object to be extended.
16212 * @param options - Additional options.
16213 *
16214 * @returns The created queue.
16215 */
16216
16217 }, {
16218 key: "destroy",
16219 value:
16220 /**
16221 * Destroy the queue. The queue will first flush all queued actions, and in case it has extended an object, will restore the original object.
16222 */
16223 function destroy() {
16224 this.flush();
16225
16226 if (this._extended) {
16227 var object = this._extended.object;
16228 var methods = this._extended.methods;
16229
16230 for (var i = 0; i < methods.length; i++) {
16231 var method = methods[i];
16232
16233 if (method.original) {
16234 // @TODO: better solution?
16235 object[method.name] = method.original;
16236 } else {
16237 // @TODO: better solution?
16238 delete object[method.name];
16239 }
16240 }
16241
16242 this._extended = null;
16243 }
16244 }
16245 /**
16246 * Replace a method on an object with a queued version.
16247 *
16248 * @param object - Object having the method.
16249 * @param method - The method name.
16250 */
16251
16252 }, {
16253 key: "replace",
16254 value: function replace(object, method) {
16255 /* eslint-disable-next-line @typescript-eslint/no-this-alias -- Function this is necessary in the function bellow, so class this has to be saved into a variable here. */
16256 var me = this;
16257 var original = object[method];
16258
16259 if (!original) {
16260 throw new Error("Method " + method + " undefined");
16261 }
16262
16263 object[method] = function () {
16264 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
16265 args[_key] = arguments[_key];
16266 }
16267
16268 // add this call to the queue
16269 me.queue({
16270 args: args,
16271 fn: original,
16272 context: this
16273 });
16274 };
16275 }
16276 /**
16277 * Queue a call.
16278 *
16279 * @param entry - The function or entry to be queued.
16280 */
16281
16282 }, {
16283 key: "queue",
16284 value: function queue(entry) {
16285 if (typeof entry === "function") {
16286 this._queue.push({
16287 fn: entry
16288 });
16289 } else {
16290 this._queue.push(entry);
16291 }
16292
16293 this._flushIfNeeded();
16294 }
16295 /**
16296 * Check whether the queue needs to be flushed.
16297 */
16298
16299 }, {
16300 key: "_flushIfNeeded",
16301 value: function _flushIfNeeded() {
16302 var _this = this;
16303
16304 // flush when the maximum is exceeded.
16305 if (this._queue.length > this.max) {
16306 this.flush();
16307 } // flush after a period of inactivity when a delay is configured
16308
16309
16310 if (this._timeout != null) {
16311 clearTimeout(this._timeout);
16312 this._timeout = null;
16313 }
16314
16315 if (this.queue.length > 0 && typeof this.delay === "number") {
16316 this._timeout = setTimeout$1(function () {
16317 _this.flush();
16318 }, this.delay);
16319 }
16320 }
16321 /**
16322 * Flush all queued calls
16323 */
16324
16325 }, {
16326 key: "flush",
16327 value: function flush() {
16328 var _context5, _context6;
16329
16330 forEach$2(_context5 = splice(_context6 = this._queue).call(_context6, 0)).call(_context5, function (entry) {
16331 entry.fn.apply(entry.context || entry.fn, entry.args || []);
16332 });
16333 }
16334 }], [{
16335 key: "extend",
16336 value: function extend(object, options) {
16337 var queue = new Queue(options);
16338
16339 if (object.flush !== undefined) {
16340 throw new Error("Target object already has a property flush");
16341 }
16342
16343 object.flush = function () {
16344 queue.flush();
16345 };
16346
16347 var methods = [{
16348 name: "flush",
16349 original: undefined
16350 }];
16351
16352 if (options && options.replace) {
16353 for (var i = 0; i < options.replace.length; i++) {
16354 var name = options.replace[i];
16355 methods.push({
16356 name: name,
16357 // @TODO: better solution?
16358 original: object[name]
16359 }); // @TODO: better solution?
16360
16361 queue.replace(object, name);
16362 }
16363 }
16364
16365 queue._extended = {
16366 object: object,
16367 methods: methods
16368 };
16369 return queue;
16370 }
16371 }]);
16372
16373 return Queue;
16374}();
16375/**
16376 * [[DataSet]] code that can be reused in [[DataView]] or other similar implementations of [[DataInterface]].
16377 *
16378 * @typeParam Item - Item type that may or may not have an id.
16379 * @typeParam IdProp - Name of the property that contains the id.
16380 */
16381
16382
16383var DataSetPart = /*#__PURE__*/function () {
16384 function DataSetPart() {
16385 _classCallCheck(this, DataSetPart);
16386
16387 this._subscribers = {
16388 "*": [],
16389 add: [],
16390 remove: [],
16391 update: []
16392 };
16393 /**
16394 * @deprecated Use on instead (PS: DataView.subscribe === DataView.on).
16395 */
16396
16397 this.subscribe = DataSetPart.prototype.on;
16398 /**
16399 * @deprecated Use off instead (PS: DataView.unsubscribe === DataView.off).
16400 */
16401
16402 this.unsubscribe = DataSetPart.prototype.off;
16403 }
16404 /**
16405 * Trigger an event
16406 *
16407 * @param event - Event name.
16408 * @param payload - Event payload.
16409 * @param senderId - Id of the sender.
16410 */
16411
16412
16413 _createClass(DataSetPart, [{
16414 key: "_trigger",
16415 value: function _trigger(event, payload, senderId) {
16416 var _context7, _context8;
16417
16418 if (event === "*") {
16419 throw new Error("Cannot trigger event *");
16420 }
16421
16422 forEach$2(_context7 = concat(_context8 = []).call(_context8, _toConsumableArray(this._subscribers[event]), _toConsumableArray(this._subscribers["*"]))).call(_context7, function (subscriber) {
16423 subscriber(event, payload, senderId != null ? senderId : null);
16424 });
16425 }
16426 /**
16427 * Subscribe to an event, add an event listener.
16428 *
16429 * @remarks Non-function callbacks are ignored.
16430 *
16431 * @param event - Event name.
16432 * @param callback - Callback method.
16433 */
16434
16435 }, {
16436 key: "on",
16437 value: function on(event, callback) {
16438 if (typeof callback === "function") {
16439 this._subscribers[event].push(callback);
16440 } // @TODO: Maybe throw for invalid callbacks?
16441
16442 }
16443 /**
16444 * Unsubscribe from an event, remove an event listener.
16445 *
16446 * @remarks If the same callback was subscribed more than once **all** occurences will be removed.
16447 *
16448 * @param event - Event name.
16449 * @param callback - Callback method.
16450 */
16451
16452 }, {
16453 key: "off",
16454 value: function off(event, callback) {
16455 var _context9;
16456
16457 this._subscribers[event] = filter(_context9 = this._subscribers[event]).call(_context9, function (subscriber) {
16458 return subscriber !== callback;
16459 });
16460 }
16461 }]);
16462
16463 return DataSetPart;
16464}();
16465/**
16466 * Data stream
16467 *
16468 * @remarks
16469 * [[DataStream]] offers an always up to date stream of items from a [[DataSet]] or [[DataView]].
16470 * That means that the stream is evaluated at the time of iteration, conversion to another data type or when [[cache]] is called, not when the [[DataStream]] was created.
16471 * Multiple invocations of for example [[toItemArray]] may yield different results (if the data source like for example [[DataSet]] gets modified).
16472 *
16473 * @typeParam Item - The item type this stream is going to work with.
16474 */
16475
16476
16477var DataStream = /*#__PURE__*/function (_Symbol$iterator) {
16478 /**
16479 * Create a new data stream.
16480 *
16481 * @param pairs - The id, item pairs.
16482 */
16483 function DataStream(pairs) {
16484 _classCallCheck(this, DataStream);
16485
16486 this._pairs = pairs;
16487 }
16488 /**
16489 * Return an iterable of key, value pairs for every entry in the stream.
16490 */
16491
16492
16493 _createClass(DataStream, [{
16494 key: _Symbol$iterator,
16495 value:
16496 /*#__PURE__*/
16497 regenerator.mark(function value() {
16498 var _iterator, _step, _step$value, id, item;
16499
16500 return regenerator.wrap(function value$(_context10) {
16501 while (1) {
16502 switch (_context10.prev = _context10.next) {
16503 case 0:
16504 _iterator = _createForOfIteratorHelper$7(this._pairs);
16505 _context10.prev = 1;
16506
16507 _iterator.s();
16508
16509 case 3:
16510 if ((_step = _iterator.n()).done) {
16511 _context10.next = 9;
16512 break;
16513 }
16514
16515 _step$value = _slicedToArray(_step.value, 2), id = _step$value[0], item = _step$value[1];
16516 _context10.next = 7;
16517 return [id, item];
16518
16519 case 7:
16520 _context10.next = 3;
16521 break;
16522
16523 case 9:
16524 _context10.next = 14;
16525 break;
16526
16527 case 11:
16528 _context10.prev = 11;
16529 _context10.t0 = _context10["catch"](1);
16530
16531 _iterator.e(_context10.t0);
16532
16533 case 14:
16534 _context10.prev = 14;
16535
16536 _iterator.f();
16537
16538 return _context10.finish(14);
16539
16540 case 17:
16541 case "end":
16542 return _context10.stop();
16543 }
16544 }
16545 }, value, this, [[1, 11, 14, 17]]);
16546 })
16547 /**
16548 * Return an iterable of key, value pairs for every entry in the stream.
16549 */
16550
16551 }, {
16552 key: "entries",
16553 value:
16554 /*#__PURE__*/
16555 regenerator.mark(function entries() {
16556 var _iterator2, _step2, _step2$value, id, item;
16557
16558 return regenerator.wrap(function entries$(_context11) {
16559 while (1) {
16560 switch (_context11.prev = _context11.next) {
16561 case 0:
16562 _iterator2 = _createForOfIteratorHelper$7(this._pairs);
16563 _context11.prev = 1;
16564
16565 _iterator2.s();
16566
16567 case 3:
16568 if ((_step2 = _iterator2.n()).done) {
16569 _context11.next = 9;
16570 break;
16571 }
16572
16573 _step2$value = _slicedToArray(_step2.value, 2), id = _step2$value[0], item = _step2$value[1];
16574 _context11.next = 7;
16575 return [id, item];
16576
16577 case 7:
16578 _context11.next = 3;
16579 break;
16580
16581 case 9:
16582 _context11.next = 14;
16583 break;
16584
16585 case 11:
16586 _context11.prev = 11;
16587 _context11.t0 = _context11["catch"](1);
16588
16589 _iterator2.e(_context11.t0);
16590
16591 case 14:
16592 _context11.prev = 14;
16593
16594 _iterator2.f();
16595
16596 return _context11.finish(14);
16597
16598 case 17:
16599 case "end":
16600 return _context11.stop();
16601 }
16602 }
16603 }, entries, this, [[1, 11, 14, 17]]);
16604 })
16605 /**
16606 * Return an iterable of keys in the stream.
16607 */
16608
16609 }, {
16610 key: "keys",
16611 value:
16612 /*#__PURE__*/
16613 regenerator.mark(function keys() {
16614 var _iterator3, _step3, _step3$value, id;
16615
16616 return regenerator.wrap(function keys$(_context12) {
16617 while (1) {
16618 switch (_context12.prev = _context12.next) {
16619 case 0:
16620 _iterator3 = _createForOfIteratorHelper$7(this._pairs);
16621 _context12.prev = 1;
16622
16623 _iterator3.s();
16624
16625 case 3:
16626 if ((_step3 = _iterator3.n()).done) {
16627 _context12.next = 9;
16628 break;
16629 }
16630
16631 _step3$value = _slicedToArray(_step3.value, 1), id = _step3$value[0];
16632 _context12.next = 7;
16633 return id;
16634
16635 case 7:
16636 _context12.next = 3;
16637 break;
16638
16639 case 9:
16640 _context12.next = 14;
16641 break;
16642
16643 case 11:
16644 _context12.prev = 11;
16645 _context12.t0 = _context12["catch"](1);
16646
16647 _iterator3.e(_context12.t0);
16648
16649 case 14:
16650 _context12.prev = 14;
16651
16652 _iterator3.f();
16653
16654 return _context12.finish(14);
16655
16656 case 17:
16657 case "end":
16658 return _context12.stop();
16659 }
16660 }
16661 }, keys, this, [[1, 11, 14, 17]]);
16662 })
16663 /**
16664 * Return an iterable of values in the stream.
16665 */
16666
16667 }, {
16668 key: "values",
16669 value:
16670 /*#__PURE__*/
16671 regenerator.mark(function values() {
16672 var _iterator4, _step4, _step4$value, item;
16673
16674 return regenerator.wrap(function values$(_context13) {
16675 while (1) {
16676 switch (_context13.prev = _context13.next) {
16677 case 0:
16678 _iterator4 = _createForOfIteratorHelper$7(this._pairs);
16679 _context13.prev = 1;
16680
16681 _iterator4.s();
16682
16683 case 3:
16684 if ((_step4 = _iterator4.n()).done) {
16685 _context13.next = 9;
16686 break;
16687 }
16688
16689 _step4$value = _slicedToArray(_step4.value, 2), item = _step4$value[1];
16690 _context13.next = 7;
16691 return item;
16692
16693 case 7:
16694 _context13.next = 3;
16695 break;
16696
16697 case 9:
16698 _context13.next = 14;
16699 break;
16700
16701 case 11:
16702 _context13.prev = 11;
16703 _context13.t0 = _context13["catch"](1);
16704
16705 _iterator4.e(_context13.t0);
16706
16707 case 14:
16708 _context13.prev = 14;
16709
16710 _iterator4.f();
16711
16712 return _context13.finish(14);
16713
16714 case 17:
16715 case "end":
16716 return _context13.stop();
16717 }
16718 }
16719 }, values, this, [[1, 11, 14, 17]]);
16720 })
16721 /**
16722 * Return an array containing all the ids in this stream.
16723 *
16724 * @remarks
16725 * The array may contain duplicities.
16726 *
16727 * @returns The array with all ids from this stream.
16728 */
16729
16730 }, {
16731 key: "toIdArray",
16732 value: function toIdArray() {
16733 var _context14;
16734
16735 return map$3(_context14 = _toConsumableArray(this._pairs)).call(_context14, function (pair) {
16736 return pair[0];
16737 });
16738 }
16739 /**
16740 * Return an array containing all the items in this stream.
16741 *
16742 * @remarks
16743 * The array may contain duplicities.
16744 *
16745 * @returns The array with all items from this stream.
16746 */
16747
16748 }, {
16749 key: "toItemArray",
16750 value: function toItemArray() {
16751 var _context15;
16752
16753 return map$3(_context15 = _toConsumableArray(this._pairs)).call(_context15, function (pair) {
16754 return pair[1];
16755 });
16756 }
16757 /**
16758 * Return an array containing all the entries in this stream.
16759 *
16760 * @remarks
16761 * The array may contain duplicities.
16762 *
16763 * @returns The array with all entries from this stream.
16764 */
16765
16766 }, {
16767 key: "toEntryArray",
16768 value: function toEntryArray() {
16769 return _toConsumableArray(this._pairs);
16770 }
16771 /**
16772 * Return an object map containing all the items in this stream accessible by ids.
16773 *
16774 * @remarks
16775 * In case of duplicate ids (coerced to string so `7 == '7'`) the last encoutered appears in the returned object.
16776 *
16777 * @returns The object map of all id → item pairs from this stream.
16778 */
16779
16780 }, {
16781 key: "toObjectMap",
16782 value: function toObjectMap() {
16783 var map = create$2(null);
16784
16785 var _iterator5 = _createForOfIteratorHelper$7(this._pairs),
16786 _step5;
16787
16788 try {
16789 for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
16790 var _step5$value = _slicedToArray(_step5.value, 2),
16791 id = _step5$value[0],
16792 item = _step5$value[1];
16793
16794 map[id] = item;
16795 }
16796 } catch (err) {
16797 _iterator5.e(err);
16798 } finally {
16799 _iterator5.f();
16800 }
16801
16802 return map;
16803 }
16804 /**
16805 * Return a map containing all the items in this stream accessible by ids.
16806 *
16807 * @returns The map of all id → item pairs from this stream.
16808 */
16809
16810 }, {
16811 key: "toMap",
16812 value: function toMap() {
16813 return new map(this._pairs);
16814 }
16815 /**
16816 * Return a set containing all the (unique) ids in this stream.
16817 *
16818 * @returns The set of all ids from this stream.
16819 */
16820
16821 }, {
16822 key: "toIdSet",
16823 value: function toIdSet() {
16824 return new set(this.toIdArray());
16825 }
16826 /**
16827 * Return a set containing all the (unique) items in this stream.
16828 *
16829 * @returns The set of all items from this stream.
16830 */
16831
16832 }, {
16833 key: "toItemSet",
16834 value: function toItemSet() {
16835 return new set(this.toItemArray());
16836 }
16837 /**
16838 * Cache the items from this stream.
16839 *
16840 * @remarks
16841 * This method allows for items to be fetched immediatelly and used (possibly multiple times) later.
16842 * It can also be used to optimize performance as [[DataStream]] would otherwise reevaluate everything upon each iteration.
16843 *
16844 * ## Example
16845 * ```javascript
16846 * const ds = new DataSet([…])
16847 *
16848 * const cachedStream = ds.stream()
16849 * .filter(…)
16850 * .sort(…)
16851 * .map(…)
16852 * .cached(…) // Data are fetched, processed and cached here.
16853 *
16854 * ds.clear()
16855 * chachedStream // Still has all the items.
16856 * ```
16857 *
16858 * @returns A new [[DataStream]] with cached items (detached from the original [[DataSet]]).
16859 */
16860
16861 }, {
16862 key: "cache",
16863 value: function cache() {
16864 return new DataStream(_toConsumableArray(this._pairs));
16865 }
16866 /**
16867 * Get the distinct values of given property.
16868 *
16869 * @param callback - The function that picks and possibly converts the property.
16870 *
16871 * @typeParam T - The type of the distinct value.
16872 *
16873 * @returns A set of all distinct properties.
16874 */
16875
16876 }, {
16877 key: "distinct",
16878 value: function distinct(callback) {
16879 var set$1 = new set();
16880
16881 var _iterator6 = _createForOfIteratorHelper$7(this._pairs),
16882 _step6;
16883
16884 try {
16885 for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
16886 var _step6$value = _slicedToArray(_step6.value, 2),
16887 id = _step6$value[0],
16888 item = _step6$value[1];
16889
16890 set$1.add(callback(item, id));
16891 }
16892 } catch (err) {
16893 _iterator6.e(err);
16894 } finally {
16895 _iterator6.f();
16896 }
16897
16898 return set$1;
16899 }
16900 /**
16901 * Filter the items of the stream.
16902 *
16903 * @param callback - The function that decides whether an item will be included.
16904 *
16905 * @returns A new data stream with the filtered items.
16906 */
16907
16908 }, {
16909 key: "filter",
16910 value: function filter(callback) {
16911 var pairs = this._pairs;
16912 return new DataStream(_defineProperty({}, iterator, /*#__PURE__*/regenerator.mark(function _callee() {
16913 var _iterator7, _step7, _step7$value, id, item;
16914
16915 return regenerator.wrap(function _callee$(_context16) {
16916 while (1) {
16917 switch (_context16.prev = _context16.next) {
16918 case 0:
16919 _iterator7 = _createForOfIteratorHelper$7(pairs);
16920 _context16.prev = 1;
16921
16922 _iterator7.s();
16923
16924 case 3:
16925 if ((_step7 = _iterator7.n()).done) {
16926 _context16.next = 10;
16927 break;
16928 }
16929
16930 _step7$value = _slicedToArray(_step7.value, 2), id = _step7$value[0], item = _step7$value[1];
16931
16932 if (!callback(item, id)) {
16933 _context16.next = 8;
16934 break;
16935 }
16936
16937 _context16.next = 8;
16938 return [id, item];
16939
16940 case 8:
16941 _context16.next = 3;
16942 break;
16943
16944 case 10:
16945 _context16.next = 15;
16946 break;
16947
16948 case 12:
16949 _context16.prev = 12;
16950 _context16.t0 = _context16["catch"](1);
16951
16952 _iterator7.e(_context16.t0);
16953
16954 case 15:
16955 _context16.prev = 15;
16956
16957 _iterator7.f();
16958
16959 return _context16.finish(15);
16960
16961 case 18:
16962 case "end":
16963 return _context16.stop();
16964 }
16965 }
16966 }, _callee, null, [[1, 12, 15, 18]]);
16967 })));
16968 }
16969 /**
16970 * Execute a callback for each item of the stream.
16971 *
16972 * @param callback - The function that will be invoked for each item.
16973 */
16974
16975 }, {
16976 key: "forEach",
16977 value: function forEach(callback) {
16978 var _iterator8 = _createForOfIteratorHelper$7(this._pairs),
16979 _step8;
16980
16981 try {
16982 for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
16983 var _step8$value = _slicedToArray(_step8.value, 2),
16984 id = _step8$value[0],
16985 item = _step8$value[1];
16986
16987 callback(item, id);
16988 }
16989 } catch (err) {
16990 _iterator8.e(err);
16991 } finally {
16992 _iterator8.f();
16993 }
16994 }
16995 /**
16996 * Map the items into a different type.
16997 *
16998 * @param callback - The function that does the conversion.
16999 *
17000 * @typeParam Mapped - The type of the item after mapping.
17001 *
17002 * @returns A new data stream with the mapped items.
17003 */
17004
17005 }, {
17006 key: "map",
17007 value: function map(callback) {
17008 var pairs = this._pairs;
17009 return new DataStream(_defineProperty({}, iterator, /*#__PURE__*/regenerator.mark(function _callee2() {
17010 var _iterator9, _step9, _step9$value, id, item;
17011
17012 return regenerator.wrap(function _callee2$(_context17) {
17013 while (1) {
17014 switch (_context17.prev = _context17.next) {
17015 case 0:
17016 _iterator9 = _createForOfIteratorHelper$7(pairs);
17017 _context17.prev = 1;
17018
17019 _iterator9.s();
17020
17021 case 3:
17022 if ((_step9 = _iterator9.n()).done) {
17023 _context17.next = 9;
17024 break;
17025 }
17026
17027 _step9$value = _slicedToArray(_step9.value, 2), id = _step9$value[0], item = _step9$value[1];
17028 _context17.next = 7;
17029 return [id, callback(item, id)];
17030
17031 case 7:
17032 _context17.next = 3;
17033 break;
17034
17035 case 9:
17036 _context17.next = 14;
17037 break;
17038
17039 case 11:
17040 _context17.prev = 11;
17041 _context17.t0 = _context17["catch"](1);
17042
17043 _iterator9.e(_context17.t0);
17044
17045 case 14:
17046 _context17.prev = 14;
17047
17048 _iterator9.f();
17049
17050 return _context17.finish(14);
17051
17052 case 17:
17053 case "end":
17054 return _context17.stop();
17055 }
17056 }
17057 }, _callee2, null, [[1, 11, 14, 17]]);
17058 })));
17059 }
17060 /**
17061 * Get the item with the maximum value of given property.
17062 *
17063 * @param callback - The function that picks and possibly converts the property.
17064 *
17065 * @returns The item with the maximum if found otherwise null.
17066 */
17067
17068 }, {
17069 key: "max",
17070 value: function max(callback) {
17071 var iter = getIterator(this._pairs);
17072
17073 var curr = iter.next();
17074
17075 if (curr.done) {
17076 return null;
17077 }
17078
17079 var maxItem = curr.value[1];
17080 var maxValue = callback(curr.value[1], curr.value[0]);
17081
17082 while (!(curr = iter.next()).done) {
17083 var _curr$value = _slicedToArray(curr.value, 2),
17084 id = _curr$value[0],
17085 item = _curr$value[1];
17086
17087 var _value = callback(item, id);
17088
17089 if (_value > maxValue) {
17090 maxValue = _value;
17091 maxItem = item;
17092 }
17093 }
17094
17095 return maxItem;
17096 }
17097 /**
17098 * Get the item with the minimum value of given property.
17099 *
17100 * @param callback - The function that picks and possibly converts the property.
17101 *
17102 * @returns The item with the minimum if found otherwise null.
17103 */
17104
17105 }, {
17106 key: "min",
17107 value: function min(callback) {
17108 var iter = getIterator(this._pairs);
17109
17110 var curr = iter.next();
17111
17112 if (curr.done) {
17113 return null;
17114 }
17115
17116 var minItem = curr.value[1];
17117 var minValue = callback(curr.value[1], curr.value[0]);
17118
17119 while (!(curr = iter.next()).done) {
17120 var _curr$value2 = _slicedToArray(curr.value, 2),
17121 id = _curr$value2[0],
17122 item = _curr$value2[1];
17123
17124 var _value2 = callback(item, id);
17125
17126 if (_value2 < minValue) {
17127 minValue = _value2;
17128 minItem = item;
17129 }
17130 }
17131
17132 return minItem;
17133 }
17134 /**
17135 * Reduce the items into a single value.
17136 *
17137 * @param callback - The function that does the reduction.
17138 * @param accumulator - The initial value of the accumulator.
17139 *
17140 * @typeParam T - The type of the accumulated value.
17141 *
17142 * @returns The reduced value.
17143 */
17144
17145 }, {
17146 key: "reduce",
17147 value: function reduce(callback, accumulator) {
17148 var _iterator10 = _createForOfIteratorHelper$7(this._pairs),
17149 _step10;
17150
17151 try {
17152 for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
17153 var _step10$value = _slicedToArray(_step10.value, 2),
17154 id = _step10$value[0],
17155 item = _step10$value[1];
17156
17157 accumulator = callback(accumulator, item, id);
17158 }
17159 } catch (err) {
17160 _iterator10.e(err);
17161 } finally {
17162 _iterator10.f();
17163 }
17164
17165 return accumulator;
17166 }
17167 /**
17168 * Sort the items.
17169 *
17170 * @param callback - Item comparator.
17171 *
17172 * @returns A new stream with sorted items.
17173 */
17174
17175 }, {
17176 key: "sort",
17177 value: function sort$1(callback) {
17178 var _this2 = this;
17179
17180 return new DataStream(_defineProperty({}, iterator, function () {
17181 var _context18;
17182
17183 return getIterator(sort(_context18 = _toConsumableArray(_this2._pairs)).call(_context18, function (_ref, _ref2) {
17184 var _ref3 = _slicedToArray(_ref, 2),
17185 idA = _ref3[0],
17186 itemA = _ref3[1];
17187
17188 var _ref4 = _slicedToArray(_ref2, 2),
17189 idB = _ref4[0],
17190 itemB = _ref4[1];
17191
17192 return callback(itemA, itemB, idA, idB);
17193 }));
17194 }));
17195 }
17196 }]);
17197
17198 return DataStream;
17199}(iterator);
17200/**
17201 * Add an id to given item if it doesn't have one already.
17202 *
17203 * @remarks
17204 * The item will be modified.
17205 *
17206 * @param item - The item that will have an id after a call to this function.
17207 * @param idProp - The key of the id property.
17208 *
17209 * @typeParam Item - Item type that may or may not have an id.
17210 * @typeParam IdProp - Name of the property that contains the id.
17211 *
17212 * @returns true
17213 */
17214
17215
17216function ensureFullItem(item, idProp) {
17217 if (item[idProp] == null) {
17218 // generate an id
17219 item[idProp] = v4();
17220 }
17221
17222 return item;
17223}
17224/**
17225 * # DataSet
17226 *
17227 * Vis.js comes with a flexible DataSet, which can be used to hold and
17228 * manipulate unstructured data and listen for changes in the data. The DataSet
17229 * is key/value based. Data items can be added, updated and removed from the
17230 * DataSet, and one can subscribe to changes in the DataSet. The data in the
17231 * DataSet can be filtered and ordered. Data can be normalized when appending it
17232 * to the DataSet as well.
17233 *
17234 * ## Example
17235 *
17236 * The following example shows how to use a DataSet.
17237 *
17238 * ```javascript
17239 * // create a DataSet
17240 * var options = {};
17241 * var data = new vis.DataSet(options);
17242 *
17243 * // add items
17244 * // note that the data items can contain different properties and data formats
17245 * data.add([
17246 * {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
17247 * {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
17248 * {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
17249 * {id: 4, text: 'item 4'}
17250 * ]);
17251 *
17252 * // subscribe to any change in the DataSet
17253 * data.on('*', function (event, properties, senderId) {
17254 * console.log('event', event, properties);
17255 * });
17256 *
17257 * // update an existing item
17258 * data.update({id: 2, group: 1});
17259 *
17260 * // remove an item
17261 * data.remove(4);
17262 *
17263 * // get all ids
17264 * var ids = data.getIds();
17265 * console.log('ids', ids);
17266 *
17267 * // get a specific item
17268 * var item1 = data.get(1);
17269 * console.log('item1', item1);
17270 *
17271 * // retrieve a filtered subset of the data
17272 * var items = data.get({
17273 * filter: function (item) {
17274 * return item.group == 1;
17275 * }
17276 * });
17277 * console.log('filtered items', items);
17278 * ```
17279 *
17280 * @typeParam Item - Item type that may or may not have an id.
17281 * @typeParam IdProp - Name of the property that contains the id.
17282 */
17283
17284
17285var DataSet = /*#__PURE__*/function (_DataSetPart) {
17286 _inherits(DataSet, _DataSetPart);
17287
17288 var _super = _createSuper$t(DataSet);
17289
17290 /**
17291 * Construct a new DataSet.
17292 *
17293 * @param data - Initial data or options.
17294 * @param options - Options (type error if data is also options).
17295 */
17296 function DataSet(data, options) {
17297 var _this3;
17298
17299 _classCallCheck(this, DataSet);
17300
17301 _this3 = _super.call(this);
17302 _this3._queue = null; // correctly read optional arguments
17303
17304 if (data && !isArray(data)) {
17305 options = data;
17306 data = [];
17307 }
17308
17309 _this3._options = options || {};
17310 _this3._data = new map(); // map with data indexed by id
17311
17312 _this3.length = 0; // number of items in the DataSet
17313
17314 _this3._idProp = _this3._options.fieldId || "id"; // name of the field containing id
17315 // add initial data when provided
17316
17317 if (data && data.length) {
17318 _this3.add(data);
17319 }
17320
17321 _this3.setOptions(options);
17322
17323 return _this3;
17324 }
17325 /** @inheritDoc */
17326
17327
17328 _createClass(DataSet, [{
17329 key: "idProp",
17330 get: function get() {
17331 return this._idProp;
17332 }
17333 /**
17334 * Set new options.
17335 *
17336 * @param options - The new options.
17337 */
17338
17339 }, {
17340 key: "setOptions",
17341 value: function setOptions(options) {
17342 if (options && options.queue !== undefined) {
17343 if (options.queue === false) {
17344 // delete queue if loaded
17345 if (this._queue) {
17346 this._queue.destroy();
17347
17348 this._queue = null;
17349 }
17350 } else {
17351 // create queue and update its options
17352 if (!this._queue) {
17353 this._queue = Queue.extend(this, {
17354 replace: ["add", "update", "remove"]
17355 });
17356 }
17357
17358 if (options.queue && _typeof(options.queue) === "object") {
17359 this._queue.setOptions(options.queue);
17360 }
17361 }
17362 }
17363 }
17364 /**
17365 * Add a data item or an array with items.
17366 *
17367 * After the items are added to the DataSet, the DataSet will trigger an event `add`. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
17368 *
17369 * ## Example
17370 *
17371 * ```javascript
17372 * // create a DataSet
17373 * const data = new vis.DataSet()
17374 *
17375 * // add items
17376 * const ids = data.add([
17377 * { id: 1, text: 'item 1' },
17378 * { id: 2, text: 'item 2' },
17379 * { text: 'item without an id' }
17380 * ])
17381 *
17382 * console.log(ids) // [1, 2, '<UUIDv4>']
17383 * ```
17384 *
17385 * @param data - Items to be added (ids will be generated if missing).
17386 * @param senderId - Sender id.
17387 *
17388 * @returns addedIds - Array with the ids (generated if not present) of the added items.
17389 *
17390 * @throws When an item with the same id as any of the added items already exists.
17391 */
17392
17393 }, {
17394 key: "add",
17395 value: function add(data, senderId) {
17396 var _this4 = this;
17397
17398 var addedIds = [];
17399 var id;
17400
17401 if (isArray(data)) {
17402 // Array
17403 var idsToAdd = map$3(data).call(data, function (d) {
17404 return d[_this4._idProp];
17405 });
17406
17407 if (some(idsToAdd).call(idsToAdd, function (id) {
17408 return _this4._data.has(id);
17409 })) {
17410 throw new Error("A duplicate id was found in the parameter array.");
17411 }
17412
17413 for (var i = 0, len = data.length; i < len; i++) {
17414 id = this._addItem(data[i]);
17415 addedIds.push(id);
17416 }
17417 } else if (data && _typeof(data) === "object") {
17418 // Single item
17419 id = this._addItem(data);
17420 addedIds.push(id);
17421 } else {
17422 throw new Error("Unknown dataType");
17423 }
17424
17425 if (addedIds.length) {
17426 this._trigger("add", {
17427 items: addedIds
17428 }, senderId);
17429 }
17430
17431 return addedIds;
17432 }
17433 /**
17434 * Update existing items. When an item does not exist, it will be created.
17435 *
17436 * @remarks
17437 * The provided properties will be merged in the existing item. When an item does not exist, it will be created.
17438 *
17439 * After the items are updated, the DataSet will trigger an event `add` for the added items, and an event `update`. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
17440 *
17441 * ## Example
17442 *
17443 * ```javascript
17444 * // create a DataSet
17445 * const data = new vis.DataSet([
17446 * { id: 1, text: 'item 1' },
17447 * { id: 2, text: 'item 2' },
17448 * { id: 3, text: 'item 3' }
17449 * ])
17450 *
17451 * // update items
17452 * const ids = data.update([
17453 * { id: 2, text: 'item 2 (updated)' },
17454 * { id: 4, text: 'item 4 (new)' }
17455 * ])
17456 *
17457 * console.log(ids) // [2, 4]
17458 * ```
17459 *
17460 * ## Warning for TypeScript users
17461 * This method may introduce partial items into the data set. Use add or updateOnly instead for better type safety.
17462 *
17463 * @param data - Items to be updated (if the id is already present) or added (if the id is missing).
17464 * @param senderId - Sender id.
17465 *
17466 * @returns updatedIds - The ids of the added (these may be newly generated if there was no id in the item from the data) or updated items.
17467 *
17468 * @throws When the supplied data is neither an item nor an array of items.
17469 */
17470
17471 }, {
17472 key: "update",
17473 value: function update(data, senderId) {
17474 var _this5 = this;
17475
17476 var addedIds = [];
17477 var updatedIds = [];
17478 var oldData = [];
17479 var updatedData = [];
17480 var idProp = this._idProp;
17481
17482 var addOrUpdate = function addOrUpdate(item) {
17483 var origId = item[idProp];
17484
17485 if (origId != null && _this5._data.has(origId)) {
17486 var fullItem = item; // it has an id, therefore it is a fullitem
17487
17488 var oldItem = assign$2({}, _this5._data.get(origId)); // update item
17489
17490
17491 var id = _this5._updateItem(fullItem);
17492
17493 updatedIds.push(id);
17494 updatedData.push(fullItem);
17495 oldData.push(oldItem);
17496 } else {
17497 // add new item
17498 var _id = _this5._addItem(item);
17499
17500 addedIds.push(_id);
17501 }
17502 };
17503
17504 if (isArray(data)) {
17505 // Array
17506 for (var i = 0, len = data.length; i < len; i++) {
17507 if (data[i] && _typeof(data[i]) === "object") {
17508 addOrUpdate(data[i]);
17509 } else {
17510 console.warn("Ignoring input item, which is not an object at index " + i);
17511 }
17512 }
17513 } else if (data && _typeof(data) === "object") {
17514 // Single item
17515 addOrUpdate(data);
17516 } else {
17517 throw new Error("Unknown dataType");
17518 }
17519
17520 if (addedIds.length) {
17521 this._trigger("add", {
17522 items: addedIds
17523 }, senderId);
17524 }
17525
17526 if (updatedIds.length) {
17527 var props = {
17528 items: updatedIds,
17529 oldData: oldData,
17530 data: updatedData
17531 }; // TODO: remove deprecated property 'data' some day
17532 //Object.defineProperty(props, 'data', {
17533 // 'get': (function() {
17534 // console.warn('Property data is deprecated. Use DataSet.get(ids) to retrieve the new data, use the oldData property on this object to get the old data');
17535 // return updatedData;
17536 // }).bind(this)
17537 //});
17538
17539 this._trigger("update", props, senderId);
17540 }
17541
17542 return concat(addedIds).call(addedIds, updatedIds);
17543 }
17544 /**
17545 * Update existing items. When an item does not exist, an error will be thrown.
17546 *
17547 * @remarks
17548 * The provided properties will be deeply merged into the existing item.
17549 * When an item does not exist (id not present in the data set or absent), an error will be thrown and nothing will be changed.
17550 *
17551 * After the items are updated, the DataSet will trigger an event `update`.
17552 * When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
17553 *
17554 * ## Example
17555 *
17556 * ```javascript
17557 * // create a DataSet
17558 * const data = new vis.DataSet([
17559 * { id: 1, text: 'item 1' },
17560 * { id: 2, text: 'item 2' },
17561 * { id: 3, text: 'item 3' },
17562 * ])
17563 *
17564 * // update items
17565 * const ids = data.update([
17566 * { id: 2, text: 'item 2 (updated)' }, // works
17567 * // { id: 4, text: 'item 4 (new)' }, // would throw
17568 * // { text: 'item 4 (new)' }, // would also throw
17569 * ])
17570 *
17571 * console.log(ids) // [2]
17572 * ```
17573 *
17574 * @param data - Updates (the id and optionally other props) to the items in this data set.
17575 * @param senderId - Sender id.
17576 *
17577 * @returns updatedIds - The ids of the updated items.
17578 *
17579 * @throws When the supplied data is neither an item nor an array of items, when the ids are missing.
17580 */
17581
17582 }, {
17583 key: "updateOnly",
17584 value: function updateOnly(data, senderId) {
17585 var _context19,
17586 _this6 = this;
17587
17588 if (!isArray(data)) {
17589 data = [data];
17590 }
17591
17592 var updateEventData = map$3(_context19 = map$3(data).call(data, function (update) {
17593 var oldData = _this6._data.get(update[_this6._idProp]);
17594
17595 if (oldData == null) {
17596 throw new Error("Updating non-existent items is not allowed.");
17597 }
17598
17599 return {
17600 oldData: oldData,
17601 update: update
17602 };
17603 })).call(_context19, function (_ref5) {
17604 var oldData = _ref5.oldData,
17605 update = _ref5.update;
17606 var id = oldData[_this6._idProp];
17607 var updatedData = pureDeepObjectAssign(oldData, update);
17608
17609 _this6._data.set(id, updatedData);
17610
17611 return {
17612 id: id,
17613 oldData: oldData,
17614 updatedData: updatedData
17615 };
17616 });
17617
17618 if (updateEventData.length) {
17619 var props = {
17620 items: map$3(updateEventData).call(updateEventData, function (value) {
17621 return value.id;
17622 }),
17623 oldData: map$3(updateEventData).call(updateEventData, function (value) {
17624 return value.oldData;
17625 }),
17626 data: map$3(updateEventData).call(updateEventData, function (value) {
17627 return value.updatedData;
17628 })
17629 }; // TODO: remove deprecated property 'data' some day
17630 //Object.defineProperty(props, 'data', {
17631 // 'get': (function() {
17632 // console.warn('Property data is deprecated. Use DataSet.get(ids) to retrieve the new data, use the oldData property on this object to get the old data');
17633 // return updatedData;
17634 // }).bind(this)
17635 //});
17636
17637 this._trigger("update", props, senderId);
17638
17639 return props.items;
17640 } else {
17641 return [];
17642 }
17643 }
17644 /** @inheritDoc */
17645
17646 }, {
17647 key: "get",
17648 value: function get(first, second) {
17649 // @TODO: Woudn't it be better to split this into multiple methods?
17650 // parse the arguments
17651 var id = undefined;
17652 var ids = undefined;
17653 var options = undefined;
17654
17655 if (isId(first)) {
17656 // get(id [, options])
17657 id = first;
17658 options = second;
17659 } else if (isArray(first)) {
17660 // get(ids [, options])
17661 ids = first;
17662 options = second;
17663 } else {
17664 // get([, options])
17665 options = first;
17666 } // determine the return type
17667
17668
17669 var returnType = options && options.returnType === "Object" ? "Object" : "Array"; // @TODO: WTF is this? Or am I missing something?
17670 // var returnType
17671 // if (options && options.returnType) {
17672 // var allowedValues = ['Array', 'Object']
17673 // returnType =
17674 // allowedValues.indexOf(options.returnType) == -1
17675 // ? 'Array'
17676 // : options.returnType
17677 // } else {
17678 // returnType = 'Array'
17679 // }
17680 // build options
17681
17682 var filter$1 = options && filter(options);
17683
17684 var items = [];
17685 var item = undefined;
17686 var itemIds = undefined;
17687 var itemId = undefined; // convert items
17688
17689 if (id != null) {
17690 // return a single item
17691 item = this._data.get(id);
17692
17693 if (item && filter$1 && !filter$1(item)) {
17694 item = undefined;
17695 }
17696 } else if (ids != null) {
17697 // return a subset of items
17698 for (var i = 0, len = ids.length; i < len; i++) {
17699 item = this._data.get(ids[i]);
17700
17701 if (item != null && (!filter$1 || filter$1(item))) {
17702 items.push(item);
17703 }
17704 }
17705 } else {
17706 var _context20;
17707
17708 // return all items
17709 itemIds = _toConsumableArray(keys(_context20 = this._data).call(_context20));
17710
17711 for (var _i = 0, _len2 = itemIds.length; _i < _len2; _i++) {
17712 itemId = itemIds[_i];
17713 item = this._data.get(itemId);
17714
17715 if (item != null && (!filter$1 || filter$1(item))) {
17716 items.push(item);
17717 }
17718 }
17719 } // order the results
17720
17721
17722 if (options && options.order && id == undefined) {
17723 this._sort(items, options.order);
17724 } // filter fields of the items
17725
17726
17727 if (options && options.fields) {
17728 var fields = options.fields;
17729
17730 if (id != undefined && item != null) {
17731 item = this._filterFields(item, fields);
17732 } else {
17733 for (var _i2 = 0, _len3 = items.length; _i2 < _len3; _i2++) {
17734 items[_i2] = this._filterFields(items[_i2], fields);
17735 }
17736 }
17737 } // return the results
17738
17739
17740 if (returnType == "Object") {
17741 var result = {};
17742
17743 for (var _i3 = 0, _len4 = items.length; _i3 < _len4; _i3++) {
17744 var resultant = items[_i3]; // @TODO: Shoudn't this be this._fieldId?
17745 // result[resultant.id] = resultant
17746
17747 var _id2 = resultant[this._idProp];
17748 result[_id2] = resultant;
17749 }
17750
17751 return result;
17752 } else {
17753 if (id != null) {
17754 var _item;
17755
17756 // a single item
17757 return (_item = item) !== null && _item !== void 0 ? _item : null;
17758 } else {
17759 // just return our array
17760 return items;
17761 }
17762 }
17763 }
17764 /** @inheritDoc */
17765
17766 }, {
17767 key: "getIds",
17768 value: function getIds(options) {
17769 var data = this._data;
17770
17771 var filter$1 = options && filter(options);
17772
17773 var order = options && options.order;
17774
17775 var itemIds = _toConsumableArray(keys(data).call(data));
17776
17777 var ids = [];
17778
17779 if (filter$1) {
17780 // get filtered items
17781 if (order) {
17782 // create ordered list
17783 var items = [];
17784
17785 for (var i = 0, len = itemIds.length; i < len; i++) {
17786 var id = itemIds[i];
17787
17788 var item = this._data.get(id);
17789
17790 if (item != null && filter$1(item)) {
17791 items.push(item);
17792 }
17793 }
17794
17795 this._sort(items, order);
17796
17797 for (var _i4 = 0, _len5 = items.length; _i4 < _len5; _i4++) {
17798 ids.push(items[_i4][this._idProp]);
17799 }
17800 } else {
17801 // create unordered list
17802 for (var _i5 = 0, _len6 = itemIds.length; _i5 < _len6; _i5++) {
17803 var _id3 = itemIds[_i5];
17804
17805 var _item2 = this._data.get(_id3);
17806
17807 if (_item2 != null && filter$1(_item2)) {
17808 ids.push(_item2[this._idProp]);
17809 }
17810 }
17811 }
17812 } else {
17813 // get all items
17814 if (order) {
17815 // create an ordered list
17816 var _items = [];
17817
17818 for (var _i6 = 0, _len7 = itemIds.length; _i6 < _len7; _i6++) {
17819 var _id4 = itemIds[_i6];
17820
17821 _items.push(data.get(_id4));
17822 }
17823
17824 this._sort(_items, order);
17825
17826 for (var _i7 = 0, _len8 = _items.length; _i7 < _len8; _i7++) {
17827 ids.push(_items[_i7][this._idProp]);
17828 }
17829 } else {
17830 // create unordered list
17831 for (var _i8 = 0, _len9 = itemIds.length; _i8 < _len9; _i8++) {
17832 var _id5 = itemIds[_i8];
17833
17834 var _item3 = data.get(_id5);
17835
17836 if (_item3 != null) {
17837 ids.push(_item3[this._idProp]);
17838 }
17839 }
17840 }
17841 }
17842
17843 return ids;
17844 }
17845 /** @inheritDoc */
17846
17847 }, {
17848 key: "getDataSet",
17849 value: function getDataSet() {
17850 return this;
17851 }
17852 /** @inheritDoc */
17853
17854 }, {
17855 key: "forEach",
17856 value: function forEach(callback, options) {
17857 var filter$1 = options && filter(options);
17858
17859 var data = this._data;
17860
17861 var itemIds = _toConsumableArray(keys(data).call(data));
17862
17863 if (options && options.order) {
17864 // execute forEach on ordered list
17865 var items = this.get(options);
17866
17867 for (var i = 0, len = items.length; i < len; i++) {
17868 var item = items[i];
17869 var id = item[this._idProp];
17870 callback(item, id);
17871 }
17872 } else {
17873 // unordered
17874 for (var _i9 = 0, _len10 = itemIds.length; _i9 < _len10; _i9++) {
17875 var _id6 = itemIds[_i9];
17876
17877 var _item4 = this._data.get(_id6);
17878
17879 if (_item4 != null && (!filter$1 || filter$1(_item4))) {
17880 callback(_item4, _id6);
17881 }
17882 }
17883 }
17884 }
17885 /** @inheritDoc */
17886
17887 }, {
17888 key: "map",
17889 value: function map(callback, options) {
17890 var filter$1 = options && filter(options);
17891
17892 var mappedItems = [];
17893 var data = this._data;
17894
17895 var itemIds = _toConsumableArray(keys(data).call(data)); // convert and filter items
17896
17897
17898 for (var i = 0, len = itemIds.length; i < len; i++) {
17899 var id = itemIds[i];
17900
17901 var item = this._data.get(id);
17902
17903 if (item != null && (!filter$1 || filter$1(item))) {
17904 mappedItems.push(callback(item, id));
17905 }
17906 } // order items
17907
17908
17909 if (options && options.order) {
17910 this._sort(mappedItems, options.order);
17911 }
17912
17913 return mappedItems;
17914 }
17915 /**
17916 * Filter the fields of an item.
17917 *
17918 * @param item - The item whose fields should be filtered.
17919 * @param fields - The names of the fields that will be kept.
17920 *
17921 * @typeParam K - Field name type.
17922 *
17923 * @returns The item without any additional fields.
17924 */
17925
17926 }, {
17927 key: "_filterFields",
17928 value: function _filterFields(item, fields) {
17929 var _context21;
17930
17931 if (!item) {
17932 // item is null
17933 return item;
17934 }
17935
17936 return reduce(_context21 = isArray(fields) ? // Use the supplied array
17937 fields : // Use the keys of the supplied object
17938 keys$3(fields)).call(_context21, function (filteredItem, field) {
17939 filteredItem[field] = item[field];
17940 return filteredItem;
17941 }, {});
17942 }
17943 /**
17944 * Sort the provided array with items.
17945 *
17946 * @param items - Items to be sorted in place.
17947 * @param order - A field name or custom sort function.
17948 *
17949 * @typeParam T - The type of the items in the items array.
17950 */
17951
17952 }, {
17953 key: "_sort",
17954 value: function _sort(items, order) {
17955 if (typeof order === "string") {
17956 // order by provided field name
17957 var name = order; // field name
17958
17959 sort(items).call(items, function (a, b) {
17960 // @TODO: How to treat missing properties?
17961 var av = a[name];
17962 var bv = b[name];
17963 return av > bv ? 1 : av < bv ? -1 : 0;
17964 });
17965 } else if (typeof order === "function") {
17966 // order by sort function
17967 sort(items).call(items, order);
17968 } else {
17969 // TODO: extend order by an Object {field:string, direction:string}
17970 // where direction can be 'asc' or 'desc'
17971 throw new TypeError("Order must be a function or a string");
17972 }
17973 }
17974 /**
17975 * Remove an item or multiple items by “reference” (only the id is used) or by id.
17976 *
17977 * The method ignores removal of non-existing items, and returns an array containing the ids of the items which are actually removed from the DataSet.
17978 *
17979 * After the items are removed, the DataSet will trigger an event `remove` for the removed items. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
17980 *
17981 * ## Example
17982 * ```javascript
17983 * // create a DataSet
17984 * const data = new vis.DataSet([
17985 * { id: 1, text: 'item 1' },
17986 * { id: 2, text: 'item 2' },
17987 * { id: 3, text: 'item 3' }
17988 * ])
17989 *
17990 * // remove items
17991 * const ids = data.remove([2, { id: 3 }, 4])
17992 *
17993 * console.log(ids) // [2, 3]
17994 * ```
17995 *
17996 * @param id - One or more items or ids of items to be removed.
17997 * @param senderId - Sender id.
17998 *
17999 * @returns The ids of the removed items.
18000 */
18001
18002 }, {
18003 key: "remove",
18004 value: function remove(id, senderId) {
18005 var removedIds = [];
18006 var removedItems = []; // force everything to be an array for simplicity
18007
18008 var ids = isArray(id) ? id : [id];
18009
18010 for (var i = 0, len = ids.length; i < len; i++) {
18011 var item = this._remove(ids[i]);
18012
18013 if (item) {
18014 var itemId = item[this._idProp];
18015
18016 if (itemId != null) {
18017 removedIds.push(itemId);
18018 removedItems.push(item);
18019 }
18020 }
18021 }
18022
18023 if (removedIds.length) {
18024 this._trigger("remove", {
18025 items: removedIds,
18026 oldData: removedItems
18027 }, senderId);
18028 }
18029
18030 return removedIds;
18031 }
18032 /**
18033 * Remove an item by its id or reference.
18034 *
18035 * @param id - Id of an item or the item itself.
18036 *
18037 * @returns The removed item if removed, null otherwise.
18038 */
18039
18040 }, {
18041 key: "_remove",
18042 value: function _remove(id) {
18043 // @TODO: It origianlly returned the item although the docs say id.
18044 // The code expects the item, so probably an error in the docs.
18045 var ident; // confirm the id to use based on the args type
18046
18047 if (isId(id)) {
18048 ident = id;
18049 } else if (id && _typeof(id) === "object") {
18050 ident = id[this._idProp]; // look for the identifier field using ._idProp
18051 } // do the removing if the item is found
18052
18053
18054 if (ident != null && this._data.has(ident)) {
18055 var item = this._data.get(ident) || null;
18056
18057 this._data.delete(ident);
18058
18059 --this.length;
18060 return item;
18061 }
18062
18063 return null;
18064 }
18065 /**
18066 * Clear the entire data set.
18067 *
18068 * After the items are removed, the [[DataSet]] will trigger an event `remove` for all removed items. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
18069 *
18070 * @param senderId - Sender id.
18071 *
18072 * @returns removedIds - The ids of all removed items.
18073 */
18074
18075 }, {
18076 key: "clear",
18077 value: function clear(senderId) {
18078 var _context22;
18079
18080 var ids = _toConsumableArray(keys(_context22 = this._data).call(_context22));
18081
18082 var items = [];
18083
18084 for (var i = 0, len = ids.length; i < len; i++) {
18085 items.push(this._data.get(ids[i]));
18086 }
18087
18088 this._data.clear();
18089
18090 this.length = 0;
18091
18092 this._trigger("remove", {
18093 items: ids,
18094 oldData: items
18095 }, senderId);
18096
18097 return ids;
18098 }
18099 /**
18100 * Find the item with maximum value of a specified field.
18101 *
18102 * @param field - Name of the property that should be searched for max value.
18103 *
18104 * @returns Item containing max value, or null if no items.
18105 */
18106
18107 }, {
18108 key: "max",
18109 value: function max(field) {
18110 var _context23;
18111
18112 var max = null;
18113 var maxField = null;
18114
18115 var _iterator11 = _createForOfIteratorHelper$7(values(_context23 = this._data).call(_context23)),
18116 _step11;
18117
18118 try {
18119 for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
18120 var item = _step11.value;
18121 var itemField = item[field];
18122
18123 if (typeof itemField === "number" && (maxField == null || itemField > maxField)) {
18124 max = item;
18125 maxField = itemField;
18126 }
18127 }
18128 } catch (err) {
18129 _iterator11.e(err);
18130 } finally {
18131 _iterator11.f();
18132 }
18133
18134 return max || null;
18135 }
18136 /**
18137 * Find the item with minimum value of a specified field.
18138 *
18139 * @param field - Name of the property that should be searched for min value.
18140 *
18141 * @returns Item containing min value, or null if no items.
18142 */
18143
18144 }, {
18145 key: "min",
18146 value: function min(field) {
18147 var _context24;
18148
18149 var min = null;
18150 var minField = null;
18151
18152 var _iterator12 = _createForOfIteratorHelper$7(values(_context24 = this._data).call(_context24)),
18153 _step12;
18154
18155 try {
18156 for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
18157 var item = _step12.value;
18158 var itemField = item[field];
18159
18160 if (typeof itemField === "number" && (minField == null || itemField < minField)) {
18161 min = item;
18162 minField = itemField;
18163 }
18164 }
18165 } catch (err) {
18166 _iterator12.e(err);
18167 } finally {
18168 _iterator12.f();
18169 }
18170
18171 return min || null;
18172 }
18173 /**
18174 * Find all distinct values of a specified field
18175 *
18176 * @param prop - The property name whose distinct values should be returned.
18177 *
18178 * @returns Unordered array containing all distinct values. Items without specified property are ignored.
18179 */
18180
18181 }, {
18182 key: "distinct",
18183 value: function distinct(prop) {
18184 var data = this._data;
18185
18186 var itemIds = _toConsumableArray(keys(data).call(data));
18187
18188 var values = [];
18189 var count = 0;
18190
18191 for (var i = 0, len = itemIds.length; i < len; i++) {
18192 var id = itemIds[i];
18193 var item = data.get(id);
18194 var _value3 = item[prop];
18195 var exists = false;
18196
18197 for (var j = 0; j < count; j++) {
18198 if (values[j] == _value3) {
18199 exists = true;
18200 break;
18201 }
18202 }
18203
18204 if (!exists && _value3 !== undefined) {
18205 values[count] = _value3;
18206 count++;
18207 }
18208 }
18209
18210 return values;
18211 }
18212 /**
18213 * Add a single item. Will fail when an item with the same id already exists.
18214 *
18215 * @param item - A new item to be added.
18216 *
18217 * @returns Added item's id. An id is generated when it is not present in the item.
18218 */
18219
18220 }, {
18221 key: "_addItem",
18222 value: function _addItem(item) {
18223 var fullItem = ensureFullItem(item, this._idProp);
18224 var id = fullItem[this._idProp]; // check whether this id is already taken
18225
18226 if (this._data.has(id)) {
18227 // item already exists
18228 throw new Error("Cannot add item: item with id " + id + " already exists");
18229 }
18230
18231 this._data.set(id, fullItem);
18232
18233 ++this.length;
18234 return id;
18235 }
18236 /**
18237 * Update a single item: merge with existing item.
18238 * Will fail when the item has no id, or when there does not exist an item with the same id.
18239 *
18240 * @param update - The new item
18241 *
18242 * @returns The id of the updated item.
18243 */
18244
18245 }, {
18246 key: "_updateItem",
18247 value: function _updateItem(update) {
18248 var id = update[this._idProp];
18249
18250 if (id == null) {
18251 throw new Error("Cannot update item: item has no id (item: " + stringify$1(update) + ")");
18252 }
18253
18254 var item = this._data.get(id);
18255
18256 if (!item) {
18257 // item doesn't exist
18258 throw new Error("Cannot update item: no item with id " + id + " found");
18259 }
18260
18261 this._data.set(id, _objectSpread$4(_objectSpread$4({}, item), update));
18262
18263 return id;
18264 }
18265 /** @inheritDoc */
18266
18267 }, {
18268 key: "stream",
18269 value: function stream(ids) {
18270 if (ids) {
18271 var data = this._data;
18272 return new DataStream(_defineProperty({}, iterator, /*#__PURE__*/regenerator.mark(function _callee3() {
18273 var _iterator13, _step13, id, item;
18274
18275 return regenerator.wrap(function _callee3$(_context25) {
18276 while (1) {
18277 switch (_context25.prev = _context25.next) {
18278 case 0:
18279 _iterator13 = _createForOfIteratorHelper$7(ids);
18280 _context25.prev = 1;
18281
18282 _iterator13.s();
18283
18284 case 3:
18285 if ((_step13 = _iterator13.n()).done) {
18286 _context25.next = 11;
18287 break;
18288 }
18289
18290 id = _step13.value;
18291 item = data.get(id);
18292
18293 if (!(item != null)) {
18294 _context25.next = 9;
18295 break;
18296 }
18297
18298 _context25.next = 9;
18299 return [id, item];
18300
18301 case 9:
18302 _context25.next = 3;
18303 break;
18304
18305 case 11:
18306 _context25.next = 16;
18307 break;
18308
18309 case 13:
18310 _context25.prev = 13;
18311 _context25.t0 = _context25["catch"](1);
18312
18313 _iterator13.e(_context25.t0);
18314
18315 case 16:
18316 _context25.prev = 16;
18317
18318 _iterator13.f();
18319
18320 return _context25.finish(16);
18321
18322 case 19:
18323 case "end":
18324 return _context25.stop();
18325 }
18326 }
18327 }, _callee3, null, [[1, 13, 16, 19]]);
18328 })));
18329 } else {
18330 var _context26;
18331
18332 return new DataStream(_defineProperty({}, iterator, bind(_context26 = entries(this._data)).call(_context26, this._data)));
18333 }
18334 }
18335 }]);
18336
18337 return DataSet;
18338}(DataSetPart);
18339/**
18340 * DataView
18341 *
18342 * A DataView offers a filtered and/or formatted view on a DataSet. One can subscribe to changes in a DataView, and easily get filtered or formatted data without having to specify filters and field types all the time.
18343 *
18344 * ## Example
18345 * ```javascript
18346 * // create a DataSet
18347 * var data = new vis.DataSet();
18348 * data.add([
18349 * {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
18350 * {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
18351 * {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
18352 * {id: 4, text: 'item 4'}
18353 * ]);
18354 *
18355 * // create a DataView
18356 * // the view will only contain items having a property group with value 1,
18357 * // and will only output fields id, text, and date.
18358 * var view = new vis.DataView(data, {
18359 * filter: function (item) {
18360 * return (item.group == 1);
18361 * },
18362 * fields: ['id', 'text', 'date']
18363 * });
18364 *
18365 * // subscribe to any change in the DataView
18366 * view.on('*', function (event, properties, senderId) {
18367 * console.log('event', event, properties);
18368 * });
18369 *
18370 * // update an item in the data set
18371 * data.update({id: 2, group: 1});
18372 *
18373 * // get all ids in the view
18374 * var ids = view.getIds();
18375 * console.log('ids', ids); // will output [1, 2]
18376 *
18377 * // get all items in the view
18378 * var items = view.get();
18379 * ```
18380 *
18381 * @typeParam Item - Item type that may or may not have an id.
18382 * @typeParam IdProp - Name of the property that contains the id.
18383 */
18384
18385
18386var DataView = /*#__PURE__*/function (_DataSetPart2) {
18387 _inherits(DataView, _DataSetPart2);
18388
18389 var _super2 = _createSuper$t(DataView);
18390
18391 /**
18392 * Create a DataView.
18393 *
18394 * @param data - The instance containing data (directly or indirectly).
18395 * @param options - Options to configure this data view.
18396 */
18397 function DataView(data, options) {
18398 var _context27;
18399
18400 var _this7;
18401
18402 _classCallCheck(this, DataView);
18403
18404 _this7 = _super2.call(this);
18405 /** @inheritDoc */
18406
18407 _this7.length = 0;
18408 _this7._ids = new set(); // ids of the items currently in memory (just contains a boolean true)
18409
18410 _this7._options = options || {};
18411 _this7._listener = bind(_context27 = _this7._onEvent).call(_context27, _assertThisInitialized(_this7));
18412
18413 _this7.setData(data);
18414
18415 return _this7;
18416 }
18417 /** @inheritDoc */
18418
18419
18420 _createClass(DataView, [{
18421 key: "idProp",
18422 get: function get() {
18423 return this.getDataSet().idProp;
18424 } // TODO: implement a function .config() to dynamically update things like configured filter
18425 // and trigger changes accordingly
18426
18427 /**
18428 * Set a data source for the view.
18429 *
18430 * @param data - The instance containing data (directly or indirectly).
18431 *
18432 * @remarks
18433 * Note that when the data view is bound to a data set it won't be garbage
18434 * collected unless the data set is too. Use `dataView.setData(null)` or
18435 * `dataView.dispose()` to enable garbage collection before you lose the last
18436 * reference.
18437 */
18438
18439 }, {
18440 key: "setData",
18441 value: function setData(data) {
18442 if (this._data) {
18443 // unsubscribe from current dataset
18444 if (this._data.off) {
18445 this._data.off("*", this._listener);
18446 } // trigger a remove of all items in memory
18447
18448
18449 var ids = this._data.getIds({
18450 filter: filter(this._options)
18451 });
18452
18453 var items = this._data.get(ids);
18454
18455 this._ids.clear();
18456
18457 this.length = 0;
18458
18459 this._trigger("remove", {
18460 items: ids,
18461 oldData: items
18462 });
18463 }
18464
18465 if (data != null) {
18466 this._data = data; // trigger an add of all added items
18467
18468 var _ids = this._data.getIds({
18469 filter: filter(this._options)
18470 });
18471
18472 for (var i = 0, len = _ids.length; i < len; i++) {
18473 var id = _ids[i];
18474
18475 this._ids.add(id);
18476 }
18477
18478 this.length = _ids.length;
18479
18480 this._trigger("add", {
18481 items: _ids
18482 });
18483 } else {
18484 this._data = new DataSet();
18485 } // subscribe to new dataset
18486
18487
18488 if (this._data.on) {
18489 this._data.on("*", this._listener);
18490 }
18491 }
18492 /**
18493 * Refresh the DataView.
18494 * Useful when the DataView has a filter function containing a variable parameter.
18495 */
18496
18497 }, {
18498 key: "refresh",
18499 value: function refresh() {
18500 var ids = this._data.getIds({
18501 filter: filter(this._options)
18502 });
18503
18504 var oldIds = _toConsumableArray(this._ids);
18505
18506 var newIds = {};
18507 var addedIds = [];
18508 var removedIds = [];
18509 var removedItems = []; // check for additions
18510
18511 for (var i = 0, len = ids.length; i < len; i++) {
18512 var id = ids[i];
18513 newIds[id] = true;
18514
18515 if (!this._ids.has(id)) {
18516 addedIds.push(id);
18517
18518 this._ids.add(id);
18519 }
18520 } // check for removals
18521
18522
18523 for (var _i10 = 0, _len11 = oldIds.length; _i10 < _len11; _i10++) {
18524 var _id7 = oldIds[_i10];
18525
18526 var item = this._data.get(_id7);
18527
18528 if (item == null) {
18529 // @TODO: Investigate.
18530 // Doesn't happen during tests or examples.
18531 // Is it really impossible or could it eventually happen?
18532 // How to handle it if it does? The types guarantee non-nullable items.
18533 console.error("If you see this, report it please.");
18534 } else if (!newIds[_id7]) {
18535 removedIds.push(_id7);
18536 removedItems.push(item);
18537
18538 this._ids.delete(_id7);
18539 }
18540 }
18541
18542 this.length += addedIds.length - removedIds.length; // trigger events
18543
18544 if (addedIds.length) {
18545 this._trigger("add", {
18546 items: addedIds
18547 });
18548 }
18549
18550 if (removedIds.length) {
18551 this._trigger("remove", {
18552 items: removedIds,
18553 oldData: removedItems
18554 });
18555 }
18556 }
18557 /** @inheritDoc */
18558
18559 }, {
18560 key: "get",
18561 value: function get(first, second) {
18562 if (this._data == null) {
18563 return null;
18564 } // parse the arguments
18565
18566
18567 var ids = null;
18568 var options;
18569
18570 if (isId(first) || isArray(first)) {
18571 ids = first;
18572 options = second;
18573 } else {
18574 options = first;
18575 } // extend the options with the default options and provided options
18576
18577
18578 var viewOptions = assign$2({}, this._options, options); // create a combined filter method when needed
18579
18580
18581 var thisFilter = filter(this._options);
18582
18583 var optionsFilter = options && filter(options);
18584
18585 if (thisFilter && optionsFilter) {
18586 viewOptions.filter = function (item) {
18587 return thisFilter(item) && optionsFilter(item);
18588 };
18589 }
18590
18591 if (ids == null) {
18592 return this._data.get(viewOptions);
18593 } else {
18594 return this._data.get(ids, viewOptions);
18595 }
18596 }
18597 /** @inheritDoc */
18598
18599 }, {
18600 key: "getIds",
18601 value: function getIds(options) {
18602 if (this._data.length) {
18603 var defaultFilter = filter(this._options);
18604
18605 var optionsFilter = options != null ? filter(options) : null;
18606 var filter$1;
18607
18608 if (optionsFilter) {
18609 if (defaultFilter) {
18610 filter$1 = function filter(item) {
18611 return defaultFilter(item) && optionsFilter(item);
18612 };
18613 } else {
18614 filter$1 = optionsFilter;
18615 }
18616 } else {
18617 filter$1 = defaultFilter;
18618 }
18619
18620 return this._data.getIds({
18621 filter: filter$1,
18622 order: options && options.order
18623 });
18624 } else {
18625 return [];
18626 }
18627 }
18628 /** @inheritDoc */
18629
18630 }, {
18631 key: "forEach",
18632 value: function forEach(callback, options) {
18633 if (this._data) {
18634 var _context28;
18635
18636 var defaultFilter = filter(this._options);
18637
18638 var optionsFilter = options && filter(options);
18639
18640 var filter$1;
18641
18642 if (optionsFilter) {
18643 if (defaultFilter) {
18644 filter$1 = function filter(item) {
18645 return defaultFilter(item) && optionsFilter(item);
18646 };
18647 } else {
18648 filter$1 = optionsFilter;
18649 }
18650 } else {
18651 filter$1 = defaultFilter;
18652 }
18653
18654 forEach$2(_context28 = this._data).call(_context28, callback, {
18655 filter: filter$1,
18656 order: options && options.order
18657 });
18658 }
18659 }
18660 /** @inheritDoc */
18661
18662 }, {
18663 key: "map",
18664 value: function map(callback, options) {
18665 if (this._data) {
18666 var _context29;
18667
18668 var defaultFilter = filter(this._options);
18669
18670 var optionsFilter = options && filter(options);
18671
18672 var filter$1;
18673
18674 if (optionsFilter) {
18675 if (defaultFilter) {
18676 filter$1 = function filter(item) {
18677 return defaultFilter(item) && optionsFilter(item);
18678 };
18679 } else {
18680 filter$1 = optionsFilter;
18681 }
18682 } else {
18683 filter$1 = defaultFilter;
18684 }
18685
18686 return map$3(_context29 = this._data).call(_context29, callback, {
18687 filter: filter$1,
18688 order: options && options.order
18689 });
18690 } else {
18691 return [];
18692 }
18693 }
18694 /** @inheritDoc */
18695
18696 }, {
18697 key: "getDataSet",
18698 value: function getDataSet() {
18699 return this._data.getDataSet();
18700 }
18701 /** @inheritDoc */
18702
18703 }, {
18704 key: "stream",
18705 value: function stream(ids) {
18706 var _context30;
18707
18708 return this._data.stream(ids || _defineProperty({}, iterator, bind(_context30 = keys(this._ids)).call(_context30, this._ids)));
18709 }
18710 /**
18711 * Render the instance unusable prior to garbage collection.
18712 *
18713 * @remarks
18714 * The intention of this method is to help discover scenarios where the data
18715 * view is being used when the programmer thinks it has been garbage collected
18716 * already. It's stricter version of `dataView.setData(null)`.
18717 */
18718
18719 }, {
18720 key: "dispose",
18721 value: function dispose() {
18722 var _this$_data;
18723
18724 if ((_this$_data = this._data) !== null && _this$_data !== void 0 && _this$_data.off) {
18725 this._data.off("*", this._listener);
18726 }
18727
18728 var message = "This data view has already been disposed of.";
18729 var replacement = {
18730 get: function get() {
18731 throw new Error(message);
18732 },
18733 set: function set() {
18734 throw new Error(message);
18735 },
18736 configurable: false
18737 };
18738
18739 var _iterator14 = _createForOfIteratorHelper$7(ownKeys$6(DataView.prototype)),
18740 _step14;
18741
18742 try {
18743 for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
18744 var key = _step14.value;
18745
18746 defineProperty$5(this, key, replacement);
18747 }
18748 } catch (err) {
18749 _iterator14.e(err);
18750 } finally {
18751 _iterator14.f();
18752 }
18753 }
18754 /**
18755 * Event listener. Will propagate all events from the connected data set to the subscribers of the DataView, but will filter the items and only trigger when there are changes in the filtered data set.
18756 *
18757 * @param event - The name of the event.
18758 * @param params - Parameters of the event.
18759 * @param senderId - Id supplied by the sender.
18760 */
18761
18762 }, {
18763 key: "_onEvent",
18764 value: function _onEvent(event, params, senderId) {
18765 if (!params || !params.items || !this._data) {
18766 return;
18767 }
18768
18769 var ids = params.items;
18770 var addedIds = [];
18771 var updatedIds = [];
18772 var removedIds = [];
18773 var oldItems = [];
18774 var updatedItems = [];
18775 var removedItems = [];
18776
18777 switch (event) {
18778 case "add":
18779 // filter the ids of the added items
18780 for (var i = 0, len = ids.length; i < len; i++) {
18781 var id = ids[i];
18782 var item = this.get(id);
18783
18784 if (item) {
18785 this._ids.add(id);
18786
18787 addedIds.push(id);
18788 }
18789 }
18790
18791 break;
18792
18793 case "update":
18794 // determine the event from the views viewpoint: an updated
18795 // item can be added, updated, or removed from this view.
18796 for (var _i11 = 0, _len12 = ids.length; _i11 < _len12; _i11++) {
18797 var _id8 = ids[_i11];
18798
18799 var _item5 = this.get(_id8);
18800
18801 if (_item5) {
18802 if (this._ids.has(_id8)) {
18803 updatedIds.push(_id8);
18804 updatedItems.push(params.data[_i11]);
18805 oldItems.push(params.oldData[_i11]);
18806 } else {
18807 this._ids.add(_id8);
18808
18809 addedIds.push(_id8);
18810 }
18811 } else {
18812 if (this._ids.has(_id8)) {
18813 this._ids.delete(_id8);
18814
18815 removedIds.push(_id8);
18816 removedItems.push(params.oldData[_i11]);
18817 }
18818 }
18819 }
18820
18821 break;
18822
18823 case "remove":
18824 // filter the ids of the removed items
18825 for (var _i12 = 0, _len13 = ids.length; _i12 < _len13; _i12++) {
18826 var _id9 = ids[_i12];
18827
18828 if (this._ids.has(_id9)) {
18829 this._ids.delete(_id9);
18830
18831 removedIds.push(_id9);
18832 removedItems.push(params.oldData[_i12]);
18833 }
18834 }
18835
18836 break;
18837 }
18838
18839 this.length += addedIds.length - removedIds.length;
18840
18841 if (addedIds.length) {
18842 this._trigger("add", {
18843 items: addedIds
18844 }, senderId);
18845 }
18846
18847 if (updatedIds.length) {
18848 this._trigger("update", {
18849 items: updatedIds,
18850 oldData: oldItems,
18851 data: updatedItems
18852 }, senderId);
18853 }
18854
18855 if (removedIds.length) {
18856 this._trigger("remove", {
18857 items: removedIds,
18858 oldData: removedItems
18859 }, senderId);
18860 }
18861 }
18862 }]);
18863
18864 return DataView;
18865}(DataSetPart);
18866/**
18867 * Check that given value is compatible with Vis Data Set interface.
18868 *
18869 * @param idProp - The expected property to contain item id.
18870 * @param v - The value to be tested.
18871 *
18872 * @returns True if all expected values and methods match, false otherwise.
18873 */
18874
18875
18876function isDataSetLike(idProp, v) {
18877 return _typeof(v) === "object" && v !== null && idProp === v.idProp && typeof v.add === "function" && typeof v.clear === "function" && typeof v.distinct === "function" && typeof forEach$2(v) === "function" && typeof v.get === "function" && typeof v.getDataSet === "function" && typeof v.getIds === "function" && typeof v.length === "number" && typeof map$3(v) === "function" && typeof v.max === "function" && typeof v.min === "function" && typeof v.off === "function" && typeof v.on === "function" && typeof v.remove === "function" && typeof v.setOptions === "function" && typeof v.stream === "function" && typeof v.update === "function" && typeof v.updateOnly === "function";
18878}
18879/**
18880 * Check that given value is compatible with Vis Data View interface.
18881 *
18882 * @param idProp - The expected property to contain item id.
18883 * @param v - The value to be tested.
18884 *
18885 * @returns True if all expected values and methods match, false otherwise.
18886 */
18887
18888
18889function isDataViewLike(idProp, v) {
18890 return _typeof(v) === "object" && v !== null && idProp === v.idProp && typeof forEach$2(v) === "function" && typeof v.get === "function" && typeof v.getDataSet === "function" && typeof v.getIds === "function" && typeof v.length === "number" && typeof map$3(v) === "function" && typeof v.off === "function" && typeof v.on === "function" && typeof v.stream === "function" && isDataSetLike(idProp, v.getDataSet());
18891}
18892
18893var index = /*#__PURE__*/Object.freeze({
18894 __proto__: null,
18895 DELETE: DELETE,
18896 DataSet: DataSet,
18897 DataStream: DataStream,
18898 DataView: DataView,
18899 Queue: Queue,
18900 createNewDataPipeFrom: createNewDataPipeFrom,
18901 isDataSetLike: isDataSetLike,
18902 isDataViewLike: isDataViewLike
18903});
18904
18905var trim = stringTrim.trim;
18906var $parseFloat = global_1.parseFloat;
18907var FORCED = 1 / $parseFloat(whitespaces + '-0') !== -Infinity; // `parseFloat` method
18908// https://tc39.es/ecma262/#sec-parsefloat-string
18909
18910var numberParseFloat = FORCED ? function parseFloat(string) {
18911 var trimmedString = trim(toString_1(string));
18912 var result = $parseFloat(trimmedString);
18913 return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
18914} : $parseFloat;
18915
18916// https://tc39.es/ecma262/#sec-parsefloat-string
18917
18918_export({
18919 global: true,
18920 forced: parseFloat != numberParseFloat
18921}, {
18922 parseFloat: numberParseFloat
18923});
18924
18925var _parseFloat$2 = path.parseFloat;
18926
18927var _parseFloat$1 = _parseFloat$2;
18928
18929var _parseFloat = _parseFloat$1;
18930
18931var getOwnPropertyNames$3 = objectGetOwnPropertyNamesExternal.f; // eslint-disable-next-line es/no-object-getownpropertynames -- required for testing
18932
18933var FAILS_ON_PRIMITIVES = fails(function () {
18934 return !Object.getOwnPropertyNames(1);
18935}); // `Object.getOwnPropertyNames` method
18936// https://tc39.es/ecma262/#sec-object.getownpropertynames
18937
18938_export({
18939 target: 'Object',
18940 stat: true,
18941 forced: FAILS_ON_PRIMITIVES
18942}, {
18943 getOwnPropertyNames: getOwnPropertyNames$3
18944});
18945
18946var Object$1 = path.Object;
18947
18948var getOwnPropertyNames$2 = function getOwnPropertyNames(it) {
18949 return Object$1.getOwnPropertyNames(it);
18950};
18951
18952var getOwnPropertyNames$1 = getOwnPropertyNames$2;
18953
18954var getOwnPropertyNames = getOwnPropertyNames$1;
18955
18956/**
18957 * Helper functions for components
18958 */
18959
18960/**
18961 * Determine values to use for (sub)options of 'chosen'.
18962 *
18963 * This option is either a boolean or an object whose values should be examined further.
18964 * The relevant structures are:
18965 *
18966 * - chosen: <boolean value>
18967 * - chosen: { subOption: <boolean or function> }
18968 *
18969 * Where subOption is 'node', 'edge' or 'label'.
18970 *
18971 * The intention of this method appears to be to set a specific priority to the options;
18972 * Since most properties are either bridged or merged into the local options objects, there
18973 * is not much point in handling them separately.
18974 * TODO: examine if 'most' in previous sentence can be replaced with 'all'. In that case, we
18975 * should be able to get rid of this method.
18976 *
18977 * @param {string} subOption option within object 'chosen' to consider; either 'node', 'edge' or 'label'
18978 * @param {object} pile array of options objects to consider
18979 *
18980 * @returns {boolean | Function} value for passed subOption of 'chosen' to use
18981 */
18982
18983function choosify(subOption, pile) {
18984 // allowed values for subOption
18985 var allowed = ["node", "edge", "label"];
18986 var value = true;
18987 var chosen = topMost(pile, "chosen");
18988
18989 if (typeof chosen === "boolean") {
18990 value = chosen;
18991 } else if (_typeof(chosen) === "object") {
18992 if (indexOf(allowed).call(allowed, subOption) === -1) {
18993 throw new Error("choosify: subOption '" + subOption + "' should be one of " + "'" + allowed.join("', '") + "'");
18994 }
18995
18996 var chosenEdge = topMost(pile, ["chosen", subOption]);
18997
18998 if (typeof chosenEdge === "boolean" || typeof chosenEdge === "function") {
18999 value = chosenEdge;
19000 }
19001 }
19002
19003 return value;
19004}
19005/**
19006 * Check if the point falls within the given rectangle.
19007 *
19008 * @param {rect} rect
19009 * @param {point} point
19010 * @param {rotationPoint} [rotationPoint] if specified, the rotation that applies to the rectangle.
19011 * @returns {boolean} true if point within rectangle, false otherwise
19012 */
19013
19014function pointInRect(rect, point, rotationPoint) {
19015 if (rect.width <= 0 || rect.height <= 0) {
19016 return false; // early out
19017 }
19018
19019 if (rotationPoint !== undefined) {
19020 // Rotate the point the same amount as the rectangle
19021 var tmp = {
19022 x: point.x - rotationPoint.x,
19023 y: point.y - rotationPoint.y
19024 };
19025
19026 if (rotationPoint.angle !== 0) {
19027 // In order to get the coordinates the same, you need to
19028 // rotate in the reverse direction
19029 var angle = -rotationPoint.angle;
19030 var tmp2 = {
19031 x: Math.cos(angle) * tmp.x - Math.sin(angle) * tmp.y,
19032 y: Math.sin(angle) * tmp.x + Math.cos(angle) * tmp.y
19033 };
19034 point = tmp2;
19035 } else {
19036 point = tmp;
19037 } // Note that if a rotation is specified, the rectangle coordinates
19038 // are **not* the full canvas coordinates. They are relative to the
19039 // rotationPoint. Hence, the point coordinates need not be translated
19040 // back in this case.
19041
19042 }
19043
19044 var right = rect.x + rect.width;
19045 var bottom = rect.y + rect.width;
19046 return rect.left < point.x && right > point.x && rect.top < point.y && bottom > point.y;
19047}
19048/**
19049 * Check if given value is acceptable as a label text.
19050 *
19051 * @param {*} text value to check; can be anything at this point
19052 * @returns {boolean} true if valid label value, false otherwise
19053 */
19054
19055function isValidLabel(text) {
19056 // Note that this is quite strict: types that *might* be converted to string are disallowed
19057 return typeof text === "string" && text !== "";
19058}
19059/**
19060 * Returns x, y of self reference circle based on provided angle
19061 *
19062 * @param {object} ctx
19063 * @param {number} angle
19064 * @param {number} radius
19065 * @param {VisNode} node
19066 *
19067 * @returns {object} x and y coordinates
19068 */
19069
19070function getSelfRefCoordinates(ctx, angle, radius, node) {
19071 var x = node.x;
19072 var y = node.y;
19073
19074 if (typeof node.distanceToBorder === "function") {
19075 //calculating opposite and adjacent
19076 //distaneToBorder becomes Hypotenuse.
19077 //Formulas sin(a) = Opposite / Hypotenuse and cos(a) = Adjacent / Hypotenuse
19078 var toBorderDist = node.distanceToBorder(ctx, angle);
19079 var yFromNodeCenter = Math.sin(angle) * toBorderDist;
19080 var xFromNodeCenter = Math.cos(angle) * toBorderDist; //xFromNodeCenter is basically x and if xFromNodeCenter equals to the distance to border then it means
19081 //that y does not need calculation because it is equal node.height / 2 or node.y
19082 //same thing with yFromNodeCenter and if yFromNodeCenter equals to the distance to border then it means
19083 //that x is equal node.width / 2 or node.x
19084
19085 if (xFromNodeCenter === toBorderDist) {
19086 x += toBorderDist;
19087 y = node.y;
19088 } else if (yFromNodeCenter === toBorderDist) {
19089 x = node.x;
19090 y -= toBorderDist;
19091 } else {
19092 x += xFromNodeCenter;
19093 y -= yFromNodeCenter;
19094 }
19095 } else if (node.shape.width > node.shape.height) {
19096 x = node.x + node.shape.width * 0.5;
19097 y = node.y - radius;
19098 } else {
19099 x = node.x + radius;
19100 y = node.y - node.shape.height * 0.5;
19101 }
19102
19103 return {
19104 x: x,
19105 y: y
19106 };
19107}
19108
19109/**
19110 * Callback to determine text dimensions, using the parent label settings.
19111 *
19112 * @callback MeasureText
19113 * @param {text} text
19114 * @param {text} mod
19115 * @returns {object} { width, values} width in pixels and font attributes
19116 */
19117
19118/**
19119 * Helper class for Label which collects results of splitting labels into lines and blocks.
19120 *
19121 * @private
19122 */
19123var LabelAccumulator = /*#__PURE__*/function () {
19124 /**
19125 * @param {MeasureText} measureText
19126 */
19127 function LabelAccumulator(measureText) {
19128 _classCallCheck(this, LabelAccumulator);
19129
19130 this.measureText = measureText;
19131 this.current = 0;
19132 this.width = 0;
19133 this.height = 0;
19134 this.lines = [];
19135 }
19136 /**
19137 * Append given text to the given line.
19138 *
19139 * @param {number} l index of line to add to
19140 * @param {string} text string to append to line
19141 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
19142 * @private
19143 */
19144
19145
19146 _createClass(LabelAccumulator, [{
19147 key: "_add",
19148 value: function _add(l, text) {
19149 var mod = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "normal";
19150
19151 if (this.lines[l] === undefined) {
19152 this.lines[l] = {
19153 width: 0,
19154 height: 0,
19155 blocks: []
19156 };
19157 } // We still need to set a block for undefined and empty texts, hence return at this point
19158 // This is necessary because we don't know at this point if we're at the
19159 // start of an empty line or not.
19160 // To compensate, empty blocks are removed in `finalize()`.
19161 //
19162 // Empty strings should still have a height
19163
19164
19165 var tmpText = text;
19166 if (text === undefined || text === "") tmpText = " "; // Determine width and get the font properties
19167
19168 var result = this.measureText(tmpText, mod);
19169
19170 var block = assign$2({}, values(result));
19171
19172 block.text = text;
19173 block.width = result.width;
19174 block.mod = mod;
19175
19176 if (text === undefined || text === "") {
19177 block.width = 0;
19178 }
19179
19180 this.lines[l].blocks.push(block); // Update the line width. We need this for determining if a string goes over max width
19181
19182 this.lines[l].width += block.width;
19183 }
19184 /**
19185 * Returns the width in pixels of the current line.
19186 *
19187 * @returns {number}
19188 */
19189
19190 }, {
19191 key: "curWidth",
19192 value: function curWidth() {
19193 var line = this.lines[this.current];
19194 if (line === undefined) return 0;
19195 return line.width;
19196 }
19197 /**
19198 * Add text in block to current line
19199 *
19200 * @param {string} text
19201 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
19202 */
19203
19204 }, {
19205 key: "append",
19206 value: function append(text) {
19207 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "normal";
19208
19209 this._add(this.current, text, mod);
19210 }
19211 /**
19212 * Add text in block to current line and start a new line
19213 *
19214 * @param {string} text
19215 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
19216 */
19217
19218 }, {
19219 key: "newLine",
19220 value: function newLine(text) {
19221 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "normal";
19222
19223 this._add(this.current, text, mod);
19224
19225 this.current++;
19226 }
19227 /**
19228 * Determine and set the heights of all the lines currently contained in this instance
19229 *
19230 * Note that width has already been set.
19231 *
19232 * @private
19233 */
19234
19235 }, {
19236 key: "determineLineHeights",
19237 value: function determineLineHeights() {
19238 for (var k = 0; k < this.lines.length; k++) {
19239 var line = this.lines[k]; // Looking for max height of blocks in line
19240
19241 var height = 0;
19242
19243 if (line.blocks !== undefined) {
19244 // Can happen if text contains e.g. '\n '
19245 for (var l = 0; l < line.blocks.length; l++) {
19246 var block = line.blocks[l];
19247
19248 if (height < block.height) {
19249 height = block.height;
19250 }
19251 }
19252 }
19253
19254 line.height = height;
19255 }
19256 }
19257 /**
19258 * Determine the full size of the label text, as determined by current lines and blocks
19259 *
19260 * @private
19261 */
19262
19263 }, {
19264 key: "determineLabelSize",
19265 value: function determineLabelSize() {
19266 var width = 0;
19267 var height = 0;
19268
19269 for (var k = 0; k < this.lines.length; k++) {
19270 var line = this.lines[k];
19271
19272 if (line.width > width) {
19273 width = line.width;
19274 }
19275
19276 height += line.height;
19277 }
19278
19279 this.width = width;
19280 this.height = height;
19281 }
19282 /**
19283 * Remove all empty blocks and empty lines we don't need
19284 *
19285 * This must be done after the width/height determination,
19286 * so that these are set properly for processing here.
19287 *
19288 * @returns {Array<Line>} Lines with empty blocks (and some empty lines) removed
19289 * @private
19290 */
19291
19292 }, {
19293 key: "removeEmptyBlocks",
19294 value: function removeEmptyBlocks() {
19295 var tmpLines = [];
19296
19297 for (var k = 0; k < this.lines.length; k++) {
19298 var line = this.lines[k]; // Note: an empty line in between text has width zero but is still relevant to layout.
19299 // So we can't use width for testing empty line here
19300
19301 if (line.blocks.length === 0) continue; // Discard final empty line always
19302
19303 if (k === this.lines.length - 1) {
19304 if (line.width === 0) continue;
19305 }
19306
19307 var tmpLine = {};
19308
19309 assign$2(tmpLine, line);
19310
19311 tmpLine.blocks = [];
19312 var firstEmptyBlock = void 0;
19313 var tmpBlocks = [];
19314
19315 for (var l = 0; l < line.blocks.length; l++) {
19316 var block = line.blocks[l];
19317
19318 if (block.width !== 0) {
19319 tmpBlocks.push(block);
19320 } else {
19321 if (firstEmptyBlock === undefined) {
19322 firstEmptyBlock = block;
19323 }
19324 }
19325 } // Ensure that there is *some* text present
19326
19327
19328 if (tmpBlocks.length === 0 && firstEmptyBlock !== undefined) {
19329 tmpBlocks.push(firstEmptyBlock);
19330 }
19331
19332 tmpLine.blocks = tmpBlocks;
19333 tmpLines.push(tmpLine);
19334 }
19335
19336 return tmpLines;
19337 }
19338 /**
19339 * Set the sizes for all lines and the whole thing.
19340 *
19341 * @returns {{width: (number|*), height: (number|*), lines: Array}}
19342 */
19343
19344 }, {
19345 key: "finalize",
19346 value: function finalize() {
19347 //console.log(JSON.stringify(this.lines, null, 2));
19348 this.determineLineHeights();
19349 this.determineLabelSize();
19350 var tmpLines = this.removeEmptyBlocks(); // Return a simple hash object for further processing.
19351
19352 return {
19353 width: this.width,
19354 height: this.height,
19355 lines: tmpLines
19356 };
19357 }
19358 }]);
19359
19360 return LabelAccumulator;
19361}();
19362
19363var tagPattern = {
19364 // HTML
19365 "<b>": /<b>/,
19366 "<i>": /<i>/,
19367 "<code>": /<code>/,
19368 "</b>": /<\/b>/,
19369 "</i>": /<\/i>/,
19370 "</code>": /<\/code>/,
19371 // Markdown
19372 "*": /\*/,
19373 // bold
19374 _: /_/,
19375 // ital
19376 "`": /`/,
19377 // mono
19378 afterBold: /[^*]/,
19379 afterItal: /[^_]/,
19380 afterMono: /[^`]/
19381};
19382/**
19383 * Internal helper class for parsing the markup tags for HTML and Markdown.
19384 *
19385 * NOTE: Sequences of tabs and spaces are reduced to single space.
19386 * Scan usage of `this.spacing` within method
19387 */
19388
19389var MarkupAccumulator = /*#__PURE__*/function () {
19390 /**
19391 * Create an instance
19392 *
19393 * @param {string} text text to parse for markup
19394 */
19395 function MarkupAccumulator(text) {
19396 _classCallCheck(this, MarkupAccumulator);
19397
19398 this.text = text;
19399 this.bold = false;
19400 this.ital = false;
19401 this.mono = false;
19402 this.spacing = false;
19403 this.position = 0;
19404 this.buffer = "";
19405 this.modStack = [];
19406 this.blocks = [];
19407 }
19408 /**
19409 * Return the mod label currently on the top of the stack
19410 *
19411 * @returns {string} label of topmost mod
19412 * @private
19413 */
19414
19415
19416 _createClass(MarkupAccumulator, [{
19417 key: "mod",
19418 value: function mod() {
19419 return this.modStack.length === 0 ? "normal" : this.modStack[0];
19420 }
19421 /**
19422 * Return the mod label currently active
19423 *
19424 * @returns {string} label of active mod
19425 * @private
19426 */
19427
19428 }, {
19429 key: "modName",
19430 value: function modName() {
19431 if (this.modStack.length === 0) return "normal";else if (this.modStack[0] === "mono") return "mono";else {
19432 if (this.bold && this.ital) {
19433 return "boldital";
19434 } else if (this.bold) {
19435 return "bold";
19436 } else if (this.ital) {
19437 return "ital";
19438 }
19439 }
19440 }
19441 /**
19442 * @private
19443 */
19444
19445 }, {
19446 key: "emitBlock",
19447 value: function emitBlock() {
19448 if (this.spacing) {
19449 this.add(" ");
19450 this.spacing = false;
19451 }
19452
19453 if (this.buffer.length > 0) {
19454 this.blocks.push({
19455 text: this.buffer,
19456 mod: this.modName()
19457 });
19458 this.buffer = "";
19459 }
19460 }
19461 /**
19462 * Output text to buffer
19463 *
19464 * @param {string} text text to add
19465 * @private
19466 */
19467
19468 }, {
19469 key: "add",
19470 value: function add(text) {
19471 if (text === " ") {
19472 this.spacing = true;
19473 }
19474
19475 if (this.spacing) {
19476 this.buffer += " ";
19477 this.spacing = false;
19478 }
19479
19480 if (text != " ") {
19481 this.buffer += text;
19482 }
19483 }
19484 /**
19485 * Handle parsing of whitespace
19486 *
19487 * @param {string} ch the character to check
19488 * @returns {boolean} true if the character was processed as whitespace, false otherwise
19489 */
19490
19491 }, {
19492 key: "parseWS",
19493 value: function parseWS(ch) {
19494 if (/[ \t]/.test(ch)) {
19495 if (!this.mono) {
19496 this.spacing = true;
19497 } else {
19498 this.add(ch);
19499 }
19500
19501 return true;
19502 }
19503
19504 return false;
19505 }
19506 /**
19507 * @param {string} tagName label for block type to set
19508 * @private
19509 */
19510
19511 }, {
19512 key: "setTag",
19513 value: function setTag(tagName) {
19514 this.emitBlock();
19515 this[tagName] = true;
19516 this.modStack.unshift(tagName);
19517 }
19518 /**
19519 * @param {string} tagName label for block type to unset
19520 * @private
19521 */
19522
19523 }, {
19524 key: "unsetTag",
19525 value: function unsetTag(tagName) {
19526 this.emitBlock();
19527 this[tagName] = false;
19528 this.modStack.shift();
19529 }
19530 /**
19531 * @param {string} tagName label for block type we are currently processing
19532 * @param {string|RegExp} tag string to match in text
19533 * @returns {boolean} true if the tag was processed, false otherwise
19534 */
19535
19536 }, {
19537 key: "parseStartTag",
19538 value: function parseStartTag(tagName, tag) {
19539 // Note: if 'mono' passed as tagName, there is a double check here. This is OK
19540 if (!this.mono && !this[tagName] && this.match(tag)) {
19541 this.setTag(tagName);
19542 return true;
19543 }
19544
19545 return false;
19546 }
19547 /**
19548 * @param {string|RegExp} tag
19549 * @param {number} [advance=true] if set, advance current position in text
19550 * @returns {boolean} true if match at given position, false otherwise
19551 * @private
19552 */
19553
19554 }, {
19555 key: "match",
19556 value: function match(tag) {
19557 var advance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
19558
19559 var _this$prepareRegExp = this.prepareRegExp(tag),
19560 _this$prepareRegExp2 = _slicedToArray(_this$prepareRegExp, 2),
19561 regExp = _this$prepareRegExp2[0],
19562 length = _this$prepareRegExp2[1];
19563
19564 var matched = regExp.test(this.text.substr(this.position, length));
19565
19566 if (matched && advance) {
19567 this.position += length - 1;
19568 }
19569
19570 return matched;
19571 }
19572 /**
19573 * @param {string} tagName label for block type we are currently processing
19574 * @param {string|RegExp} tag string to match in text
19575 * @param {RegExp} [nextTag] regular expression to match for characters *following* the current tag
19576 * @returns {boolean} true if the tag was processed, false otherwise
19577 */
19578
19579 }, {
19580 key: "parseEndTag",
19581 value: function parseEndTag(tagName, tag, nextTag) {
19582 var checkTag = this.mod() === tagName;
19583
19584 if (tagName === "mono") {
19585 // special handling for 'mono'
19586 checkTag = checkTag && this.mono;
19587 } else {
19588 checkTag = checkTag && !this.mono;
19589 }
19590
19591 if (checkTag && this.match(tag)) {
19592 if (nextTag !== undefined) {
19593 // Purpose of the following match is to prevent a direct unset/set of a given tag
19594 // E.g. '*bold **still bold*' => '*bold still bold*'
19595 if (this.position === this.text.length - 1 || this.match(nextTag, false)) {
19596 this.unsetTag(tagName);
19597 }
19598 } else {
19599 this.unsetTag(tagName);
19600 }
19601
19602 return true;
19603 }
19604
19605 return false;
19606 }
19607 /**
19608 * @param {string|RegExp} tag string to match in text
19609 * @param {value} value string to replace tag with, if found at current position
19610 * @returns {boolean} true if the tag was processed, false otherwise
19611 */
19612
19613 }, {
19614 key: "replace",
19615 value: function replace(tag, value) {
19616 if (this.match(tag)) {
19617 this.add(value);
19618 this.position += length - 1;
19619 return true;
19620 }
19621
19622 return false;
19623 }
19624 /**
19625 * Create a regular expression for the tag if it isn't already one.
19626 *
19627 * The return value is an array `[RegExp, number]`, with exactly two value, where:
19628 * - RegExp is the regular expression to use
19629 * - number is the lenth of the input string to match
19630 *
19631 * @param {string|RegExp} tag string to match in text
19632 * @returns {Array} regular expression to use and length of input string to match
19633 * @private
19634 */
19635
19636 }, {
19637 key: "prepareRegExp",
19638 value: function prepareRegExp(tag) {
19639 var length;
19640 var regExp;
19641
19642 if (tag instanceof RegExp) {
19643 regExp = tag;
19644 length = 1; // ASSUMPTION: regexp only tests one character
19645 } else {
19646 // use prepared regexp if present
19647 var prepared = tagPattern[tag];
19648
19649 if (prepared !== undefined) {
19650 regExp = prepared;
19651 } else {
19652 regExp = new RegExp(tag);
19653 }
19654
19655 length = tag.length;
19656 }
19657
19658 return [regExp, length];
19659 }
19660 }]);
19661
19662 return MarkupAccumulator;
19663}();
19664/**
19665 * Helper class for Label which explodes the label text into lines and blocks within lines
19666 *
19667 * @private
19668 */
19669
19670
19671var LabelSplitter = /*#__PURE__*/function () {
19672 /**
19673 * @param {CanvasRenderingContext2D} ctx Canvas rendering context
19674 * @param {Label} parent reference to the Label instance using current instance
19675 * @param {boolean} selected
19676 * @param {boolean} hover
19677 */
19678 function LabelSplitter(ctx, parent, selected, hover) {
19679 var _this = this;
19680
19681 _classCallCheck(this, LabelSplitter);
19682
19683 this.ctx = ctx;
19684 this.parent = parent;
19685 this.selected = selected;
19686 this.hover = hover;
19687 /**
19688 * Callback to determine text width; passed to LabelAccumulator instance
19689 *
19690 * @param {string} text string to determine width of
19691 * @param {string} mod font type to use for this text
19692 * @returns {object} { width, values} width in pixels and font attributes
19693 */
19694
19695 var textWidth = function textWidth(text, mod) {
19696 if (text === undefined) return 0; // TODO: This can be done more efficiently with caching
19697 // This will set the ctx.font correctly, depending on selected/hover and mod - so that ctx.measureText() will be accurate.
19698
19699 var values = _this.parent.getFormattingValues(ctx, selected, hover, mod);
19700
19701 var width = 0;
19702
19703 if (text !== "") {
19704 var measure = _this.ctx.measureText(text);
19705
19706 width = measure.width;
19707 }
19708
19709 return {
19710 width: width,
19711 values: values
19712 };
19713 };
19714
19715 this.lines = new LabelAccumulator(textWidth);
19716 }
19717 /**
19718 * Split passed text of a label into lines and blocks.
19719 *
19720 * # NOTE
19721 *
19722 * The handling of spacing is option dependent:
19723 *
19724 * - if `font.multi : false`, all spaces are retained
19725 * - if `font.multi : true`, every sequence of spaces is compressed to a single space
19726 *
19727 * This might not be the best way to do it, but this is as it has been working till now.
19728 * In order not to break existing functionality, for the time being this behaviour will
19729 * be retained in any code changes.
19730 *
19731 * @param {string} text text to split
19732 * @returns {Array<line>}
19733 */
19734
19735
19736 _createClass(LabelSplitter, [{
19737 key: "process",
19738 value: function process(text) {
19739 if (!isValidLabel(text)) {
19740 return this.lines.finalize();
19741 }
19742
19743 var font = this.parent.fontOptions; // Normalize the end-of-line's to a single representation - order important
19744
19745 text = text.replace(/\r\n/g, "\n"); // Dos EOL's
19746
19747 text = text.replace(/\r/g, "\n"); // Mac EOL's
19748 // Note that at this point, there can be no \r's in the text.
19749 // This is used later on splitStringIntoLines() to split multifont texts.
19750
19751 var nlLines = String(text).split("\n");
19752 var lineCount = nlLines.length;
19753
19754 if (font.multi) {
19755 // Multi-font case: styling tags active
19756 for (var i = 0; i < lineCount; i++) {
19757 var blocks = this.splitBlocks(nlLines[i], font.multi); // Post: Sequences of tabs and spaces are reduced to single space
19758
19759 if (blocks === undefined) continue;
19760
19761 if (blocks.length === 0) {
19762 this.lines.newLine("");
19763 continue;
19764 }
19765
19766 if (font.maxWdt > 0) {
19767 // widthConstraint.maximum defined
19768 //console.log('Running widthConstraint multi, max: ' + this.fontOptions.maxWdt);
19769 for (var j = 0; j < blocks.length; j++) {
19770 var mod = blocks[j].mod;
19771 var _text = blocks[j].text;
19772 this.splitStringIntoLines(_text, mod, true);
19773 }
19774 } else {
19775 // widthConstraint.maximum NOT defined
19776 for (var _j = 0; _j < blocks.length; _j++) {
19777 var _mod = blocks[_j].mod;
19778 var _text2 = blocks[_j].text;
19779 this.lines.append(_text2, _mod);
19780 }
19781 }
19782
19783 this.lines.newLine();
19784 }
19785 } else {
19786 // Single-font case
19787 if (font.maxWdt > 0) {
19788 // widthConstraint.maximum defined
19789 // console.log('Running widthConstraint normal, max: ' + this.fontOptions.maxWdt);
19790 for (var _i = 0; _i < lineCount; _i++) {
19791 this.splitStringIntoLines(nlLines[_i]);
19792 }
19793 } else {
19794 // widthConstraint.maximum NOT defined
19795 for (var _i2 = 0; _i2 < lineCount; _i2++) {
19796 this.lines.newLine(nlLines[_i2]);
19797 }
19798 }
19799 }
19800
19801 return this.lines.finalize();
19802 }
19803 /**
19804 * normalize the markup system
19805 *
19806 * @param {boolean|'md'|'markdown'|'html'} markupSystem
19807 * @returns {string}
19808 */
19809
19810 }, {
19811 key: "decodeMarkupSystem",
19812 value: function decodeMarkupSystem(markupSystem) {
19813 var system = "none";
19814
19815 if (markupSystem === "markdown" || markupSystem === "md") {
19816 system = "markdown";
19817 } else if (markupSystem === true || markupSystem === "html") {
19818 system = "html";
19819 }
19820
19821 return system;
19822 }
19823 /**
19824 *
19825 * @param {string} text
19826 * @returns {Array}
19827 */
19828
19829 }, {
19830 key: "splitHtmlBlocks",
19831 value: function splitHtmlBlocks(text) {
19832 var s = new MarkupAccumulator(text);
19833
19834 var parseEntities = function parseEntities(ch) {
19835 if (/&/.test(ch)) {
19836 var parsed = s.replace(s.text, "&lt;", "<") || s.replace(s.text, "&amp;", "&");
19837
19838 if (!parsed) {
19839 s.add("&");
19840 }
19841
19842 return true;
19843 }
19844
19845 return false;
19846 };
19847
19848 while (s.position < s.text.length) {
19849 var ch = s.text.charAt(s.position);
19850 var parsed = s.parseWS(ch) || /</.test(ch) && (s.parseStartTag("bold", "<b>") || s.parseStartTag("ital", "<i>") || s.parseStartTag("mono", "<code>") || s.parseEndTag("bold", "</b>") || s.parseEndTag("ital", "</i>") || s.parseEndTag("mono", "</code>")) || parseEntities(ch);
19851
19852 if (!parsed) {
19853 s.add(ch);
19854 }
19855
19856 s.position++;
19857 }
19858
19859 s.emitBlock();
19860 return s.blocks;
19861 }
19862 /**
19863 *
19864 * @param {string} text
19865 * @returns {Array}
19866 */
19867
19868 }, {
19869 key: "splitMarkdownBlocks",
19870 value: function splitMarkdownBlocks(text) {
19871 var _this2 = this;
19872
19873 var s = new MarkupAccumulator(text);
19874 var beginable = true;
19875
19876 var parseOverride = function parseOverride(ch) {
19877 if (/\\/.test(ch)) {
19878 if (s.position < _this2.text.length + 1) {
19879 s.position++;
19880 ch = _this2.text.charAt(s.position);
19881
19882 if (/ \t/.test(ch)) {
19883 s.spacing = true;
19884 } else {
19885 s.add(ch);
19886 beginable = false;
19887 }
19888 }
19889
19890 return true;
19891 }
19892
19893 return false;
19894 };
19895
19896 while (s.position < s.text.length) {
19897 var ch = s.text.charAt(s.position);
19898 var parsed = s.parseWS(ch) || parseOverride(ch) || (beginable || s.spacing) && (s.parseStartTag("bold", "*") || s.parseStartTag("ital", "_") || s.parseStartTag("mono", "`")) || s.parseEndTag("bold", "*", "afterBold") || s.parseEndTag("ital", "_", "afterItal") || s.parseEndTag("mono", "`", "afterMono");
19899
19900 if (!parsed) {
19901 s.add(ch);
19902 beginable = false;
19903 }
19904
19905 s.position++;
19906 }
19907
19908 s.emitBlock();
19909 return s.blocks;
19910 }
19911 /**
19912 * Explodes a piece of text into single-font blocks using a given markup
19913 *
19914 * @param {string} text
19915 * @param {boolean|'md'|'markdown'|'html'} markupSystem
19916 * @returns {Array.<{text: string, mod: string}>}
19917 * @private
19918 */
19919
19920 }, {
19921 key: "splitBlocks",
19922 value: function splitBlocks(text, markupSystem) {
19923 var system = this.decodeMarkupSystem(markupSystem);
19924
19925 if (system === "none") {
19926 return [{
19927 text: text,
19928 mod: "normal"
19929 }];
19930 } else if (system === "markdown") {
19931 return this.splitMarkdownBlocks(text);
19932 } else if (system === "html") {
19933 return this.splitHtmlBlocks(text);
19934 }
19935 }
19936 /**
19937 * @param {string} text
19938 * @returns {boolean} true if text length over the current max with
19939 * @private
19940 */
19941
19942 }, {
19943 key: "overMaxWidth",
19944 value: function overMaxWidth(text) {
19945 var width = this.ctx.measureText(text).width;
19946 return this.lines.curWidth() + width > this.parent.fontOptions.maxWdt;
19947 }
19948 /**
19949 * Determine the longest part of the sentence which still fits in the
19950 * current max width.
19951 *
19952 * @param {Array} words Array of strings signifying a text lines
19953 * @returns {number} index of first item in string making string go over max
19954 * @private
19955 */
19956
19957 }, {
19958 key: "getLongestFit",
19959 value: function getLongestFit(words) {
19960 var text = "";
19961 var w = 0;
19962
19963 while (w < words.length) {
19964 var pre = text === "" ? "" : " ";
19965 var newText = text + pre + words[w];
19966 if (this.overMaxWidth(newText)) break;
19967 text = newText;
19968 w++;
19969 }
19970
19971 return w;
19972 }
19973 /**
19974 * Determine the longest part of the string which still fits in the
19975 * current max width.
19976 *
19977 * @param {Array} words Array of strings signifying a text lines
19978 * @returns {number} index of first item in string making string go over max
19979 */
19980
19981 }, {
19982 key: "getLongestFitWord",
19983 value: function getLongestFitWord(words) {
19984 var w = 0;
19985
19986 while (w < words.length) {
19987 if (this.overMaxWidth(slice$1(words).call(words, 0, w))) break;
19988 w++;
19989 }
19990
19991 return w;
19992 }
19993 /**
19994 * Split the passed text into lines, according to width constraint (if any).
19995 *
19996 * The method assumes that the input string is a single line, i.e. without lines break.
19997 *
19998 * This method retains spaces, if still present (case `font.multi: false`).
19999 * A space which falls on an internal line break, will be replaced by a newline.
20000 * There is no special handling of tabs; these go along with the flow.
20001 *
20002 * @param {string} str
20003 * @param {string} [mod='normal']
20004 * @param {boolean} [appendLast=false]
20005 * @private
20006 */
20007
20008 }, {
20009 key: "splitStringIntoLines",
20010 value: function splitStringIntoLines(str) {
20011 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "normal";
20012 var appendLast = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
20013 // Set the canvas context font, based upon the current selected/hover state
20014 // and the provided mod, so the text measurement performed by getLongestFit
20015 // will be accurate - and not just use the font of whoever last used the canvas.
20016 this.parent.getFormattingValues(this.ctx, this.selected, this.hover, mod); // Still-present spaces are relevant, retain them
20017
20018 str = str.replace(/^( +)/g, "$1\r");
20019 str = str.replace(/([^\r][^ ]*)( +)/g, "$1\r$2\r");
20020 var words = str.split("\r");
20021
20022 while (words.length > 0) {
20023 var w = this.getLongestFit(words);
20024
20025 if (w === 0) {
20026 // Special case: the first word is already larger than the max width.
20027 var word = words[0]; // Break the word to the largest part that fits the line
20028
20029 var x = this.getLongestFitWord(word);
20030 this.lines.newLine(slice$1(word).call(word, 0, x), mod); // Adjust the word, so that the rest will be done next iteration
20031
20032 words[0] = slice$1(word).call(word, x);
20033 } else {
20034 // skip any space that is replaced by a newline
20035 var newW = w;
20036
20037 if (words[w - 1] === " ") {
20038 w--;
20039 } else if (words[newW] === " ") {
20040 newW++;
20041 }
20042
20043 var text = slice$1(words).call(words, 0, w).join("");
20044
20045 if (w == words.length && appendLast) {
20046 this.lines.append(text, mod);
20047 } else {
20048 this.lines.newLine(text, mod);
20049 } // Adjust the word, so that the rest will be done next iteration
20050
20051
20052 words = slice$1(words).call(words, newW);
20053 }
20054 }
20055 }
20056 }]);
20057
20058 return LabelSplitter;
20059}();
20060
20061/**
20062 * List of special styles for multi-fonts
20063 *
20064 * @private
20065 */
20066
20067var multiFontStyle = ["bold", "ital", "boldital", "mono"];
20068/**
20069 * A Label to be used for Nodes or Edges.
20070 */
20071
20072var Label = /*#__PURE__*/function () {
20073 /**
20074 * @param {object} body
20075 * @param {object} options
20076 * @param {boolean} [edgelabel=false]
20077 */
20078 function Label(body, options) {
20079 var edgelabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
20080
20081 _classCallCheck(this, Label);
20082
20083 this.body = body;
20084 this.pointToSelf = false;
20085 this.baseSize = undefined;
20086 this.fontOptions = {}; // instance variable containing the *instance-local* font options
20087
20088 this.setOptions(options);
20089 this.size = {
20090 top: 0,
20091 left: 0,
20092 width: 0,
20093 height: 0,
20094 yLine: 0
20095 };
20096 this.isEdgeLabel = edgelabel;
20097 }
20098 /**
20099 * @param {object} options the options of the parent Node-instance
20100 */
20101
20102
20103 _createClass(Label, [{
20104 key: "setOptions",
20105 value: function setOptions(options) {
20106 this.elementOptions = options; // Reference to the options of the parent Node-instance
20107
20108 this.initFontOptions(options.font);
20109
20110 if (isValidLabel(options.label)) {
20111 this.labelDirty = true;
20112 } else {
20113 // Bad label! Change the option value to prevent bad stuff happening
20114 options.label = undefined;
20115 }
20116
20117 if (options.font !== undefined && options.font !== null) {
20118 // font options can be deleted at various levels
20119 if (typeof options.font === "string") {
20120 this.baseSize = this.fontOptions.size;
20121 } else if (_typeof(options.font) === "object") {
20122 var size = options.font.size;
20123
20124 if (size !== undefined) {
20125 this.baseSize = size;
20126 }
20127 }
20128 }
20129 }
20130 /**
20131 * Init the font Options structure.
20132 *
20133 * Member fontOptions serves as an accumulator for the current font options.
20134 * As such, it needs to be completely separated from the node options.
20135 *
20136 * @param {object} newFontOptions the new font options to process
20137 * @private
20138 */
20139
20140 }, {
20141 key: "initFontOptions",
20142 value: function initFontOptions(newFontOptions) {
20143 var _this = this;
20144
20145 // Prepare the multi-font option objects.
20146 // These will be filled in propagateFonts(), if required
20147 forEach$1(multiFontStyle, function (style) {
20148 _this.fontOptions[style] = {};
20149 }); // Handle shorthand option, if present
20150
20151 if (Label.parseFontString(this.fontOptions, newFontOptions)) {
20152 this.fontOptions.vadjust = 0;
20153 return;
20154 } // Copy over the non-multifont options, if specified
20155
20156
20157 forEach$1(newFontOptions, function (prop, n) {
20158 if (prop !== undefined && prop !== null && _typeof(prop) !== "object") {
20159 _this.fontOptions[n] = prop;
20160 }
20161 });
20162 }
20163 /**
20164 * If in-variable is a string, parse it as a font specifier.
20165 *
20166 * Note that following is not done here and have to be done after the call:
20167 * - Not all font options are set (vadjust, mod)
20168 *
20169 * @param {object} outOptions out-parameter, object in which to store the parse results (if any)
20170 * @param {object} inOptions font options to parse
20171 * @returns {boolean} true if font parsed as string, false otherwise
20172 * @static
20173 */
20174
20175 }, {
20176 key: "constrain",
20177 value:
20178 /**
20179 * Set the width and height constraints based on 'nearest' value
20180 *
20181 * @param {Array} pile array of option objects to consider
20182 * @returns {object} the actual constraint values to use
20183 * @private
20184 */
20185 function constrain(pile) {
20186 // NOTE: constrainWidth and constrainHeight never set!
20187 // NOTE: for edge labels, only 'maxWdt' set
20188 // Node labels can set all the fields
20189 var fontOptions = {
20190 constrainWidth: false,
20191 maxWdt: -1,
20192 minWdt: -1,
20193 constrainHeight: false,
20194 minHgt: -1,
20195 valign: "middle"
20196 };
20197 var widthConstraint = topMost(pile, "widthConstraint");
20198
20199 if (typeof widthConstraint === "number") {
20200 fontOptions.maxWdt = Number(widthConstraint);
20201 fontOptions.minWdt = Number(widthConstraint);
20202 } else if (_typeof(widthConstraint) === "object") {
20203 var widthConstraintMaximum = topMost(pile, ["widthConstraint", "maximum"]);
20204
20205 if (typeof widthConstraintMaximum === "number") {
20206 fontOptions.maxWdt = Number(widthConstraintMaximum);
20207 }
20208
20209 var widthConstraintMinimum = topMost(pile, ["widthConstraint", "minimum"]);
20210
20211 if (typeof widthConstraintMinimum === "number") {
20212 fontOptions.minWdt = Number(widthConstraintMinimum);
20213 }
20214 }
20215
20216 var heightConstraint = topMost(pile, "heightConstraint");
20217
20218 if (typeof heightConstraint === "number") {
20219 fontOptions.minHgt = Number(heightConstraint);
20220 } else if (_typeof(heightConstraint) === "object") {
20221 var heightConstraintMinimum = topMost(pile, ["heightConstraint", "minimum"]);
20222
20223 if (typeof heightConstraintMinimum === "number") {
20224 fontOptions.minHgt = Number(heightConstraintMinimum);
20225 }
20226
20227 var heightConstraintValign = topMost(pile, ["heightConstraint", "valign"]);
20228
20229 if (typeof heightConstraintValign === "string") {
20230 if (heightConstraintValign === "top" || heightConstraintValign === "bottom") {
20231 fontOptions.valign = heightConstraintValign;
20232 }
20233 }
20234 }
20235
20236 return fontOptions;
20237 }
20238 /**
20239 * Set options and update internal state
20240 *
20241 * @param {object} options options to set
20242 * @param {Array} pile array of option objects to consider for option 'chosen'
20243 */
20244
20245 }, {
20246 key: "update",
20247 value: function update(options, pile) {
20248 this.setOptions(options, true);
20249 this.propagateFonts(pile);
20250 deepExtend(this.fontOptions, this.constrain(pile));
20251 this.fontOptions.chooser = choosify("label", pile);
20252 }
20253 /**
20254 * When margins are set in an element, adjust sizes is called to remove them
20255 * from the width/height constraints. This must be done prior to label sizing.
20256 *
20257 * @param {{top: number, right: number, bottom: number, left: number}} margins
20258 */
20259
20260 }, {
20261 key: "adjustSizes",
20262 value: function adjustSizes(margins) {
20263 var widthBias = margins ? margins.right + margins.left : 0;
20264
20265 if (this.fontOptions.constrainWidth) {
20266 this.fontOptions.maxWdt -= widthBias;
20267 this.fontOptions.minWdt -= widthBias;
20268 }
20269
20270 var heightBias = margins ? margins.top + margins.bottom : 0;
20271
20272 if (this.fontOptions.constrainHeight) {
20273 this.fontOptions.minHgt -= heightBias;
20274 }
20275 } /////////////////////////////////////////////////////////
20276 // Methods for handling options piles
20277 // Eventually, these will be moved to a separate class
20278 /////////////////////////////////////////////////////////
20279
20280 /**
20281 * Add the font members of the passed list of option objects to the pile.
20282 *
20283 * @param {Pile} dstPile pile of option objects add to
20284 * @param {Pile} srcPile pile of option objects to take font options from
20285 * @private
20286 */
20287
20288 }, {
20289 key: "addFontOptionsToPile",
20290 value: function addFontOptionsToPile(dstPile, srcPile) {
20291 for (var i = 0; i < srcPile.length; ++i) {
20292 this.addFontToPile(dstPile, srcPile[i]);
20293 }
20294 }
20295 /**
20296 * Add given font option object to the list of objects (the 'pile') to consider for determining
20297 * multi-font option values.
20298 *
20299 * @param {Pile} pile pile of option objects to use
20300 * @param {object} options instance to add to pile
20301 * @private
20302 */
20303
20304 }, {
20305 key: "addFontToPile",
20306 value: function addFontToPile(pile, options) {
20307 if (options === undefined) return;
20308 if (options.font === undefined || options.font === null) return;
20309 var item = options.font;
20310 pile.push(item);
20311 }
20312 /**
20313 * Collect all own-property values from the font pile that aren't multi-font option objectss.
20314 *
20315 * @param {Pile} pile pile of option objects to use
20316 * @returns {object} object with all current own basic font properties
20317 * @private
20318 */
20319
20320 }, {
20321 key: "getBasicOptions",
20322 value: function getBasicOptions(pile) {
20323 var ret = {}; // Scans the whole pile to get all options present
20324
20325 for (var n = 0; n < pile.length; ++n) {
20326 var fontOptions = pile[n]; // Convert shorthand if necessary
20327
20328 var tmpShorthand = {};
20329
20330 if (Label.parseFontString(tmpShorthand, fontOptions)) {
20331 fontOptions = tmpShorthand;
20332 }
20333
20334 forEach$1(fontOptions, function (opt, name) {
20335 if (opt === undefined) return; // multi-font option need not be present
20336
20337 if (Object.prototype.hasOwnProperty.call(ret, name)) return; // Keep first value we encounter
20338
20339 if (indexOf(multiFontStyle).call(multiFontStyle, name) !== -1) {
20340 // Skip multi-font properties but we do need the structure
20341 ret[name] = {};
20342 } else {
20343 ret[name] = opt;
20344 }
20345 });
20346 }
20347
20348 return ret;
20349 }
20350 /**
20351 * Return the value for given option for the given multi-font.
20352 *
20353 * All available option objects are trawled in the set order to construct the option values.
20354 *
20355 * ---------------------------------------------------------------------
20356 * ## Traversal of pile for multi-fonts
20357 *
20358 * The determination of multi-font option values is a special case, because any values not
20359 * present in the multi-font options should by definition be taken from the main font options,
20360 * i.e. from the current 'parent' object of the multi-font option.
20361 *
20362 * ### Search order for multi-fonts
20363 *
20364 * 'bold' used as example:
20365 *
20366 * - search in option group 'bold' in local properties
20367 * - search in main font option group in local properties
20368 *
20369 * ---------------------------------------------------------------------
20370 *
20371 * @param {Pile} pile pile of option objects to use
20372 * @param {MultiFontStyle} multiName sub path for the multi-font
20373 * @param {string} option the option to search for, for the given multi-font
20374 * @returns {string|number} the value for the given option
20375 * @private
20376 */
20377
20378 }, {
20379 key: "getFontOption",
20380 value: function getFontOption(pile, multiName, option) {
20381 var multiFont; // Search multi font in local properties
20382
20383 for (var n = 0; n < pile.length; ++n) {
20384 var fontOptions = pile[n];
20385
20386 if (Object.prototype.hasOwnProperty.call(fontOptions, multiName)) {
20387 multiFont = fontOptions[multiName];
20388 if (multiFont === undefined || multiFont === null) continue; // Convert shorthand if necessary
20389 // TODO: inefficient to do this conversion every time; find a better way.
20390
20391 var tmpShorthand = {};
20392
20393 if (Label.parseFontString(tmpShorthand, multiFont)) {
20394 multiFont = tmpShorthand;
20395 }
20396
20397 if (Object.prototype.hasOwnProperty.call(multiFont, option)) {
20398 return multiFont[option];
20399 }
20400 }
20401 } // Option is not mentioned in the multi font options; take it from the parent font options.
20402 // These have already been converted with getBasicOptions(), so use the converted values.
20403
20404
20405 if (Object.prototype.hasOwnProperty.call(this.fontOptions, option)) {
20406 return this.fontOptions[option];
20407 } // A value **must** be found; you should never get here.
20408
20409
20410 throw new Error("Did not find value for multi-font for property: '" + option + "'");
20411 }
20412 /**
20413 * Return all options values for the given multi-font.
20414 *
20415 * All available option objects are trawled in the set order to construct the option values.
20416 *
20417 * @param {Pile} pile pile of option objects to use
20418 * @param {MultiFontStyle} multiName sub path for the mod-font
20419 * @returns {MultiFontOptions}
20420 * @private
20421 */
20422
20423 }, {
20424 key: "getFontOptions",
20425 value: function getFontOptions(pile, multiName) {
20426 var result = {};
20427 var optionNames = ["color", "size", "face", "mod", "vadjust"]; // List of allowed options per multi-font
20428
20429 for (var i = 0; i < optionNames.length; ++i) {
20430 var mod = optionNames[i];
20431 result[mod] = this.getFontOption(pile, multiName, mod);
20432 }
20433
20434 return result;
20435 } /////////////////////////////////////////////////////////
20436 // End methods for handling options piles
20437 /////////////////////////////////////////////////////////
20438
20439 /**
20440 * Collapse the font options for the multi-font to single objects, from
20441 * the chain of option objects passed (the 'pile').
20442 *
20443 * @param {Pile} pile sequence of option objects to consider.
20444 * First item in list assumed to be the newly set options.
20445 */
20446
20447 }, {
20448 key: "propagateFonts",
20449 value: function propagateFonts(pile) {
20450 var _this2 = this;
20451
20452 var fontPile = []; // sequence of font objects to consider, order important
20453 // Note that this.elementOptions is not used here.
20454
20455 this.addFontOptionsToPile(fontPile, pile);
20456 this.fontOptions = this.getBasicOptions(fontPile); // We set multifont values even if multi === false, for consistency (things break otherwise)
20457
20458 var _loop = function _loop(i) {
20459 var mod = multiFontStyle[i];
20460 var modOptions = _this2.fontOptions[mod];
20461
20462 var tmpMultiFontOptions = _this2.getFontOptions(fontPile, mod); // Copy over found values
20463
20464
20465 forEach$1(tmpMultiFontOptions, function (option, n) {
20466 modOptions[n] = option;
20467 });
20468 modOptions.size = Number(modOptions.size);
20469 modOptions.vadjust = Number(modOptions.vadjust);
20470 };
20471
20472 for (var i = 0; i < multiFontStyle.length; ++i) {
20473 _loop(i);
20474 }
20475 }
20476 /**
20477 * Main function. This is called from anything that wants to draw a label.
20478 *
20479 * @param {CanvasRenderingContext2D} ctx
20480 * @param {number} x
20481 * @param {number} y
20482 * @param {boolean} selected
20483 * @param {boolean} hover
20484 * @param {string} [baseline='middle']
20485 */
20486
20487 }, {
20488 key: "draw",
20489 value: function draw(ctx, x, y, selected, hover) {
20490 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : "middle";
20491 // if no label, return
20492 if (this.elementOptions.label === undefined) return; // check if we have to render the label
20493
20494 var viewFontSize = this.fontOptions.size * this.body.view.scale;
20495 if (this.elementOptions.label && viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) return; // This ensures that there will not be HUGE letters on screen
20496 // by setting an upper limit on the visible text size (regardless of zoomLevel)
20497
20498 if (viewFontSize >= this.elementOptions.scaling.label.maxVisible) {
20499 viewFontSize = Number(this.elementOptions.scaling.label.maxVisible) / this.body.view.scale;
20500 } // update the size cache if required
20501
20502
20503 this.calculateLabelSize(ctx, selected, hover, x, y, baseline);
20504
20505 this._drawBackground(ctx);
20506
20507 this._drawText(ctx, x, this.size.yLine, baseline, viewFontSize);
20508 }
20509 /**
20510 * Draws the label background
20511 *
20512 * @param {CanvasRenderingContext2D} ctx
20513 * @private
20514 */
20515
20516 }, {
20517 key: "_drawBackground",
20518 value: function _drawBackground(ctx) {
20519 if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") {
20520 ctx.fillStyle = this.fontOptions.background;
20521 var size = this.getSize();
20522 ctx.fillRect(size.left, size.top, size.width, size.height);
20523 }
20524 }
20525 /**
20526 *
20527 * @param {CanvasRenderingContext2D} ctx
20528 * @param {number} x
20529 * @param {number} y
20530 * @param {string} [baseline='middle']
20531 * @param {number} viewFontSize
20532 * @private
20533 */
20534
20535 }, {
20536 key: "_drawText",
20537 value: function _drawText(ctx, x, y) {
20538 var baseline = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "middle";
20539 var viewFontSize = arguments.length > 4 ? arguments[4] : undefined;
20540
20541 var _this$_setAlignment = this._setAlignment(ctx, x, y, baseline);
20542
20543 var _this$_setAlignment2 = _slicedToArray(_this$_setAlignment, 2);
20544
20545 x = _this$_setAlignment2[0];
20546 y = _this$_setAlignment2[1];
20547 ctx.textAlign = "left";
20548 x = x - this.size.width / 2; // Shift label 1/2-distance to the left
20549
20550 if (this.fontOptions.valign && this.size.height > this.size.labelHeight) {
20551 if (this.fontOptions.valign === "top") {
20552 y -= (this.size.height - this.size.labelHeight) / 2;
20553 }
20554
20555 if (this.fontOptions.valign === "bottom") {
20556 y += (this.size.height - this.size.labelHeight) / 2;
20557 }
20558 } // draw the text
20559
20560
20561 for (var i = 0; i < this.lineCount; i++) {
20562 var line = this.lines[i];
20563
20564 if (line && line.blocks) {
20565 var width = 0;
20566
20567 if (this.isEdgeLabel || this.fontOptions.align === "center") {
20568 width += (this.size.width - line.width) / 2;
20569 } else if (this.fontOptions.align === "right") {
20570 width += this.size.width - line.width;
20571 }
20572
20573 for (var j = 0; j < line.blocks.length; j++) {
20574 var block = line.blocks[j];
20575 ctx.font = block.font;
20576
20577 var _this$_getColor = this._getColor(block.color, viewFontSize, block.strokeColor),
20578 _this$_getColor2 = _slicedToArray(_this$_getColor, 2),
20579 fontColor = _this$_getColor2[0],
20580 strokeColor = _this$_getColor2[1];
20581
20582 if (block.strokeWidth > 0) {
20583 ctx.lineWidth = block.strokeWidth;
20584 ctx.strokeStyle = strokeColor;
20585 ctx.lineJoin = "round";
20586 }
20587
20588 ctx.fillStyle = fontColor;
20589
20590 if (block.strokeWidth > 0) {
20591 ctx.strokeText(block.text, x + width, y + block.vadjust);
20592 }
20593
20594 ctx.fillText(block.text, x + width, y + block.vadjust);
20595 width += block.width;
20596 }
20597
20598 y += line.height;
20599 }
20600 }
20601 }
20602 /**
20603 *
20604 * @param {CanvasRenderingContext2D} ctx
20605 * @param {number} x
20606 * @param {number} y
20607 * @param {string} baseline
20608 * @returns {Array.<number>}
20609 * @private
20610 */
20611
20612 }, {
20613 key: "_setAlignment",
20614 value: function _setAlignment(ctx, x, y, baseline) {
20615 // check for label alignment (for edges)
20616 // TODO: make alignment for nodes
20617 if (this.isEdgeLabel && this.fontOptions.align !== "horizontal" && this.pointToSelf === false) {
20618 x = 0;
20619 y = 0;
20620 var lineMargin = 2;
20621
20622 if (this.fontOptions.align === "top") {
20623 ctx.textBaseline = "alphabetic";
20624 y -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
20625 } else if (this.fontOptions.align === "bottom") {
20626 ctx.textBaseline = "hanging";
20627 y += 2 * lineMargin; // distance from edge, required because we use hanging. Hanging has less difference between browsers
20628 } else {
20629 ctx.textBaseline = "middle";
20630 }
20631 } else {
20632 ctx.textBaseline = baseline;
20633 }
20634
20635 return [x, y];
20636 }
20637 /**
20638 * fade in when relative scale is between threshold and threshold - 1.
20639 * If the relative scale would be smaller than threshold -1 the draw function would have returned before coming here.
20640 *
20641 * @param {string} color The font color to use
20642 * @param {number} viewFontSize
20643 * @param {string} initialStrokeColor
20644 * @returns {Array.<string>} An array containing the font color and stroke color
20645 * @private
20646 */
20647
20648 }, {
20649 key: "_getColor",
20650 value: function _getColor(color, viewFontSize, initialStrokeColor) {
20651 var fontColor = color || "#000000";
20652 var strokeColor = initialStrokeColor || "#ffffff";
20653
20654 if (viewFontSize <= this.elementOptions.scaling.label.drawThreshold) {
20655 var opacity = Math.max(0, Math.min(1, 1 - (this.elementOptions.scaling.label.drawThreshold - viewFontSize)));
20656 fontColor = overrideOpacity(fontColor, opacity);
20657 strokeColor = overrideOpacity(strokeColor, opacity);
20658 }
20659
20660 return [fontColor, strokeColor];
20661 }
20662 /**
20663 *
20664 * @param {CanvasRenderingContext2D} ctx
20665 * @param {boolean} selected
20666 * @param {boolean} hover
20667 * @returns {{width: number, height: number}}
20668 */
20669
20670 }, {
20671 key: "getTextSize",
20672 value: function getTextSize(ctx) {
20673 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
20674 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
20675
20676 this._processLabel(ctx, selected, hover);
20677
20678 return {
20679 width: this.size.width,
20680 height: this.size.height,
20681 lineCount: this.lineCount
20682 };
20683 }
20684 /**
20685 * Get the current dimensions of the label
20686 *
20687 * @returns {rect}
20688 */
20689
20690 }, {
20691 key: "getSize",
20692 value: function getSize() {
20693 var lineMargin = 2;
20694 var x = this.size.left; // default values which might be overridden below
20695
20696 var y = this.size.top - 0.5 * lineMargin; // idem
20697
20698 if (this.isEdgeLabel) {
20699 var x2 = -this.size.width * 0.5;
20700
20701 switch (this.fontOptions.align) {
20702 case "middle":
20703 x = x2;
20704 y = -this.size.height * 0.5;
20705 break;
20706
20707 case "top":
20708 x = x2;
20709 y = -(this.size.height + lineMargin);
20710 break;
20711
20712 case "bottom":
20713 x = x2;
20714 y = lineMargin;
20715 break;
20716 }
20717 }
20718
20719 var ret = {
20720 left: x,
20721 top: y,
20722 width: this.size.width,
20723 height: this.size.height
20724 };
20725 return ret;
20726 }
20727 /**
20728 *
20729 * @param {CanvasRenderingContext2D} ctx
20730 * @param {boolean} selected
20731 * @param {boolean} hover
20732 * @param {number} [x=0]
20733 * @param {number} [y=0]
20734 * @param {'middle'|'hanging'} [baseline='middle']
20735 */
20736
20737 }, {
20738 key: "calculateLabelSize",
20739 value: function calculateLabelSize(ctx, selected, hover) {
20740 var x = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
20741 var y = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
20742 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : "middle";
20743
20744 this._processLabel(ctx, selected, hover);
20745
20746 this.size.left = x - this.size.width * 0.5;
20747 this.size.top = y - this.size.height * 0.5;
20748 this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size;
20749
20750 if (baseline === "hanging") {
20751 this.size.top += 0.5 * this.fontOptions.size;
20752 this.size.top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
20753
20754 this.size.yLine += 4; // distance from node
20755 }
20756 }
20757 /**
20758 *
20759 * @param {CanvasRenderingContext2D} ctx
20760 * @param {boolean} selected
20761 * @param {boolean} hover
20762 * @param {string} mod
20763 * @returns {{color, size, face, mod, vadjust, strokeWidth: *, strokeColor: (*|string|allOptions.edges.font.strokeColor|{string}|allOptions.nodes.font.strokeColor|Array)}}
20764 */
20765
20766 }, {
20767 key: "getFormattingValues",
20768 value: function getFormattingValues(ctx, selected, hover, mod) {
20769 var getValue = function getValue(fontOptions, mod, option) {
20770 if (mod === "normal") {
20771 if (option === "mod") return "";
20772 return fontOptions[option];
20773 }
20774
20775 if (fontOptions[mod][option] !== undefined) {
20776 // Grumbl leaving out test on undefined equals false for ""
20777 return fontOptions[mod][option];
20778 } else {
20779 // Take from parent font option
20780 return fontOptions[option];
20781 }
20782 };
20783
20784 var values = {
20785 color: getValue(this.fontOptions, mod, "color"),
20786 size: getValue(this.fontOptions, mod, "size"),
20787 face: getValue(this.fontOptions, mod, "face"),
20788 mod: getValue(this.fontOptions, mod, "mod"),
20789 vadjust: getValue(this.fontOptions, mod, "vadjust"),
20790 strokeWidth: this.fontOptions.strokeWidth,
20791 strokeColor: this.fontOptions.strokeColor
20792 };
20793
20794 if (selected || hover) {
20795 if (mod === "normal" && this.fontOptions.chooser === true && this.elementOptions.labelHighlightBold) {
20796 values.mod = "bold";
20797 } else {
20798 if (typeof this.fontOptions.chooser === "function") {
20799 this.fontOptions.chooser(values, this.elementOptions.id, selected, hover);
20800 }
20801 }
20802 }
20803
20804 var fontString = "";
20805
20806 if (values.mod !== undefined && values.mod !== "") {
20807 // safeguard for undefined - this happened
20808 fontString += values.mod + " ";
20809 }
20810
20811 fontString += values.size + "px " + values.face;
20812 ctx.font = fontString.replace(/"/g, "");
20813 values.font = ctx.font;
20814 values.height = values.size;
20815 return values;
20816 }
20817 /**
20818 *
20819 * @param {boolean} selected
20820 * @param {boolean} hover
20821 * @returns {boolean}
20822 */
20823
20824 }, {
20825 key: "differentState",
20826 value: function differentState(selected, hover) {
20827 return selected !== this.selectedState || hover !== this.hoverState;
20828 }
20829 /**
20830 * This explodes the passed text into lines and determines the width, height and number of lines.
20831 *
20832 * @param {CanvasRenderingContext2D} ctx
20833 * @param {boolean} selected
20834 * @param {boolean} hover
20835 * @param {string} inText the text to explode
20836 * @returns {{width, height, lines}|*}
20837 * @private
20838 */
20839
20840 }, {
20841 key: "_processLabelText",
20842 value: function _processLabelText(ctx, selected, hover, inText) {
20843 var splitter = new LabelSplitter(ctx, this, selected, hover);
20844 return splitter.process(inText);
20845 }
20846 /**
20847 * This explodes the label string into lines and sets the width, height and number of lines.
20848 *
20849 * @param {CanvasRenderingContext2D} ctx
20850 * @param {boolean} selected
20851 * @param {boolean} hover
20852 * @private
20853 */
20854
20855 }, {
20856 key: "_processLabel",
20857 value: function _processLabel(ctx, selected, hover) {
20858 if (this.labelDirty === false && !this.differentState(selected, hover)) return;
20859
20860 var state = this._processLabelText(ctx, selected, hover, this.elementOptions.label);
20861
20862 if (this.fontOptions.minWdt > 0 && state.width < this.fontOptions.minWdt) {
20863 state.width = this.fontOptions.minWdt;
20864 }
20865
20866 this.size.labelHeight = state.height;
20867
20868 if (this.fontOptions.minHgt > 0 && state.height < this.fontOptions.minHgt) {
20869 state.height = this.fontOptions.minHgt;
20870 }
20871
20872 this.lines = state.lines;
20873 this.lineCount = state.lines.length;
20874 this.size.width = state.width;
20875 this.size.height = state.height;
20876 this.selectedState = selected;
20877 this.hoverState = hover;
20878 this.labelDirty = false;
20879 }
20880 /**
20881 * Check if this label is visible
20882 *
20883 * @returns {boolean} true if this label will be show, false otherwise
20884 */
20885
20886 }, {
20887 key: "visible",
20888 value: function visible() {
20889 if (this.size.width === 0 || this.size.height === 0 || this.elementOptions.label === undefined) {
20890 return false; // nothing to display
20891 }
20892
20893 var viewFontSize = this.fontOptions.size * this.body.view.scale;
20894
20895 if (viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) {
20896 return false; // Too small or too far away to show
20897 }
20898
20899 return true;
20900 }
20901 }], [{
20902 key: "parseFontString",
20903 value: function parseFontString(outOptions, inOptions) {
20904 if (!inOptions || typeof inOptions !== "string") return false;
20905 var newOptionsArray = inOptions.split(" ");
20906 outOptions.size = +newOptionsArray[0].replace("px", "");
20907 outOptions.face = newOptionsArray[1];
20908 outOptions.color = newOptionsArray[2];
20909 return true;
20910 }
20911 }]);
20912
20913 return Label;
20914}();
20915
20916/**
20917 * The Base class for all Nodes.
20918 */
20919var NodeBase = /*#__PURE__*/function () {
20920 /**
20921 * @param {object} options
20922 * @param {object} body
20923 * @param {Label} labelModule
20924 */
20925 function NodeBase(options, body, labelModule) {
20926 _classCallCheck(this, NodeBase);
20927
20928 this.body = body;
20929 this.labelModule = labelModule;
20930 this.setOptions(options);
20931 this.top = undefined;
20932 this.left = undefined;
20933 this.height = undefined;
20934 this.width = undefined;
20935 this.radius = undefined;
20936 this.margin = undefined;
20937 this.refreshNeeded = true;
20938 this.boundingBox = {
20939 top: 0,
20940 left: 0,
20941 right: 0,
20942 bottom: 0
20943 };
20944 }
20945 /**
20946 *
20947 * @param {object} options
20948 */
20949
20950
20951 _createClass(NodeBase, [{
20952 key: "setOptions",
20953 value: function setOptions(options) {
20954 this.options = options;
20955 }
20956 /**
20957 *
20958 * @param {Label} labelModule
20959 * @private
20960 */
20961
20962 }, {
20963 key: "_setMargins",
20964 value: function _setMargins(labelModule) {
20965 this.margin = {};
20966
20967 if (this.options.margin) {
20968 if (_typeof(this.options.margin) == "object") {
20969 this.margin.top = this.options.margin.top;
20970 this.margin.right = this.options.margin.right;
20971 this.margin.bottom = this.options.margin.bottom;
20972 this.margin.left = this.options.margin.left;
20973 } else {
20974 this.margin.top = this.options.margin;
20975 this.margin.right = this.options.margin;
20976 this.margin.bottom = this.options.margin;
20977 this.margin.left = this.options.margin;
20978 }
20979 }
20980
20981 labelModule.adjustSizes(this.margin);
20982 }
20983 /**
20984 *
20985 * @param {CanvasRenderingContext2D} ctx
20986 * @param {number} angle
20987 * @returns {number}
20988 * @private
20989 */
20990
20991 }, {
20992 key: "_distanceToBorder",
20993 value: function _distanceToBorder(ctx, angle) {
20994 var borderWidth = this.options.borderWidth;
20995
20996 if (ctx) {
20997 this.resize(ctx);
20998 }
20999
21000 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
21001 }
21002 /**
21003 *
21004 * @param {CanvasRenderingContext2D} ctx
21005 * @param {ArrowOptions} values
21006 */
21007
21008 }, {
21009 key: "enableShadow",
21010 value: function enableShadow(ctx, values) {
21011 if (values.shadow) {
21012 ctx.shadowColor = values.shadowColor;
21013 ctx.shadowBlur = values.shadowSize;
21014 ctx.shadowOffsetX = values.shadowX;
21015 ctx.shadowOffsetY = values.shadowY;
21016 }
21017 }
21018 /**
21019 *
21020 * @param {CanvasRenderingContext2D} ctx
21021 * @param {ArrowOptions} values
21022 */
21023
21024 }, {
21025 key: "disableShadow",
21026 value: function disableShadow(ctx, values) {
21027 if (values.shadow) {
21028 ctx.shadowColor = "rgba(0,0,0,0)";
21029 ctx.shadowBlur = 0;
21030 ctx.shadowOffsetX = 0;
21031 ctx.shadowOffsetY = 0;
21032 }
21033 }
21034 /**
21035 *
21036 * @param {CanvasRenderingContext2D} ctx
21037 * @param {ArrowOptions} values
21038 */
21039
21040 }, {
21041 key: "enableBorderDashes",
21042 value: function enableBorderDashes(ctx, values) {
21043 if (values.borderDashes !== false) {
21044 if (ctx.setLineDash !== undefined) {
21045 var dashes = values.borderDashes;
21046
21047 if (dashes === true) {
21048 dashes = [5, 15];
21049 }
21050
21051 ctx.setLineDash(dashes);
21052 } else {
21053 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
21054 this.options.shapeProperties.borderDashes = false;
21055 values.borderDashes = false;
21056 }
21057 }
21058 }
21059 /**
21060 *
21061 * @param {CanvasRenderingContext2D} ctx
21062 * @param {ArrowOptions} values
21063 */
21064
21065 }, {
21066 key: "disableBorderDashes",
21067 value: function disableBorderDashes(ctx, values) {
21068 if (values.borderDashes !== false) {
21069 if (ctx.setLineDash !== undefined) {
21070 ctx.setLineDash([0]);
21071 } else {
21072 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
21073 this.options.shapeProperties.borderDashes = false;
21074 values.borderDashes = false;
21075 }
21076 }
21077 }
21078 /**
21079 * Determine if the shape of a node needs to be recalculated.
21080 *
21081 * @param {boolean} selected
21082 * @param {boolean} hover
21083 * @returns {boolean}
21084 * @protected
21085 */
21086
21087 }, {
21088 key: "needsRefresh",
21089 value: function needsRefresh(selected, hover) {
21090 if (this.refreshNeeded === true) {
21091 // This is probably not the best location to reset this member.
21092 // However, in the current logic, it is the most convenient one.
21093 this.refreshNeeded = false;
21094 return true;
21095 }
21096
21097 return this.width === undefined || this.labelModule.differentState(selected, hover);
21098 }
21099 /**
21100 *
21101 * @param {CanvasRenderingContext2D} ctx
21102 * @param {ArrowOptions} values
21103 */
21104
21105 }, {
21106 key: "initContextForDraw",
21107 value: function initContextForDraw(ctx, values) {
21108 var borderWidth = values.borderWidth / this.body.view.scale;
21109 ctx.lineWidth = Math.min(this.width, borderWidth);
21110 ctx.strokeStyle = values.borderColor;
21111 ctx.fillStyle = values.color;
21112 }
21113 /**
21114 *
21115 * @param {CanvasRenderingContext2D} ctx
21116 * @param {ArrowOptions} values
21117 */
21118
21119 }, {
21120 key: "performStroke",
21121 value: function performStroke(ctx, values) {
21122 var borderWidth = values.borderWidth / this.body.view.scale; //draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
21123
21124 ctx.save(); // if borders are zero width, they will be drawn with width 1 by default. This prevents that
21125
21126 if (borderWidth > 0) {
21127 this.enableBorderDashes(ctx, values); //draw the border
21128
21129 ctx.stroke(); //disable dashed border for other elements
21130
21131 this.disableBorderDashes(ctx, values);
21132 }
21133
21134 ctx.restore();
21135 }
21136 /**
21137 *
21138 * @param {CanvasRenderingContext2D} ctx
21139 * @param {ArrowOptions} values
21140 */
21141
21142 }, {
21143 key: "performFill",
21144 value: function performFill(ctx, values) {
21145 ctx.save();
21146 ctx.fillStyle = values.color; // draw shadow if enabled
21147
21148 this.enableShadow(ctx, values); // draw the background
21149
21150 fill(ctx).call(ctx); // disable shadows for other elements.
21151
21152
21153 this.disableShadow(ctx, values);
21154 ctx.restore();
21155 this.performStroke(ctx, values);
21156 }
21157 /**
21158 *
21159 * @param {number} margin
21160 * @private
21161 */
21162
21163 }, {
21164 key: "_addBoundingBoxMargin",
21165 value: function _addBoundingBoxMargin(margin) {
21166 this.boundingBox.left -= margin;
21167 this.boundingBox.top -= margin;
21168 this.boundingBox.bottom += margin;
21169 this.boundingBox.right += margin;
21170 }
21171 /**
21172 * Actual implementation of this method call.
21173 *
21174 * Doing it like this makes it easier to override
21175 * in the child classes.
21176 *
21177 * @param {number} x width
21178 * @param {number} y height
21179 * @param {CanvasRenderingContext2D} ctx
21180 * @param {boolean} selected
21181 * @param {boolean} hover
21182 * @private
21183 */
21184
21185 }, {
21186 key: "_updateBoundingBox",
21187 value: function _updateBoundingBox(x, y, ctx, selected, hover) {
21188 if (ctx !== undefined) {
21189 this.resize(ctx, selected, hover);
21190 }
21191
21192 this.left = x - this.width / 2;
21193 this.top = y - this.height / 2;
21194 this.boundingBox.left = this.left;
21195 this.boundingBox.top = this.top;
21196 this.boundingBox.bottom = this.top + this.height;
21197 this.boundingBox.right = this.left + this.width;
21198 }
21199 /**
21200 * Default implementation of this method call.
21201 * This acts as a stub which can be overridden.
21202 *
21203 * @param {number} x width
21204 * @param {number} y height
21205 * @param {CanvasRenderingContext2D} ctx
21206 * @param {boolean} selected
21207 * @param {boolean} hover
21208 */
21209
21210 }, {
21211 key: "updateBoundingBox",
21212 value: function updateBoundingBox(x, y, ctx, selected, hover) {
21213 this._updateBoundingBox(x, y, ctx, selected, hover);
21214 }
21215 /**
21216 * Determine the dimensions to use for nodes with an internal label
21217 *
21218 * Currently, these are: Circle, Ellipse, Database, Box
21219 * The other nodes have external labels, and will not call this method
21220 *
21221 * If there is no label, decent default values are supplied.
21222 *
21223 * @param {CanvasRenderingContext2D} ctx
21224 * @param {boolean} [selected]
21225 * @param {boolean} [hover]
21226 * @returns {{width:number, height:number}}
21227 */
21228
21229 }, {
21230 key: "getDimensionsFromLabel",
21231 value: function getDimensionsFromLabel(ctx, selected, hover) {
21232 // NOTE: previously 'textSize' was not put in 'this' for Ellipse
21233 // TODO: examine the consequences.
21234 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
21235 var width = this.textSize.width;
21236 var height = this.textSize.height;
21237 var DEFAULT_SIZE = 14;
21238
21239 if (width === 0) {
21240 // This happens when there is no label text set
21241 width = DEFAULT_SIZE; // use a decent default
21242
21243 height = DEFAULT_SIZE; // if width zero, then height also always zero
21244 }
21245
21246 return {
21247 width: width,
21248 height: height
21249 };
21250 }
21251 }]);
21252
21253 return NodeBase;
21254}();
21255
21256function _createSuper$s(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$s(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
21257
21258function _isNativeReflectConstruct$s() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
21259/**
21260 * A Box Node/Cluster shape.
21261 *
21262 * @augments NodeBase
21263 */
21264
21265var Box$1 = /*#__PURE__*/function (_NodeBase) {
21266 _inherits(Box, _NodeBase);
21267
21268 var _super = _createSuper$s(Box);
21269
21270 /**
21271 * @param {object} options
21272 * @param {object} body
21273 * @param {Label} labelModule
21274 */
21275 function Box(options, body, labelModule) {
21276 var _this;
21277
21278 _classCallCheck(this, Box);
21279
21280 _this = _super.call(this, options, body, labelModule);
21281
21282 _this._setMargins(labelModule);
21283
21284 return _this;
21285 }
21286 /**
21287 *
21288 * @param {CanvasRenderingContext2D} ctx
21289 * @param {boolean} [selected]
21290 * @param {boolean} [hover]
21291 */
21292
21293
21294 _createClass(Box, [{
21295 key: "resize",
21296 value: function resize(ctx) {
21297 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
21298 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
21299
21300 if (this.needsRefresh(selected, hover)) {
21301 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
21302 this.width = dimensions.width + this.margin.right + this.margin.left;
21303 this.height = dimensions.height + this.margin.top + this.margin.bottom;
21304 this.radius = this.width / 2;
21305 }
21306 }
21307 /**
21308 *
21309 * @param {CanvasRenderingContext2D} ctx
21310 * @param {number} x width
21311 * @param {number} y height
21312 * @param {boolean} selected
21313 * @param {boolean} hover
21314 * @param {ArrowOptions} values
21315 */
21316
21317 }, {
21318 key: "draw",
21319 value: function draw(ctx, x, y, selected, hover, values) {
21320 this.resize(ctx, selected, hover);
21321 this.left = x - this.width / 2;
21322 this.top = y - this.height / 2;
21323 this.initContextForDraw(ctx, values);
21324 drawRoundRect(ctx, this.left, this.top, this.width, this.height, values.borderRadius);
21325 this.performFill(ctx, values);
21326 this.updateBoundingBox(x, y, ctx, selected, hover);
21327 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
21328 }
21329 /**
21330 *
21331 * @param {number} x width
21332 * @param {number} y height
21333 * @param {CanvasRenderingContext2D} ctx
21334 * @param {boolean} selected
21335 * @param {boolean} hover
21336 */
21337
21338 }, {
21339 key: "updateBoundingBox",
21340 value: function updateBoundingBox(x, y, ctx, selected, hover) {
21341 this._updateBoundingBox(x, y, ctx, selected, hover);
21342
21343 var borderRadius = this.options.shapeProperties.borderRadius; // only effective for box
21344
21345 this._addBoundingBoxMargin(borderRadius);
21346 }
21347 /**
21348 *
21349 * @param {CanvasRenderingContext2D} ctx
21350 * @param {number} angle
21351 * @returns {number}
21352 */
21353
21354 }, {
21355 key: "distanceToBorder",
21356 value: function distanceToBorder(ctx, angle) {
21357 if (ctx) {
21358 this.resize(ctx);
21359 }
21360
21361 var borderWidth = this.options.borderWidth;
21362 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
21363 }
21364 }]);
21365
21366 return Box;
21367}(NodeBase);
21368
21369function _createSuper$r(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$r(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
21370
21371function _isNativeReflectConstruct$r() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
21372/**
21373 * NOTE: This is a bad base class
21374 *
21375 * Child classes are:
21376 *
21377 * Image - uses *only* image methods
21378 * Circle - uses *only* _drawRawCircle
21379 * CircleImage - uses all
21380 *
21381 * TODO: Refactor, move _drawRawCircle to different module, derive Circle from NodeBase
21382 * Rename this to ImageBase
21383 * Consolidate common code in Image and CircleImage to base class
21384 *
21385 * @augments NodeBase
21386 */
21387
21388var CircleImageBase = /*#__PURE__*/function (_NodeBase) {
21389 _inherits(CircleImageBase, _NodeBase);
21390
21391 var _super = _createSuper$r(CircleImageBase);
21392
21393 /**
21394 * @param {object} options
21395 * @param {object} body
21396 * @param {Label} labelModule
21397 */
21398 function CircleImageBase(options, body, labelModule) {
21399 var _this;
21400
21401 _classCallCheck(this, CircleImageBase);
21402
21403 _this = _super.call(this, options, body, labelModule);
21404 _this.labelOffset = 0;
21405 _this.selected = false;
21406 return _this;
21407 }
21408 /**
21409 *
21410 * @param {object} options
21411 * @param {object} [imageObj]
21412 * @param {object} [imageObjAlt]
21413 */
21414
21415
21416 _createClass(CircleImageBase, [{
21417 key: "setOptions",
21418 value: function setOptions(options, imageObj, imageObjAlt) {
21419 this.options = options;
21420
21421 if (!(imageObj === undefined && imageObjAlt === undefined)) {
21422 this.setImages(imageObj, imageObjAlt);
21423 }
21424 }
21425 /**
21426 * Set the images for this node.
21427 *
21428 * The images can be updated after the initial setting of options;
21429 * therefore, this method needs to be reentrant.
21430 *
21431 * For correct working in error cases, it is necessary to properly set
21432 * field 'nodes.brokenImage' in the options.
21433 *
21434 * @param {Image} imageObj required; main image to show for this node
21435 * @param {Image|undefined} imageObjAlt optional; image to show when node is selected
21436 */
21437
21438 }, {
21439 key: "setImages",
21440 value: function setImages(imageObj, imageObjAlt) {
21441 if (imageObjAlt && this.selected) {
21442 this.imageObj = imageObjAlt;
21443 this.imageObjAlt = imageObj;
21444 } else {
21445 this.imageObj = imageObj;
21446 this.imageObjAlt = imageObjAlt;
21447 }
21448 }
21449 /**
21450 * Set selection and switch between the base and the selected image.
21451 *
21452 * Do the switch only if imageObjAlt exists.
21453 *
21454 * @param {boolean} selected value of new selected state for current node
21455 */
21456
21457 }, {
21458 key: "switchImages",
21459 value: function switchImages(selected) {
21460 var selection_changed = selected && !this.selected || !selected && this.selected;
21461 this.selected = selected; // Remember new selection
21462
21463 if (this.imageObjAlt !== undefined && selection_changed) {
21464 var imageTmp = this.imageObj;
21465 this.imageObj = this.imageObjAlt;
21466 this.imageObjAlt = imageTmp;
21467 }
21468 }
21469 /**
21470 * Returns Image Padding from node options
21471 *
21472 * @returns {{top: number,left: number,bottom: number,right: number}} image padding inside this shape
21473 * @private
21474 */
21475
21476 }, {
21477 key: "_getImagePadding",
21478 value: function _getImagePadding() {
21479 var imgPadding = {
21480 top: 0,
21481 right: 0,
21482 bottom: 0,
21483 left: 0
21484 };
21485
21486 if (this.options.imagePadding) {
21487 var optImgPadding = this.options.imagePadding;
21488
21489 if (_typeof(optImgPadding) == "object") {
21490 imgPadding.top = optImgPadding.top;
21491 imgPadding.right = optImgPadding.right;
21492 imgPadding.bottom = optImgPadding.bottom;
21493 imgPadding.left = optImgPadding.left;
21494 } else {
21495 imgPadding.top = optImgPadding;
21496 imgPadding.right = optImgPadding;
21497 imgPadding.bottom = optImgPadding;
21498 imgPadding.left = optImgPadding;
21499 }
21500 }
21501
21502 return imgPadding;
21503 }
21504 /**
21505 * Adjust the node dimensions for a loaded image.
21506 *
21507 * Pre: this.imageObj is valid
21508 */
21509
21510 }, {
21511 key: "_resizeImage",
21512 value: function _resizeImage() {
21513 var width, height;
21514
21515 if (this.options.shapeProperties.useImageSize === false) {
21516 // Use the size property
21517 var ratio_width = 1;
21518 var ratio_height = 1; // Only calculate the proper ratio if both width and height not zero
21519
21520 if (this.imageObj.width && this.imageObj.height) {
21521 if (this.imageObj.width > this.imageObj.height) {
21522 ratio_width = this.imageObj.width / this.imageObj.height;
21523 } else {
21524 ratio_height = this.imageObj.height / this.imageObj.width;
21525 }
21526 }
21527
21528 width = this.options.size * 2 * ratio_width;
21529 height = this.options.size * 2 * ratio_height;
21530 } else {
21531 // Use the image size with image padding
21532 var imgPadding = this._getImagePadding();
21533
21534 width = this.imageObj.width + imgPadding.left + imgPadding.right;
21535 height = this.imageObj.height + imgPadding.top + imgPadding.bottom;
21536 }
21537
21538 this.width = width;
21539 this.height = height;
21540 this.radius = 0.5 * this.width;
21541 }
21542 /**
21543 *
21544 * @param {CanvasRenderingContext2D} ctx
21545 * @param {number} x width
21546 * @param {number} y height
21547 * @param {ArrowOptions} values
21548 * @private
21549 */
21550
21551 }, {
21552 key: "_drawRawCircle",
21553 value: function _drawRawCircle(ctx, x, y, values) {
21554 this.initContextForDraw(ctx, values);
21555 drawCircle(ctx, x, y, values.size);
21556 this.performFill(ctx, values);
21557 }
21558 /**
21559 *
21560 * @param {CanvasRenderingContext2D} ctx
21561 * @param {ArrowOptions} values
21562 * @private
21563 */
21564
21565 }, {
21566 key: "_drawImageAtPosition",
21567 value: function _drawImageAtPosition(ctx, values) {
21568 if (this.imageObj.width != 0) {
21569 // draw the image
21570 ctx.globalAlpha = values.opacity !== undefined ? values.opacity : 1; // draw shadow if enabled
21571
21572 this.enableShadow(ctx, values);
21573 var factor = 1;
21574
21575 if (this.options.shapeProperties.interpolation === true) {
21576 factor = this.imageObj.width / this.width / this.body.view.scale;
21577 }
21578
21579 var imgPadding = this._getImagePadding();
21580
21581 var imgPosLeft = this.left + imgPadding.left;
21582 var imgPosTop = this.top + imgPadding.top;
21583 var imgWidth = this.width - imgPadding.left - imgPadding.right;
21584 var imgHeight = this.height - imgPadding.top - imgPadding.bottom;
21585 this.imageObj.drawImageAtPosition(ctx, factor, imgPosLeft, imgPosTop, imgWidth, imgHeight); // disable shadows for other elements.
21586
21587 this.disableShadow(ctx, values);
21588 }
21589 }
21590 /**
21591 *
21592 * @param {CanvasRenderingContext2D} ctx
21593 * @param {number} x width
21594 * @param {number} y height
21595 * @param {boolean} selected
21596 * @param {boolean} hover
21597 * @private
21598 */
21599
21600 }, {
21601 key: "_drawImageLabel",
21602 value: function _drawImageLabel(ctx, x, y, selected, hover) {
21603 var offset = 0;
21604
21605 if (this.height !== undefined) {
21606 offset = this.height * 0.5;
21607 var labelDimensions = this.labelModule.getTextSize(ctx, selected, hover);
21608
21609 if (labelDimensions.lineCount >= 1) {
21610 offset += labelDimensions.height / 2;
21611 }
21612 }
21613
21614 var yLabel = y + offset;
21615
21616 if (this.options.label) {
21617 this.labelOffset = offset;
21618 }
21619
21620 this.labelModule.draw(ctx, x, yLabel, selected, hover, "hanging");
21621 }
21622 }]);
21623
21624 return CircleImageBase;
21625}(NodeBase);
21626
21627function _createSuper$q(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$q(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
21628
21629function _isNativeReflectConstruct$q() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
21630/**
21631 * A Circle Node/Cluster shape.
21632 *
21633 * @augments CircleImageBase
21634 */
21635
21636var Circle$1 = /*#__PURE__*/function (_CircleImageBase) {
21637 _inherits(Circle, _CircleImageBase);
21638
21639 var _super = _createSuper$q(Circle);
21640
21641 /**
21642 * @param {object} options
21643 * @param {object} body
21644 * @param {Label} labelModule
21645 */
21646 function Circle(options, body, labelModule) {
21647 var _this;
21648
21649 _classCallCheck(this, Circle);
21650
21651 _this = _super.call(this, options, body, labelModule);
21652
21653 _this._setMargins(labelModule);
21654
21655 return _this;
21656 }
21657 /**
21658 *
21659 * @param {CanvasRenderingContext2D} ctx
21660 * @param {boolean} [selected]
21661 * @param {boolean} [hover]
21662 */
21663
21664
21665 _createClass(Circle, [{
21666 key: "resize",
21667 value: function resize(ctx) {
21668 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
21669 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
21670
21671 if (this.needsRefresh(selected, hover)) {
21672 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
21673 var diameter = Math.max(dimensions.width + this.margin.right + this.margin.left, dimensions.height + this.margin.top + this.margin.bottom);
21674 this.options.size = diameter / 2; // NOTE: this size field only set here, not in Ellipse, Database, Box
21675
21676 this.width = diameter;
21677 this.height = diameter;
21678 this.radius = this.width / 2;
21679 }
21680 }
21681 /**
21682 *
21683 * @param {CanvasRenderingContext2D} ctx
21684 * @param {number} x width
21685 * @param {number} y height
21686 * @param {boolean} selected
21687 * @param {boolean} hover
21688 * @param {ArrowOptions} values
21689 */
21690
21691 }, {
21692 key: "draw",
21693 value: function draw(ctx, x, y, selected, hover, values) {
21694 this.resize(ctx, selected, hover);
21695 this.left = x - this.width / 2;
21696 this.top = y - this.height / 2;
21697
21698 this._drawRawCircle(ctx, x, y, values);
21699
21700 this.updateBoundingBox(x, y);
21701 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, y, selected, hover);
21702 }
21703 /**
21704 *
21705 * @param {number} x width
21706 * @param {number} y height
21707 */
21708
21709 }, {
21710 key: "updateBoundingBox",
21711 value: function updateBoundingBox(x, y) {
21712 this.boundingBox.top = y - this.options.size;
21713 this.boundingBox.left = x - this.options.size;
21714 this.boundingBox.right = x + this.options.size;
21715 this.boundingBox.bottom = y + this.options.size;
21716 }
21717 /**
21718 *
21719 * @param {CanvasRenderingContext2D} ctx
21720 * @returns {number}
21721 */
21722
21723 }, {
21724 key: "distanceToBorder",
21725 value: function distanceToBorder(ctx) {
21726 if (ctx) {
21727 this.resize(ctx);
21728 }
21729
21730 return this.width * 0.5;
21731 }
21732 }]);
21733
21734 return Circle;
21735}(CircleImageBase);
21736
21737function _createSuper$p(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$p(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
21738
21739function _isNativeReflectConstruct$p() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
21740/**
21741 * A CircularImage Node/Cluster shape.
21742 *
21743 * @augments CircleImageBase
21744 */
21745
21746var CircularImage = /*#__PURE__*/function (_CircleImageBase) {
21747 _inherits(CircularImage, _CircleImageBase);
21748
21749 var _super = _createSuper$p(CircularImage);
21750
21751 /**
21752 * @param {object} options
21753 * @param {object} body
21754 * @param {Label} labelModule
21755 * @param {Image} imageObj
21756 * @param {Image} imageObjAlt
21757 */
21758 function CircularImage(options, body, labelModule, imageObj, imageObjAlt) {
21759 var _this;
21760
21761 _classCallCheck(this, CircularImage);
21762
21763 _this = _super.call(this, options, body, labelModule);
21764
21765 _this.setImages(imageObj, imageObjAlt);
21766
21767 return _this;
21768 }
21769 /**
21770 *
21771 * @param {CanvasRenderingContext2D} ctx
21772 * @param {boolean} [selected]
21773 * @param {boolean} [hover]
21774 */
21775
21776
21777 _createClass(CircularImage, [{
21778 key: "resize",
21779 value: function resize(ctx) {
21780 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
21781 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
21782 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
21783
21784 if (imageAbsent) {
21785 var diameter = this.options.size * 2;
21786 this.width = diameter;
21787 this.height = diameter;
21788 this.radius = 0.5 * this.width;
21789 return;
21790 } // At this point, an image is present, i.e. this.imageObj is valid.
21791
21792
21793 if (this.needsRefresh(selected, hover)) {
21794 this._resizeImage();
21795 }
21796 }
21797 /**
21798 *
21799 * @param {CanvasRenderingContext2D} ctx
21800 * @param {number} x width
21801 * @param {number} y height
21802 * @param {boolean} selected
21803 * @param {boolean} hover
21804 * @param {ArrowOptions} values
21805 */
21806
21807 }, {
21808 key: "draw",
21809 value: function draw(ctx, x, y, selected, hover, values) {
21810 this.switchImages(selected);
21811 this.resize();
21812 var labelX = x,
21813 labelY = y;
21814
21815 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
21816 this.left = x;
21817 this.top = y;
21818 labelX += this.width / 2;
21819 labelY += this.height / 2;
21820 } else {
21821 this.left = x - this.width / 2;
21822 this.top = y - this.height / 2;
21823 } // draw the background circle. IMPORTANT: the stroke in this method is used by the clip method below.
21824
21825
21826 this._drawRawCircle(ctx, labelX, labelY, values); // now we draw in the circle, we save so we can revert the clip operation after drawing.
21827
21828
21829 ctx.save(); // clip is used to use the stroke in drawRawCircle as an area that we can draw in.
21830
21831 ctx.clip(); // draw the image
21832
21833 this._drawImageAtPosition(ctx, values); // restore so we can again draw on the full canvas
21834
21835
21836 ctx.restore();
21837
21838 this._drawImageLabel(ctx, labelX, labelY, selected, hover);
21839
21840 this.updateBoundingBox(x, y);
21841 } // TODO: compare with Circle.updateBoundingBox(), consolidate? More stuff is happening here
21842
21843 /**
21844 *
21845 * @param {number} x width
21846 * @param {number} y height
21847 */
21848
21849 }, {
21850 key: "updateBoundingBox",
21851 value: function updateBoundingBox(x, y) {
21852 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
21853 this.boundingBox.top = y;
21854 this.boundingBox.left = x;
21855 this.boundingBox.right = x + this.options.size * 2;
21856 this.boundingBox.bottom = y + this.options.size * 2;
21857 } else {
21858 this.boundingBox.top = y - this.options.size;
21859 this.boundingBox.left = x - this.options.size;
21860 this.boundingBox.right = x + this.options.size;
21861 this.boundingBox.bottom = y + this.options.size;
21862 } // TODO: compare with Image.updateBoundingBox(), consolidate?
21863
21864
21865 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
21866 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
21867 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
21868 }
21869 /**
21870 *
21871 * @param {CanvasRenderingContext2D} ctx
21872 * @returns {number}
21873 */
21874
21875 }, {
21876 key: "distanceToBorder",
21877 value: function distanceToBorder(ctx) {
21878 if (ctx) {
21879 this.resize(ctx);
21880 }
21881
21882 return this.width * 0.5;
21883 }
21884 }]);
21885
21886 return CircularImage;
21887}(CircleImageBase);
21888
21889function _createSuper$o(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$o(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
21890
21891function _isNativeReflectConstruct$o() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
21892/**
21893 * Base class for constructing Node/Cluster Shapes.
21894 *
21895 * @augments NodeBase
21896 */
21897
21898var ShapeBase = /*#__PURE__*/function (_NodeBase) {
21899 _inherits(ShapeBase, _NodeBase);
21900
21901 var _super = _createSuper$o(ShapeBase);
21902
21903 /**
21904 * @param {object} options
21905 * @param {object} body
21906 * @param {Label} labelModule
21907 */
21908 function ShapeBase(options, body, labelModule) {
21909 _classCallCheck(this, ShapeBase);
21910
21911 return _super.call(this, options, body, labelModule);
21912 }
21913 /**
21914 *
21915 * @param {CanvasRenderingContext2D} ctx
21916 * @param {boolean} [selected]
21917 * @param {boolean} [hover]
21918 * @param {object} [values={size: this.options.size}]
21919 */
21920
21921
21922 _createClass(ShapeBase, [{
21923 key: "resize",
21924 value: function resize(ctx) {
21925 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
21926 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
21927 var values = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {
21928 size: this.options.size
21929 };
21930
21931 if (this.needsRefresh(selected, hover)) {
21932 var _this$customSizeWidth, _this$customSizeHeigh;
21933
21934 this.labelModule.getTextSize(ctx, selected, hover);
21935 var size = 2 * values.size;
21936 this.width = (_this$customSizeWidth = this.customSizeWidth) !== null && _this$customSizeWidth !== void 0 ? _this$customSizeWidth : size;
21937 this.height = (_this$customSizeHeigh = this.customSizeHeight) !== null && _this$customSizeHeigh !== void 0 ? _this$customSizeHeigh : size;
21938 this.radius = 0.5 * this.width;
21939 }
21940 }
21941 /**
21942 *
21943 * @param {CanvasRenderingContext2D} ctx
21944 * @param {string} shape
21945 * @param {number} sizeMultiplier - Unused! TODO: Remove next major release
21946 * @param {number} x
21947 * @param {number} y
21948 * @param {boolean} selected
21949 * @param {boolean} hover
21950 * @param {ArrowOptions} values
21951 * @private
21952 *
21953 * @returns {object} Callbacks to draw later on higher layers.
21954 */
21955
21956 }, {
21957 key: "_drawShape",
21958 value: function _drawShape(ctx, shape, sizeMultiplier, x, y, selected, hover, values) {
21959 var _this = this;
21960
21961 this.resize(ctx, selected, hover, values);
21962 this.left = x - this.width / 2;
21963 this.top = y - this.height / 2;
21964 this.initContextForDraw(ctx, values);
21965 getShape(shape)(ctx, x, y, values.size);
21966 this.performFill(ctx, values);
21967
21968 if (this.options.icon !== undefined) {
21969 if (this.options.icon.code !== undefined) {
21970 ctx.font = (selected ? "bold " : "") + this.height / 2 + "px " + (this.options.icon.face || "FontAwesome");
21971 ctx.fillStyle = this.options.icon.color || "black";
21972 ctx.textAlign = "center";
21973 ctx.textBaseline = "middle";
21974 ctx.fillText(this.options.icon.code, x, y);
21975 }
21976 }
21977
21978 return {
21979 drawExternalLabel: function drawExternalLabel() {
21980 if (_this.options.label !== undefined) {
21981 // Need to call following here in order to ensure value for
21982 // `this.labelModule.size.height`.
21983 _this.labelModule.calculateLabelSize(ctx, selected, hover, x, y, "hanging");
21984
21985 var yLabel = y + 0.5 * _this.height + 0.5 * _this.labelModule.size.height;
21986
21987 _this.labelModule.draw(ctx, x, yLabel, selected, hover, "hanging");
21988 }
21989
21990 _this.updateBoundingBox(x, y);
21991 }
21992 };
21993 }
21994 /**
21995 *
21996 * @param {number} x
21997 * @param {number} y
21998 */
21999
22000 }, {
22001 key: "updateBoundingBox",
22002 value: function updateBoundingBox(x, y) {
22003 this.boundingBox.top = y - this.options.size;
22004 this.boundingBox.left = x - this.options.size;
22005 this.boundingBox.right = x + this.options.size;
22006 this.boundingBox.bottom = y + this.options.size;
22007
22008 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
22009 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
22010 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
22011 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
22012 }
22013 }
22014 }]);
22015
22016 return ShapeBase;
22017}(NodeBase);
22018
22019function ownKeys$3(object, enumerableOnly) { var keys = keys$3(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
22020
22021function _objectSpread$3(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context; forEach$2(_context = ownKeys$3(Object(source), true)).call(_context, function (key) { _defineProperty(target, key, source[key]); }); } else if (getOwnPropertyDescriptors) { defineProperties(target, getOwnPropertyDescriptors(source)); } else { var _context2; forEach$2(_context2 = ownKeys$3(Object(source))).call(_context2, function (key) { defineProperty$5(target, key, getOwnPropertyDescriptor$2(source, key)); }); } } return target; }
22022
22023function _createSuper$n(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$n(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22024
22025function _isNativeReflectConstruct$n() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22026/**
22027 * A CustomShape Node/Cluster shape.
22028 *
22029 * @augments ShapeBase
22030 */
22031
22032var CustomShape = /*#__PURE__*/function (_ShapeBase) {
22033 _inherits(CustomShape, _ShapeBase);
22034
22035 var _super = _createSuper$n(CustomShape);
22036
22037 /**
22038 * @param {object} options
22039 * @param {object} body
22040 * @param {Label} labelModule
22041 * @param {Function} ctxRenderer
22042
22043 */
22044 function CustomShape(options, body, labelModule, ctxRenderer) {
22045 var _this;
22046
22047 _classCallCheck(this, CustomShape);
22048
22049 _this = _super.call(this, options, body, labelModule, ctxRenderer);
22050 _this.ctxRenderer = ctxRenderer;
22051 return _this;
22052 }
22053 /**
22054 *
22055 * @param {CanvasRenderingContext2D} ctx
22056 * @param {number} x width
22057 * @param {number} y height
22058 * @param {boolean} selected
22059 * @param {boolean} hover
22060 * @param {ArrowOptions} values
22061 *
22062 * @returns {object} Callbacks to draw later on different layers.
22063 */
22064
22065
22066 _createClass(CustomShape, [{
22067 key: "draw",
22068 value: function draw(ctx, x, y, selected, hover, values) {
22069 this.resize(ctx, selected, hover, values);
22070 this.left = x - this.width / 2;
22071 this.top = y - this.height / 2; // Guard right away because someone may just draw in the function itself.
22072
22073 ctx.save();
22074 var drawLater = this.ctxRenderer({
22075 ctx: ctx,
22076 id: this.options.id,
22077 x: x,
22078 y: y,
22079 state: {
22080 selected: selected,
22081 hover: hover
22082 },
22083 style: _objectSpread$3({}, values),
22084 label: this.options.label
22085 }); // Render the node shape bellow arrows.
22086
22087 if (drawLater.drawNode != null) {
22088 drawLater.drawNode();
22089 }
22090
22091 ctx.restore();
22092
22093 if (drawLater.drawExternalLabel) {
22094 // Guard the external label (above arrows) drawing function.
22095 var drawExternalLabel = drawLater.drawExternalLabel;
22096
22097 drawLater.drawExternalLabel = function () {
22098 ctx.save();
22099 drawExternalLabel();
22100 ctx.restore();
22101 };
22102 }
22103
22104 if (drawLater.nodeDimensions) {
22105 this.customSizeWidth = drawLater.nodeDimensions.width;
22106 this.customSizeHeight = drawLater.nodeDimensions.height;
22107 }
22108
22109 return drawLater;
22110 }
22111 /**
22112 *
22113 * @param {CanvasRenderingContext2D} ctx
22114 * @param {number} angle
22115 * @returns {number}
22116 */
22117
22118 }, {
22119 key: "distanceToBorder",
22120 value: function distanceToBorder(ctx, angle) {
22121 return this._distanceToBorder(ctx, angle);
22122 }
22123 }]);
22124
22125 return CustomShape;
22126}(ShapeBase);
22127
22128function _createSuper$m(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$m(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22129
22130function _isNativeReflectConstruct$m() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22131/**
22132 * A Database Node/Cluster shape.
22133 *
22134 * @augments NodeBase
22135 */
22136
22137var Database = /*#__PURE__*/function (_NodeBase) {
22138 _inherits(Database, _NodeBase);
22139
22140 var _super = _createSuper$m(Database);
22141
22142 /**
22143 * @param {object} options
22144 * @param {object} body
22145 * @param {Label} labelModule
22146 */
22147 function Database(options, body, labelModule) {
22148 var _this;
22149
22150 _classCallCheck(this, Database);
22151
22152 _this = _super.call(this, options, body, labelModule);
22153
22154 _this._setMargins(labelModule);
22155
22156 return _this;
22157 }
22158 /**
22159 *
22160 * @param {CanvasRenderingContext2D} ctx
22161 * @param {boolean} selected
22162 * @param {boolean} hover
22163 */
22164
22165
22166 _createClass(Database, [{
22167 key: "resize",
22168 value: function resize(ctx, selected, hover) {
22169 if (this.needsRefresh(selected, hover)) {
22170 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
22171 var size = dimensions.width + this.margin.right + this.margin.left;
22172 this.width = size;
22173 this.height = size;
22174 this.radius = this.width / 2;
22175 }
22176 }
22177 /**
22178 *
22179 * @param {CanvasRenderingContext2D} ctx
22180 * @param {number} x width
22181 * @param {number} y height
22182 * @param {boolean} selected
22183 * @param {boolean} hover
22184 * @param {ArrowOptions} values
22185 */
22186
22187 }, {
22188 key: "draw",
22189 value: function draw(ctx, x, y, selected, hover, values) {
22190 this.resize(ctx, selected, hover);
22191 this.left = x - this.width / 2;
22192 this.top = y - this.height / 2;
22193 this.initContextForDraw(ctx, values);
22194 drawDatabase(ctx, x - this.width / 2, y - this.height / 2, this.width, this.height);
22195 this.performFill(ctx, values);
22196 this.updateBoundingBox(x, y, ctx, selected, hover);
22197 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
22198 }
22199 /**
22200 *
22201 * @param {CanvasRenderingContext2D} ctx
22202 * @param {number} angle
22203 * @returns {number}
22204 */
22205
22206 }, {
22207 key: "distanceToBorder",
22208 value: function distanceToBorder(ctx, angle) {
22209 return this._distanceToBorder(ctx, angle);
22210 }
22211 }]);
22212
22213 return Database;
22214}(NodeBase);
22215
22216function _createSuper$l(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$l(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22217
22218function _isNativeReflectConstruct$l() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22219/**
22220 * A Diamond Node/Cluster shape.
22221 *
22222 * @augments ShapeBase
22223 */
22224
22225var Diamond$1 = /*#__PURE__*/function (_ShapeBase) {
22226 _inherits(Diamond, _ShapeBase);
22227
22228 var _super = _createSuper$l(Diamond);
22229
22230 /**
22231 * @param {object} options
22232 * @param {object} body
22233 * @param {Label} labelModule
22234 */
22235 function Diamond(options, body, labelModule) {
22236 _classCallCheck(this, Diamond);
22237
22238 return _super.call(this, options, body, labelModule);
22239 }
22240 /**
22241 *
22242 * @param {CanvasRenderingContext2D} ctx
22243 * @param {number} x width
22244 * @param {number} y height
22245 * @param {boolean} selected
22246 * @param {boolean} hover
22247 * @param {ArrowOptions} values
22248 *
22249 * @returns {object} Callbacks to draw later on higher layers.
22250 */
22251
22252
22253 _createClass(Diamond, [{
22254 key: "draw",
22255 value: function draw(ctx, x, y, selected, hover, values) {
22256 return this._drawShape(ctx, "diamond", 4, x, y, selected, hover, values);
22257 }
22258 /**
22259 *
22260 * @param {CanvasRenderingContext2D} ctx
22261 * @param {number} angle
22262 * @returns {number}
22263 */
22264
22265 }, {
22266 key: "distanceToBorder",
22267 value: function distanceToBorder(ctx, angle) {
22268 return this._distanceToBorder(ctx, angle);
22269 }
22270 }]);
22271
22272 return Diamond;
22273}(ShapeBase);
22274
22275function _createSuper$k(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$k(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22276
22277function _isNativeReflectConstruct$k() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22278/**
22279 * A Dot Node/Cluster shape.
22280 *
22281 * @augments ShapeBase
22282 */
22283
22284var Dot = /*#__PURE__*/function (_ShapeBase) {
22285 _inherits(Dot, _ShapeBase);
22286
22287 var _super = _createSuper$k(Dot);
22288
22289 /**
22290 * @param {object} options
22291 * @param {object} body
22292 * @param {Label} labelModule
22293 */
22294 function Dot(options, body, labelModule) {
22295 _classCallCheck(this, Dot);
22296
22297 return _super.call(this, options, body, labelModule);
22298 }
22299 /**
22300 *
22301 * @param {CanvasRenderingContext2D} ctx
22302 * @param {number} x width
22303 * @param {number} y height
22304 * @param {boolean} selected
22305 * @param {boolean} hover
22306 * @param {ArrowOptions} values
22307 *
22308 * @returns {object} Callbacks to draw later on higher layers.
22309 */
22310
22311
22312 _createClass(Dot, [{
22313 key: "draw",
22314 value: function draw(ctx, x, y, selected, hover, values) {
22315 return this._drawShape(ctx, "circle", 2, x, y, selected, hover, values);
22316 }
22317 /**
22318 *
22319 * @param {CanvasRenderingContext2D} ctx
22320 * @returns {number}
22321 */
22322
22323 }, {
22324 key: "distanceToBorder",
22325 value: function distanceToBorder(ctx) {
22326 if (ctx) {
22327 this.resize(ctx);
22328 }
22329
22330 return this.options.size;
22331 }
22332 }]);
22333
22334 return Dot;
22335}(ShapeBase);
22336
22337function _createSuper$j(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$j(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22338
22339function _isNativeReflectConstruct$j() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22340/**
22341 * Am Ellipse Node/Cluster shape.
22342 *
22343 * @augments NodeBase
22344 */
22345
22346var Ellipse = /*#__PURE__*/function (_NodeBase) {
22347 _inherits(Ellipse, _NodeBase);
22348
22349 var _super = _createSuper$j(Ellipse);
22350
22351 /**
22352 * @param {object} options
22353 * @param {object} body
22354 * @param {Label} labelModule
22355 */
22356 function Ellipse(options, body, labelModule) {
22357 _classCallCheck(this, Ellipse);
22358
22359 return _super.call(this, options, body, labelModule);
22360 }
22361 /**
22362 *
22363 * @param {CanvasRenderingContext2D} ctx
22364 * @param {boolean} [selected]
22365 * @param {boolean} [hover]
22366 */
22367
22368
22369 _createClass(Ellipse, [{
22370 key: "resize",
22371 value: function resize(ctx) {
22372 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
22373 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
22374
22375 if (this.needsRefresh(selected, hover)) {
22376 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
22377 this.height = dimensions.height * 2;
22378 this.width = dimensions.width + dimensions.height;
22379 this.radius = 0.5 * this.width;
22380 }
22381 }
22382 /**
22383 *
22384 * @param {CanvasRenderingContext2D} ctx
22385 * @param {number} x width
22386 * @param {number} y height
22387 * @param {boolean} selected
22388 * @param {boolean} hover
22389 * @param {ArrowOptions} values
22390 */
22391
22392 }, {
22393 key: "draw",
22394 value: function draw(ctx, x, y, selected, hover, values) {
22395 this.resize(ctx, selected, hover);
22396 this.left = x - this.width * 0.5;
22397 this.top = y - this.height * 0.5;
22398 this.initContextForDraw(ctx, values);
22399 drawEllipse(ctx, this.left, this.top, this.width, this.height);
22400 this.performFill(ctx, values);
22401 this.updateBoundingBox(x, y, ctx, selected, hover);
22402 this.labelModule.draw(ctx, x, y, selected, hover);
22403 }
22404 /**
22405 *
22406 * @param {CanvasRenderingContext2D} ctx
22407 * @param {number} angle
22408 * @returns {number}
22409 */
22410
22411 }, {
22412 key: "distanceToBorder",
22413 value: function distanceToBorder(ctx, angle) {
22414 if (ctx) {
22415 this.resize(ctx);
22416 }
22417
22418 var a = this.width * 0.5;
22419 var b = this.height * 0.5;
22420 var w = Math.sin(angle) * a;
22421 var h = Math.cos(angle) * b;
22422 return a * b / Math.sqrt(w * w + h * h);
22423 }
22424 }]);
22425
22426 return Ellipse;
22427}(NodeBase);
22428
22429function _createSuper$i(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$i(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22430
22431function _isNativeReflectConstruct$i() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22432/**
22433 * An icon replacement for the default Node shape.
22434 *
22435 * @augments NodeBase
22436 */
22437
22438var Icon = /*#__PURE__*/function (_NodeBase) {
22439 _inherits(Icon, _NodeBase);
22440
22441 var _super = _createSuper$i(Icon);
22442
22443 /**
22444 * @param {object} options
22445 * @param {object} body
22446 * @param {Label} labelModule
22447 */
22448 function Icon(options, body, labelModule) {
22449 var _this;
22450
22451 _classCallCheck(this, Icon);
22452
22453 _this = _super.call(this, options, body, labelModule);
22454
22455 _this._setMargins(labelModule);
22456
22457 return _this;
22458 }
22459 /**
22460 *
22461 * @param {CanvasRenderingContext2D} ctx - Unused.
22462 * @param {boolean} [selected]
22463 * @param {boolean} [hover]
22464 */
22465
22466
22467 _createClass(Icon, [{
22468 key: "resize",
22469 value: function resize(ctx, selected, hover) {
22470 if (this.needsRefresh(selected, hover)) {
22471 this.iconSize = {
22472 width: Number(this.options.icon.size),
22473 height: Number(this.options.icon.size)
22474 };
22475 this.width = this.iconSize.width + this.margin.right + this.margin.left;
22476 this.height = this.iconSize.height + this.margin.top + this.margin.bottom;
22477 this.radius = 0.5 * this.width;
22478 }
22479 }
22480 /**
22481 *
22482 * @param {CanvasRenderingContext2D} ctx
22483 * @param {number} x width
22484 * @param {number} y height
22485 * @param {boolean} selected
22486 * @param {boolean} hover
22487 * @param {ArrowOptions} values
22488 *
22489 * @returns {object} Callbacks to draw later on higher layers.
22490 */
22491
22492 }, {
22493 key: "draw",
22494 value: function draw(ctx, x, y, selected, hover, values) {
22495 var _this2 = this;
22496
22497 this.resize(ctx, selected, hover);
22498 this.options.icon.size = this.options.icon.size || 50;
22499 this.left = x - this.width / 2;
22500 this.top = y - this.height / 2;
22501
22502 this._icon(ctx, x, y, selected, hover, values);
22503
22504 return {
22505 drawExternalLabel: function drawExternalLabel() {
22506 if (_this2.options.label !== undefined) {
22507 var iconTextSpacing = 5;
22508
22509 _this2.labelModule.draw(ctx, _this2.left + _this2.iconSize.width / 2 + _this2.margin.left, y + _this2.height / 2 + iconTextSpacing, selected);
22510 }
22511
22512 _this2.updateBoundingBox(x, y);
22513 }
22514 };
22515 }
22516 /**
22517 *
22518 * @param {number} x
22519 * @param {number} y
22520 */
22521
22522 }, {
22523 key: "updateBoundingBox",
22524 value: function updateBoundingBox(x, y) {
22525 this.boundingBox.top = y - this.options.icon.size * 0.5;
22526 this.boundingBox.left = x - this.options.icon.size * 0.5;
22527 this.boundingBox.right = x + this.options.icon.size * 0.5;
22528 this.boundingBox.bottom = y + this.options.icon.size * 0.5;
22529
22530 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
22531 var iconTextSpacing = 5;
22532 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
22533 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
22534 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height + iconTextSpacing);
22535 }
22536 }
22537 /**
22538 *
22539 * @param {CanvasRenderingContext2D} ctx
22540 * @param {number} x width
22541 * @param {number} y height
22542 * @param {boolean} selected
22543 * @param {boolean} hover - Unused
22544 * @param {ArrowOptions} values
22545 */
22546
22547 }, {
22548 key: "_icon",
22549 value: function _icon(ctx, x, y, selected, hover, values) {
22550 var iconSize = Number(this.options.icon.size);
22551
22552 if (this.options.icon.code !== undefined) {
22553 ctx.font = [this.options.icon.weight != null ? this.options.icon.weight : selected ? "bold" : "", // If the weight is forced (for example to make Font Awesome 5 work
22554 // properly) substitute slightly bigger size for bold font face.
22555 (this.options.icon.weight != null && selected ? 5 : 0) + iconSize + "px", this.options.icon.face].join(" "); // draw icon
22556
22557 ctx.fillStyle = this.options.icon.color || "black";
22558 ctx.textAlign = "center";
22559 ctx.textBaseline = "middle"; // draw shadow if enabled
22560
22561 this.enableShadow(ctx, values);
22562 ctx.fillText(this.options.icon.code, x, y); // disable shadows for other elements.
22563
22564 this.disableShadow(ctx, values);
22565 } else {
22566 console.error("When using the icon shape, you need to define the code in the icon options object. This can be done per node or globally.");
22567 }
22568 }
22569 /**
22570 *
22571 * @param {CanvasRenderingContext2D} ctx
22572 * @param {number} angle
22573 * @returns {number}
22574 */
22575
22576 }, {
22577 key: "distanceToBorder",
22578 value: function distanceToBorder(ctx, angle) {
22579 return this._distanceToBorder(ctx, angle);
22580 }
22581 }]);
22582
22583 return Icon;
22584}(NodeBase);
22585
22586function _createSuper$h(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$h(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22587
22588function _isNativeReflectConstruct$h() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22589/**
22590 * An image-based replacement for the default Node shape.
22591 *
22592 * @augments CircleImageBase
22593 */
22594
22595var Image$2 = /*#__PURE__*/function (_CircleImageBase) {
22596 _inherits(Image, _CircleImageBase);
22597
22598 var _super = _createSuper$h(Image);
22599
22600 /**
22601 * @param {object} options
22602 * @param {object} body
22603 * @param {Label} labelModule
22604 * @param {Image} imageObj
22605 * @param {Image} imageObjAlt
22606 */
22607 function Image(options, body, labelModule, imageObj, imageObjAlt) {
22608 var _this;
22609
22610 _classCallCheck(this, Image);
22611
22612 _this = _super.call(this, options, body, labelModule);
22613
22614 _this.setImages(imageObj, imageObjAlt);
22615
22616 return _this;
22617 }
22618 /**
22619 *
22620 * @param {CanvasRenderingContext2D} ctx - Unused.
22621 * @param {boolean} [selected]
22622 * @param {boolean} [hover]
22623 */
22624
22625
22626 _createClass(Image, [{
22627 key: "resize",
22628 value: function resize(ctx) {
22629 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
22630 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
22631 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
22632
22633 if (imageAbsent) {
22634 var side = this.options.size * 2;
22635 this.width = side;
22636 this.height = side;
22637 return;
22638 }
22639
22640 if (this.needsRefresh(selected, hover)) {
22641 this._resizeImage();
22642 }
22643 }
22644 /**
22645 *
22646 * @param {CanvasRenderingContext2D} ctx
22647 * @param {number} x width
22648 * @param {number} y height
22649 * @param {boolean} selected
22650 * @param {boolean} hover
22651 * @param {ArrowOptions} values
22652 */
22653
22654 }, {
22655 key: "draw",
22656 value: function draw(ctx, x, y, selected, hover, values) {
22657 ctx.save();
22658 this.switchImages(selected);
22659 this.resize();
22660 var labelX = x,
22661 labelY = y;
22662
22663 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
22664 this.left = x;
22665 this.top = y;
22666 labelX += this.width / 2;
22667 labelY += this.height / 2;
22668 } else {
22669 this.left = x - this.width / 2;
22670 this.top = y - this.height / 2;
22671 }
22672
22673 if (this.options.shapeProperties.useBorderWithImage === true) {
22674 var neutralborderWidth = this.options.borderWidth;
22675 var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
22676 var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
22677 ctx.lineWidth = Math.min(this.width, borderWidth);
22678 ctx.beginPath();
22679 var strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
22680 var fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
22681
22682 if (values.opacity !== undefined) {
22683 strokeStyle = overrideOpacity(strokeStyle, values.opacity);
22684 fillStyle = overrideOpacity(fillStyle, values.opacity);
22685 } // setup the line properties.
22686
22687
22688 ctx.strokeStyle = strokeStyle; // set a fillstyle
22689
22690 ctx.fillStyle = fillStyle; // draw a rectangle to form the border around. This rectangle is filled so the opacity of a picture (in future vis releases?) can be used to tint the image
22691
22692 ctx.rect(this.left - 0.5 * ctx.lineWidth, this.top - 0.5 * ctx.lineWidth, this.width + ctx.lineWidth, this.height + ctx.lineWidth);
22693
22694 fill(ctx).call(ctx);
22695
22696 this.performStroke(ctx, values);
22697 ctx.closePath();
22698 }
22699
22700 this._drawImageAtPosition(ctx, values);
22701
22702 this._drawImageLabel(ctx, labelX, labelY, selected, hover);
22703
22704 this.updateBoundingBox(x, y);
22705 ctx.restore();
22706 }
22707 /**
22708 *
22709 * @param {number} x
22710 * @param {number} y
22711 */
22712
22713 }, {
22714 key: "updateBoundingBox",
22715 value: function updateBoundingBox(x, y) {
22716 this.resize();
22717
22718 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
22719 this.left = x;
22720 this.top = y;
22721 } else {
22722 this.left = x - this.width / 2;
22723 this.top = y - this.height / 2;
22724 }
22725
22726 this.boundingBox.left = this.left;
22727 this.boundingBox.top = this.top;
22728 this.boundingBox.bottom = this.top + this.height;
22729 this.boundingBox.right = this.left + this.width;
22730
22731 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
22732 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
22733 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
22734 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
22735 }
22736 }
22737 /**
22738 *
22739 * @param {CanvasRenderingContext2D} ctx
22740 * @param {number} angle
22741 * @returns {number}
22742 */
22743
22744 }, {
22745 key: "distanceToBorder",
22746 value: function distanceToBorder(ctx, angle) {
22747 return this._distanceToBorder(ctx, angle);
22748 }
22749 }]);
22750
22751 return Image;
22752}(CircleImageBase);
22753
22754function _createSuper$g(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$g(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22755
22756function _isNativeReflectConstruct$g() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22757/**
22758 * A Square Node/Cluster shape.
22759 *
22760 * @augments ShapeBase
22761 */
22762
22763var Square = /*#__PURE__*/function (_ShapeBase) {
22764 _inherits(Square, _ShapeBase);
22765
22766 var _super = _createSuper$g(Square);
22767
22768 /**
22769 * @param {object} options
22770 * @param {object} body
22771 * @param {Label} labelModule
22772 */
22773 function Square(options, body, labelModule) {
22774 _classCallCheck(this, Square);
22775
22776 return _super.call(this, options, body, labelModule);
22777 }
22778 /**
22779 *
22780 * @param {CanvasRenderingContext2D} ctx
22781 * @param {number} x width
22782 * @param {number} y height
22783 * @param {boolean} selected
22784 * @param {boolean} hover
22785 * @param {ArrowOptions} values
22786 *
22787 * @returns {object} Callbacks to draw later on higher layers.
22788 */
22789
22790
22791 _createClass(Square, [{
22792 key: "draw",
22793 value: function draw(ctx, x, y, selected, hover, values) {
22794 return this._drawShape(ctx, "square", 2, x, y, selected, hover, values);
22795 }
22796 /**
22797 *
22798 * @param {CanvasRenderingContext2D} ctx
22799 * @param {number} angle
22800 * @returns {number}
22801 */
22802
22803 }, {
22804 key: "distanceToBorder",
22805 value: function distanceToBorder(ctx, angle) {
22806 return this._distanceToBorder(ctx, angle);
22807 }
22808 }]);
22809
22810 return Square;
22811}(ShapeBase);
22812
22813function _createSuper$f(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$f(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22814
22815function _isNativeReflectConstruct$f() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22816/**
22817 * A Hexagon Node/Cluster shape.
22818 *
22819 * @augments ShapeBase
22820 */
22821
22822var Hexagon = /*#__PURE__*/function (_ShapeBase) {
22823 _inherits(Hexagon, _ShapeBase);
22824
22825 var _super = _createSuper$f(Hexagon);
22826
22827 /**
22828 * @param {object} options
22829 * @param {object} body
22830 * @param {Label} labelModule
22831 */
22832 function Hexagon(options, body, labelModule) {
22833 _classCallCheck(this, Hexagon);
22834
22835 return _super.call(this, options, body, labelModule);
22836 }
22837 /**
22838 *
22839 * @param {CanvasRenderingContext2D} ctx
22840 * @param {number} x width
22841 * @param {number} y height
22842 * @param {boolean} selected
22843 * @param {boolean} hover
22844 * @param {ArrowOptions} values
22845 *
22846 * @returns {object} Callbacks to draw later on higher layers.
22847 */
22848
22849
22850 _createClass(Hexagon, [{
22851 key: "draw",
22852 value: function draw(ctx, x, y, selected, hover, values) {
22853 return this._drawShape(ctx, "hexagon", 4, x, y, selected, hover, values);
22854 }
22855 /**
22856 *
22857 * @param {CanvasRenderingContext2D} ctx
22858 * @param {number} angle
22859 * @returns {number}
22860 */
22861
22862 }, {
22863 key: "distanceToBorder",
22864 value: function distanceToBorder(ctx, angle) {
22865 return this._distanceToBorder(ctx, angle);
22866 }
22867 }]);
22868
22869 return Hexagon;
22870}(ShapeBase);
22871
22872function _createSuper$e(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$e(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22873
22874function _isNativeReflectConstruct$e() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22875/**
22876 * A Star Node/Cluster shape.
22877 *
22878 * @augments ShapeBase
22879 */
22880
22881var Star = /*#__PURE__*/function (_ShapeBase) {
22882 _inherits(Star, _ShapeBase);
22883
22884 var _super = _createSuper$e(Star);
22885
22886 /**
22887 * @param {object} options
22888 * @param {object} body
22889 * @param {Label} labelModule
22890 */
22891 function Star(options, body, labelModule) {
22892 _classCallCheck(this, Star);
22893
22894 return _super.call(this, options, body, labelModule);
22895 }
22896 /**
22897 *
22898 * @param {CanvasRenderingContext2D} ctx
22899 * @param {number} x width
22900 * @param {number} y height
22901 * @param {boolean} selected
22902 * @param {boolean} hover
22903 * @param {ArrowOptions} values
22904 *
22905 * @returns {object} Callbacks to draw later on higher layers.
22906 */
22907
22908
22909 _createClass(Star, [{
22910 key: "draw",
22911 value: function draw(ctx, x, y, selected, hover, values) {
22912 return this._drawShape(ctx, "star", 4, x, y, selected, hover, values);
22913 }
22914 /**
22915 *
22916 * @param {CanvasRenderingContext2D} ctx
22917 * @param {number} angle
22918 * @returns {number}
22919 */
22920
22921 }, {
22922 key: "distanceToBorder",
22923 value: function distanceToBorder(ctx, angle) {
22924 return this._distanceToBorder(ctx, angle);
22925 }
22926 }]);
22927
22928 return Star;
22929}(ShapeBase);
22930
22931function _createSuper$d(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$d(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
22932
22933function _isNativeReflectConstruct$d() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
22934/**
22935 * A text-based replacement for the default Node shape.
22936 *
22937 * @augments NodeBase
22938 */
22939
22940var Text = /*#__PURE__*/function (_NodeBase) {
22941 _inherits(Text, _NodeBase);
22942
22943 var _super = _createSuper$d(Text);
22944
22945 /**
22946 * @param {object} options
22947 * @param {object} body
22948 * @param {Label} labelModule
22949 */
22950 function Text(options, body, labelModule) {
22951 var _this;
22952
22953 _classCallCheck(this, Text);
22954
22955 _this = _super.call(this, options, body, labelModule);
22956
22957 _this._setMargins(labelModule);
22958
22959 return _this;
22960 }
22961 /**
22962 *
22963 * @param {CanvasRenderingContext2D} ctx
22964 * @param {boolean} selected
22965 * @param {boolean} hover
22966 */
22967
22968
22969 _createClass(Text, [{
22970 key: "resize",
22971 value: function resize(ctx, selected, hover) {
22972 if (this.needsRefresh(selected, hover)) {
22973 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
22974 this.width = this.textSize.width + this.margin.right + this.margin.left;
22975 this.height = this.textSize.height + this.margin.top + this.margin.bottom;
22976 this.radius = 0.5 * this.width;
22977 }
22978 }
22979 /**
22980 *
22981 * @param {CanvasRenderingContext2D} ctx
22982 * @param {number} x width
22983 * @param {number} y height
22984 * @param {boolean} selected
22985 * @param {boolean} hover
22986 * @param {ArrowOptions} values
22987 */
22988
22989 }, {
22990 key: "draw",
22991 value: function draw(ctx, x, y, selected, hover, values) {
22992 this.resize(ctx, selected, hover);
22993 this.left = x - this.width / 2;
22994 this.top = y - this.height / 2; // draw shadow if enabled
22995
22996 this.enableShadow(ctx, values);
22997 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover); // disable shadows for other elements.
22998
22999 this.disableShadow(ctx, values);
23000 this.updateBoundingBox(x, y, ctx, selected, hover);
23001 }
23002 /**
23003 *
23004 * @param {CanvasRenderingContext2D} ctx
23005 * @param {number} angle
23006 * @returns {number}
23007 */
23008
23009 }, {
23010 key: "distanceToBorder",
23011 value: function distanceToBorder(ctx, angle) {
23012 return this._distanceToBorder(ctx, angle);
23013 }
23014 }]);
23015
23016 return Text;
23017}(NodeBase);
23018
23019function _createSuper$c(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$c(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
23020
23021function _isNativeReflectConstruct$c() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
23022/**
23023 * A Triangle Node/Cluster shape.
23024 *
23025 * @augments ShapeBase
23026 */
23027
23028var Triangle$1 = /*#__PURE__*/function (_ShapeBase) {
23029 _inherits(Triangle, _ShapeBase);
23030
23031 var _super = _createSuper$c(Triangle);
23032
23033 /**
23034 * @param {object} options
23035 * @param {object} body
23036 * @param {Label} labelModule
23037 */
23038 function Triangle(options, body, labelModule) {
23039 _classCallCheck(this, Triangle);
23040
23041 return _super.call(this, options, body, labelModule);
23042 }
23043 /**
23044 *
23045 * @param {CanvasRenderingContext2D} ctx
23046 * @param {number} x
23047 * @param {number} y
23048 * @param {boolean} selected
23049 * @param {boolean} hover
23050 * @param {ArrowOptions} values
23051 *
23052 * @returns {object} Callbacks to draw later on higher layers.
23053 */
23054
23055
23056 _createClass(Triangle, [{
23057 key: "draw",
23058 value: function draw(ctx, x, y, selected, hover, values) {
23059 return this._drawShape(ctx, "triangle", 3, x, y, selected, hover, values);
23060 }
23061 /**
23062 *
23063 * @param {CanvasRenderingContext2D} ctx
23064 * @param {number} angle
23065 * @returns {number}
23066 */
23067
23068 }, {
23069 key: "distanceToBorder",
23070 value: function distanceToBorder(ctx, angle) {
23071 return this._distanceToBorder(ctx, angle);
23072 }
23073 }]);
23074
23075 return Triangle;
23076}(ShapeBase);
23077
23078function _createSuper$b(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$b(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
23079
23080function _isNativeReflectConstruct$b() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
23081/**
23082 * A downward facing Triangle Node/Cluster shape.
23083 *
23084 * @augments ShapeBase
23085 */
23086
23087var TriangleDown = /*#__PURE__*/function (_ShapeBase) {
23088 _inherits(TriangleDown, _ShapeBase);
23089
23090 var _super = _createSuper$b(TriangleDown);
23091
23092 /**
23093 * @param {object} options
23094 * @param {object} body
23095 * @param {Label} labelModule
23096 */
23097 function TriangleDown(options, body, labelModule) {
23098 _classCallCheck(this, TriangleDown);
23099
23100 return _super.call(this, options, body, labelModule);
23101 }
23102 /**
23103 *
23104 * @param {CanvasRenderingContext2D} ctx
23105 * @param {number} x
23106 * @param {number} y
23107 * @param {boolean} selected
23108 * @param {boolean} hover
23109 * @param {ArrowOptions} values
23110 *
23111 * @returns {object} Callbacks to draw later on higher layers.
23112 */
23113
23114
23115 _createClass(TriangleDown, [{
23116 key: "draw",
23117 value: function draw(ctx, x, y, selected, hover, values) {
23118 return this._drawShape(ctx, "triangleDown", 3, x, y, selected, hover, values);
23119 }
23120 /**
23121 *
23122 * @param {CanvasRenderingContext2D} ctx
23123 * @param {number} angle
23124 * @returns {number}
23125 */
23126
23127 }, {
23128 key: "distanceToBorder",
23129 value: function distanceToBorder(ctx, angle) {
23130 return this._distanceToBorder(ctx, angle);
23131 }
23132 }]);
23133
23134 return TriangleDown;
23135}(ShapeBase);
23136
23137function ownKeys$2(object, enumerableOnly) { var keys = keys$3(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
23138
23139function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context5; forEach$2(_context5 = ownKeys$2(Object(source), true)).call(_context5, function (key) { _defineProperty(target, key, source[key]); }); } else if (getOwnPropertyDescriptors) { defineProperties(target, getOwnPropertyDescriptors(source)); } else { var _context6; forEach$2(_context6 = ownKeys$2(Object(source))).call(_context6, function (key) { defineProperty$5(target, key, getOwnPropertyDescriptor$2(source, key)); }); } } return target; }
23140/**
23141 * A node. A node can be connected to other nodes via one or multiple edges.
23142 */
23143
23144var Node = /*#__PURE__*/function () {
23145 /**
23146 *
23147 * @param {object} options An object containing options for the node. All
23148 * options are optional, except for the id.
23149 * {number} id Id of the node. Required
23150 * {string} label Text label for the node
23151 * {number} x Horizontal position of the node
23152 * {number} y Vertical position of the node
23153 * {string} shape Node shape
23154 * {string} image An image url
23155 * {string} title A title text, can be HTML
23156 * {anytype} group A group name or number
23157 *
23158 * @param {object} body Shared state of current network instance
23159 * @param {Network.Images} imagelist A list with images. Only needed when the node has an image
23160 * @param {Groups} grouplist A list with groups. Needed for retrieving group options
23161 * @param {object} globalOptions Current global node options; these serve as defaults for the node instance
23162 * @param {object} defaultOptions Global default options for nodes; note that this is also the prototype
23163 * for parameter `globalOptions`.
23164 */
23165 function Node(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
23166 _classCallCheck(this, Node);
23167
23168 this.options = bridgeObject(globalOptions);
23169 this.globalOptions = globalOptions;
23170 this.defaultOptions = defaultOptions;
23171 this.body = body;
23172 this.edges = []; // all edges connected to this node
23173 // set defaults for the options
23174
23175 this.id = undefined;
23176 this.imagelist = imagelist;
23177 this.grouplist = grouplist; // state options
23178
23179 this.x = undefined;
23180 this.y = undefined;
23181 this.baseSize = this.options.size;
23182 this.baseFontSize = this.options.font.size;
23183 this.predefinedPosition = false; // used to check if initial fit should just take the range or approximate
23184
23185 this.selected = false;
23186 this.hover = false;
23187 this.labelModule = new Label(this.body, this.options, false
23188 /* Not edge label */
23189 );
23190 this.setOptions(options);
23191 }
23192 /**
23193 * Attach a edge to the node
23194 *
23195 * @param {Edge} edge
23196 */
23197
23198
23199 _createClass(Node, [{
23200 key: "attachEdge",
23201 value: function attachEdge(edge) {
23202 var _context;
23203
23204 if (indexOf(_context = this.edges).call(_context, edge) === -1) {
23205 this.edges.push(edge);
23206 }
23207 }
23208 /**
23209 * Detach a edge from the node
23210 *
23211 * @param {Edge} edge
23212 */
23213
23214 }, {
23215 key: "detachEdge",
23216 value: function detachEdge(edge) {
23217 var _context2;
23218
23219 var index = indexOf(_context2 = this.edges).call(_context2, edge);
23220
23221 if (index != -1) {
23222 var _context3;
23223
23224 splice(_context3 = this.edges).call(_context3, index, 1);
23225 }
23226 }
23227 /**
23228 * Set or overwrite options for the node
23229 *
23230 * @param {object} options an object with options
23231 * @returns {null|boolean}
23232 */
23233
23234 }, {
23235 key: "setOptions",
23236 value: function setOptions(options) {
23237 var currentShape = this.options.shape;
23238
23239 if (!options) {
23240 return; // Note that the return value will be 'undefined'! This is OK.
23241 } // Save the color for later.
23242 // This is necessary in order to prevent local color from being overwritten by group color.
23243 // TODO: To prevent such workarounds the way options are handled should be rewritten from scratch.
23244 // This is not the only problem with current options handling.
23245
23246
23247 if (typeof options.color !== "undefined") {
23248 this._localColor = options.color;
23249 } // basic options
23250
23251
23252 if (options.id !== undefined) {
23253 this.id = options.id;
23254 }
23255
23256 if (this.id === undefined) {
23257 throw new Error("Node must have an id");
23258 }
23259
23260 Node.checkMass(options, this.id); // set these options locally
23261 // clear x and y positions
23262
23263 if (options.x !== undefined) {
23264 if (options.x === null) {
23265 this.x = undefined;
23266 this.predefinedPosition = false;
23267 } else {
23268 this.x = _parseInt(options.x);
23269 this.predefinedPosition = true;
23270 }
23271 }
23272
23273 if (options.y !== undefined) {
23274 if (options.y === null) {
23275 this.y = undefined;
23276 this.predefinedPosition = false;
23277 } else {
23278 this.y = _parseInt(options.y);
23279 this.predefinedPosition = true;
23280 }
23281 }
23282
23283 if (options.size !== undefined) {
23284 this.baseSize = options.size;
23285 }
23286
23287 if (options.value !== undefined) {
23288 options.value = _parseFloat(options.value);
23289 } // this transforms all shorthands into fully defined options
23290
23291
23292 Node.parseOptions(this.options, options, true, this.globalOptions, this.grouplist);
23293 var pile = [options, this.options, this.defaultOptions];
23294 this.chooser = choosify("node", pile);
23295
23296 this._load_images();
23297
23298 this.updateLabelModule(options); // Need to set local opacity after `this.updateLabelModule(options);` because `this.updateLabelModule(options);` overrites local opacity with group opacity
23299
23300 if (options.opacity !== undefined && Node.checkOpacity(options.opacity)) {
23301 this.options.opacity = options.opacity;
23302 }
23303
23304 this.updateShape(currentShape);
23305 return options.hidden !== undefined || options.physics !== undefined;
23306 }
23307 /**
23308 * Load the images from the options, for the nodes that need them.
23309 *
23310 * Images are always loaded, even if they are not used in the current shape.
23311 * The user may switch to an image shape later on.
23312 *
23313 * @private
23314 */
23315
23316 }, {
23317 key: "_load_images",
23318 value: function _load_images() {
23319 if (this.options.shape === "circularImage" || this.options.shape === "image") {
23320 if (this.options.image === undefined) {
23321 throw new Error("Option image must be defined for node type '" + this.options.shape + "'");
23322 }
23323 }
23324
23325 if (this.options.image === undefined) {
23326 return;
23327 }
23328
23329 if (this.imagelist === undefined) {
23330 throw new Error("Internal Error: No images provided");
23331 }
23332
23333 if (typeof this.options.image === "string") {
23334 this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
23335 } else {
23336 if (this.options.image.unselected === undefined) {
23337 throw new Error("No unselected image provided");
23338 }
23339
23340 this.imageObj = this.imagelist.load(this.options.image.unselected, this.options.brokenImage, this.id);
23341
23342 if (this.options.image.selected !== undefined) {
23343 this.imageObjAlt = this.imagelist.load(this.options.image.selected, this.options.brokenImage, this.id);
23344 } else {
23345 this.imageObjAlt = undefined;
23346 }
23347 }
23348 }
23349 /**
23350 * Check that opacity is only between 0 and 1
23351 *
23352 * @param {number} opacity
23353 * @returns {boolean}
23354 */
23355
23356 }, {
23357 key: "getFormattingValues",
23358 value:
23359 /**
23360 *
23361 * @returns {{color: *, borderWidth: *, borderColor: *, size: *, borderDashes: (boolean|Array|allOptions.nodes.shapeProperties.borderDashes|{boolean, array}), borderRadius: (number|allOptions.nodes.shapeProperties.borderRadius|{number}|Array), shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *}}
23362 */
23363 function getFormattingValues() {
23364 var values = {
23365 color: this.options.color.background,
23366 opacity: this.options.opacity,
23367 borderWidth: this.options.borderWidth,
23368 borderColor: this.options.color.border,
23369 size: this.options.size,
23370 borderDashes: this.options.shapeProperties.borderDashes,
23371 borderRadius: this.options.shapeProperties.borderRadius,
23372 shadow: this.options.shadow.enabled,
23373 shadowColor: this.options.shadow.color,
23374 shadowSize: this.options.shadow.size,
23375 shadowX: this.options.shadow.x,
23376 shadowY: this.options.shadow.y
23377 };
23378
23379 if (this.selected || this.hover) {
23380 if (this.chooser === true) {
23381 if (this.selected) {
23382 if (this.options.borderWidthSelected != null) {
23383 values.borderWidth = this.options.borderWidthSelected;
23384 } else {
23385 values.borderWidth *= 2;
23386 }
23387
23388 values.color = this.options.color.highlight.background;
23389 values.borderColor = this.options.color.highlight.border;
23390 values.shadow = this.options.shadow.enabled;
23391 } else if (this.hover) {
23392 values.color = this.options.color.hover.background;
23393 values.borderColor = this.options.color.hover.border;
23394 values.shadow = this.options.shadow.enabled;
23395 }
23396 } else if (typeof this.chooser === "function") {
23397 this.chooser(values, this.options.id, this.selected, this.hover);
23398
23399 if (values.shadow === false) {
23400 if (values.shadowColor !== this.options.shadow.color || values.shadowSize !== this.options.shadow.size || values.shadowX !== this.options.shadow.x || values.shadowY !== this.options.shadow.y) {
23401 values.shadow = true;
23402 }
23403 }
23404 }
23405 } else {
23406 values.shadow = this.options.shadow.enabled;
23407 }
23408
23409 if (this.options.opacity !== undefined) {
23410 var opacity = this.options.opacity;
23411 values.borderColor = overrideOpacity(values.borderColor, opacity);
23412 values.color = overrideOpacity(values.color, opacity);
23413 values.shadowColor = overrideOpacity(values.shadowColor, opacity);
23414 }
23415
23416 return values;
23417 }
23418 /**
23419 *
23420 * @param {object} options
23421 */
23422
23423 }, {
23424 key: "updateLabelModule",
23425 value: function updateLabelModule(options) {
23426 if (this.options.label === undefined || this.options.label === null) {
23427 this.options.label = "";
23428 }
23429
23430 Node.updateGroupOptions(this.options, _objectSpread$2(_objectSpread$2({}, options), {}, {
23431 color: options && options.color || this._localColor || undefined
23432 }), this.grouplist); //
23433 // Note:The prototype chain for this.options is:
23434 //
23435 // this.options -> NodesHandler.options -> NodesHandler.defaultOptions
23436 // (also: this.globalOptions)
23437 //
23438 // Note that the prototypes are mentioned explicitly in the pile list below;
23439 // WE DON'T WANT THE ORDER OF THE PROTOTYPES!!!! At least, not for font handling of labels.
23440 // This is a good indication that the prototype usage of options is deficient.
23441 //
23442
23443 var currentGroup = this.grouplist.get(this.options.group, false);
23444 var pile = [options, // new options
23445 this.options, // current node options, see comment above for prototype
23446 currentGroup, // group options, if any
23447 this.globalOptions, // Currently set global node options
23448 this.defaultOptions // Default global node options
23449 ];
23450 this.labelModule.update(this.options, pile);
23451
23452 if (this.labelModule.baseSize !== undefined) {
23453 this.baseFontSize = this.labelModule.baseSize;
23454 }
23455 }
23456 /**
23457 *
23458 * @param {string} currentShape
23459 */
23460
23461 }, {
23462 key: "updateShape",
23463 value: function updateShape(currentShape) {
23464 if (currentShape === this.options.shape && this.shape) {
23465 this.shape.setOptions(this.options, this.imageObj, this.imageObjAlt);
23466 } else {
23467 // choose draw method depending on the shape
23468 switch (this.options.shape) {
23469 case "box":
23470 this.shape = new Box$1(this.options, this.body, this.labelModule);
23471 break;
23472
23473 case "circle":
23474 this.shape = new Circle$1(this.options, this.body, this.labelModule);
23475 break;
23476
23477 case "circularImage":
23478 this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
23479 break;
23480
23481 case "custom":
23482 this.shape = new CustomShape(this.options, this.body, this.labelModule, this.options.ctxRenderer);
23483 break;
23484
23485 case "database":
23486 this.shape = new Database(this.options, this.body, this.labelModule);
23487 break;
23488
23489 case "diamond":
23490 this.shape = new Diamond$1(this.options, this.body, this.labelModule);
23491 break;
23492
23493 case "dot":
23494 this.shape = new Dot(this.options, this.body, this.labelModule);
23495 break;
23496
23497 case "ellipse":
23498 this.shape = new Ellipse(this.options, this.body, this.labelModule);
23499 break;
23500
23501 case "icon":
23502 this.shape = new Icon(this.options, this.body, this.labelModule);
23503 break;
23504
23505 case "image":
23506 this.shape = new Image$2(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
23507 break;
23508
23509 case "square":
23510 this.shape = new Square(this.options, this.body, this.labelModule);
23511 break;
23512
23513 case "hexagon":
23514 this.shape = new Hexagon(this.options, this.body, this.labelModule);
23515 break;
23516
23517 case "star":
23518 this.shape = new Star(this.options, this.body, this.labelModule);
23519 break;
23520
23521 case "text":
23522 this.shape = new Text(this.options, this.body, this.labelModule);
23523 break;
23524
23525 case "triangle":
23526 this.shape = new Triangle$1(this.options, this.body, this.labelModule);
23527 break;
23528
23529 case "triangleDown":
23530 this.shape = new TriangleDown(this.options, this.body, this.labelModule);
23531 break;
23532
23533 default:
23534 this.shape = new Ellipse(this.options, this.body, this.labelModule);
23535 break;
23536 }
23537 }
23538
23539 this.needsRefresh();
23540 }
23541 /**
23542 * select this node
23543 */
23544
23545 }, {
23546 key: "select",
23547 value: function select() {
23548 this.selected = true;
23549 this.needsRefresh();
23550 }
23551 /**
23552 * unselect this node
23553 */
23554
23555 }, {
23556 key: "unselect",
23557 value: function unselect() {
23558 this.selected = false;
23559 this.needsRefresh();
23560 }
23561 /**
23562 * Reset the calculated size of the node, forces it to recalculate its size
23563 */
23564
23565 }, {
23566 key: "needsRefresh",
23567 value: function needsRefresh() {
23568 this.shape.refreshNeeded = true;
23569 }
23570 /**
23571 * get the title of this node.
23572 *
23573 * @returns {string} title The title of the node, or undefined when no title
23574 * has been set.
23575 */
23576
23577 }, {
23578 key: "getTitle",
23579 value: function getTitle() {
23580 return this.options.title;
23581 }
23582 /**
23583 * Calculate the distance to the border of the Node
23584 *
23585 * @param {CanvasRenderingContext2D} ctx
23586 * @param {number} angle Angle in radians
23587 * @returns {number} distance Distance to the border in pixels
23588 */
23589
23590 }, {
23591 key: "distanceToBorder",
23592 value: function distanceToBorder(ctx, angle) {
23593 return this.shape.distanceToBorder(ctx, angle);
23594 }
23595 /**
23596 * Check if this node has a fixed x and y position
23597 *
23598 * @returns {boolean} true if fixed, false if not
23599 */
23600
23601 }, {
23602 key: "isFixed",
23603 value: function isFixed() {
23604 return this.options.fixed.x && this.options.fixed.y;
23605 }
23606 /**
23607 * check if this node is selecte
23608 *
23609 * @returns {boolean} selected True if node is selected, else false
23610 */
23611
23612 }, {
23613 key: "isSelected",
23614 value: function isSelected() {
23615 return this.selected;
23616 }
23617 /**
23618 * Retrieve the value of the node. Can be undefined
23619 *
23620 * @returns {number} value
23621 */
23622
23623 }, {
23624 key: "getValue",
23625 value: function getValue() {
23626 return this.options.value;
23627 }
23628 /**
23629 * Get the current dimensions of the label
23630 *
23631 * @returns {rect}
23632 */
23633
23634 }, {
23635 key: "getLabelSize",
23636 value: function getLabelSize() {
23637 return this.labelModule.size();
23638 }
23639 /**
23640 * Adjust the value range of the node. The node will adjust it's size
23641 * based on its value.
23642 *
23643 * @param {number} min
23644 * @param {number} max
23645 * @param {number} total
23646 */
23647
23648 }, {
23649 key: "setValueRange",
23650 value: function setValueRange(min, max, total) {
23651 if (this.options.value !== undefined) {
23652 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
23653 var sizeDiff = this.options.scaling.max - this.options.scaling.min;
23654
23655 if (this.options.scaling.label.enabled === true) {
23656 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
23657 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
23658 }
23659
23660 this.options.size = this.options.scaling.min + scale * sizeDiff;
23661 } else {
23662 this.options.size = this.baseSize;
23663 this.options.font.size = this.baseFontSize;
23664 }
23665
23666 this.updateLabelModule();
23667 }
23668 /**
23669 * Draw this node in the given canvas
23670 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
23671 *
23672 * @param {CanvasRenderingContext2D} ctx
23673 *
23674 * @returns {object} Callbacks to draw later on higher layers.
23675 */
23676
23677 }, {
23678 key: "draw",
23679 value: function draw(ctx) {
23680 var values = this.getFormattingValues();
23681 return this.shape.draw(ctx, this.x, this.y, this.selected, this.hover, values) || {};
23682 }
23683 /**
23684 * Update the bounding box of the shape
23685 *
23686 * @param {CanvasRenderingContext2D} ctx
23687 */
23688
23689 }, {
23690 key: "updateBoundingBox",
23691 value: function updateBoundingBox(ctx) {
23692 this.shape.updateBoundingBox(this.x, this.y, ctx);
23693 }
23694 /**
23695 * Recalculate the size of this node in the given canvas
23696 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
23697 *
23698 * @param {CanvasRenderingContext2D} ctx
23699 */
23700
23701 }, {
23702 key: "resize",
23703 value: function resize(ctx) {
23704 var values = this.getFormattingValues();
23705 this.shape.resize(ctx, this.selected, this.hover, values);
23706 }
23707 /**
23708 * Determine all visual elements of this node instance, in which the given
23709 * point falls within the bounding shape.
23710 *
23711 * @param {point} point
23712 * @returns {Array.<nodeClickItem|nodeLabelClickItem>} list with the items which are on the point
23713 */
23714
23715 }, {
23716 key: "getItemsOnPoint",
23717 value: function getItemsOnPoint(point) {
23718 var ret = [];
23719
23720 if (this.labelModule.visible()) {
23721 if (pointInRect(this.labelModule.getSize(), point)) {
23722 ret.push({
23723 nodeId: this.id,
23724 labelId: 0
23725 });
23726 }
23727 }
23728
23729 if (pointInRect(this.shape.boundingBox, point)) {
23730 ret.push({
23731 nodeId: this.id
23732 });
23733 }
23734
23735 return ret;
23736 }
23737 /**
23738 * Check if this object is overlapping with the provided object
23739 *
23740 * @param {object} obj an object with parameters left, top, right, bottom
23741 * @returns {boolean} True if location is located on node
23742 */
23743
23744 }, {
23745 key: "isOverlappingWith",
23746 value: function isOverlappingWith(obj) {
23747 return this.shape.left < obj.right && this.shape.left + this.shape.width > obj.left && this.shape.top < obj.bottom && this.shape.top + this.shape.height > obj.top;
23748 }
23749 /**
23750 * Check if this object is overlapping with the provided object
23751 *
23752 * @param {object} obj an object with parameters left, top, right, bottom
23753 * @returns {boolean} True if location is located on node
23754 */
23755
23756 }, {
23757 key: "isBoundingBoxOverlappingWith",
23758 value: function isBoundingBoxOverlappingWith(obj) {
23759 return this.shape.boundingBox.left < obj.right && this.shape.boundingBox.right > obj.left && this.shape.boundingBox.top < obj.bottom && this.shape.boundingBox.bottom > obj.top;
23760 }
23761 /**
23762 * Check valid values for mass
23763 *
23764 * The mass may not be negative or zero. If it is, reset to 1
23765 *
23766 * @param {object} options
23767 * @param {Node.id} id
23768 * @static
23769 */
23770
23771 }], [{
23772 key: "checkOpacity",
23773 value: function checkOpacity(opacity) {
23774 return 0 <= opacity && opacity <= 1;
23775 }
23776 /**
23777 * Check that origin is 'center' or 'top-left'
23778 *
23779 * @param {string} origin
23780 * @returns {boolean}
23781 */
23782
23783 }, {
23784 key: "checkCoordinateOrigin",
23785 value: function checkCoordinateOrigin(origin) {
23786 return origin === undefined || origin === "center" || origin === "top-left";
23787 }
23788 /**
23789 * Copy group option values into the node options.
23790 *
23791 * The group options override the global node options, so the copy of group options
23792 * must happen *after* the global node options have been set.
23793 *
23794 * This method must also be called also if the global node options have changed and the group options did not.
23795 *
23796 * @param {object} parentOptions
23797 * @param {object} newOptions new values for the options, currently only passed in for check
23798 * @param {object} groupList
23799 */
23800
23801 }, {
23802 key: "updateGroupOptions",
23803 value: function updateGroupOptions(parentOptions, newOptions, groupList) {
23804 var _context4;
23805
23806 if (groupList === undefined) return; // No groups, nothing to do
23807
23808 var group = parentOptions.group; // paranoia: the selected group is already merged into node options, check.
23809
23810 if (newOptions !== undefined && newOptions.group !== undefined && group !== newOptions.group) {
23811 throw new Error("updateGroupOptions: group values in options don't match.");
23812 }
23813
23814 var hasGroup = typeof group === "number" || typeof group === "string" && group != "";
23815 if (!hasGroup) return; // current node has no group, no need to merge
23816
23817 var groupObj = groupList.get(group);
23818
23819 if (groupObj.opacity !== undefined && newOptions.opacity === undefined) {
23820 if (!Node.checkOpacity(groupObj.opacity)) {
23821 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + groupObj.opacity);
23822 groupObj.opacity = undefined;
23823 }
23824 } // Skip any new option to avoid them being overridden by the group options.
23825
23826
23827 var skipProperties = filter(_context4 = getOwnPropertyNames(newOptions)).call(_context4, function (p) {
23828 return newOptions[p] != null;
23829 }); // Always skip merging group font options into parent; these are required to be distinct for labels
23830
23831
23832 skipProperties.push("font");
23833 selectiveNotDeepExtend(skipProperties, parentOptions, groupObj); // the color object needs to be completely defined.
23834 // Since groups can partially overwrite the colors, we parse it again, just in case.
23835
23836 parentOptions.color = parseColor(parentOptions.color);
23837 }
23838 /**
23839 * This process all possible shorthands in the new options and makes sure that the parentOptions are fully defined.
23840 * Static so it can also be used by the handler.
23841 *
23842 * @param {object} parentOptions
23843 * @param {object} newOptions
23844 * @param {boolean} [allowDeletion=false]
23845 * @param {object} [globalOptions={}]
23846 * @param {object} [groupList]
23847 * @static
23848 */
23849
23850 }, {
23851 key: "parseOptions",
23852 value: function parseOptions(parentOptions, newOptions) {
23853 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
23854 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
23855 var groupList = arguments.length > 4 ? arguments[4] : undefined;
23856 var fields = ["color", "fixed", "shadow"];
23857 selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);
23858 Node.checkMass(newOptions);
23859
23860 if (parentOptions.opacity !== undefined) {
23861 if (!Node.checkOpacity(parentOptions.opacity)) {
23862 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + parentOptions.opacity);
23863 parentOptions.opacity = undefined;
23864 }
23865 }
23866
23867 if (newOptions.opacity !== undefined) {
23868 if (!Node.checkOpacity(newOptions.opacity)) {
23869 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + newOptions.opacity);
23870 newOptions.opacity = undefined;
23871 }
23872 }
23873
23874 if (newOptions.shapeProperties && !Node.checkCoordinateOrigin(newOptions.shapeProperties.coordinateOrigin)) {
23875 console.error("Invalid option for node coordinateOrigin, found: " + newOptions.shapeProperties.coordinateOrigin);
23876 } // merge the shadow options into the parent.
23877
23878
23879 mergeOptions(parentOptions, newOptions, "shadow", globalOptions); // individual shape newOptions
23880
23881 if (newOptions.color !== undefined && newOptions.color !== null) {
23882 var parsedColor = parseColor(newOptions.color);
23883 fillIfDefined(parentOptions.color, parsedColor);
23884 } else if (allowDeletion === true && newOptions.color === null) {
23885 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
23886 } // handle the fixed options
23887
23888
23889 if (newOptions.fixed !== undefined && newOptions.fixed !== null) {
23890 if (typeof newOptions.fixed === "boolean") {
23891 parentOptions.fixed.x = newOptions.fixed;
23892 parentOptions.fixed.y = newOptions.fixed;
23893 } else {
23894 if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === "boolean") {
23895 parentOptions.fixed.x = newOptions.fixed.x;
23896 }
23897
23898 if (newOptions.fixed.y !== undefined && typeof newOptions.fixed.y === "boolean") {
23899 parentOptions.fixed.y = newOptions.fixed.y;
23900 }
23901 }
23902 }
23903
23904 if (allowDeletion === true && newOptions.font === null) {
23905 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
23906 }
23907
23908 Node.updateGroupOptions(parentOptions, newOptions, groupList); // handle the scaling options, specifically the label part
23909
23910 if (newOptions.scaling !== undefined) {
23911 mergeOptions(parentOptions.scaling, newOptions.scaling, "label", globalOptions.scaling);
23912 }
23913 }
23914 }, {
23915 key: "checkMass",
23916 value: function checkMass(options, id) {
23917 if (options.mass !== undefined && options.mass <= 0) {
23918 var strId = "";
23919
23920 if (id !== undefined) {
23921 strId = " in node id: " + id;
23922 }
23923
23924 console.error("%cNegative or zero mass disallowed" + strId + ", setting mass to 1.", VALIDATOR_PRINT_STYLE$1);
23925 options.mass = 1;
23926 }
23927 }
23928 }]);
23929
23930 return Node;
23931}();
23932
23933function _createForOfIteratorHelper$6(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (isArray(o) || (it = _unsupportedIterableToArray$6(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
23934
23935function _unsupportedIterableToArray$6(o, minLen) { var _context4; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$6(o, minLen); var n = slice$1(_context4 = Object.prototype.toString.call(o)).call(_context4, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from_1$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$6(o, minLen); }
23936
23937function _arrayLikeToArray$6(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
23938/**
23939 * Handler for Nodes
23940 */
23941
23942var NodesHandler = /*#__PURE__*/function () {
23943 /**
23944 * @param {object} body
23945 * @param {Images} images
23946 * @param {Array.<Group>} groups
23947 * @param {LayoutEngine} layoutEngine
23948 */
23949 function NodesHandler(body, images, groups, layoutEngine) {
23950 var _context,
23951 _this = this;
23952
23953 _classCallCheck(this, NodesHandler);
23954
23955 this.body = body;
23956 this.images = images;
23957 this.groups = groups;
23958 this.layoutEngine = layoutEngine; // create the node API in the body container
23959
23960 this.body.functions.createNode = bind(_context = this.create).call(_context, this);
23961 this.nodesListeners = {
23962 add: function add(event, params) {
23963 _this.add(params.items);
23964 },
23965 update: function update(event, params) {
23966 _this.update(params.items, params.data, params.oldData);
23967 },
23968 remove: function remove(event, params) {
23969 _this.remove(params.items);
23970 }
23971 };
23972 this.defaultOptions = {
23973 borderWidth: 1,
23974 borderWidthSelected: undefined,
23975 brokenImage: undefined,
23976 color: {
23977 border: "#2B7CE9",
23978 background: "#97C2FC",
23979 highlight: {
23980 border: "#2B7CE9",
23981 background: "#D2E5FF"
23982 },
23983 hover: {
23984 border: "#2B7CE9",
23985 background: "#D2E5FF"
23986 }
23987 },
23988 opacity: undefined,
23989 // number between 0 and 1
23990 fixed: {
23991 x: false,
23992 y: false
23993 },
23994 font: {
23995 color: "#343434",
23996 size: 14,
23997 // px
23998 face: "arial",
23999 background: "none",
24000 strokeWidth: 0,
24001 // px
24002 strokeColor: "#ffffff",
24003 align: "center",
24004 vadjust: 0,
24005 multi: false,
24006 bold: {
24007 mod: "bold"
24008 },
24009 boldital: {
24010 mod: "bold italic"
24011 },
24012 ital: {
24013 mod: "italic"
24014 },
24015 mono: {
24016 mod: "",
24017 size: 15,
24018 // px
24019 face: "monospace",
24020 vadjust: 2
24021 }
24022 },
24023 group: undefined,
24024 hidden: false,
24025 icon: {
24026 face: "FontAwesome",
24027 //'FontAwesome',
24028 code: undefined,
24029 //'\uf007',
24030 size: 50,
24031 //50,
24032 color: "#2B7CE9" //'#aa00ff'
24033
24034 },
24035 image: undefined,
24036 // --> URL
24037 imagePadding: {
24038 // only for image shape
24039 top: 0,
24040 right: 0,
24041 bottom: 0,
24042 left: 0
24043 },
24044 label: undefined,
24045 labelHighlightBold: true,
24046 level: undefined,
24047 margin: {
24048 top: 5,
24049 right: 5,
24050 bottom: 5,
24051 left: 5
24052 },
24053 mass: 1,
24054 physics: true,
24055 scaling: {
24056 min: 10,
24057 max: 30,
24058 label: {
24059 enabled: false,
24060 min: 14,
24061 max: 30,
24062 maxVisible: 30,
24063 drawThreshold: 5
24064 },
24065 customScalingFunction: function customScalingFunction(min, max, total, value) {
24066 if (max === min) {
24067 return 0.5;
24068 } else {
24069 var scale = 1 / (max - min);
24070 return Math.max(0, (value - min) * scale);
24071 }
24072 }
24073 },
24074 shadow: {
24075 enabled: false,
24076 color: "rgba(0,0,0,0.5)",
24077 size: 10,
24078 x: 5,
24079 y: 5
24080 },
24081 shape: "ellipse",
24082 shapeProperties: {
24083 borderDashes: false,
24084 // only for borders
24085 borderRadius: 6,
24086 // only for box shape
24087 interpolation: true,
24088 // only for image and circularImage shapes
24089 useImageSize: false,
24090 // only for image and circularImage shapes
24091 useBorderWithImage: false,
24092 // only for image shape
24093 coordinateOrigin: "center" // only for image and circularImage shapes
24094
24095 },
24096 size: 25,
24097 title: undefined,
24098 value: undefined,
24099 x: undefined,
24100 y: undefined
24101 }; // Protect from idiocy
24102
24103 if (this.defaultOptions.mass <= 0) {
24104 throw "Internal error: mass in defaultOptions of NodesHandler may not be zero or negative";
24105 }
24106
24107 this.options = bridgeObject(this.defaultOptions);
24108 this.bindEventListeners();
24109 }
24110 /**
24111 * Binds event listeners
24112 */
24113
24114
24115 _createClass(NodesHandler, [{
24116 key: "bindEventListeners",
24117 value: function bindEventListeners() {
24118 var _context2,
24119 _context3,
24120 _this2 = this;
24121
24122 // refresh the nodes. Used when reverting from hierarchical layout
24123 this.body.emitter.on("refreshNodes", bind(_context2 = this.refresh).call(_context2, this));
24124 this.body.emitter.on("refresh", bind(_context3 = this.refresh).call(_context3, this));
24125 this.body.emitter.on("destroy", function () {
24126 forEach$1(_this2.nodesListeners, function (callback, event) {
24127 if (_this2.body.data.nodes) _this2.body.data.nodes.off(event, callback);
24128 });
24129 delete _this2.body.functions.createNode;
24130 delete _this2.nodesListeners.add;
24131 delete _this2.nodesListeners.update;
24132 delete _this2.nodesListeners.remove;
24133 delete _this2.nodesListeners;
24134 });
24135 }
24136 /**
24137 *
24138 * @param {object} options
24139 */
24140
24141 }, {
24142 key: "setOptions",
24143 value: function setOptions(options) {
24144 if (options !== undefined) {
24145 Node.parseOptions(this.options, options); // Need to set opacity here because Node.parseOptions is also used for groups,
24146 // if you set opacity in Node.parseOptions it overwrites group opacity.
24147
24148 if (options.opacity !== undefined) {
24149 if (isNan(options.opacity) || !_isFinite(options.opacity) || options.opacity < 0 || options.opacity > 1) {
24150 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + options.opacity);
24151 } else {
24152 this.options.opacity = options.opacity;
24153 }
24154 } // update the shape in all nodes
24155
24156
24157 if (options.shape !== undefined) {
24158 for (var nodeId in this.body.nodes) {
24159 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
24160 this.body.nodes[nodeId].updateShape();
24161 }
24162 }
24163 } // Update the labels of nodes if any relevant options changed.
24164
24165
24166 if (typeof options.font !== "undefined" || typeof options.widthConstraint !== "undefined" || typeof options.heightConstraint !== "undefined") {
24167 for (var _i = 0, _Object$keys = keys$3(this.body.nodes); _i < _Object$keys.length; _i++) {
24168 var _nodeId = _Object$keys[_i];
24169
24170 this.body.nodes[_nodeId].updateLabelModule();
24171
24172 this.body.nodes[_nodeId].needsRefresh();
24173 }
24174 } // update the shape size in all nodes
24175
24176
24177 if (options.size !== undefined) {
24178 for (var _nodeId2 in this.body.nodes) {
24179 if (Object.prototype.hasOwnProperty.call(this.body.nodes, _nodeId2)) {
24180 this.body.nodes[_nodeId2].needsRefresh();
24181 }
24182 }
24183 } // update the state of the variables if needed
24184
24185
24186 if (options.hidden !== undefined || options.physics !== undefined) {
24187 this.body.emitter.emit("_dataChanged");
24188 }
24189 }
24190 }
24191 /**
24192 * Set a data set with nodes for the network
24193 *
24194 * @param {Array | DataSet | DataView} nodes The data containing the nodes.
24195 * @param {boolean} [doNotEmit=false] - Suppress data changed event.
24196 * @private
24197 */
24198
24199 }, {
24200 key: "setData",
24201 value: function setData(nodes) {
24202 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
24203 var oldNodesData = this.body.data.nodes;
24204
24205 if (isDataViewLike("id", nodes)) {
24206 this.body.data.nodes = nodes;
24207 } else if (isArray(nodes)) {
24208 this.body.data.nodes = new DataSet();
24209 this.body.data.nodes.add(nodes);
24210 } else if (!nodes) {
24211 this.body.data.nodes = new DataSet();
24212 } else {
24213 throw new TypeError("Array or DataSet expected");
24214 }
24215
24216 if (oldNodesData) {
24217 // unsubscribe from old dataset
24218 forEach$1(this.nodesListeners, function (callback, event) {
24219 oldNodesData.off(event, callback);
24220 });
24221 } // remove drawn nodes
24222
24223
24224 this.body.nodes = {};
24225
24226 if (this.body.data.nodes) {
24227 // subscribe to new dataset
24228 var me = this;
24229 forEach$1(this.nodesListeners, function (callback, event) {
24230 me.body.data.nodes.on(event, callback);
24231 }); // draw all new nodes
24232
24233 var ids = this.body.data.nodes.getIds();
24234 this.add(ids, true);
24235 }
24236
24237 if (doNotEmit === false) {
24238 this.body.emitter.emit("_dataChanged");
24239 }
24240 }
24241 /**
24242 * Add nodes
24243 *
24244 * @param {number[] | string[]} ids
24245 * @param {boolean} [doNotEmit=false]
24246 * @private
24247 */
24248
24249 }, {
24250 key: "add",
24251 value: function add(ids) {
24252 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
24253 var id;
24254 var newNodes = [];
24255
24256 for (var i = 0; i < ids.length; i++) {
24257 id = ids[i];
24258 var properties = this.body.data.nodes.get(id);
24259 var node = this.create(properties);
24260 newNodes.push(node);
24261 this.body.nodes[id] = node; // note: this may replace an existing node
24262 }
24263
24264 this.layoutEngine.positionInitially(newNodes);
24265
24266 if (doNotEmit === false) {
24267 this.body.emitter.emit("_dataChanged");
24268 }
24269 }
24270 /**
24271 * Update existing nodes, or create them when not yet existing
24272 *
24273 * @param {number[] | string[]} ids id's of changed nodes
24274 * @param {Array} changedData array with changed data
24275 * @param {Array|undefined} oldData optional; array with previous data
24276 * @private
24277 */
24278
24279 }, {
24280 key: "update",
24281 value: function update(ids, changedData, oldData) {
24282 var nodes = this.body.nodes;
24283 var dataChanged = false;
24284
24285 for (var i = 0; i < ids.length; i++) {
24286 var id = ids[i];
24287 var node = nodes[id];
24288 var data = changedData[i];
24289
24290 if (node !== undefined) {
24291 // update node
24292 if (node.setOptions(data)) {
24293 dataChanged = true;
24294 }
24295 } else {
24296 dataChanged = true; // create node
24297
24298 node = this.create(data);
24299 nodes[id] = node;
24300 }
24301 }
24302
24303 if (!dataChanged && oldData !== undefined) {
24304 // Check for any changes which should trigger a layout recalculation
24305 // For now, this is just 'level' for hierarchical layout
24306 // Assumption: old and new data arranged in same order; at time of writing, this holds.
24307 dataChanged = some(changedData).call(changedData, function (newValue, index) {
24308 var oldValue = oldData[index];
24309 return oldValue && oldValue.level !== newValue.level;
24310 });
24311 }
24312
24313 if (dataChanged === true) {
24314 this.body.emitter.emit("_dataChanged");
24315 } else {
24316 this.body.emitter.emit("_dataUpdated");
24317 }
24318 }
24319 /**
24320 * Remove existing nodes. If nodes do not exist, the method will just ignore it.
24321 *
24322 * @param {number[] | string[]} ids
24323 * @private
24324 */
24325
24326 }, {
24327 key: "remove",
24328 value: function remove(ids) {
24329 var nodes = this.body.nodes;
24330
24331 for (var i = 0; i < ids.length; i++) {
24332 var id = ids[i];
24333 delete nodes[id];
24334 }
24335
24336 this.body.emitter.emit("_dataChanged");
24337 }
24338 /**
24339 * create a node
24340 *
24341 * @param {object} properties
24342 * @param {class} [constructorClass=Node.default]
24343 * @returns {*}
24344 */
24345
24346 }, {
24347 key: "create",
24348 value: function create(properties) {
24349 var constructorClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Node;
24350 return new constructorClass(properties, this.body, this.images, this.groups, this.options, this.defaultOptions);
24351 }
24352 /**
24353 *
24354 * @param {boolean} [clearPositions=false]
24355 */
24356
24357 }, {
24358 key: "refresh",
24359 value: function refresh() {
24360 var _this3 = this;
24361
24362 var clearPositions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
24363 forEach$1(this.body.nodes, function (node, nodeId) {
24364 var data = _this3.body.data.nodes.get(nodeId);
24365
24366 if (data !== undefined) {
24367 if (clearPositions === true) {
24368 node.setOptions({
24369 x: null,
24370 y: null
24371 });
24372 }
24373
24374 node.setOptions({
24375 fixed: false
24376 });
24377 node.setOptions(data);
24378 }
24379 });
24380 }
24381 /**
24382 * Returns the positions of the nodes.
24383 *
24384 * @param {Array.<Node.id> | string} [ids] --> optional, can be array of nodeIds, can be string
24385 * @returns {{}}
24386 */
24387
24388 }, {
24389 key: "getPositions",
24390 value: function getPositions(ids) {
24391 var dataArray = {};
24392
24393 if (ids !== undefined) {
24394 if (isArray(ids) === true) {
24395 for (var i = 0; i < ids.length; i++) {
24396 if (this.body.nodes[ids[i]] !== undefined) {
24397 var node = this.body.nodes[ids[i]];
24398 dataArray[ids[i]] = {
24399 x: Math.round(node.x),
24400 y: Math.round(node.y)
24401 };
24402 }
24403 }
24404 } else {
24405 if (this.body.nodes[ids] !== undefined) {
24406 var _node = this.body.nodes[ids];
24407 dataArray[ids] = {
24408 x: Math.round(_node.x),
24409 y: Math.round(_node.y)
24410 };
24411 }
24412 }
24413 } else {
24414 for (var _i2 = 0; _i2 < this.body.nodeIndices.length; _i2++) {
24415 var _node2 = this.body.nodes[this.body.nodeIndices[_i2]];
24416 dataArray[this.body.nodeIndices[_i2]] = {
24417 x: Math.round(_node2.x),
24418 y: Math.round(_node2.y)
24419 };
24420 }
24421 }
24422
24423 return dataArray;
24424 }
24425 /**
24426 * Retrieves the x y position of a specific id.
24427 *
24428 * @param {string} id The id to retrieve.
24429 *
24430 * @throws {TypeError} If no id is included.
24431 * @throws {ReferenceError} If an invalid id is provided.
24432 *
24433 * @returns {{ x: number, y: number }} Returns X, Y canvas position of the node with given id.
24434 */
24435
24436 }, {
24437 key: "getPosition",
24438 value: function getPosition(id) {
24439 if (id == undefined) {
24440 throw new TypeError("No id was specified for getPosition method.");
24441 } else if (this.body.nodes[id] == undefined) {
24442 throw new ReferenceError("NodeId provided for getPosition does not exist. Provided: ".concat(id));
24443 } else {
24444 return {
24445 x: Math.round(this.body.nodes[id].x),
24446 y: Math.round(this.body.nodes[id].y)
24447 };
24448 }
24449 }
24450 /**
24451 * Load the XY positions of the nodes into the dataset.
24452 */
24453
24454 }, {
24455 key: "storePositions",
24456 value: function storePositions() {
24457 // todo: add support for clusters and hierarchical.
24458 var dataArray = [];
24459 var dataset = this.body.data.nodes.getDataSet();
24460
24461 var _iterator = _createForOfIteratorHelper$6(dataset.get()),
24462 _step;
24463
24464 try {
24465 for (_iterator.s(); !(_step = _iterator.n()).done;) {
24466 var dsNode = _step.value;
24467 var id = dsNode.id;
24468 var bodyNode = this.body.nodes[id];
24469 var x = Math.round(bodyNode.x);
24470 var y = Math.round(bodyNode.y);
24471
24472 if (dsNode.x !== x || dsNode.y !== y) {
24473 dataArray.push({
24474 id: id,
24475 x: x,
24476 y: y
24477 });
24478 }
24479 }
24480 } catch (err) {
24481 _iterator.e(err);
24482 } finally {
24483 _iterator.f();
24484 }
24485
24486 dataset.update(dataArray);
24487 }
24488 /**
24489 * get the bounding box of a node.
24490 *
24491 * @param {Node.id} nodeId
24492 * @returns {j|*}
24493 */
24494
24495 }, {
24496 key: "getBoundingBox",
24497 value: function getBoundingBox(nodeId) {
24498 if (this.body.nodes[nodeId] !== undefined) {
24499 return this.body.nodes[nodeId].shape.boundingBox;
24500 }
24501 }
24502 /**
24503 * Get the Ids of nodes connected to this node.
24504 *
24505 * @param {Node.id} nodeId
24506 * @param {'to'|'from'|undefined} direction values 'from' and 'to' select respectively parent and child nodes only.
24507 * Any other value returns both parent and child nodes.
24508 * @returns {Array}
24509 */
24510
24511 }, {
24512 key: "getConnectedNodes",
24513 value: function getConnectedNodes(nodeId, direction) {
24514 var nodeList = [];
24515
24516 if (this.body.nodes[nodeId] !== undefined) {
24517 var node = this.body.nodes[nodeId];
24518 var nodeObj = {}; // used to quickly check if node already exists
24519
24520 for (var i = 0; i < node.edges.length; i++) {
24521 var edge = node.edges[i];
24522
24523 if (direction !== "to" && edge.toId == node.id) {
24524 // these are double equals since ids can be numeric or string
24525 if (nodeObj[edge.fromId] === undefined) {
24526 nodeList.push(edge.fromId);
24527 nodeObj[edge.fromId] = true;
24528 }
24529 } else if (direction !== "from" && edge.fromId == node.id) {
24530 // these are double equals since ids can be numeric or string
24531 if (nodeObj[edge.toId] === undefined) {
24532 nodeList.push(edge.toId);
24533 nodeObj[edge.toId] = true;
24534 }
24535 }
24536 }
24537 }
24538
24539 return nodeList;
24540 }
24541 /**
24542 * Get the ids of the edges connected to this node.
24543 *
24544 * @param {Node.id} nodeId
24545 * @returns {*}
24546 */
24547
24548 }, {
24549 key: "getConnectedEdges",
24550 value: function getConnectedEdges(nodeId) {
24551 var edgeList = [];
24552
24553 if (this.body.nodes[nodeId] !== undefined) {
24554 var node = this.body.nodes[nodeId];
24555
24556 for (var i = 0; i < node.edges.length; i++) {
24557 edgeList.push(node.edges[i].id);
24558 }
24559 } else {
24560 console.error("NodeId provided for getConnectedEdges does not exist. Provided: ", nodeId);
24561 }
24562
24563 return edgeList;
24564 }
24565 /**
24566 * Move a node.
24567 *
24568 * @param {Node.id} nodeId
24569 * @param {number} x
24570 * @param {number} y
24571 */
24572
24573 }, {
24574 key: "moveNode",
24575 value: function moveNode(nodeId, x, y) {
24576 var _this4 = this;
24577
24578 if (this.body.nodes[nodeId] !== undefined) {
24579 this.body.nodes[nodeId].x = Number(x);
24580 this.body.nodes[nodeId].y = Number(y);
24581
24582 setTimeout$1(function () {
24583 _this4.body.emitter.emit("startSimulation");
24584 }, 0);
24585 } else {
24586 console.error("Node id supplied to moveNode does not exist. Provided: ", nodeId);
24587 }
24588 }
24589 }]);
24590
24591 return NodesHandler;
24592}();
24593
24594// https://tc39.es/ecma262/#sec-reflect.get
24595
24596function get$5(target, propertyKey
24597/* , receiver */
24598) {
24599 var receiver = arguments.length < 3 ? target : arguments[2];
24600 var descriptor, prototype;
24601 if (anObject(target) === receiver) return target[propertyKey];
24602 if (descriptor = objectGetOwnPropertyDescriptor.f(target, propertyKey)) return has$1(descriptor, 'value') ? descriptor.value : descriptor.get === undefined ? undefined : descriptor.get.call(receiver);
24603 if (isObject$1(prototype = objectGetPrototypeOf(target))) return get$5(prototype, propertyKey, receiver);
24604}
24605
24606_export({
24607 target: 'Reflect',
24608 stat: true
24609}, {
24610 get: get$5
24611});
24612
24613var get$4 = path.Reflect.get;
24614
24615var get$3 = get$4;
24616
24617var get$2 = get$3;
24618
24619var get$1 = get$2;
24620
24621var getOwnPropertyDescriptor$1 = getOwnPropertyDescriptor$3;
24622
24623var getOwnPropertyDescriptor = getOwnPropertyDescriptor$1;
24624
24625var superPropBase = createCommonjsModule(function (module) {
24626 function _superPropBase(object, property) {
24627 while (!Object.prototype.hasOwnProperty.call(object, property)) {
24628 object = getPrototypeOf(object);
24629 if (object === null) break;
24630 }
24631
24632 return object;
24633 }
24634
24635 module.exports = _superPropBase;
24636 module.exports["default"] = module.exports, module.exports.__esModule = true;
24637});
24638unwrapExports(superPropBase);
24639
24640var get = createCommonjsModule(function (module) {
24641 function _get(target, property, receiver) {
24642 if (typeof Reflect !== "undefined" && get$1) {
24643 module.exports = _get = get$1;
24644 module.exports["default"] = module.exports, module.exports.__esModule = true;
24645 } else {
24646 module.exports = _get = function _get(target, property, receiver) {
24647 var base = superPropBase(target, property);
24648 if (!base) return;
24649
24650 var desc = getOwnPropertyDescriptor(base, property);
24651
24652 if (desc.get) {
24653 return desc.get.call(receiver);
24654 }
24655
24656 return desc.value;
24657 };
24658
24659 module.exports["default"] = module.exports, module.exports.__esModule = true;
24660 }
24661
24662 return _get(target, property, receiver || target);
24663 }
24664
24665 module.exports = _get;
24666 module.exports["default"] = module.exports, module.exports.__esModule = true;
24667});
24668var _get = unwrapExports(get);
24669
24670var $hypot = Math.hypot;
24671var abs = Math.abs;
24672var sqrt = Math.sqrt; // Chrome 77 bug
24673// https://bugs.chromium.org/p/v8/issues/detail?id=9546
24674
24675var BUGGY = !!$hypot && $hypot(Infinity, NaN) !== Infinity; // `Math.hypot` method
24676// https://tc39.es/ecma262/#sec-math.hypot
24677
24678_export({
24679 target: 'Math',
24680 stat: true,
24681 forced: BUGGY
24682}, {
24683 // eslint-disable-next-line no-unused-vars -- required for `.length`
24684 hypot: function hypot(value1, value2) {
24685 var sum = 0;
24686 var i = 0;
24687 var aLen = arguments.length;
24688 var larg = 0;
24689 var arg, div;
24690
24691 while (i < aLen) {
24692 arg = abs(arguments[i++]);
24693
24694 if (larg < arg) {
24695 div = larg / arg;
24696 sum = sum * div * div + 1;
24697 larg = arg;
24698 } else if (arg > 0) {
24699 div = arg / larg;
24700 sum += div * div;
24701 } else sum += arg;
24702 }
24703
24704 return larg === Infinity ? Infinity : larg * sqrt(sum);
24705 }
24706});
24707
24708var hypot$2 = path.Math.hypot;
24709
24710var hypot$1 = hypot$2;
24711
24712var hypot = hypot$1;
24713
24714function _createSuper$a(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$a(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
24715
24716function _isNativeReflectConstruct$a() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
24717/**
24718 * Common methods for endpoints
24719 *
24720 * @class
24721 */
24722
24723var EndPoint = /*#__PURE__*/function () {
24724 function EndPoint() {
24725 _classCallCheck(this, EndPoint);
24726 }
24727
24728 _createClass(EndPoint, null, [{
24729 key: "transform",
24730 value:
24731 /**
24732 * Apply transformation on points for display.
24733 *
24734 * The following is done:
24735 * - rotate by the specified angle
24736 * - multiply the (normalized) coordinates by the passed length
24737 * - offset by the target coordinates
24738 *
24739 * @param points - The point(s) to be transformed.
24740 * @param arrowData - The data determining the result of the transformation.
24741 */
24742 function transform(points, arrowData) {
24743 if (!isArray(points)) {
24744 points = [points];
24745 }
24746
24747 var x = arrowData.point.x;
24748 var y = arrowData.point.y;
24749 var angle = arrowData.angle;
24750 var length = arrowData.length;
24751
24752 for (var i = 0; i < points.length; ++i) {
24753 var p = points[i];
24754 var xt = p.x * Math.cos(angle) - p.y * Math.sin(angle);
24755 var yt = p.x * Math.sin(angle) + p.y * Math.cos(angle);
24756 p.x = x + length * xt;
24757 p.y = y + length * yt;
24758 }
24759 }
24760 /**
24761 * Draw a closed path using the given real coordinates.
24762 *
24763 * @param ctx - The path will be rendered into this context.
24764 * @param points - The points of the path.
24765 */
24766
24767 }, {
24768 key: "drawPath",
24769 value: function drawPath(ctx, points) {
24770 ctx.beginPath();
24771 ctx.moveTo(points[0].x, points[0].y);
24772
24773 for (var i = 1; i < points.length; ++i) {
24774 ctx.lineTo(points[i].x, points[i].y);
24775 }
24776
24777 ctx.closePath();
24778 }
24779 }]);
24780
24781 return EndPoint;
24782}();
24783/**
24784 * Drawing methods for the arrow endpoint.
24785 */
24786
24787
24788var Image$1 = /*#__PURE__*/function (_EndPoint) {
24789 _inherits(Image, _EndPoint);
24790
24791 var _super = _createSuper$a(Image);
24792
24793 function Image() {
24794 _classCallCheck(this, Image);
24795
24796 return _super.apply(this, arguments);
24797 }
24798
24799 _createClass(Image, null, [{
24800 key: "draw",
24801 value:
24802 /**
24803 * Draw this shape at the end of a line.
24804 *
24805 * @param ctx - The shape will be rendered into this context.
24806 * @param arrowData - The data determining the shape.
24807 *
24808 * @returns False as there is no way to fill an image.
24809 */
24810 function draw(ctx, arrowData) {
24811 if (arrowData.image) {
24812 ctx.save();
24813 ctx.translate(arrowData.point.x, arrowData.point.y);
24814 ctx.rotate(Math.PI / 2 + arrowData.angle);
24815 var width = arrowData.imageWidth != null ? arrowData.imageWidth : arrowData.image.width;
24816 var height = arrowData.imageHeight != null ? arrowData.imageHeight : arrowData.image.height;
24817 arrowData.image.drawImageAtPosition(ctx, 1, // scale
24818 -width / 2, // x
24819 0, // y
24820 width, height);
24821 ctx.restore();
24822 }
24823
24824 return false;
24825 }
24826 }]);
24827
24828 return Image;
24829}(EndPoint);
24830/**
24831 * Drawing methods for the arrow endpoint.
24832 */
24833
24834
24835var Arrow = /*#__PURE__*/function (_EndPoint2) {
24836 _inherits(Arrow, _EndPoint2);
24837
24838 var _super2 = _createSuper$a(Arrow);
24839
24840 function Arrow() {
24841 _classCallCheck(this, Arrow);
24842
24843 return _super2.apply(this, arguments);
24844 }
24845
24846 _createClass(Arrow, null, [{
24847 key: "draw",
24848 value:
24849 /**
24850 * Draw this shape at the end of a line.
24851 *
24852 * @param ctx - The shape will be rendered into this context.
24853 * @param arrowData - The data determining the shape.
24854 *
24855 * @returns True because ctx.fill() can be used to fill the arrow.
24856 */
24857 function draw(ctx, arrowData) {
24858 // Normalized points of closed path, in the order that they should be drawn.
24859 // (0, 0) is the attachment point, and the point around which should be rotated
24860 var points = [{
24861 x: 0,
24862 y: 0
24863 }, {
24864 x: -1,
24865 y: 0.3
24866 }, {
24867 x: -0.9,
24868 y: 0
24869 }, {
24870 x: -1,
24871 y: -0.3
24872 }];
24873 EndPoint.transform(points, arrowData);
24874 EndPoint.drawPath(ctx, points);
24875 return true;
24876 }
24877 }]);
24878
24879 return Arrow;
24880}(EndPoint);
24881/**
24882 * Drawing methods for the crow endpoint.
24883 */
24884
24885
24886var Crow = /*#__PURE__*/function () {
24887 function Crow() {
24888 _classCallCheck(this, Crow);
24889 }
24890
24891 _createClass(Crow, null, [{
24892 key: "draw",
24893 value:
24894 /**
24895 * Draw this shape at the end of a line.
24896 *
24897 * @param ctx - The shape will be rendered into this context.
24898 * @param arrowData - The data determining the shape.
24899 *
24900 * @returns True because ctx.fill() can be used to fill the arrow.
24901 */
24902 function draw(ctx, arrowData) {
24903 // Normalized points of closed path, in the order that they should be drawn.
24904 // (0, 0) is the attachment point, and the point around which should be rotated
24905 var points = [{
24906 x: -1,
24907 y: 0
24908 }, {
24909 x: 0,
24910 y: 0.3
24911 }, {
24912 x: -0.4,
24913 y: 0
24914 }, {
24915 x: 0,
24916 y: -0.3
24917 }];
24918 EndPoint.transform(points, arrowData);
24919 EndPoint.drawPath(ctx, points);
24920 return true;
24921 }
24922 }]);
24923
24924 return Crow;
24925}();
24926/**
24927 * Drawing methods for the curve endpoint.
24928 */
24929
24930
24931var Curve = /*#__PURE__*/function () {
24932 function Curve() {
24933 _classCallCheck(this, Curve);
24934 }
24935
24936 _createClass(Curve, null, [{
24937 key: "draw",
24938 value:
24939 /**
24940 * Draw this shape at the end of a line.
24941 *
24942 * @param ctx - The shape will be rendered into this context.
24943 * @param arrowData - The data determining the shape.
24944 *
24945 * @returns True because ctx.fill() can be used to fill the arrow.
24946 */
24947 function draw(ctx, arrowData) {
24948 // Normalized points of closed path, in the order that they should be drawn.
24949 // (0, 0) is the attachment point, and the point around which should be rotated
24950 var point = {
24951 x: -0.4,
24952 y: 0
24953 };
24954 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
24955
24956 ctx.strokeStyle = ctx.fillStyle;
24957 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define curve endpoint as semicircle.
24958
24959 var pi = Math.PI;
24960 var startAngle = arrowData.angle - pi / 2;
24961 var endAngle = arrowData.angle + pi / 2;
24962 ctx.beginPath();
24963 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
24964 ctx.stroke();
24965 return true;
24966 }
24967 }]);
24968
24969 return Curve;
24970}();
24971/**
24972 * Drawing methods for the inverted curve endpoint.
24973 */
24974
24975
24976var InvertedCurve = /*#__PURE__*/function () {
24977 function InvertedCurve() {
24978 _classCallCheck(this, InvertedCurve);
24979 }
24980
24981 _createClass(InvertedCurve, null, [{
24982 key: "draw",
24983 value:
24984 /**
24985 * Draw this shape at the end of a line.
24986 *
24987 * @param ctx - The shape will be rendered into this context.
24988 * @param arrowData - The data determining the shape.
24989 *
24990 * @returns True because ctx.fill() can be used to fill the arrow.
24991 */
24992 function draw(ctx, arrowData) {
24993 // Normalized points of closed path, in the order that they should be drawn.
24994 // (0, 0) is the attachment point, and the point around which should be rotated
24995 var point = {
24996 x: -0.3,
24997 y: 0
24998 };
24999 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
25000
25001 ctx.strokeStyle = ctx.fillStyle;
25002 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define inverted curve endpoint as semicircle.
25003
25004 var pi = Math.PI;
25005 var startAngle = arrowData.angle + pi / 2;
25006 var endAngle = arrowData.angle + 3 * pi / 2;
25007 ctx.beginPath();
25008 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
25009 ctx.stroke();
25010 return true;
25011 }
25012 }]);
25013
25014 return InvertedCurve;
25015}();
25016/**
25017 * Drawing methods for the trinagle endpoint.
25018 */
25019
25020
25021var Triangle = /*#__PURE__*/function () {
25022 function Triangle() {
25023 _classCallCheck(this, Triangle);
25024 }
25025
25026 _createClass(Triangle, null, [{
25027 key: "draw",
25028 value:
25029 /**
25030 * Draw this shape at the end of a line.
25031 *
25032 * @param ctx - The shape will be rendered into this context.
25033 * @param arrowData - The data determining the shape.
25034 *
25035 * @returns True because ctx.fill() can be used to fill the arrow.
25036 */
25037 function draw(ctx, arrowData) {
25038 // Normalized points of closed path, in the order that they should be drawn.
25039 // (0, 0) is the attachment point, and the point around which should be rotated
25040 var points = [{
25041 x: 0.02,
25042 y: 0
25043 }, {
25044 x: -1,
25045 y: 0.3
25046 }, {
25047 x: -1,
25048 y: -0.3
25049 }];
25050 EndPoint.transform(points, arrowData);
25051 EndPoint.drawPath(ctx, points);
25052 return true;
25053 }
25054 }]);
25055
25056 return Triangle;
25057}();
25058/**
25059 * Drawing methods for the inverted trinagle endpoint.
25060 */
25061
25062
25063var InvertedTriangle = /*#__PURE__*/function () {
25064 function InvertedTriangle() {
25065 _classCallCheck(this, InvertedTriangle);
25066 }
25067
25068 _createClass(InvertedTriangle, null, [{
25069 key: "draw",
25070 value:
25071 /**
25072 * Draw this shape at the end of a line.
25073 *
25074 * @param ctx - The shape will be rendered into this context.
25075 * @param arrowData - The data determining the shape.
25076 *
25077 * @returns True because ctx.fill() can be used to fill the arrow.
25078 */
25079 function draw(ctx, arrowData) {
25080 // Normalized points of closed path, in the order that they should be drawn.
25081 // (0, 0) is the attachment point, and the point around which should be rotated
25082 var points = [{
25083 x: 0,
25084 y: 0.3
25085 }, {
25086 x: 0,
25087 y: -0.3
25088 }, {
25089 x: -1,
25090 y: 0
25091 }];
25092 EndPoint.transform(points, arrowData);
25093 EndPoint.drawPath(ctx, points);
25094 return true;
25095 }
25096 }]);
25097
25098 return InvertedTriangle;
25099}();
25100/**
25101 * Drawing methods for the circle endpoint.
25102 */
25103
25104
25105var Circle = /*#__PURE__*/function () {
25106 function Circle() {
25107 _classCallCheck(this, Circle);
25108 }
25109
25110 _createClass(Circle, null, [{
25111 key: "draw",
25112 value:
25113 /**
25114 * Draw this shape at the end of a line.
25115 *
25116 * @param ctx - The shape will be rendered into this context.
25117 * @param arrowData - The data determining the shape.
25118 *
25119 * @returns True because ctx.fill() can be used to fill the arrow.
25120 */
25121 function draw(ctx, arrowData) {
25122 var point = {
25123 x: -0.4,
25124 y: 0
25125 };
25126 EndPoint.transform(point, arrowData);
25127 drawCircle(ctx, point.x, point.y, arrowData.length * 0.4);
25128 return true;
25129 }
25130 }]);
25131
25132 return Circle;
25133}();
25134/**
25135 * Drawing methods for the bar endpoint.
25136 */
25137
25138
25139var Bar = /*#__PURE__*/function () {
25140 function Bar() {
25141 _classCallCheck(this, Bar);
25142 }
25143
25144 _createClass(Bar, null, [{
25145 key: "draw",
25146 value:
25147 /**
25148 * Draw this shape at the end of a line.
25149 *
25150 * @param ctx - The shape will be rendered into this context.
25151 * @param arrowData - The data determining the shape.
25152 *
25153 * @returns True because ctx.fill() can be used to fill the arrow.
25154 */
25155 function draw(ctx, arrowData) {
25156 /*
25157 var points = [
25158 {x:0, y:0.5},
25159 {x:0, y:-0.5}
25160 ];
25161 EndPoint.transform(points, arrowData);
25162 ctx.beginPath();
25163 ctx.moveTo(points[0].x, points[0].y);
25164 ctx.lineTo(points[1].x, points[1].y);
25165 ctx.stroke();
25166 */
25167 var points = [{
25168 x: 0,
25169 y: 0.5
25170 }, {
25171 x: 0,
25172 y: -0.5
25173 }, {
25174 x: -0.15,
25175 y: -0.5
25176 }, {
25177 x: -0.15,
25178 y: 0.5
25179 }];
25180 EndPoint.transform(points, arrowData);
25181 EndPoint.drawPath(ctx, points);
25182 return true;
25183 }
25184 }]);
25185
25186 return Bar;
25187}();
25188/**
25189 * Drawing methods for the box endpoint.
25190 */
25191
25192
25193var Box = /*#__PURE__*/function () {
25194 function Box() {
25195 _classCallCheck(this, Box);
25196 }
25197
25198 _createClass(Box, null, [{
25199 key: "draw",
25200 value:
25201 /**
25202 * Draw this shape at the end of a line.
25203 *
25204 * @param ctx - The shape will be rendered into this context.
25205 * @param arrowData - The data determining the shape.
25206 *
25207 * @returns True because ctx.fill() can be used to fill the arrow.
25208 */
25209 function draw(ctx, arrowData) {
25210 var points = [{
25211 x: 0,
25212 y: 0.3
25213 }, {
25214 x: 0,
25215 y: -0.3
25216 }, {
25217 x: -0.6,
25218 y: -0.3
25219 }, {
25220 x: -0.6,
25221 y: 0.3
25222 }];
25223 EndPoint.transform(points, arrowData);
25224 EndPoint.drawPath(ctx, points);
25225 return true;
25226 }
25227 }]);
25228
25229 return Box;
25230}();
25231/**
25232 * Drawing methods for the diamond endpoint.
25233 */
25234
25235
25236var Diamond = /*#__PURE__*/function () {
25237 function Diamond() {
25238 _classCallCheck(this, Diamond);
25239 }
25240
25241 _createClass(Diamond, null, [{
25242 key: "draw",
25243 value:
25244 /**
25245 * Draw this shape at the end of a line.
25246 *
25247 * @param ctx - The shape will be rendered into this context.
25248 * @param arrowData - The data determining the shape.
25249 *
25250 * @returns True because ctx.fill() can be used to fill the arrow.
25251 */
25252 function draw(ctx, arrowData) {
25253 var points = [{
25254 x: 0,
25255 y: 0
25256 }, {
25257 x: -0.5,
25258 y: -0.3
25259 }, {
25260 x: -1,
25261 y: 0
25262 }, {
25263 x: -0.5,
25264 y: 0.3
25265 }];
25266 EndPoint.transform(points, arrowData);
25267 EndPoint.drawPath(ctx, points);
25268 return true;
25269 }
25270 }]);
25271
25272 return Diamond;
25273}();
25274/**
25275 * Drawing methods for the vee endpoint.
25276 */
25277
25278
25279var Vee = /*#__PURE__*/function () {
25280 function Vee() {
25281 _classCallCheck(this, Vee);
25282 }
25283
25284 _createClass(Vee, null, [{
25285 key: "draw",
25286 value:
25287 /**
25288 * Draw this shape at the end of a line.
25289 *
25290 * @param ctx - The shape will be rendered into this context.
25291 * @param arrowData - The data determining the shape.
25292 *
25293 * @returns True because ctx.fill() can be used to fill the arrow.
25294 */
25295 function draw(ctx, arrowData) {
25296 // Normalized points of closed path, in the order that they should be drawn.
25297 // (0, 0) is the attachment point, and the point around which should be rotated
25298 var points = [{
25299 x: -1,
25300 y: 0.3
25301 }, {
25302 x: -0.5,
25303 y: 0
25304 }, {
25305 x: -1,
25306 y: -0.3
25307 }, {
25308 x: 0,
25309 y: 0
25310 }];
25311 EndPoint.transform(points, arrowData);
25312 EndPoint.drawPath(ctx, points);
25313 return true;
25314 }
25315 }]);
25316
25317 return Vee;
25318}();
25319/**
25320 * Drawing methods for the endpoints.
25321 */
25322
25323
25324var EndPoints = /*#__PURE__*/function () {
25325 function EndPoints() {
25326 _classCallCheck(this, EndPoints);
25327 }
25328
25329 _createClass(EndPoints, null, [{
25330 key: "draw",
25331 value:
25332 /**
25333 * Draw an endpoint.
25334 *
25335 * @param ctx - The shape will be rendered into this context.
25336 * @param arrowData - The data determining the shape.
25337 *
25338 * @returns True if ctx.fill() can be used to fill the arrow, false otherwise.
25339 */
25340 function draw(ctx, arrowData) {
25341 var type;
25342
25343 if (arrowData.type) {
25344 type = arrowData.type.toLowerCase();
25345 }
25346
25347 switch (type) {
25348 case "image":
25349 return Image$1.draw(ctx, arrowData);
25350
25351 case "circle":
25352 return Circle.draw(ctx, arrowData);
25353
25354 case "box":
25355 return Box.draw(ctx, arrowData);
25356
25357 case "crow":
25358 return Crow.draw(ctx, arrowData);
25359
25360 case "curve":
25361 return Curve.draw(ctx, arrowData);
25362
25363 case "diamond":
25364 return Diamond.draw(ctx, arrowData);
25365
25366 case "inv_curve":
25367 return InvertedCurve.draw(ctx, arrowData);
25368
25369 case "triangle":
25370 return Triangle.draw(ctx, arrowData);
25371
25372 case "inv_triangle":
25373 return InvertedTriangle.draw(ctx, arrowData);
25374
25375 case "bar":
25376 return Bar.draw(ctx, arrowData);
25377
25378 case "vee":
25379 return Vee.draw(ctx, arrowData);
25380
25381 case "arrow": // fall-through
25382
25383 default:
25384 return Arrow.draw(ctx, arrowData);
25385 }
25386 }
25387 }]);
25388
25389 return EndPoints;
25390}();
25391
25392function ownKeys$1(object, enumerableOnly) { var keys = keys$3(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
25393
25394function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context2; forEach$2(_context2 = ownKeys$1(Object(source), true)).call(_context2, function (key) { _defineProperty(target, key, source[key]); }); } else if (getOwnPropertyDescriptors) { defineProperties(target, getOwnPropertyDescriptors(source)); } else { var _context3; forEach$2(_context3 = ownKeys$1(Object(source))).call(_context3, function (key) { defineProperty$5(target, key, getOwnPropertyDescriptor$2(source, key)); }); } } return target; }
25395/**
25396 * The Base Class for all edges.
25397 */
25398
25399var EdgeBase = /*#__PURE__*/function () {
25400 /**
25401 * Create a new instance.
25402 *
25403 * @param options - The options object of given edge.
25404 * @param _body - The body of the network.
25405 * @param _labelModule - Label module.
25406 */
25407 function EdgeBase(options, _body, _labelModule) {
25408 _classCallCheck(this, EdgeBase);
25409
25410 this._body = _body;
25411 this._labelModule = _labelModule;
25412 this.color = {};
25413 this.colorDirty = true;
25414 this.hoverWidth = 1.5;
25415 this.selectionWidth = 2;
25416 this.setOptions(options);
25417 this.fromPoint = this.from;
25418 this.toPoint = this.to;
25419 }
25420 /** @inheritDoc */
25421
25422
25423 _createClass(EdgeBase, [{
25424 key: "connect",
25425 value: function connect() {
25426 this.from = this._body.nodes[this.options.from];
25427 this.to = this._body.nodes[this.options.to];
25428 }
25429 /** @inheritDoc */
25430
25431 }, {
25432 key: "cleanup",
25433 value: function cleanup() {
25434 return false;
25435 }
25436 /**
25437 * Set new edge options.
25438 *
25439 * @param options - The new edge options object.
25440 */
25441
25442 }, {
25443 key: "setOptions",
25444 value: function setOptions(options) {
25445 this.options = options;
25446 this.from = this._body.nodes[this.options.from];
25447 this.to = this._body.nodes[this.options.to];
25448 this.id = this.options.id;
25449 }
25450 /** @inheritDoc */
25451
25452 }, {
25453 key: "drawLine",
25454 value: function drawLine(ctx, values, _selected, _hover) {
25455 var viaNode = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : this.getViaNode();
25456 // set style
25457 ctx.strokeStyle = this.getColor(ctx, values);
25458 ctx.lineWidth = values.width;
25459
25460 if (values.dashes !== false) {
25461 this._drawDashedLine(ctx, values, viaNode);
25462 } else {
25463 this._drawLine(ctx, values, viaNode);
25464 }
25465 }
25466 /**
25467 * Draw a line with given style between two nodes through supplied node(s).
25468 *
25469 * @param ctx - The context that will be used for rendering.
25470 * @param values - Formatting values like color, opacity or shadow.
25471 * @param viaNode - Additional control point(s) for the edge.
25472 * @param fromPoint - TODO: Seems ignored, remove?
25473 * @param toPoint - TODO: Seems ignored, remove?
25474 */
25475
25476 }, {
25477 key: "_drawLine",
25478 value: function _drawLine(ctx, values, viaNode, fromPoint, toPoint) {
25479 if (this.from != this.to) {
25480 // draw line
25481 this._line(ctx, values, viaNode, fromPoint, toPoint);
25482 } else {
25483 var _this$_getCircleData = this._getCircleData(ctx),
25484 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
25485 x = _this$_getCircleData2[0],
25486 y = _this$_getCircleData2[1],
25487 radius = _this$_getCircleData2[2];
25488
25489 this._circle(ctx, values, x, y, radius);
25490 }
25491 }
25492 /**
25493 * Draw a dashed line with given style between two nodes through supplied node(s).
25494 *
25495 * @param ctx - The context that will be used for rendering.
25496 * @param values - Formatting values like color, opacity or shadow.
25497 * @param viaNode - Additional control point(s) for the edge.
25498 * @param _fromPoint - Ignored (TODO: remove in the future).
25499 * @param _toPoint - Ignored (TODO: remove in the future).
25500 */
25501
25502 }, {
25503 key: "_drawDashedLine",
25504 value: function _drawDashedLine(ctx, values, viaNode, _fromPoint, _toPoint) {
25505 ctx.lineCap = "round";
25506 var pattern = isArray(values.dashes) ? values.dashes : [5, 5]; // only firefox and chrome support this method, else we use the legacy one.
25507
25508 if (ctx.setLineDash !== undefined) {
25509 ctx.save(); // set dash settings for chrome or firefox
25510
25511 ctx.setLineDash(pattern);
25512 ctx.lineDashOffset = 0; // draw the line
25513
25514 if (this.from != this.to) {
25515 // draw line
25516 this._line(ctx, values, viaNode);
25517 } else {
25518 var _this$_getCircleData3 = this._getCircleData(ctx),
25519 _this$_getCircleData4 = _slicedToArray(_this$_getCircleData3, 3),
25520 x = _this$_getCircleData4[0],
25521 y = _this$_getCircleData4[1],
25522 radius = _this$_getCircleData4[2];
25523
25524 this._circle(ctx, values, x, y, radius);
25525 } // restore the dash settings.
25526
25527
25528 ctx.setLineDash([0]);
25529 ctx.lineDashOffset = 0;
25530 ctx.restore();
25531 } else {
25532 // unsupporting smooth lines
25533 if (this.from != this.to) {
25534 // draw line
25535 drawDashedLine(ctx, this.from.x, this.from.y, this.to.x, this.to.y, pattern);
25536 } else {
25537 var _this$_getCircleData5 = this._getCircleData(ctx),
25538 _this$_getCircleData6 = _slicedToArray(_this$_getCircleData5, 3),
25539 _x = _this$_getCircleData6[0],
25540 _y = _this$_getCircleData6[1],
25541 _radius = _this$_getCircleData6[2];
25542
25543 this._circle(ctx, values, _x, _y, _radius);
25544 } // draw shadow if enabled
25545
25546
25547 this.enableShadow(ctx, values);
25548 ctx.stroke(); // disable shadows for other elements.
25549
25550 this.disableShadow(ctx, values);
25551 }
25552 }
25553 /**
25554 * Find the intersection between the border of the node and the edge.
25555 *
25556 * @param node - The node (either from or to node of the edge).
25557 * @param ctx - The context that will be used for rendering.
25558 * @param options - Additional options.
25559 *
25560 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
25561 */
25562
25563 }, {
25564 key: "findBorderPosition",
25565 value: function findBorderPosition(node, ctx, options) {
25566 if (this.from != this.to) {
25567 return this._findBorderPosition(node, ctx, options);
25568 } else {
25569 return this._findBorderPositionCircle(node, ctx, options);
25570 }
25571 }
25572 /** @inheritDoc */
25573
25574 }, {
25575 key: "findBorderPositions",
25576 value: function findBorderPositions(ctx) {
25577 if (this.from != this.to) {
25578 return {
25579 from: this._findBorderPosition(this.from, ctx),
25580 to: this._findBorderPosition(this.to, ctx)
25581 };
25582 } else {
25583 var _context;
25584
25585 var _this$_getCircleData$ = slice$1(_context = this._getCircleData(ctx)).call(_context, 0, 2),
25586 _this$_getCircleData$2 = _slicedToArray(_this$_getCircleData$, 2),
25587 x = _this$_getCircleData$2[0],
25588 y = _this$_getCircleData$2[1];
25589
25590 return {
25591 from: this._findBorderPositionCircle(this.from, ctx, {
25592 x: x,
25593 y: y,
25594 low: 0.25,
25595 high: 0.6,
25596 direction: -1
25597 }),
25598 to: this._findBorderPositionCircle(this.from, ctx, {
25599 x: x,
25600 y: y,
25601 low: 0.6,
25602 high: 0.8,
25603 direction: 1
25604 })
25605 };
25606 }
25607 }
25608 /**
25609 * Compute the center point and radius of an edge connected to the same node at both ends.
25610 *
25611 * @param ctx - The context that will be used for rendering.
25612 *
25613 * @returns `[x, y, radius]`
25614 */
25615
25616 }, {
25617 key: "_getCircleData",
25618 value: function _getCircleData(ctx) {
25619 var radius = this.options.selfReference.size;
25620
25621 if (ctx !== undefined) {
25622 if (this.from.shape.width === undefined) {
25623 this.from.shape.resize(ctx);
25624 }
25625 } // get circle coordinates
25626
25627
25628 var coordinates = getSelfRefCoordinates(ctx, this.options.selfReference.angle, radius, this.from);
25629 return [coordinates.x, coordinates.y, radius];
25630 }
25631 /**
25632 * Get a point on a circle.
25633 *
25634 * @param x - Center of the circle on the x axis.
25635 * @param y - Center of the circle on the y axis.
25636 * @param radius - Radius of the circle.
25637 * @param position - Value between 0 (line start) and 1 (line end).
25638 *
25639 * @returns Cartesian coordinates of requested point on the circle.
25640 */
25641
25642 }, {
25643 key: "_pointOnCircle",
25644 value: function _pointOnCircle(x, y, radius, position) {
25645 var angle = position * 2 * Math.PI;
25646 return {
25647 x: x + radius * Math.cos(angle),
25648 y: y - radius * Math.sin(angle)
25649 };
25650 }
25651 /**
25652 * Find the intersection between the border of the node and the edge.
25653 *
25654 * @remarks
25655 * This function uses binary search to look for the point where the circle crosses the border of the node.
25656 *
25657 * @param nearNode - The node (either from or to node of the edge).
25658 * @param ctx - The context that will be used for rendering.
25659 * @param options - Additional options.
25660 *
25661 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
25662 */
25663
25664 }, {
25665 key: "_findBorderPositionCircle",
25666 value: function _findBorderPositionCircle(nearNode, ctx, options) {
25667 var x = options.x;
25668 var y = options.y;
25669 var low = options.low;
25670 var high = options.high;
25671 var direction = options.direction;
25672 var maxIterations = 10;
25673 var radius = this.options.selfReference.size;
25674 var threshold = 0.05;
25675 var pos;
25676 var middle = (low + high) * 0.5;
25677 var endPointOffset = 0;
25678
25679 if (this.options.arrowStrikethrough === true) {
25680 if (direction === -1) {
25681 endPointOffset = this.options.endPointOffset.from;
25682 } else if (direction === 1) {
25683 endPointOffset = this.options.endPointOffset.to;
25684 }
25685 }
25686
25687 var iteration = 0;
25688
25689 do {
25690 middle = (low + high) * 0.5;
25691 pos = this._pointOnCircle(x, y, radius, middle);
25692 var angle = Math.atan2(nearNode.y - pos.y, nearNode.x - pos.x);
25693 var distanceToBorder = nearNode.distanceToBorder(ctx, angle) + endPointOffset;
25694 var distanceToPoint = Math.sqrt(Math.pow(pos.x - nearNode.x, 2) + Math.pow(pos.y - nearNode.y, 2));
25695 var difference = distanceToBorder - distanceToPoint;
25696
25697 if (Math.abs(difference) < threshold) {
25698 break; // found
25699 } else if (difference > 0) {
25700 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
25701 if (direction > 0) {
25702 low = middle;
25703 } else {
25704 high = middle;
25705 }
25706 } else {
25707 if (direction > 0) {
25708 high = middle;
25709 } else {
25710 low = middle;
25711 }
25712 }
25713
25714 ++iteration;
25715 } while (low <= high && iteration < maxIterations);
25716
25717 return _objectSpread$1(_objectSpread$1({}, pos), {}, {
25718 t: middle
25719 });
25720 }
25721 /**
25722 * Get the line width of the edge. Depends on width and whether one of the connected nodes is selected.
25723 *
25724 * @param selected - Determines wheter the line is selected.
25725 * @param hover - Determines wheter the line is being hovered, only applies if selected is false.
25726 *
25727 * @returns The width of the line.
25728 */
25729
25730 }, {
25731 key: "getLineWidth",
25732 value: function getLineWidth(selected, hover) {
25733 if (selected === true) {
25734 return Math.max(this.selectionWidth, 0.3 / this._body.view.scale);
25735 } else if (hover === true) {
25736 return Math.max(this.hoverWidth, 0.3 / this._body.view.scale);
25737 } else {
25738 return Math.max(this.options.width, 0.3 / this._body.view.scale);
25739 }
25740 }
25741 /**
25742 * Compute the color or gradient for given edge.
25743 *
25744 * @param ctx - The context that will be used for rendering.
25745 * @param values - Formatting values like color, opacity or shadow.
25746 * @param _selected - Ignored (TODO: remove in the future).
25747 * @param _hover - Ignored (TODO: remove in the future).
25748 *
25749 * @returns Color string if single color is inherited or gradient if two.
25750 */
25751
25752 }, {
25753 key: "getColor",
25754 value: function getColor(ctx, values) {
25755 if (values.inheritsColor !== false) {
25756 // when this is a loop edge, just use the 'from' method
25757 if (values.inheritsColor === "both" && this.from.id !== this.to.id) {
25758 var grd = ctx.createLinearGradient(this.from.x, this.from.y, this.to.x, this.to.y);
25759 var fromColor = this.from.options.color.highlight.border;
25760 var toColor = this.to.options.color.highlight.border;
25761
25762 if (this.from.selected === false && this.to.selected === false) {
25763 fromColor = overrideOpacity(this.from.options.color.border, values.opacity);
25764 toColor = overrideOpacity(this.to.options.color.border, values.opacity);
25765 } else if (this.from.selected === true && this.to.selected === false) {
25766 toColor = this.to.options.color.border;
25767 } else if (this.from.selected === false && this.to.selected === true) {
25768 fromColor = this.from.options.color.border;
25769 }
25770
25771 grd.addColorStop(0, fromColor);
25772 grd.addColorStop(1, toColor); // -------------------- this returns -------------------- //
25773
25774 return grd;
25775 }
25776
25777 if (values.inheritsColor === "to") {
25778 return overrideOpacity(this.to.options.color.border, values.opacity);
25779 } else {
25780 // "from"
25781 return overrideOpacity(this.from.options.color.border, values.opacity);
25782 }
25783 } else {
25784 return overrideOpacity(values.color, values.opacity);
25785 }
25786 }
25787 /**
25788 * Draw a line from a node to itself, a circle.
25789 *
25790 * @param ctx - The context that will be used for rendering.
25791 * @param values - Formatting values like color, opacity or shadow.
25792 * @param x - Center of the circle on the x axis.
25793 * @param y - Center of the circle on the y axis.
25794 * @param radius - Radius of the circle.
25795 */
25796
25797 }, {
25798 key: "_circle",
25799 value: function _circle(ctx, values, x, y, radius) {
25800 // draw shadow if enabled
25801 this.enableShadow(ctx, values); //full circle
25802
25803 var angleFrom = 0;
25804 var angleTo = Math.PI * 2;
25805
25806 if (!this.options.selfReference.renderBehindTheNode) {
25807 //render only parts which are not overlaping with parent node
25808 //need to find x,y of from point and x,y to point
25809 //calculating radians
25810 var low = this.options.selfReference.angle;
25811 var high = this.options.selfReference.angle + Math.PI;
25812
25813 var pointTFrom = this._findBorderPositionCircle(this.from, ctx, {
25814 x: x,
25815 y: y,
25816 low: low,
25817 high: high,
25818 direction: -1
25819 });
25820
25821 var pointTTo = this._findBorderPositionCircle(this.from, ctx, {
25822 x: x,
25823 y: y,
25824 low: low,
25825 high: high,
25826 direction: 1
25827 });
25828
25829 angleFrom = Math.atan2(pointTFrom.y - y, pointTFrom.x - x);
25830 angleTo = Math.atan2(pointTTo.y - y, pointTTo.x - x);
25831 } // draw a circle
25832
25833
25834 ctx.beginPath();
25835 ctx.arc(x, y, radius, angleFrom, angleTo, false);
25836 ctx.stroke(); // disable shadows for other elements.
25837
25838 this.disableShadow(ctx, values);
25839 }
25840 /**
25841 * @inheritDoc
25842 *
25843 * @remarks
25844 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
25845 */
25846
25847 }, {
25848 key: "getDistanceToEdge",
25849 value: function getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
25850 if (this.from != this.to) {
25851 return this._getDistanceToEdge(x1, y1, x2, y2, x3, y3);
25852 } else {
25853 var _this$_getCircleData7 = this._getCircleData(undefined),
25854 _this$_getCircleData8 = _slicedToArray(_this$_getCircleData7, 3),
25855 x = _this$_getCircleData8[0],
25856 y = _this$_getCircleData8[1],
25857 radius = _this$_getCircleData8[2];
25858
25859 var dx = x - x3;
25860 var dy = y - y3;
25861 return Math.abs(Math.sqrt(dx * dx + dy * dy) - radius);
25862 }
25863 }
25864 /**
25865 * Calculate the distance between a point (x3, y3) and a line segment from (x1, y1) to (x2, y2).
25866 *
25867 * @param x1 - First end of the line segment on the x axis.
25868 * @param y1 - First end of the line segment on the y axis.
25869 * @param x2 - Second end of the line segment on the x axis.
25870 * @param y2 - Second end of the line segment on the y axis.
25871 * @param x3 - Position of the point on the x axis.
25872 * @param y3 - Position of the point on the y axis.
25873 *
25874 * @returns The distance between the line segment and the point.
25875 */
25876
25877 }, {
25878 key: "_getDistanceToLine",
25879 value: function _getDistanceToLine(x1, y1, x2, y2, x3, y3) {
25880 var px = x2 - x1;
25881 var py = y2 - y1;
25882 var something = px * px + py * py;
25883 var u = ((x3 - x1) * px + (y3 - y1) * py) / something;
25884
25885 if (u > 1) {
25886 u = 1;
25887 } else if (u < 0) {
25888 u = 0;
25889 }
25890
25891 var x = x1 + u * px;
25892 var y = y1 + u * py;
25893 var dx = x - x3;
25894 var dy = y - y3; //# Note: If the actual distance does not matter,
25895 //# if you only want to compare what this function
25896 //# returns to other results of this function, you
25897 //# can just return the squared distance instead
25898 //# (i.e. remove the sqrt) to gain a little performance
25899
25900 return Math.sqrt(dx * dx + dy * dy);
25901 }
25902 /** @inheritDoc */
25903
25904 }, {
25905 key: "getArrowData",
25906 value: function getArrowData(ctx, position, viaNode, _selected, _hover, values) {
25907 // set lets
25908 var angle;
25909 var arrowPoint;
25910 var node1;
25911 var node2;
25912 var reversed;
25913 var scaleFactor;
25914 var type;
25915 var lineWidth = values.width;
25916
25917 if (position === "from") {
25918 node1 = this.from;
25919 node2 = this.to;
25920 reversed = values.fromArrowScale < 0;
25921 scaleFactor = Math.abs(values.fromArrowScale);
25922 type = values.fromArrowType;
25923 } else if (position === "to") {
25924 node1 = this.to;
25925 node2 = this.from;
25926 reversed = values.toArrowScale < 0;
25927 scaleFactor = Math.abs(values.toArrowScale);
25928 type = values.toArrowType;
25929 } else {
25930 node1 = this.to;
25931 node2 = this.from;
25932 reversed = values.middleArrowScale < 0;
25933 scaleFactor = Math.abs(values.middleArrowScale);
25934 type = values.middleArrowType;
25935 }
25936
25937 var length = 15 * scaleFactor + 3 * lineWidth; // 3* lineWidth is the width of the edge.
25938 // if not connected to itself
25939
25940 if (node1 != node2) {
25941 var approximateEdgeLength = hypot(node1.x - node2.x, node1.y - node2.y);
25942
25943 var relativeLength = length / approximateEdgeLength;
25944
25945 if (position !== "middle") {
25946 // draw arrow head
25947 if (this.options.smooth.enabled === true) {
25948 var pointT = this._findBorderPosition(node1, ctx, {
25949 via: viaNode
25950 });
25951
25952 var guidePos = this.getPoint(pointT.t + relativeLength * (position === "from" ? 1 : -1), viaNode);
25953 angle = Math.atan2(pointT.y - guidePos.y, pointT.x - guidePos.x);
25954 arrowPoint = pointT;
25955 } else {
25956 angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
25957 arrowPoint = this._findBorderPosition(node1, ctx);
25958 }
25959 } else {
25960 // Negative half length reverses arrow direction.
25961 var halfLength = (reversed ? -relativeLength : relativeLength) / 2;
25962 var guidePos1 = this.getPoint(0.5 + halfLength, viaNode);
25963 var guidePos2 = this.getPoint(0.5 - halfLength, viaNode);
25964 angle = Math.atan2(guidePos1.y - guidePos2.y, guidePos1.x - guidePos2.x);
25965 arrowPoint = this.getPoint(0.5, viaNode);
25966 }
25967 } else {
25968 // draw circle
25969 var _this$_getCircleData9 = this._getCircleData(ctx),
25970 _this$_getCircleData10 = _slicedToArray(_this$_getCircleData9, 3),
25971 x = _this$_getCircleData10[0],
25972 y = _this$_getCircleData10[1],
25973 radius = _this$_getCircleData10[2];
25974
25975 if (position === "from") {
25976 var low = this.options.selfReference.angle;
25977 var high = this.options.selfReference.angle + Math.PI;
25978
25979 var _pointT = this._findBorderPositionCircle(this.from, ctx, {
25980 x: x,
25981 y: y,
25982 low: low,
25983 high: high,
25984 direction: -1
25985 });
25986
25987 angle = _pointT.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
25988 arrowPoint = _pointT;
25989 } else if (position === "to") {
25990 var _low = this.options.selfReference.angle;
25991
25992 var _high = this.options.selfReference.angle + Math.PI;
25993
25994 var _pointT2 = this._findBorderPositionCircle(this.from, ctx, {
25995 x: x,
25996 y: y,
25997 low: _low,
25998 high: _high,
25999 direction: 1
26000 });
26001
26002 angle = _pointT2.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI;
26003 arrowPoint = _pointT2;
26004 } else {
26005 var pos = this.options.selfReference.angle / (2 * Math.PI);
26006 arrowPoint = this._pointOnCircle(x, y, radius, pos);
26007 angle = pos * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
26008 }
26009 }
26010
26011 var xi = arrowPoint.x - length * 0.9 * Math.cos(angle);
26012 var yi = arrowPoint.y - length * 0.9 * Math.sin(angle);
26013 var arrowCore = {
26014 x: xi,
26015 y: yi
26016 };
26017 return {
26018 point: arrowPoint,
26019 core: arrowCore,
26020 angle: angle,
26021 length: length,
26022 type: type
26023 };
26024 }
26025 /** @inheritDoc */
26026
26027 }, {
26028 key: "drawArrowHead",
26029 value: function drawArrowHead(ctx, values, _selected, _hover, arrowData) {
26030 // set style
26031 ctx.strokeStyle = this.getColor(ctx, values);
26032 ctx.fillStyle = ctx.strokeStyle;
26033 ctx.lineWidth = values.width;
26034 var canFill = EndPoints.draw(ctx, arrowData);
26035
26036 if (canFill) {
26037 // draw shadow if enabled
26038 this.enableShadow(ctx, values);
26039
26040 fill(ctx).call(ctx); // disable shadows for other elements.
26041
26042
26043 this.disableShadow(ctx, values);
26044 }
26045 }
26046 /**
26047 * Set the shadow formatting values in the context if enabled, do nothing otherwise.
26048 *
26049 * @param ctx - The context that will be used for rendering.
26050 * @param values - Formatting values for the shadow.
26051 */
26052
26053 }, {
26054 key: "enableShadow",
26055 value: function enableShadow(ctx, values) {
26056 if (values.shadow === true) {
26057 ctx.shadowColor = values.shadowColor;
26058 ctx.shadowBlur = values.shadowSize;
26059 ctx.shadowOffsetX = values.shadowX;
26060 ctx.shadowOffsetY = values.shadowY;
26061 }
26062 }
26063 /**
26064 * Reset the shadow formatting values in the context if enabled, do nothing otherwise.
26065 *
26066 * @param ctx - The context that will be used for rendering.
26067 * @param values - Formatting values for the shadow.
26068 */
26069
26070 }, {
26071 key: "disableShadow",
26072 value: function disableShadow(ctx, values) {
26073 if (values.shadow === true) {
26074 ctx.shadowColor = "rgba(0,0,0,0)";
26075 ctx.shadowBlur = 0;
26076 ctx.shadowOffsetX = 0;
26077 ctx.shadowOffsetY = 0;
26078 }
26079 }
26080 /**
26081 * Render the background according to the formatting values.
26082 *
26083 * @param ctx - The context that will be used for rendering.
26084 * @param values - Formatting values for the background.
26085 */
26086
26087 }, {
26088 key: "drawBackground",
26089 value: function drawBackground(ctx, values) {
26090 if (values.background !== false) {
26091 // save original line attrs
26092 var origCtxAttr = {
26093 strokeStyle: ctx.strokeStyle,
26094 lineWidth: ctx.lineWidth,
26095 dashes: ctx.dashes
26096 };
26097 ctx.strokeStyle = values.backgroundColor;
26098 ctx.lineWidth = values.backgroundSize;
26099 this.setStrokeDashed(ctx, values.backgroundDashes);
26100 ctx.stroke(); // restore original line attrs
26101
26102 ctx.strokeStyle = origCtxAttr.strokeStyle;
26103 ctx.lineWidth = origCtxAttr.lineWidth;
26104 ctx.dashes = origCtxAttr.dashes;
26105 this.setStrokeDashed(ctx, values.dashes);
26106 }
26107 }
26108 /**
26109 * Set the line dash pattern if supported. Logs a warning to the console if it isn't supported.
26110 *
26111 * @param ctx - The context that will be used for rendering.
26112 * @param dashes - The pattern [line, space, line…], true for default dashed line or false for normal line.
26113 */
26114
26115 }, {
26116 key: "setStrokeDashed",
26117 value: function setStrokeDashed(ctx, dashes) {
26118 if (dashes !== false) {
26119 if (ctx.setLineDash !== undefined) {
26120 var pattern = isArray(dashes) ? dashes : [5, 5];
26121 ctx.setLineDash(pattern);
26122 } else {
26123 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
26124 }
26125 } else {
26126 if (ctx.setLineDash !== undefined) {
26127 ctx.setLineDash([]);
26128 } else {
26129 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
26130 }
26131 }
26132 }
26133 }]);
26134
26135 return EdgeBase;
26136}();
26137
26138function ownKeys(object, enumerableOnly) { var keys = keys$3(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
26139
26140function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context; forEach$2(_context = ownKeys(Object(source), true)).call(_context, function (key) { _defineProperty(target, key, source[key]); }); } else if (getOwnPropertyDescriptors) { defineProperties(target, getOwnPropertyDescriptors(source)); } else { var _context2; forEach$2(_context2 = ownKeys(Object(source))).call(_context2, function (key) { defineProperty$5(target, key, getOwnPropertyDescriptor$2(source, key)); }); } } return target; }
26141
26142function _createSuper$9(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$9(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
26143
26144function _isNativeReflectConstruct$9() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
26145/**
26146 * The Base Class for all Bezier edges.
26147 * Bezier curves are used to model smooth gradual curves in paths between nodes.
26148 */
26149
26150var BezierEdgeBase = /*#__PURE__*/function (_EdgeBase) {
26151 _inherits(BezierEdgeBase, _EdgeBase);
26152
26153 var _super = _createSuper$9(BezierEdgeBase);
26154
26155 /**
26156 * Create a new instance.
26157 *
26158 * @param options - The options object of given edge.
26159 * @param body - The body of the network.
26160 * @param labelModule - Label module.
26161 */
26162 function BezierEdgeBase(options, body, labelModule) {
26163 _classCallCheck(this, BezierEdgeBase);
26164
26165 return _super.call(this, options, body, labelModule);
26166 }
26167 /**
26168 * Find the intersection between the border of the node and the edge.
26169 *
26170 * @remarks
26171 * This function uses binary search to look for the point where the bezier curve crosses the border of the node.
26172 *
26173 * @param nearNode - The node (either from or to node of the edge).
26174 * @param ctx - The context that will be used for rendering.
26175 * @param viaNode - Additional node(s) the edge passes through.
26176 *
26177 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
26178 */
26179
26180
26181 _createClass(BezierEdgeBase, [{
26182 key: "_findBorderPositionBezier",
26183 value: function _findBorderPositionBezier(nearNode, ctx) {
26184 var viaNode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this._getViaCoordinates();
26185 var maxIterations = 10;
26186 var threshold = 0.2;
26187 var from = false;
26188 var high = 1;
26189 var low = 0;
26190 var node = this.to;
26191 var pos;
26192 var middle;
26193 var endPointOffset = this.options.endPointOffset ? this.options.endPointOffset.to : 0;
26194
26195 if (nearNode.id === this.from.id) {
26196 node = this.from;
26197 from = true;
26198 endPointOffset = this.options.endPointOffset ? this.options.endPointOffset.from : 0;
26199 }
26200
26201 if (this.options.arrowStrikethrough === false) {
26202 endPointOffset = 0;
26203 }
26204
26205 var iteration = 0;
26206
26207 do {
26208 middle = (low + high) * 0.5;
26209 pos = this.getPoint(middle, viaNode);
26210 var angle = Math.atan2(node.y - pos.y, node.x - pos.x);
26211 var distanceToBorder = node.distanceToBorder(ctx, angle) + endPointOffset;
26212 var distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2));
26213 var difference = distanceToBorder - distanceToPoint;
26214
26215 if (Math.abs(difference) < threshold) {
26216 break; // found
26217 } else if (difference < 0) {
26218 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
26219 if (from === false) {
26220 low = middle;
26221 } else {
26222 high = middle;
26223 }
26224 } else {
26225 if (from === false) {
26226 high = middle;
26227 } else {
26228 low = middle;
26229 }
26230 }
26231
26232 ++iteration;
26233 } while (low <= high && iteration < maxIterations);
26234
26235 return _objectSpread(_objectSpread({}, pos), {}, {
26236 t: middle
26237 });
26238 }
26239 /**
26240 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
26241 *
26242 * @remarks
26243 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
26244 *
26245 * @param x1 - First end of the line segment on the x axis.
26246 * @param y1 - First end of the line segment on the y axis.
26247 * @param x2 - Second end of the line segment on the x axis.
26248 * @param y2 - Second end of the line segment on the y axis.
26249 * @param x3 - Position of the point on the x axis.
26250 * @param y3 - Position of the point on the y axis.
26251 * @param via - The control point for the edge.
26252 *
26253 * @returns The distance between the line segment and the point.
26254 */
26255
26256 }, {
26257 key: "_getDistanceToBezierEdge",
26258 value: function _getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via) {
26259 // x3,y3 is the point
26260 var minDistance = 1e9;
26261 var distance;
26262 var i, t, x, y;
26263 var lastX = x1;
26264 var lastY = y1;
26265
26266 for (i = 1; i < 10; i++) {
26267 t = 0.1 * i;
26268 x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * via.x + Math.pow(t, 2) * x2;
26269 y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * via.y + Math.pow(t, 2) * y2;
26270
26271 if (i > 0) {
26272 distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
26273 minDistance = distance < minDistance ? distance : minDistance;
26274 }
26275
26276 lastX = x;
26277 lastY = y;
26278 }
26279
26280 return minDistance;
26281 }
26282 /**
26283 * Render a bezier curve between two nodes.
26284 *
26285 * @remarks
26286 * The method accepts zero, one or two control points.
26287 * Passing zero control points just draws a straight line.
26288 *
26289 * @param ctx - The context that will be used for rendering.
26290 * @param values - Style options for edge drawing.
26291 * @param viaNode1 - First control point for curve drawing.
26292 * @param viaNode2 - Second control point for curve drawing.
26293 */
26294
26295 }, {
26296 key: "_bezierCurve",
26297 value: function _bezierCurve(ctx, values, viaNode1, viaNode2) {
26298 ctx.beginPath();
26299 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
26300
26301 if (viaNode1 != null && viaNode1.x != null) {
26302 if (viaNode2 != null && viaNode2.x != null) {
26303 ctx.bezierCurveTo(viaNode1.x, viaNode1.y, viaNode2.x, viaNode2.y, this.toPoint.x, this.toPoint.y);
26304 } else {
26305 ctx.quadraticCurveTo(viaNode1.x, viaNode1.y, this.toPoint.x, this.toPoint.y);
26306 }
26307 } else {
26308 // fallback to normal straight edge
26309 ctx.lineTo(this.toPoint.x, this.toPoint.y);
26310 } // draw a background
26311
26312
26313 this.drawBackground(ctx, values); // draw shadow if enabled
26314
26315 this.enableShadow(ctx, values);
26316 ctx.stroke();
26317 this.disableShadow(ctx, values);
26318 }
26319 /** @inheritDoc */
26320
26321 }, {
26322 key: "getViaNode",
26323 value: function getViaNode() {
26324 return this._getViaCoordinates();
26325 }
26326 }]);
26327
26328 return BezierEdgeBase;
26329}(EdgeBase);
26330
26331function _createSuper$8(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$8(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
26332
26333function _isNativeReflectConstruct$8() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
26334/**
26335 * A Dynamic Bezier Edge. Bezier curves are used to model smooth gradual
26336 * curves in paths between nodes. The Dynamic piece refers to how the curve
26337 * reacts to physics changes.
26338 *
26339 * @augments BezierEdgeBase
26340 */
26341
26342var BezierEdgeDynamic = /*#__PURE__*/function (_BezierEdgeBase) {
26343 _inherits(BezierEdgeDynamic, _BezierEdgeBase);
26344
26345 var _super = _createSuper$8(BezierEdgeDynamic);
26346
26347 /**
26348 * Create a new instance.
26349 *
26350 * @param options - The options object of given edge.
26351 * @param body - The body of the network.
26352 * @param labelModule - Label module.
26353 */
26354 function BezierEdgeDynamic(options, body, labelModule) {
26355 var _this;
26356
26357 _classCallCheck(this, BezierEdgeDynamic);
26358
26359 //this.via = undefined; // Here for completeness but not allowed to defined before super() is invoked.
26360 _this = _super.call(this, options, body, labelModule); // --> this calls the setOptions below
26361
26362 _this.via = _this.via; // constructor → super → super → setOptions → setupSupportNode
26363
26364 _this._boundFunction = function () {
26365 _this.positionBezierNode();
26366 };
26367
26368 _this._body.emitter.on("_repositionBezierNodes", _this._boundFunction);
26369
26370 return _this;
26371 }
26372 /** @inheritDoc */
26373
26374
26375 _createClass(BezierEdgeDynamic, [{
26376 key: "setOptions",
26377 value: function setOptions(options) {
26378 _get(_getPrototypeOf(BezierEdgeDynamic.prototype), "setOptions", this).call(this, options); // check if the physics has changed.
26379
26380
26381 var physicsChange = false;
26382
26383 if (this.options.physics !== options.physics) {
26384 physicsChange = true;
26385 } // set the options and the to and from nodes
26386
26387
26388 this.options = options;
26389 this.id = this.options.id;
26390 this.from = this._body.nodes[this.options.from];
26391 this.to = this._body.nodes[this.options.to]; // setup the support node and connect
26392
26393 this.setupSupportNode();
26394 this.connect(); // when we change the physics state of the edge, we reposition the support node.
26395
26396 if (physicsChange === true) {
26397 this.via.setOptions({
26398 physics: this.options.physics
26399 });
26400 this.positionBezierNode();
26401 }
26402 }
26403 /** @inheritDoc */
26404
26405 }, {
26406 key: "connect",
26407 value: function connect() {
26408 this.from = this._body.nodes[this.options.from];
26409 this.to = this._body.nodes[this.options.to];
26410
26411 if (this.from === undefined || this.to === undefined || this.options.physics === false) {
26412 this.via.setOptions({
26413 physics: false
26414 });
26415 } else {
26416 // fix weird behaviour where a self referencing node has physics enabled
26417 if (this.from.id === this.to.id) {
26418 this.via.setOptions({
26419 physics: false
26420 });
26421 } else {
26422 this.via.setOptions({
26423 physics: true
26424 });
26425 }
26426 }
26427 }
26428 /** @inheritDoc */
26429
26430 }, {
26431 key: "cleanup",
26432 value: function cleanup() {
26433 this._body.emitter.off("_repositionBezierNodes", this._boundFunction);
26434
26435 if (this.via !== undefined) {
26436 delete this._body.nodes[this.via.id];
26437 this.via = undefined;
26438 return true;
26439 }
26440
26441 return false;
26442 }
26443 /**
26444 * Create and add a support node if not already present.
26445 *
26446 * @remarks
26447 * Bezier curves require an anchor point to calculate the smooth flow.
26448 * These points are nodes.
26449 * These nodes are invisible but are used for the force calculation.
26450 *
26451 * The changed data is not called, if needed, it is returned by the main edge constructor.
26452 */
26453
26454 }, {
26455 key: "setupSupportNode",
26456 value: function setupSupportNode() {
26457 if (this.via === undefined) {
26458 var nodeId = "edgeId:" + this.id;
26459
26460 var node = this._body.functions.createNode({
26461 id: nodeId,
26462 shape: "circle",
26463 physics: true,
26464 hidden: true
26465 });
26466
26467 this._body.nodes[nodeId] = node;
26468 this.via = node;
26469 this.via.parentEdgeId = this.id;
26470 this.positionBezierNode();
26471 }
26472 }
26473 /**
26474 * Position bezier node.
26475 */
26476
26477 }, {
26478 key: "positionBezierNode",
26479 value: function positionBezierNode() {
26480 if (this.via !== undefined && this.from !== undefined && this.to !== undefined) {
26481 this.via.x = 0.5 * (this.from.x + this.to.x);
26482 this.via.y = 0.5 * (this.from.y + this.to.y);
26483 } else if (this.via !== undefined) {
26484 this.via.x = 0;
26485 this.via.y = 0;
26486 }
26487 }
26488 /** @inheritDoc */
26489
26490 }, {
26491 key: "_line",
26492 value: function _line(ctx, values, viaNode) {
26493 this._bezierCurve(ctx, values, viaNode);
26494 }
26495 /** @inheritDoc */
26496
26497 }, {
26498 key: "_getViaCoordinates",
26499 value: function _getViaCoordinates() {
26500 return this.via;
26501 }
26502 /** @inheritDoc */
26503
26504 }, {
26505 key: "getViaNode",
26506 value: function getViaNode() {
26507 return this.via;
26508 }
26509 /** @inheritDoc */
26510
26511 }, {
26512 key: "getPoint",
26513 value: function getPoint(position) {
26514 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.via;
26515
26516 if (this.from === this.to) {
26517 var _this$_getCircleData = this._getCircleData(),
26518 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
26519 cx = _this$_getCircleData2[0],
26520 cy = _this$_getCircleData2[1],
26521 cr = _this$_getCircleData2[2];
26522
26523 var a = 2 * Math.PI * (1 - position);
26524 return {
26525 x: cx + cr * Math.sin(a),
26526 y: cy + cr - cr * (1 - Math.cos(a))
26527 };
26528 } else {
26529 return {
26530 x: Math.pow(1 - position, 2) * this.fromPoint.x + 2 * position * (1 - position) * viaNode.x + Math.pow(position, 2) * this.toPoint.x,
26531 y: Math.pow(1 - position, 2) * this.fromPoint.y + 2 * position * (1 - position) * viaNode.y + Math.pow(position, 2) * this.toPoint.y
26532 };
26533 }
26534 }
26535 /** @inheritDoc */
26536
26537 }, {
26538 key: "_findBorderPosition",
26539 value: function _findBorderPosition(nearNode, ctx) {
26540 return this._findBorderPositionBezier(nearNode, ctx, this.via);
26541 }
26542 /** @inheritDoc */
26543
26544 }, {
26545 key: "_getDistanceToEdge",
26546 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
26547 // x3,y3 is the point
26548 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, this.via);
26549 }
26550 }]);
26551
26552 return BezierEdgeDynamic;
26553}(BezierEdgeBase);
26554
26555function _createSuper$7(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$7(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
26556
26557function _isNativeReflectConstruct$7() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
26558/**
26559 * A Static Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
26560 */
26561
26562var BezierEdgeStatic = /*#__PURE__*/function (_BezierEdgeBase) {
26563 _inherits(BezierEdgeStatic, _BezierEdgeBase);
26564
26565 var _super = _createSuper$7(BezierEdgeStatic);
26566
26567 /**
26568 * Create a new instance.
26569 *
26570 * @param options - The options object of given edge.
26571 * @param body - The body of the network.
26572 * @param labelModule - Label module.
26573 */
26574 function BezierEdgeStatic(options, body, labelModule) {
26575 _classCallCheck(this, BezierEdgeStatic);
26576
26577 return _super.call(this, options, body, labelModule);
26578 }
26579 /** @inheritDoc */
26580
26581
26582 _createClass(BezierEdgeStatic, [{
26583 key: "_line",
26584 value: function _line(ctx, values, viaNode) {
26585 this._bezierCurve(ctx, values, viaNode);
26586 }
26587 /** @inheritDoc */
26588
26589 }, {
26590 key: "getViaNode",
26591 value: function getViaNode() {
26592 return this._getViaCoordinates();
26593 }
26594 /**
26595 * Compute the coordinates of the via node.
26596 *
26597 * @remarks
26598 * We do not use the to and fromPoints here to make the via nodes the same as edges without arrows.
26599 *
26600 * @returns Cartesian coordinates of the via node.
26601 */
26602
26603 }, {
26604 key: "_getViaCoordinates",
26605 value: function _getViaCoordinates() {
26606 // Assumption: x/y coordinates in from/to always defined
26607 var factor = this.options.smooth.roundness;
26608 var type = this.options.smooth.type;
26609 var dx = Math.abs(this.from.x - this.to.x);
26610 var dy = Math.abs(this.from.y - this.to.y);
26611
26612 if (type === "discrete" || type === "diagonalCross") {
26613 var stepX;
26614 var stepY;
26615
26616 if (dx <= dy) {
26617 stepX = stepY = factor * dy;
26618 } else {
26619 stepX = stepY = factor * dx;
26620 }
26621
26622 if (this.from.x > this.to.x) {
26623 stepX = -stepX;
26624 }
26625
26626 if (this.from.y >= this.to.y) {
26627 stepY = -stepY;
26628 }
26629
26630 var xVia = this.from.x + stepX;
26631 var yVia = this.from.y + stepY;
26632
26633 if (type === "discrete") {
26634 if (dx <= dy) {
26635 xVia = dx < factor * dy ? this.from.x : xVia;
26636 } else {
26637 yVia = dy < factor * dx ? this.from.y : yVia;
26638 }
26639 }
26640
26641 return {
26642 x: xVia,
26643 y: yVia
26644 };
26645 } else if (type === "straightCross") {
26646 var _stepX = (1 - factor) * dx;
26647
26648 var _stepY = (1 - factor) * dy;
26649
26650 if (dx <= dy) {
26651 // up - down
26652 _stepX = 0;
26653
26654 if (this.from.y < this.to.y) {
26655 _stepY = -_stepY;
26656 }
26657 } else {
26658 // left - right
26659 if (this.from.x < this.to.x) {
26660 _stepX = -_stepX;
26661 }
26662
26663 _stepY = 0;
26664 }
26665
26666 return {
26667 x: this.to.x + _stepX,
26668 y: this.to.y + _stepY
26669 };
26670 } else if (type === "horizontal") {
26671 var _stepX2 = (1 - factor) * dx;
26672
26673 if (this.from.x < this.to.x) {
26674 _stepX2 = -_stepX2;
26675 }
26676
26677 return {
26678 x: this.to.x + _stepX2,
26679 y: this.from.y
26680 };
26681 } else if (type === "vertical") {
26682 var _stepY2 = (1 - factor) * dy;
26683
26684 if (this.from.y < this.to.y) {
26685 _stepY2 = -_stepY2;
26686 }
26687
26688 return {
26689 x: this.from.x,
26690 y: this.to.y + _stepY2
26691 };
26692 } else if (type === "curvedCW") {
26693 dx = this.to.x - this.from.x;
26694 dy = this.from.y - this.to.y;
26695 var radius = Math.sqrt(dx * dx + dy * dy);
26696 var pi = Math.PI;
26697 var originalAngle = Math.atan2(dy, dx);
26698 var myAngle = (originalAngle + (factor * 0.5 + 0.5) * pi) % (2 * pi);
26699 return {
26700 x: this.from.x + (factor * 0.5 + 0.5) * radius * Math.sin(myAngle),
26701 y: this.from.y + (factor * 0.5 + 0.5) * radius * Math.cos(myAngle)
26702 };
26703 } else if (type === "curvedCCW") {
26704 dx = this.to.x - this.from.x;
26705 dy = this.from.y - this.to.y;
26706
26707 var _radius = Math.sqrt(dx * dx + dy * dy);
26708
26709 var _pi = Math.PI;
26710
26711 var _originalAngle = Math.atan2(dy, dx);
26712
26713 var _myAngle = (_originalAngle + (-factor * 0.5 + 0.5) * _pi) % (2 * _pi);
26714
26715 return {
26716 x: this.from.x + (factor * 0.5 + 0.5) * _radius * Math.sin(_myAngle),
26717 y: this.from.y + (factor * 0.5 + 0.5) * _radius * Math.cos(_myAngle)
26718 };
26719 } else {
26720 // continuous
26721 var _stepX3;
26722
26723 var _stepY3;
26724
26725 if (dx <= dy) {
26726 _stepX3 = _stepY3 = factor * dy;
26727 } else {
26728 _stepX3 = _stepY3 = factor * dx;
26729 }
26730
26731 if (this.from.x > this.to.x) {
26732 _stepX3 = -_stepX3;
26733 }
26734
26735 if (this.from.y >= this.to.y) {
26736 _stepY3 = -_stepY3;
26737 }
26738
26739 var _xVia = this.from.x + _stepX3;
26740
26741 var _yVia = this.from.y + _stepY3;
26742
26743 if (dx <= dy) {
26744 if (this.from.x <= this.to.x) {
26745 _xVia = this.to.x < _xVia ? this.to.x : _xVia;
26746 } else {
26747 _xVia = this.to.x > _xVia ? this.to.x : _xVia;
26748 }
26749 } else {
26750 if (this.from.y >= this.to.y) {
26751 _yVia = this.to.y > _yVia ? this.to.y : _yVia;
26752 } else {
26753 _yVia = this.to.y < _yVia ? this.to.y : _yVia;
26754 }
26755 }
26756
26757 return {
26758 x: _xVia,
26759 y: _yVia
26760 };
26761 }
26762 }
26763 /** @inheritDoc */
26764
26765 }, {
26766 key: "_findBorderPosition",
26767 value: function _findBorderPosition(nearNode, ctx) {
26768 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
26769 return this._findBorderPositionBezier(nearNode, ctx, options.via);
26770 }
26771 /** @inheritDoc */
26772
26773 }, {
26774 key: "_getDistanceToEdge",
26775 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
26776 var viaNode = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates();
26777 // x3,y3 is the point
26778 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, viaNode);
26779 }
26780 /** @inheritDoc */
26781
26782 }, {
26783 key: "getPoint",
26784 value: function getPoint(position) {
26785 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates();
26786 var t = position;
26787 var x = Math.pow(1 - t, 2) * this.fromPoint.x + 2 * t * (1 - t) * viaNode.x + Math.pow(t, 2) * this.toPoint.x;
26788 var y = Math.pow(1 - t, 2) * this.fromPoint.y + 2 * t * (1 - t) * viaNode.y + Math.pow(t, 2) * this.toPoint.y;
26789 return {
26790 x: x,
26791 y: y
26792 };
26793 }
26794 }]);
26795
26796 return BezierEdgeStatic;
26797}(BezierEdgeBase);
26798
26799function _createSuper$6(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$6(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
26800
26801function _isNativeReflectConstruct$6() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
26802/**
26803 * A Base Class for all Cubic Bezier Edges. Bezier curves are used to model
26804 * smooth gradual curves in paths between nodes.
26805 *
26806 * @augments BezierEdgeBase
26807 */
26808
26809var CubicBezierEdgeBase = /*#__PURE__*/function (_BezierEdgeBase) {
26810 _inherits(CubicBezierEdgeBase, _BezierEdgeBase);
26811
26812 var _super = _createSuper$6(CubicBezierEdgeBase);
26813
26814 /**
26815 * Create a new instance.
26816 *
26817 * @param options - The options object of given edge.
26818 * @param body - The body of the network.
26819 * @param labelModule - Label module.
26820 */
26821 function CubicBezierEdgeBase(options, body, labelModule) {
26822 _classCallCheck(this, CubicBezierEdgeBase);
26823
26824 return _super.call(this, options, body, labelModule);
26825 }
26826 /**
26827 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
26828 *
26829 * @remarks
26830 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
26831 * https://en.wikipedia.org/wiki/B%C3%A9zier_curve
26832 *
26833 * @param x1 - First end of the line segment on the x axis.
26834 * @param y1 - First end of the line segment on the y axis.
26835 * @param x2 - Second end of the line segment on the x axis.
26836 * @param y2 - Second end of the line segment on the y axis.
26837 * @param x3 - Position of the point on the x axis.
26838 * @param y3 - Position of the point on the y axis.
26839 * @param via1 - The first point this edge passes through.
26840 * @param via2 - The second point this edge passes through.
26841 *
26842 * @returns The distance between the line segment and the point.
26843 */
26844
26845
26846 _createClass(CubicBezierEdgeBase, [{
26847 key: "_getDistanceToBezierEdge2",
26848 value: function _getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2) {
26849 // x3,y3 is the point
26850 var minDistance = 1e9;
26851 var lastX = x1;
26852 var lastY = y1;
26853 var vec = [0, 0, 0, 0];
26854
26855 for (var i = 1; i < 10; i++) {
26856 var t = 0.1 * i;
26857 vec[0] = Math.pow(1 - t, 3);
26858 vec[1] = 3 * t * Math.pow(1 - t, 2);
26859 vec[2] = 3 * Math.pow(t, 2) * (1 - t);
26860 vec[3] = Math.pow(t, 3);
26861 var x = vec[0] * x1 + vec[1] * via1.x + vec[2] * via2.x + vec[3] * x2;
26862 var y = vec[0] * y1 + vec[1] * via1.y + vec[2] * via2.y + vec[3] * y2;
26863
26864 if (i > 0) {
26865 var distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
26866
26867 minDistance = distance < minDistance ? distance : minDistance;
26868 }
26869
26870 lastX = x;
26871 lastY = y;
26872 }
26873
26874 return minDistance;
26875 }
26876 }]);
26877
26878 return CubicBezierEdgeBase;
26879}(BezierEdgeBase);
26880
26881function _createSuper$5(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$5(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
26882
26883function _isNativeReflectConstruct$5() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
26884/**
26885 * A Cubic Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
26886 */
26887
26888var CubicBezierEdge = /*#__PURE__*/function (_CubicBezierEdgeBase) {
26889 _inherits(CubicBezierEdge, _CubicBezierEdgeBase);
26890
26891 var _super = _createSuper$5(CubicBezierEdge);
26892
26893 /**
26894 * Create a new instance.
26895 *
26896 * @param options - The options object of given edge.
26897 * @param body - The body of the network.
26898 * @param labelModule - Label module.
26899 */
26900 function CubicBezierEdge(options, body, labelModule) {
26901 _classCallCheck(this, CubicBezierEdge);
26902
26903 return _super.call(this, options, body, labelModule);
26904 }
26905 /** @inheritDoc */
26906
26907
26908 _createClass(CubicBezierEdge, [{
26909 key: "_line",
26910 value: function _line(ctx, values, viaNodes) {
26911 // get the coordinates of the support points.
26912 var via1 = viaNodes[0];
26913 var via2 = viaNodes[1];
26914
26915 this._bezierCurve(ctx, values, via1, via2);
26916 }
26917 /**
26918 * Compute the additional points the edge passes through.
26919 *
26920 * @returns Cartesian coordinates of the points the edge passes through.
26921 */
26922
26923 }, {
26924 key: "_getViaCoordinates",
26925 value: function _getViaCoordinates() {
26926 var dx = this.from.x - this.to.x;
26927 var dy = this.from.y - this.to.y;
26928 var x1;
26929 var y1;
26930 var x2;
26931 var y2;
26932 var roundness = this.options.smooth.roundness; // horizontal if x > y or if direction is forced or if direction is horizontal
26933
26934 if ((Math.abs(dx) > Math.abs(dy) || this.options.smooth.forceDirection === true || this.options.smooth.forceDirection === "horizontal") && this.options.smooth.forceDirection !== "vertical") {
26935 y1 = this.from.y;
26936 y2 = this.to.y;
26937 x1 = this.from.x - roundness * dx;
26938 x2 = this.to.x + roundness * dx;
26939 } else {
26940 y1 = this.from.y - roundness * dy;
26941 y2 = this.to.y + roundness * dy;
26942 x1 = this.from.x;
26943 x2 = this.to.x;
26944 }
26945
26946 return [{
26947 x: x1,
26948 y: y1
26949 }, {
26950 x: x2,
26951 y: y2
26952 }];
26953 }
26954 /** @inheritDoc */
26955
26956 }, {
26957 key: "getViaNode",
26958 value: function getViaNode() {
26959 return this._getViaCoordinates();
26960 }
26961 /** @inheritDoc */
26962
26963 }, {
26964 key: "_findBorderPosition",
26965 value: function _findBorderPosition(nearNode, ctx) {
26966 return this._findBorderPositionBezier(nearNode, ctx);
26967 }
26968 /** @inheritDoc */
26969
26970 }, {
26971 key: "_getDistanceToEdge",
26972 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
26973 var _ref = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates(),
26974 _ref2 = _slicedToArray(_ref, 2),
26975 via1 = _ref2[0],
26976 via2 = _ref2[1];
26977
26978 // x3,y3 is the point
26979 return this._getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2);
26980 }
26981 /** @inheritDoc */
26982
26983 }, {
26984 key: "getPoint",
26985 value: function getPoint(position) {
26986 var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates(),
26987 _ref4 = _slicedToArray(_ref3, 2),
26988 via1 = _ref4[0],
26989 via2 = _ref4[1];
26990
26991 var t = position;
26992 var vec = [Math.pow(1 - t, 3), 3 * t * Math.pow(1 - t, 2), 3 * Math.pow(t, 2) * (1 - t), Math.pow(t, 3)];
26993 var x = vec[0] * this.fromPoint.x + vec[1] * via1.x + vec[2] * via2.x + vec[3] * this.toPoint.x;
26994 var y = vec[0] * this.fromPoint.y + vec[1] * via1.y + vec[2] * via2.y + vec[3] * this.toPoint.y;
26995 return {
26996 x: x,
26997 y: y
26998 };
26999 }
27000 }]);
27001
27002 return CubicBezierEdge;
27003}(CubicBezierEdgeBase);
27004
27005function _createSuper$4(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$4(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
27006
27007function _isNativeReflectConstruct$4() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
27008/**
27009 * A Straight Edge.
27010 */
27011
27012var StraightEdge = /*#__PURE__*/function (_EdgeBase) {
27013 _inherits(StraightEdge, _EdgeBase);
27014
27015 var _super = _createSuper$4(StraightEdge);
27016
27017 /**
27018 * Create a new instance.
27019 *
27020 * @param options - The options object of given edge.
27021 * @param body - The body of the network.
27022 * @param labelModule - Label module.
27023 */
27024 function StraightEdge(options, body, labelModule) {
27025 _classCallCheck(this, StraightEdge);
27026
27027 return _super.call(this, options, body, labelModule);
27028 }
27029 /** @inheritDoc */
27030
27031
27032 _createClass(StraightEdge, [{
27033 key: "_line",
27034 value: function _line(ctx, values) {
27035 // draw a straight line
27036 ctx.beginPath();
27037 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
27038 ctx.lineTo(this.toPoint.x, this.toPoint.y); // draw shadow if enabled
27039
27040 this.enableShadow(ctx, values);
27041 ctx.stroke();
27042 this.disableShadow(ctx, values);
27043 }
27044 /** @inheritDoc */
27045
27046 }, {
27047 key: "getViaNode",
27048 value: function getViaNode() {
27049 return undefined;
27050 }
27051 /** @inheritDoc */
27052
27053 }, {
27054 key: "getPoint",
27055 value: function getPoint(position) {
27056 return {
27057 x: (1 - position) * this.fromPoint.x + position * this.toPoint.x,
27058 y: (1 - position) * this.fromPoint.y + position * this.toPoint.y
27059 };
27060 }
27061 /** @inheritDoc */
27062
27063 }, {
27064 key: "_findBorderPosition",
27065 value: function _findBorderPosition(nearNode, ctx) {
27066 var node1 = this.to;
27067 var node2 = this.from;
27068
27069 if (nearNode.id === this.from.id) {
27070 node1 = this.from;
27071 node2 = this.to;
27072 }
27073
27074 var angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
27075 var dx = node1.x - node2.x;
27076 var dy = node1.y - node2.y;
27077 var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
27078 var toBorderDist = nearNode.distanceToBorder(ctx, angle);
27079 var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
27080 return {
27081 x: (1 - toBorderPoint) * node2.x + toBorderPoint * node1.x,
27082 y: (1 - toBorderPoint) * node2.y + toBorderPoint * node1.y,
27083 t: 0
27084 };
27085 }
27086 /** @inheritDoc */
27087
27088 }, {
27089 key: "_getDistanceToEdge",
27090 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
27091 // x3,y3 is the point
27092 return this._getDistanceToLine(x1, y1, x2, y2, x3, y3);
27093 }
27094 }]);
27095
27096 return StraightEdge;
27097}(EdgeBase);
27098
27099/**
27100 * An edge connects two nodes and has a specific direction.
27101 */
27102
27103var Edge = /*#__PURE__*/function () {
27104 /**
27105 * @param {object} options values specific to this edge, must contain at least 'from' and 'to'
27106 * @param {object} body shared state from Network instance
27107 * @param {Network.Images} imagelist A list with images. Only needed when the edge has image arrows.
27108 * @param {object} globalOptions options from the EdgesHandler instance
27109 * @param {object} defaultOptions default options from the EdgeHandler instance. Value and reference are constant
27110 */
27111 function Edge(options, body, imagelist, globalOptions, defaultOptions) {
27112 _classCallCheck(this, Edge);
27113
27114 if (body === undefined) {
27115 throw new Error("No body provided");
27116 } // Since globalOptions is constant in values as well as reference,
27117 // Following needs to be done only once.
27118
27119
27120 this.options = bridgeObject(globalOptions);
27121 this.globalOptions = globalOptions;
27122 this.defaultOptions = defaultOptions;
27123 this.body = body;
27124 this.imagelist = imagelist; // initialize variables
27125
27126 this.id = undefined;
27127 this.fromId = undefined;
27128 this.toId = undefined;
27129 this.selected = false;
27130 this.hover = false;
27131 this.labelDirty = true;
27132 this.baseWidth = this.options.width;
27133 this.baseFontSize = this.options.font.size;
27134 this.from = undefined; // a node
27135
27136 this.to = undefined; // a node
27137
27138 this.edgeType = undefined;
27139 this.connected = false;
27140 this.labelModule = new Label(this.body, this.options, true
27141 /* It's an edge label */
27142 );
27143 this.setOptions(options);
27144 }
27145 /**
27146 * Set or overwrite options for the edge
27147 *
27148 * @param {object} options an object with options
27149 * @returns {undefined|boolean} undefined if no options, true if layout affecting data changed, false otherwise.
27150 */
27151
27152
27153 _createClass(Edge, [{
27154 key: "setOptions",
27155 value: function setOptions(options) {
27156 if (!options) {
27157 return;
27158 } // Following options if changed affect the layout.
27159
27160
27161 var affectsLayout = typeof options.physics !== "undefined" && this.options.physics !== options.physics || typeof options.hidden !== "undefined" && (this.options.hidden || false) !== (options.hidden || false) || typeof options.from !== "undefined" && this.options.from !== options.from || typeof options.to !== "undefined" && this.options.to !== options.to;
27162 Edge.parseOptions(this.options, options, true, this.globalOptions);
27163
27164 if (options.id !== undefined) {
27165 this.id = options.id;
27166 }
27167
27168 if (options.from !== undefined) {
27169 this.fromId = options.from;
27170 }
27171
27172 if (options.to !== undefined) {
27173 this.toId = options.to;
27174 }
27175
27176 if (options.title !== undefined) {
27177 this.title = options.title;
27178 }
27179
27180 if (options.value !== undefined) {
27181 options.value = _parseFloat(options.value);
27182 }
27183
27184 var pile = [options, this.options, this.defaultOptions];
27185 this.chooser = choosify("edge", pile); // update label Module
27186
27187 this.updateLabelModule(options); // Update edge type, this if changed affects the layout.
27188
27189 affectsLayout = this.updateEdgeType() || affectsLayout; // if anything has been updates, reset the selection width and the hover width
27190
27191 this._setInteractionWidths(); // A node is connected when it has a from and to node that both exist in the network.body.nodes.
27192
27193
27194 this.connect();
27195 return affectsLayout;
27196 }
27197 /**
27198 *
27199 * @param {object} parentOptions
27200 * @param {object} newOptions
27201 * @param {boolean} [allowDeletion=false]
27202 * @param {object} [globalOptions={}]
27203 * @param {boolean} [copyFromGlobals=false]
27204 */
27205
27206 }, {
27207 key: "getFormattingValues",
27208 value:
27209 /**
27210 *
27211 * @returns {ArrowOptions}
27212 */
27213 function getFormattingValues() {
27214 var toArrow = this.options.arrows.to === true || this.options.arrows.to.enabled === true;
27215 var fromArrow = this.options.arrows.from === true || this.options.arrows.from.enabled === true;
27216 var middleArrow = this.options.arrows.middle === true || this.options.arrows.middle.enabled === true;
27217 var inheritsColor = this.options.color.inherit;
27218 var values = {
27219 toArrow: toArrow,
27220 toArrowScale: this.options.arrows.to.scaleFactor,
27221 toArrowType: this.options.arrows.to.type,
27222 toArrowSrc: this.options.arrows.to.src,
27223 toArrowImageWidth: this.options.arrows.to.imageWidth,
27224 toArrowImageHeight: this.options.arrows.to.imageHeight,
27225 middleArrow: middleArrow,
27226 middleArrowScale: this.options.arrows.middle.scaleFactor,
27227 middleArrowType: this.options.arrows.middle.type,
27228 middleArrowSrc: this.options.arrows.middle.src,
27229 middleArrowImageWidth: this.options.arrows.middle.imageWidth,
27230 middleArrowImageHeight: this.options.arrows.middle.imageHeight,
27231 fromArrow: fromArrow,
27232 fromArrowScale: this.options.arrows.from.scaleFactor,
27233 fromArrowType: this.options.arrows.from.type,
27234 fromArrowSrc: this.options.arrows.from.src,
27235 fromArrowImageWidth: this.options.arrows.from.imageWidth,
27236 fromArrowImageHeight: this.options.arrows.from.imageHeight,
27237 arrowStrikethrough: this.options.arrowStrikethrough,
27238 color: inheritsColor ? undefined : this.options.color.color,
27239 inheritsColor: inheritsColor,
27240 opacity: this.options.color.opacity,
27241 hidden: this.options.hidden,
27242 length: this.options.length,
27243 shadow: this.options.shadow.enabled,
27244 shadowColor: this.options.shadow.color,
27245 shadowSize: this.options.shadow.size,
27246 shadowX: this.options.shadow.x,
27247 shadowY: this.options.shadow.y,
27248 dashes: this.options.dashes,
27249 width: this.options.width,
27250 background: this.options.background.enabled,
27251 backgroundColor: this.options.background.color,
27252 backgroundSize: this.options.background.size,
27253 backgroundDashes: this.options.background.dashes
27254 };
27255
27256 if (this.selected || this.hover) {
27257 if (this.chooser === true) {
27258 if (this.selected) {
27259 var selectedWidth = this.options.selectionWidth;
27260
27261 if (typeof selectedWidth === "function") {
27262 values.width = selectedWidth(values.width);
27263 } else if (typeof selectedWidth === "number") {
27264 values.width += selectedWidth;
27265 }
27266
27267 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
27268 values.color = this.options.color.highlight;
27269 values.shadow = this.options.shadow.enabled;
27270 } else if (this.hover) {
27271 var hoverWidth = this.options.hoverWidth;
27272
27273 if (typeof hoverWidth === "function") {
27274 values.width = hoverWidth(values.width);
27275 } else if (typeof hoverWidth === "number") {
27276 values.width += hoverWidth;
27277 }
27278
27279 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
27280 values.color = this.options.color.hover;
27281 values.shadow = this.options.shadow.enabled;
27282 }
27283 } else if (typeof this.chooser === "function") {
27284 this.chooser(values, this.options.id, this.selected, this.hover);
27285
27286 if (values.color !== undefined) {
27287 values.inheritsColor = false;
27288 }
27289
27290 if (values.shadow === false) {
27291 if (values.shadowColor !== this.options.shadow.color || values.shadowSize !== this.options.shadow.size || values.shadowX !== this.options.shadow.x || values.shadowY !== this.options.shadow.y) {
27292 values.shadow = true;
27293 }
27294 }
27295 }
27296 } else {
27297 values.shadow = this.options.shadow.enabled;
27298 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
27299 }
27300
27301 return values;
27302 }
27303 /**
27304 * update the options in the label module
27305 *
27306 * @param {object} options
27307 */
27308
27309 }, {
27310 key: "updateLabelModule",
27311 value: function updateLabelModule(options) {
27312 var pile = [options, this.options, this.globalOptions, // Currently set global edge options
27313 this.defaultOptions];
27314 this.labelModule.update(this.options, pile);
27315
27316 if (this.labelModule.baseSize !== undefined) {
27317 this.baseFontSize = this.labelModule.baseSize;
27318 }
27319 }
27320 /**
27321 * update the edge type, set the options
27322 *
27323 * @returns {boolean}
27324 */
27325
27326 }, {
27327 key: "updateEdgeType",
27328 value: function updateEdgeType() {
27329 var smooth = this.options.smooth;
27330 var dataChanged = false;
27331 var changeInType = true;
27332
27333 if (this.edgeType !== undefined) {
27334 if (this.edgeType instanceof BezierEdgeDynamic && smooth.enabled === true && smooth.type === "dynamic" || this.edgeType instanceof CubicBezierEdge && smooth.enabled === true && smooth.type === "cubicBezier" || this.edgeType instanceof BezierEdgeStatic && smooth.enabled === true && smooth.type !== "dynamic" && smooth.type !== "cubicBezier" || this.edgeType instanceof StraightEdge && smooth.type.enabled === false) {
27335 changeInType = false;
27336 }
27337
27338 if (changeInType === true) {
27339 dataChanged = this.cleanup();
27340 }
27341 }
27342
27343 if (changeInType === true) {
27344 if (smooth.enabled === true) {
27345 if (smooth.type === "dynamic") {
27346 dataChanged = true;
27347 this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
27348 } else if (smooth.type === "cubicBezier") {
27349 this.edgeType = new CubicBezierEdge(this.options, this.body, this.labelModule);
27350 } else {
27351 this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
27352 }
27353 } else {
27354 this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
27355 }
27356 } else {
27357 // if nothing changes, we just set the options.
27358 this.edgeType.setOptions(this.options);
27359 }
27360
27361 return dataChanged;
27362 }
27363 /**
27364 * Connect an edge to its nodes
27365 */
27366
27367 }, {
27368 key: "connect",
27369 value: function connect() {
27370 this.disconnect();
27371 this.from = this.body.nodes[this.fromId] || undefined;
27372 this.to = this.body.nodes[this.toId] || undefined;
27373 this.connected = this.from !== undefined && this.to !== undefined;
27374
27375 if (this.connected === true) {
27376 this.from.attachEdge(this);
27377 this.to.attachEdge(this);
27378 } else {
27379 if (this.from) {
27380 this.from.detachEdge(this);
27381 }
27382
27383 if (this.to) {
27384 this.to.detachEdge(this);
27385 }
27386 }
27387
27388 this.edgeType.connect();
27389 }
27390 /**
27391 * Disconnect an edge from its nodes
27392 */
27393
27394 }, {
27395 key: "disconnect",
27396 value: function disconnect() {
27397 if (this.from) {
27398 this.from.detachEdge(this);
27399 this.from = undefined;
27400 }
27401
27402 if (this.to) {
27403 this.to.detachEdge(this);
27404 this.to = undefined;
27405 }
27406
27407 this.connected = false;
27408 }
27409 /**
27410 * get the title of this edge.
27411 *
27412 * @returns {string} title The title of the edge, or undefined when no title
27413 * has been set.
27414 */
27415
27416 }, {
27417 key: "getTitle",
27418 value: function getTitle() {
27419 return this.title;
27420 }
27421 /**
27422 * check if this node is selecte
27423 *
27424 * @returns {boolean} selected True if node is selected, else false
27425 */
27426
27427 }, {
27428 key: "isSelected",
27429 value: function isSelected() {
27430 return this.selected;
27431 }
27432 /**
27433 * Retrieve the value of the edge. Can be undefined
27434 *
27435 * @returns {number} value
27436 */
27437
27438 }, {
27439 key: "getValue",
27440 value: function getValue() {
27441 return this.options.value;
27442 }
27443 /**
27444 * Adjust the value range of the edge. The edge will adjust it's width
27445 * based on its value.
27446 *
27447 * @param {number} min
27448 * @param {number} max
27449 * @param {number} total
27450 */
27451
27452 }, {
27453 key: "setValueRange",
27454 value: function setValueRange(min, max, total) {
27455 if (this.options.value !== undefined) {
27456 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
27457 var widthDiff = this.options.scaling.max - this.options.scaling.min;
27458
27459 if (this.options.scaling.label.enabled === true) {
27460 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
27461 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
27462 }
27463
27464 this.options.width = this.options.scaling.min + scale * widthDiff;
27465 } else {
27466 this.options.width = this.baseWidth;
27467 this.options.font.size = this.baseFontSize;
27468 }
27469
27470 this._setInteractionWidths();
27471
27472 this.updateLabelModule();
27473 }
27474 /**
27475 *
27476 * @private
27477 */
27478
27479 }, {
27480 key: "_setInteractionWidths",
27481 value: function _setInteractionWidths() {
27482 if (typeof this.options.hoverWidth === "function") {
27483 this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
27484 } else {
27485 this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
27486 }
27487
27488 if (typeof this.options.selectionWidth === "function") {
27489 this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
27490 } else {
27491 this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
27492 }
27493 }
27494 /**
27495 * Redraw a edge
27496 * Draw this edge in the given canvas
27497 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
27498 *
27499 * @param {CanvasRenderingContext2D} ctx
27500 */
27501
27502 }, {
27503 key: "draw",
27504 value: function draw(ctx) {
27505 var values = this.getFormattingValues();
27506
27507 if (values.hidden) {
27508 return;
27509 } // get the via node from the edge type
27510
27511
27512 var viaNode = this.edgeType.getViaNode(); // draw line and label
27513
27514 this.edgeType.drawLine(ctx, values, this.selected, this.hover, viaNode);
27515 this.drawLabel(ctx, viaNode);
27516 }
27517 /**
27518 * Redraw arrows
27519 * Draw this arrows in the given canvas
27520 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
27521 *
27522 * @param {CanvasRenderingContext2D} ctx
27523 */
27524
27525 }, {
27526 key: "drawArrows",
27527 value: function drawArrows(ctx) {
27528 var values = this.getFormattingValues();
27529
27530 if (values.hidden) {
27531 return;
27532 } // get the via node from the edge type
27533
27534
27535 var viaNode = this.edgeType.getViaNode();
27536 var arrowData = {}; // restore edge targets to defaults
27537
27538 this.edgeType.fromPoint = this.edgeType.from;
27539 this.edgeType.toPoint = this.edgeType.to; // from and to arrows give a different end point for edges. we set them here
27540
27541 if (values.fromArrow) {
27542 arrowData.from = this.edgeType.getArrowData(ctx, "from", viaNode, this.selected, this.hover, values);
27543 if (values.arrowStrikethrough === false) this.edgeType.fromPoint = arrowData.from.core;
27544
27545 if (values.fromArrowSrc) {
27546 arrowData.from.image = this.imagelist.load(values.fromArrowSrc);
27547 }
27548
27549 if (values.fromArrowImageWidth) {
27550 arrowData.from.imageWidth = values.fromArrowImageWidth;
27551 }
27552
27553 if (values.fromArrowImageHeight) {
27554 arrowData.from.imageHeight = values.fromArrowImageHeight;
27555 }
27556 }
27557
27558 if (values.toArrow) {
27559 arrowData.to = this.edgeType.getArrowData(ctx, "to", viaNode, this.selected, this.hover, values);
27560 if (values.arrowStrikethrough === false) this.edgeType.toPoint = arrowData.to.core;
27561
27562 if (values.toArrowSrc) {
27563 arrowData.to.image = this.imagelist.load(values.toArrowSrc);
27564 }
27565
27566 if (values.toArrowImageWidth) {
27567 arrowData.to.imageWidth = values.toArrowImageWidth;
27568 }
27569
27570 if (values.toArrowImageHeight) {
27571 arrowData.to.imageHeight = values.toArrowImageHeight;
27572 }
27573 } // the middle arrow depends on the line, which can depend on the to and from arrows so we do this one lastly.
27574
27575
27576 if (values.middleArrow) {
27577 arrowData.middle = this.edgeType.getArrowData(ctx, "middle", viaNode, this.selected, this.hover, values);
27578
27579 if (values.middleArrowSrc) {
27580 arrowData.middle.image = this.imagelist.load(values.middleArrowSrc);
27581 }
27582
27583 if (values.middleArrowImageWidth) {
27584 arrowData.middle.imageWidth = values.middleArrowImageWidth;
27585 }
27586
27587 if (values.middleArrowImageHeight) {
27588 arrowData.middle.imageHeight = values.middleArrowImageHeight;
27589 }
27590 }
27591
27592 if (values.fromArrow) {
27593 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.from);
27594 }
27595
27596 if (values.middleArrow) {
27597 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.middle);
27598 }
27599
27600 if (values.toArrow) {
27601 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.to);
27602 }
27603 }
27604 /**
27605 *
27606 * @param {CanvasRenderingContext2D} ctx
27607 * @param {Node} viaNode
27608 */
27609
27610 }, {
27611 key: "drawLabel",
27612 value: function drawLabel(ctx, viaNode) {
27613 if (this.options.label !== undefined) {
27614 // set style
27615 var node1 = this.from;
27616 var node2 = this.to;
27617
27618 if (this.labelModule.differentState(this.selected, this.hover)) {
27619 this.labelModule.getTextSize(ctx, this.selected, this.hover);
27620 }
27621
27622 var point;
27623
27624 if (node1.id != node2.id) {
27625 this.labelModule.pointToSelf = false;
27626 point = this.edgeType.getPoint(0.5, viaNode);
27627 ctx.save();
27628
27629 var rotationPoint = this._getRotation(ctx);
27630
27631 if (rotationPoint.angle != 0) {
27632 ctx.translate(rotationPoint.x, rotationPoint.y);
27633 ctx.rotate(rotationPoint.angle);
27634 } // draw the label
27635
27636
27637 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
27638 /*
27639 // Useful debug code: draw a border around the label
27640 // This should **not** be enabled in production!
27641 var size = this.labelModule.getSize();; // ;; intentional so lint catches it
27642 ctx.strokeStyle = "#ff0000";
27643 ctx.strokeRect(size.left, size.top, size.width, size.height);
27644 // End debug code
27645 */
27646
27647 ctx.restore();
27648 } else {
27649 // Ignore the orientations.
27650 this.labelModule.pointToSelf = true; // get circle coordinates
27651
27652 var coordinates = getSelfRefCoordinates(ctx, this.options.selfReference.angle, this.options.selfReference.size, node1);
27653 point = this._pointOnCircle(coordinates.x, coordinates.y, this.options.selfReference.size, this.options.selfReference.angle);
27654 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
27655 }
27656 }
27657 }
27658 /**
27659 * Determine all visual elements of this edge instance, in which the given
27660 * point falls within the bounding shape.
27661 *
27662 * @param {point} point
27663 * @returns {Array.<edgeClickItem|edgeLabelClickItem>} list with the items which are on the point
27664 */
27665
27666 }, {
27667 key: "getItemsOnPoint",
27668 value: function getItemsOnPoint(point) {
27669 var ret = [];
27670
27671 if (this.labelModule.visible()) {
27672 var rotationPoint = this._getRotation();
27673
27674 if (pointInRect(this.labelModule.getSize(), point, rotationPoint)) {
27675 ret.push({
27676 edgeId: this.id,
27677 labelId: 0
27678 });
27679 }
27680 }
27681
27682 var obj = {
27683 left: point.x,
27684 top: point.y
27685 };
27686
27687 if (this.isOverlappingWith(obj)) {
27688 ret.push({
27689 edgeId: this.id
27690 });
27691 }
27692
27693 return ret;
27694 }
27695 /**
27696 * Check if this object is overlapping with the provided object
27697 *
27698 * @param {object} obj an object with parameters left, top
27699 * @returns {boolean} True if location is located on the edge
27700 */
27701
27702 }, {
27703 key: "isOverlappingWith",
27704 value: function isOverlappingWith(obj) {
27705 if (this.connected) {
27706 var distMax = 10;
27707 var xFrom = this.from.x;
27708 var yFrom = this.from.y;
27709 var xTo = this.to.x;
27710 var yTo = this.to.y;
27711 var xObj = obj.left;
27712 var yObj = obj.top;
27713 var dist = this.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);
27714 return dist < distMax;
27715 } else {
27716 return false;
27717 }
27718 }
27719 /**
27720 * Determine the rotation point, if any.
27721 *
27722 * @param {CanvasRenderingContext2D} [ctx] if passed, do a recalculation of the label size
27723 * @returns {rotationPoint} the point to rotate around and the angle in radians to rotate
27724 * @private
27725 */
27726
27727 }, {
27728 key: "_getRotation",
27729 value: function _getRotation(ctx) {
27730 var viaNode = this.edgeType.getViaNode();
27731 var point = this.edgeType.getPoint(0.5, viaNode);
27732
27733 if (ctx !== undefined) {
27734 this.labelModule.calculateLabelSize(ctx, this.selected, this.hover, point.x, point.y);
27735 }
27736
27737 var ret = {
27738 x: point.x,
27739 y: this.labelModule.size.yLine,
27740 angle: 0
27741 };
27742
27743 if (!this.labelModule.visible()) {
27744 return ret; // Don't even bother doing the atan2, there's nothing to draw
27745 }
27746
27747 if (this.options.font.align === "horizontal") {
27748 return ret; // No need to calculate angle
27749 }
27750
27751 var dy = this.from.y - this.to.y;
27752 var dx = this.from.x - this.to.x;
27753 var angle = Math.atan2(dy, dx); // radians
27754 // rotate so that label is readable
27755
27756 if (angle < -1 && dx < 0 || angle > 0 && dx < 0) {
27757 angle += Math.PI;
27758 }
27759
27760 ret.angle = angle;
27761 return ret;
27762 }
27763 /**
27764 * Get a point on a circle
27765 *
27766 * @param {number} x
27767 * @param {number} y
27768 * @param {number} radius
27769 * @param {number} angle
27770 * @returns {object} point
27771 * @private
27772 */
27773
27774 }, {
27775 key: "_pointOnCircle",
27776 value: function _pointOnCircle(x, y, radius, angle) {
27777 return {
27778 x: x + radius * Math.cos(angle),
27779 y: y - radius * Math.sin(angle)
27780 };
27781 }
27782 /**
27783 * Sets selected state to true
27784 */
27785
27786 }, {
27787 key: "select",
27788 value: function select() {
27789 this.selected = true;
27790 }
27791 /**
27792 * Sets selected state to false
27793 */
27794
27795 }, {
27796 key: "unselect",
27797 value: function unselect() {
27798 this.selected = false;
27799 }
27800 /**
27801 * cleans all required things on delete
27802 *
27803 * @returns {*}
27804 */
27805
27806 }, {
27807 key: "cleanup",
27808 value: function cleanup() {
27809 return this.edgeType.cleanup();
27810 }
27811 /**
27812 * Remove edge from the list and perform necessary cleanup.
27813 */
27814
27815 }, {
27816 key: "remove",
27817 value: function remove() {
27818 this.cleanup();
27819 this.disconnect();
27820 delete this.body.edges[this.id];
27821 }
27822 /**
27823 * Check if both connecting nodes exist
27824 *
27825 * @returns {boolean}
27826 */
27827
27828 }, {
27829 key: "endPointsValid",
27830 value: function endPointsValid() {
27831 return this.body.nodes[this.fromId] !== undefined && this.body.nodes[this.toId] !== undefined;
27832 }
27833 }], [{
27834 key: "parseOptions",
27835 value: function parseOptions(parentOptions, newOptions) {
27836 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
27837 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
27838 var copyFromGlobals = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
27839 var fields = ["endPointOffset", "arrowStrikethrough", "id", "from", "hidden", "hoverWidth", "labelHighlightBold", "length", "line", "opacity", "physics", "scaling", "selectionWidth", "selfReferenceSize", "selfReference", "to", "title", "value", "width", "font", "chosen", "widthConstraint"]; // only deep extend the items in the field array. These do not have shorthand.
27840
27841 selectiveDeepExtend(fields, parentOptions, newOptions, allowDeletion); // Only use endPointOffset values (from and to) if it's valid values
27842
27843 if (newOptions.endPointOffset !== undefined && newOptions.endPointOffset.from !== undefined) {
27844 if (_isFinite(newOptions.endPointOffset.from)) {
27845 parentOptions.endPointOffset.from = newOptions.endPointOffset.from;
27846 } else {
27847 parentOptions.endPointOffset.from = globalOptions.endPointOffset.from !== undefined ? globalOptions.endPointOffset.from : 0;
27848 console.error("endPointOffset.from is not a valid number");
27849 }
27850 }
27851
27852 if (newOptions.endPointOffset !== undefined && newOptions.endPointOffset.to !== undefined) {
27853 if (_isFinite(newOptions.endPointOffset.to)) {
27854 parentOptions.endPointOffset.to = newOptions.endPointOffset.to;
27855 } else {
27856 parentOptions.endPointOffset.to = globalOptions.endPointOffset.to !== undefined ? globalOptions.endPointOffset.to : 0;
27857 console.error("endPointOffset.to is not a valid number");
27858 }
27859 } // Only copy label if it's a legal value.
27860
27861
27862 if (isValidLabel(newOptions.label)) {
27863 parentOptions.label = newOptions.label;
27864 } else if (!isValidLabel(parentOptions.label)) {
27865 parentOptions.label = undefined;
27866 }
27867
27868 mergeOptions(parentOptions, newOptions, "smooth", globalOptions);
27869 mergeOptions(parentOptions, newOptions, "shadow", globalOptions);
27870 mergeOptions(parentOptions, newOptions, "background", globalOptions);
27871
27872 if (newOptions.dashes !== undefined && newOptions.dashes !== null) {
27873 parentOptions.dashes = newOptions.dashes;
27874 } else if (allowDeletion === true && newOptions.dashes === null) {
27875 parentOptions.dashes = create$2(globalOptions.dashes); // this sets the pointer of the option back to the global option.
27876 } // set the scaling newOptions
27877
27878
27879 if (newOptions.scaling !== undefined && newOptions.scaling !== null) {
27880 if (newOptions.scaling.min !== undefined) {
27881 parentOptions.scaling.min = newOptions.scaling.min;
27882 }
27883
27884 if (newOptions.scaling.max !== undefined) {
27885 parentOptions.scaling.max = newOptions.scaling.max;
27886 }
27887
27888 mergeOptions(parentOptions.scaling, newOptions.scaling, "label", globalOptions.scaling);
27889 } else if (allowDeletion === true && newOptions.scaling === null) {
27890 parentOptions.scaling = create$2(globalOptions.scaling); // this sets the pointer of the option back to the global option.
27891 } // handle multiple input cases for arrows
27892
27893
27894 if (newOptions.arrows !== undefined && newOptions.arrows !== null) {
27895 if (typeof newOptions.arrows === "string") {
27896 var arrows = newOptions.arrows.toLowerCase();
27897 parentOptions.arrows.to.enabled = indexOf(arrows).call(arrows, "to") != -1;
27898 parentOptions.arrows.middle.enabled = indexOf(arrows).call(arrows, "middle") != -1;
27899 parentOptions.arrows.from.enabled = indexOf(arrows).call(arrows, "from") != -1;
27900 } else if (_typeof(newOptions.arrows) === "object") {
27901 mergeOptions(parentOptions.arrows, newOptions.arrows, "to", globalOptions.arrows);
27902 mergeOptions(parentOptions.arrows, newOptions.arrows, "middle", globalOptions.arrows);
27903 mergeOptions(parentOptions.arrows, newOptions.arrows, "from", globalOptions.arrows);
27904 } else {
27905 throw new Error("The arrow newOptions can only be an object or a string. Refer to the documentation. You used:" + stringify$1(newOptions.arrows));
27906 }
27907 } else if (allowDeletion === true && newOptions.arrows === null) {
27908 parentOptions.arrows = create$2(globalOptions.arrows); // this sets the pointer of the option back to the global option.
27909 } // handle multiple input cases for color
27910
27911
27912 if (newOptions.color !== undefined && newOptions.color !== null) {
27913 var fromColor = isString(newOptions.color) ? {
27914 color: newOptions.color,
27915 highlight: newOptions.color,
27916 hover: newOptions.color,
27917 inherit: false,
27918 opacity: 1
27919 } : newOptions.color;
27920 var toColor = parentOptions.color; // If passed, fill in values from default options - required in the case of no prototype bridging
27921
27922 if (copyFromGlobals) {
27923 deepExtend(toColor, globalOptions.color, false, allowDeletion);
27924 } else {
27925 // Clear local properties - need to do it like this in order to retain prototype bridges
27926 for (var i in toColor) {
27927 if (Object.prototype.hasOwnProperty.call(toColor, i)) {
27928 delete toColor[i];
27929 }
27930 }
27931 }
27932
27933 if (isString(toColor)) {
27934 toColor.color = toColor;
27935 toColor.highlight = toColor;
27936 toColor.hover = toColor;
27937 toColor.inherit = false;
27938
27939 if (fromColor.opacity === undefined) {
27940 toColor.opacity = 1.0; // set default
27941 }
27942 } else {
27943 var colorsDefined = false;
27944
27945 if (fromColor.color !== undefined) {
27946 toColor.color = fromColor.color;
27947 colorsDefined = true;
27948 }
27949
27950 if (fromColor.highlight !== undefined) {
27951 toColor.highlight = fromColor.highlight;
27952 colorsDefined = true;
27953 }
27954
27955 if (fromColor.hover !== undefined) {
27956 toColor.hover = fromColor.hover;
27957 colorsDefined = true;
27958 }
27959
27960 if (fromColor.inherit !== undefined) {
27961 toColor.inherit = fromColor.inherit;
27962 }
27963
27964 if (fromColor.opacity !== undefined) {
27965 toColor.opacity = Math.min(1, Math.max(0, fromColor.opacity));
27966 }
27967
27968 if (colorsDefined === true) {
27969 toColor.inherit = false;
27970 } else {
27971 if (toColor.inherit === undefined) {
27972 toColor.inherit = "from"; // Set default
27973 }
27974 }
27975 }
27976 } else if (allowDeletion === true && newOptions.color === null) {
27977 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
27978 }
27979
27980 if (allowDeletion === true && newOptions.font === null) {
27981 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
27982 }
27983
27984 if (Object.prototype.hasOwnProperty.call(newOptions, "selfReferenceSize")) {
27985 console.warn("The selfReferenceSize property has been deprecated. Please use selfReference property instead. The selfReference can be set like thise selfReference:{size:30, angle:Math.PI / 4}");
27986 parentOptions.selfReference.size = newOptions.selfReferenceSize;
27987 }
27988 }
27989 }]);
27990
27991 return Edge;
27992}();
27993
27994/**
27995 * Handler for Edges
27996 */
27997
27998var EdgesHandler = /*#__PURE__*/function () {
27999 /**
28000 * @param {object} body
28001 * @param {Array.<Image>} images
28002 * @param {Array.<Group>} groups
28003 */
28004 function EdgesHandler(body, images, groups) {
28005 var _context,
28006 _this = this;
28007
28008 _classCallCheck(this, EdgesHandler);
28009
28010 this.body = body;
28011 this.images = images;
28012 this.groups = groups; // create the edge API in the body container
28013
28014 this.body.functions.createEdge = bind(_context = this.create).call(_context, this);
28015 this.edgesListeners = {
28016 add: function add(event, params) {
28017 _this.add(params.items);
28018 },
28019 update: function update(event, params) {
28020 _this.update(params.items);
28021 },
28022 remove: function remove(event, params) {
28023 _this.remove(params.items);
28024 }
28025 };
28026 this.options = {};
28027 this.defaultOptions = {
28028 arrows: {
28029 to: {
28030 enabled: false,
28031 scaleFactor: 1,
28032 type: "arrow"
28033 },
28034 // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
28035 middle: {
28036 enabled: false,
28037 scaleFactor: 1,
28038 type: "arrow"
28039 },
28040 from: {
28041 enabled: false,
28042 scaleFactor: 1,
28043 type: "arrow"
28044 }
28045 },
28046 endPointOffset: {
28047 from: 0,
28048 to: 0
28049 },
28050 arrowStrikethrough: true,
28051 color: {
28052 color: "#848484",
28053 highlight: "#848484",
28054 hover: "#848484",
28055 inherit: "from",
28056 opacity: 1.0
28057 },
28058 dashes: false,
28059 font: {
28060 color: "#343434",
28061 size: 14,
28062 // px
28063 face: "arial",
28064 background: "none",
28065 strokeWidth: 2,
28066 // px
28067 strokeColor: "#ffffff",
28068 align: "horizontal",
28069 multi: false,
28070 vadjust: 0,
28071 bold: {
28072 mod: "bold"
28073 },
28074 boldital: {
28075 mod: "bold italic"
28076 },
28077 ital: {
28078 mod: "italic"
28079 },
28080 mono: {
28081 mod: "",
28082 size: 15,
28083 // px
28084 face: "courier new",
28085 vadjust: 2
28086 }
28087 },
28088 hidden: false,
28089 hoverWidth: 1.5,
28090 label: undefined,
28091 labelHighlightBold: true,
28092 length: undefined,
28093 physics: true,
28094 scaling: {
28095 min: 1,
28096 max: 15,
28097 label: {
28098 enabled: true,
28099 min: 14,
28100 max: 30,
28101 maxVisible: 30,
28102 drawThreshold: 5
28103 },
28104 customScalingFunction: function customScalingFunction(min, max, total, value) {
28105 if (max === min) {
28106 return 0.5;
28107 } else {
28108 var scale = 1 / (max - min);
28109 return Math.max(0, (value - min) * scale);
28110 }
28111 }
28112 },
28113 selectionWidth: 1.5,
28114 selfReference: {
28115 size: 20,
28116 angle: Math.PI / 4,
28117 renderBehindTheNode: true
28118 },
28119 shadow: {
28120 enabled: false,
28121 color: "rgba(0,0,0,0.5)",
28122 size: 10,
28123 x: 5,
28124 y: 5
28125 },
28126 background: {
28127 enabled: false,
28128 color: "rgba(111,111,111,1)",
28129 size: 10,
28130 dashes: false
28131 },
28132 smooth: {
28133 enabled: true,
28134 type: "dynamic",
28135 forceDirection: "none",
28136 roundness: 0.5
28137 },
28138 title: undefined,
28139 width: 1,
28140 value: undefined
28141 };
28142 deepExtend(this.options, this.defaultOptions);
28143 this.bindEventListeners();
28144 }
28145 /**
28146 * Binds event listeners
28147 */
28148
28149
28150 _createClass(EdgesHandler, [{
28151 key: "bindEventListeners",
28152 value: function bindEventListeners() {
28153 var _this2 = this,
28154 _context2,
28155 _context3;
28156
28157 // this allows external modules to force all dynamic curves to turn static.
28158 this.body.emitter.on("_forceDisableDynamicCurves", function (type) {
28159 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
28160
28161 if (type === "dynamic") {
28162 type = "continuous";
28163 }
28164
28165 var dataChanged = false;
28166
28167 for (var edgeId in _this2.body.edges) {
28168 if (Object.prototype.hasOwnProperty.call(_this2.body.edges, edgeId)) {
28169 var edge = _this2.body.edges[edgeId];
28170
28171 var edgeData = _this2.body.data.edges.get(edgeId); // only forcibly remove the smooth curve if the data has been set of the edge has the smooth curves defined.
28172 // this is because a change in the global would not affect these curves.
28173
28174
28175 if (edgeData != null) {
28176 var smoothOptions = edgeData.smooth;
28177
28178 if (smoothOptions !== undefined) {
28179 if (smoothOptions.enabled === true && smoothOptions.type === "dynamic") {
28180 if (type === undefined) {
28181 edge.setOptions({
28182 smooth: false
28183 });
28184 } else {
28185 edge.setOptions({
28186 smooth: {
28187 type: type
28188 }
28189 });
28190 }
28191
28192 dataChanged = true;
28193 }
28194 }
28195 }
28196 }
28197 }
28198
28199 if (emit === true && dataChanged === true) {
28200 _this2.body.emitter.emit("_dataChanged");
28201 }
28202 }); // this is called when options of EXISTING nodes or edges have changed.
28203 //
28204 // NOTE: Not true, called when options have NOT changed, for both existing as well as new nodes.
28205 // See update() for logic.
28206 // TODO: Verify and examine the consequences of this. It might still trigger when
28207 // non-option fields have changed, but then reconnecting edges is still useless.
28208 // Alternatively, it might also be called when edges are removed.
28209 //
28210
28211 this.body.emitter.on("_dataUpdated", function () {
28212 _this2.reconnectEdges();
28213 }); // refresh the edges. Used when reverting from hierarchical layout
28214
28215 this.body.emitter.on("refreshEdges", bind(_context2 = this.refresh).call(_context2, this));
28216 this.body.emitter.on("refresh", bind(_context3 = this.refresh).call(_context3, this));
28217 this.body.emitter.on("destroy", function () {
28218 forEach$1(_this2.edgesListeners, function (callback, event) {
28219 if (_this2.body.data.edges) _this2.body.data.edges.off(event, callback);
28220 });
28221 delete _this2.body.functions.createEdge;
28222 delete _this2.edgesListeners.add;
28223 delete _this2.edgesListeners.update;
28224 delete _this2.edgesListeners.remove;
28225 delete _this2.edgesListeners;
28226 });
28227 }
28228 /**
28229 *
28230 * @param {object} options
28231 */
28232
28233 }, {
28234 key: "setOptions",
28235 value: function setOptions(options) {
28236 if (options !== undefined) {
28237 // use the parser from the Edge class to fill in all shorthand notations
28238 Edge.parseOptions(this.options, options, true, this.defaultOptions, true); // update smooth settings in all edges
28239
28240 var dataChanged = false;
28241
28242 if (options.smooth !== undefined) {
28243 for (var edgeId in this.body.edges) {
28244 if (Object.prototype.hasOwnProperty.call(this.body.edges, edgeId)) {
28245 dataChanged = this.body.edges[edgeId].updateEdgeType() || dataChanged;
28246 }
28247 }
28248 } // update fonts in all edges
28249
28250
28251 if (options.font !== undefined) {
28252 for (var _edgeId in this.body.edges) {
28253 if (Object.prototype.hasOwnProperty.call(this.body.edges, _edgeId)) {
28254 this.body.edges[_edgeId].updateLabelModule();
28255 }
28256 }
28257 } // update the state of the variables if needed
28258
28259
28260 if (options.hidden !== undefined || options.physics !== undefined || dataChanged === true) {
28261 this.body.emitter.emit("_dataChanged");
28262 }
28263 }
28264 }
28265 /**
28266 * Load edges by reading the data table
28267 *
28268 * @param {Array | DataSet | DataView} edges The data containing the edges.
28269 * @param {boolean} [doNotEmit=false] - Suppress data changed event.
28270 * @private
28271 */
28272
28273 }, {
28274 key: "setData",
28275 value: function setData(edges) {
28276 var _this3 = this;
28277
28278 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
28279 var oldEdgesData = this.body.data.edges;
28280
28281 if (isDataViewLike("id", edges)) {
28282 this.body.data.edges = edges;
28283 } else if (isArray(edges)) {
28284 this.body.data.edges = new DataSet();
28285 this.body.data.edges.add(edges);
28286 } else if (!edges) {
28287 this.body.data.edges = new DataSet();
28288 } else {
28289 throw new TypeError("Array or DataSet expected");
28290 } // TODO: is this null or undefined or false?
28291
28292
28293 if (oldEdgesData) {
28294 // unsubscribe from old dataset
28295 forEach$1(this.edgesListeners, function (callback, event) {
28296 oldEdgesData.off(event, callback);
28297 });
28298 } // remove drawn edges
28299
28300
28301 this.body.edges = {}; // TODO: is this null or undefined or false?
28302
28303 if (this.body.data.edges) {
28304 // subscribe to new dataset
28305 forEach$1(this.edgesListeners, function (callback, event) {
28306 _this3.body.data.edges.on(event, callback);
28307 }); // draw all new nodes
28308
28309 var ids = this.body.data.edges.getIds();
28310 this.add(ids, true);
28311 }
28312
28313 this.body.emitter.emit("_adjustEdgesForHierarchicalLayout");
28314
28315 if (doNotEmit === false) {
28316 this.body.emitter.emit("_dataChanged");
28317 }
28318 }
28319 /**
28320 * Add edges
28321 *
28322 * @param {number[] | string[]} ids
28323 * @param {boolean} [doNotEmit=false]
28324 * @private
28325 */
28326
28327 }, {
28328 key: "add",
28329 value: function add(ids) {
28330 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
28331 var edges = this.body.edges;
28332 var edgesData = this.body.data.edges;
28333
28334 for (var i = 0; i < ids.length; i++) {
28335 var id = ids[i];
28336 var oldEdge = edges[id];
28337
28338 if (oldEdge) {
28339 oldEdge.disconnect();
28340 }
28341
28342 var data = edgesData.get(id, {
28343 showInternalIds: true
28344 });
28345 edges[id] = this.create(data);
28346 }
28347
28348 this.body.emitter.emit("_adjustEdgesForHierarchicalLayout");
28349
28350 if (doNotEmit === false) {
28351 this.body.emitter.emit("_dataChanged");
28352 }
28353 }
28354 /**
28355 * Update existing edges, or create them when not yet existing
28356 *
28357 * @param {number[] | string[]} ids
28358 * @private
28359 */
28360
28361 }, {
28362 key: "update",
28363 value: function update(ids) {
28364 var edges = this.body.edges;
28365 var edgesData = this.body.data.edges;
28366 var dataChanged = false;
28367
28368 for (var i = 0; i < ids.length; i++) {
28369 var id = ids[i];
28370 var data = edgesData.get(id);
28371 var edge = edges[id];
28372
28373 if (edge !== undefined) {
28374 // update edge
28375 edge.disconnect();
28376 dataChanged = edge.setOptions(data) || dataChanged; // if a support node is added, data can be changed.
28377
28378 edge.connect();
28379 } else {
28380 // create edge
28381 this.body.edges[id] = this.create(data);
28382 dataChanged = true;
28383 }
28384 }
28385
28386 if (dataChanged === true) {
28387 this.body.emitter.emit("_adjustEdgesForHierarchicalLayout");
28388 this.body.emitter.emit("_dataChanged");
28389 } else {
28390 this.body.emitter.emit("_dataUpdated");
28391 }
28392 }
28393 /**
28394 * Remove existing edges. Non existing ids will be ignored
28395 *
28396 * @param {number[] | string[]} ids
28397 * @param {boolean} [emit=true]
28398 * @private
28399 */
28400
28401 }, {
28402 key: "remove",
28403 value: function remove(ids) {
28404 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
28405 if (ids.length === 0) return; // early out
28406
28407 var edges = this.body.edges;
28408 forEach$1(ids, function (id) {
28409 var edge = edges[id];
28410
28411 if (edge !== undefined) {
28412 edge.remove();
28413 }
28414 });
28415
28416 if (emit) {
28417 this.body.emitter.emit("_dataChanged");
28418 }
28419 }
28420 /**
28421 * Refreshes Edge Handler
28422 */
28423
28424 }, {
28425 key: "refresh",
28426 value: function refresh() {
28427 var _this4 = this;
28428
28429 forEach$1(this.body.edges, function (edge, edgeId) {
28430 var data = _this4.body.data.edges.get(edgeId);
28431
28432 if (data !== undefined) {
28433 edge.setOptions(data);
28434 }
28435 });
28436 }
28437 /**
28438 *
28439 * @param {object} properties
28440 * @returns {Edge}
28441 */
28442
28443 }, {
28444 key: "create",
28445 value: function create(properties) {
28446 return new Edge(properties, this.body, this.images, this.options, this.defaultOptions);
28447 }
28448 /**
28449 * Reconnect all edges
28450 *
28451 * @private
28452 */
28453
28454 }, {
28455 key: "reconnectEdges",
28456 value: function reconnectEdges() {
28457 var id;
28458 var nodes = this.body.nodes;
28459 var edges = this.body.edges;
28460
28461 for (id in nodes) {
28462 if (Object.prototype.hasOwnProperty.call(nodes, id)) {
28463 nodes[id].edges = [];
28464 }
28465 }
28466
28467 for (id in edges) {
28468 if (Object.prototype.hasOwnProperty.call(edges, id)) {
28469 var edge = edges[id];
28470 edge.from = null;
28471 edge.to = null;
28472 edge.connect();
28473 }
28474 }
28475 }
28476 /**
28477 *
28478 * @param {Edge.id} edgeId
28479 * @returns {Array}
28480 */
28481
28482 }, {
28483 key: "getConnectedNodes",
28484 value: function getConnectedNodes(edgeId) {
28485 var nodeList = [];
28486
28487 if (this.body.edges[edgeId] !== undefined) {
28488 var edge = this.body.edges[edgeId];
28489
28490 if (edge.fromId !== undefined) {
28491 nodeList.push(edge.fromId);
28492 }
28493
28494 if (edge.toId !== undefined) {
28495 nodeList.push(edge.toId);
28496 }
28497 }
28498
28499 return nodeList;
28500 }
28501 /**
28502 * There is no direct relation between the nodes and the edges DataSet,
28503 * so the right place to do call this is in the handler for event `_dataUpdated`.
28504 */
28505
28506 }, {
28507 key: "_updateState",
28508 value: function _updateState() {
28509 this._addMissingEdges();
28510
28511 this._removeInvalidEdges();
28512 }
28513 /**
28514 * Scan for missing nodes and remove corresponding edges, if any.
28515 *
28516 * @private
28517 */
28518
28519 }, {
28520 key: "_removeInvalidEdges",
28521 value: function _removeInvalidEdges() {
28522 var _this5 = this;
28523
28524 var edgesToDelete = [];
28525 forEach$1(this.body.edges, function (edge, id) {
28526 var toNode = _this5.body.nodes[edge.toId];
28527 var fromNode = _this5.body.nodes[edge.fromId]; // Skip clustering edges here, let the Clustering module handle those
28528
28529 if (toNode !== undefined && toNode.isCluster === true || fromNode !== undefined && fromNode.isCluster === true) {
28530 return;
28531 }
28532
28533 if (toNode === undefined || fromNode === undefined) {
28534 edgesToDelete.push(id);
28535 }
28536 });
28537 this.remove(edgesToDelete, false);
28538 }
28539 /**
28540 * add all edges from dataset that are not in the cached state
28541 *
28542 * @private
28543 */
28544
28545 }, {
28546 key: "_addMissingEdges",
28547 value: function _addMissingEdges() {
28548 var edgesData = this.body.data.edges;
28549
28550 if (edgesData === undefined || edgesData === null) {
28551 return; // No edges DataSet yet; can happen on startup
28552 }
28553
28554 var edges = this.body.edges;
28555 var addIds = [];
28556
28557 forEach$2(edgesData).call(edgesData, function (edgeData, edgeId) {
28558 var edge = edges[edgeId];
28559
28560 if (edge === undefined) {
28561 addIds.push(edgeId);
28562 }
28563 });
28564
28565 this.add(addIds, true);
28566 }
28567 }]);
28568
28569 return EdgesHandler;
28570}();
28571
28572/**
28573 * Barnes Hut Solver
28574 */
28575
28576var BarnesHutSolver = /*#__PURE__*/function () {
28577 /**
28578 * @param {object} body
28579 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
28580 * @param {object} options
28581 */
28582 function BarnesHutSolver(body, physicsBody, options) {
28583 _classCallCheck(this, BarnesHutSolver);
28584
28585 this.body = body;
28586 this.physicsBody = physicsBody;
28587 this.barnesHutTree;
28588 this.setOptions(options);
28589 this._rng = Alea("BARNES HUT SOLVER"); // debug: show grid
28590 // this.body.emitter.on("afterDrawing", (ctx) => {this._debug(ctx,'#ff0000')})
28591 }
28592 /**
28593 *
28594 * @param {object} options
28595 */
28596
28597
28598 _createClass(BarnesHutSolver, [{
28599 key: "setOptions",
28600 value: function setOptions(options) {
28601 this.options = options;
28602 this.thetaInversed = 1 / this.options.theta; // if 1 then min distance = 0.5, if 0.5 then min distance = 0.5 + 0.5*node.shape.radius
28603
28604 this.overlapAvoidanceFactor = 1 - Math.max(0, Math.min(1, this.options.avoidOverlap));
28605 }
28606 /**
28607 * This function calculates the forces the nodes apply on each other based on a gravitational model.
28608 * The Barnes Hut method is used to speed up this N-body simulation.
28609 *
28610 * @private
28611 */
28612
28613 }, {
28614 key: "solve",
28615 value: function solve() {
28616 if (this.options.gravitationalConstant !== 0 && this.physicsBody.physicsNodeIndices.length > 0) {
28617 var node;
28618 var nodes = this.body.nodes;
28619 var nodeIndices = this.physicsBody.physicsNodeIndices;
28620 var nodeCount = nodeIndices.length; // create the tree
28621
28622 var barnesHutTree = this._formBarnesHutTree(nodes, nodeIndices); // for debugging
28623
28624
28625 this.barnesHutTree = barnesHutTree; // place the nodes one by one recursively
28626
28627 for (var i = 0; i < nodeCount; i++) {
28628 node = nodes[nodeIndices[i]];
28629
28630 if (node.options.mass > 0) {
28631 // starting with root is irrelevant, it never passes the BarnesHutSolver condition
28632 this._getForceContributions(barnesHutTree.root, node);
28633 }
28634 }
28635 }
28636 }
28637 /**
28638 * @param {object} parentBranch
28639 * @param {Node} node
28640 * @private
28641 */
28642
28643 }, {
28644 key: "_getForceContributions",
28645 value: function _getForceContributions(parentBranch, node) {
28646 this._getForceContribution(parentBranch.children.NW, node);
28647
28648 this._getForceContribution(parentBranch.children.NE, node);
28649
28650 this._getForceContribution(parentBranch.children.SW, node);
28651
28652 this._getForceContribution(parentBranch.children.SE, node);
28653 }
28654 /**
28655 * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass.
28656 * If a region contains a single node, we check if it is not itself, then we apply the force.
28657 *
28658 * @param {object} parentBranch
28659 * @param {Node} node
28660 * @private
28661 */
28662
28663 }, {
28664 key: "_getForceContribution",
28665 value: function _getForceContribution(parentBranch, node) {
28666 // we get no force contribution from an empty region
28667 if (parentBranch.childrenCount > 0) {
28668 // get the distance from the center of mass to the node.
28669 var dx = parentBranch.centerOfMass.x - node.x;
28670 var dy = parentBranch.centerOfMass.y - node.y;
28671 var distance = Math.sqrt(dx * dx + dy * dy); // BarnesHutSolver condition
28672 // original condition : s/d < theta = passed === d/s > 1/theta = passed
28673 // calcSize = 1/s --> d * 1/s > 1/theta = passed
28674
28675 if (distance * parentBranch.calcSize > this.thetaInversed) {
28676 this._calculateForces(distance, dx, dy, node, parentBranch);
28677 } else {
28678 // Did not pass the condition, go into children if available
28679 if (parentBranch.childrenCount === 4) {
28680 this._getForceContributions(parentBranch, node);
28681 } else {
28682 // parentBranch must have only one node, if it was empty we wouldnt be here
28683 if (parentBranch.children.data.id != node.id) {
28684 // if it is not self
28685 this._calculateForces(distance, dx, dy, node, parentBranch);
28686 }
28687 }
28688 }
28689 }
28690 }
28691 /**
28692 * Calculate the forces based on the distance.
28693 *
28694 * @param {number} distance
28695 * @param {number} dx
28696 * @param {number} dy
28697 * @param {Node} node
28698 * @param {object} parentBranch
28699 * @private
28700 */
28701
28702 }, {
28703 key: "_calculateForces",
28704 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
28705 if (distance === 0) {
28706 distance = 0.1;
28707 dx = distance;
28708 }
28709
28710 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
28711 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
28712 } // the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
28713 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
28714
28715
28716 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass / Math.pow(distance, 3);
28717 var fx = dx * gravityForce;
28718 var fy = dy * gravityForce;
28719 this.physicsBody.forces[node.id].x += fx;
28720 this.physicsBody.forces[node.id].y += fy;
28721 }
28722 /**
28723 * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes.
28724 *
28725 * @param {Array.<Node>} nodes
28726 * @param {Array.<number>} nodeIndices
28727 * @returns {{root: {centerOfMass: {x: number, y: number}, mass: number, range: {minX: number, maxX: number, minY: number, maxY: number}, size: number, calcSize: number, children: {data: null}, maxWidth: number, level: number, childrenCount: number}}} BarnesHutTree
28728 * @private
28729 */
28730
28731 }, {
28732 key: "_formBarnesHutTree",
28733 value: function _formBarnesHutTree(nodes, nodeIndices) {
28734 var node;
28735 var nodeCount = nodeIndices.length;
28736 var minX = nodes[nodeIndices[0]].x;
28737 var minY = nodes[nodeIndices[0]].y;
28738 var maxX = nodes[nodeIndices[0]].x;
28739 var maxY = nodes[nodeIndices[0]].y; // get the range of the nodes
28740
28741 for (var i = 1; i < nodeCount; i++) {
28742 var _node = nodes[nodeIndices[i]];
28743 var x = _node.x;
28744 var y = _node.y;
28745
28746 if (_node.options.mass > 0) {
28747 if (x < minX) {
28748 minX = x;
28749 }
28750
28751 if (x > maxX) {
28752 maxX = x;
28753 }
28754
28755 if (y < minY) {
28756 minY = y;
28757 }
28758
28759 if (y > maxY) {
28760 maxY = y;
28761 }
28762 }
28763 } // make the range a square
28764
28765
28766 var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
28767
28768 if (sizeDiff > 0) {
28769 minY -= 0.5 * sizeDiff;
28770 maxY += 0.5 * sizeDiff;
28771 } // xSize > ySize
28772 else {
28773 minX += 0.5 * sizeDiff;
28774 maxX -= 0.5 * sizeDiff;
28775 } // xSize < ySize
28776
28777
28778 var minimumTreeSize = 1e-5;
28779 var rootSize = Math.max(minimumTreeSize, Math.abs(maxX - minX));
28780 var halfRootSize = 0.5 * rootSize;
28781 var centerX = 0.5 * (minX + maxX),
28782 centerY = 0.5 * (minY + maxY); // construct the barnesHutTree
28783
28784 var barnesHutTree = {
28785 root: {
28786 centerOfMass: {
28787 x: 0,
28788 y: 0
28789 },
28790 mass: 0,
28791 range: {
28792 minX: centerX - halfRootSize,
28793 maxX: centerX + halfRootSize,
28794 minY: centerY - halfRootSize,
28795 maxY: centerY + halfRootSize
28796 },
28797 size: rootSize,
28798 calcSize: 1 / rootSize,
28799 children: {
28800 data: null
28801 },
28802 maxWidth: 0,
28803 level: 0,
28804 childrenCount: 4
28805 }
28806 };
28807
28808 this._splitBranch(barnesHutTree.root); // place the nodes one by one recursively
28809
28810
28811 for (var _i = 0; _i < nodeCount; _i++) {
28812 node = nodes[nodeIndices[_i]];
28813
28814 if (node.options.mass > 0) {
28815 this._placeInTree(barnesHutTree.root, node);
28816 }
28817 } // make global
28818
28819
28820 return barnesHutTree;
28821 }
28822 /**
28823 * this updates the mass of a branch. this is increased by adding a node.
28824 *
28825 * @param {object} parentBranch
28826 * @param {Node} node
28827 * @private
28828 */
28829
28830 }, {
28831 key: "_updateBranchMass",
28832 value: function _updateBranchMass(parentBranch, node) {
28833 var centerOfMass = parentBranch.centerOfMass;
28834 var totalMass = parentBranch.mass + node.options.mass;
28835 var totalMassInv = 1 / totalMass;
28836 centerOfMass.x = centerOfMass.x * parentBranch.mass + node.x * node.options.mass;
28837 centerOfMass.x *= totalMassInv;
28838 centerOfMass.y = centerOfMass.y * parentBranch.mass + node.y * node.options.mass;
28839 centerOfMass.y *= totalMassInv;
28840 parentBranch.mass = totalMass;
28841 var biggestSize = Math.max(Math.max(node.height, node.radius), node.width);
28842 parentBranch.maxWidth = parentBranch.maxWidth < biggestSize ? biggestSize : parentBranch.maxWidth;
28843 }
28844 /**
28845 * determine in which branch the node will be placed.
28846 *
28847 * @param {object} parentBranch
28848 * @param {Node} node
28849 * @param {boolean} skipMassUpdate
28850 * @private
28851 */
28852
28853 }, {
28854 key: "_placeInTree",
28855 value: function _placeInTree(parentBranch, node, skipMassUpdate) {
28856 if (skipMassUpdate != true || skipMassUpdate === undefined) {
28857 // update the mass of the branch.
28858 this._updateBranchMass(parentBranch, node);
28859 }
28860
28861 var range = parentBranch.children.NW.range;
28862 var region;
28863
28864 if (range.maxX > node.x) {
28865 // in NW or SW
28866 if (range.maxY > node.y) {
28867 region = "NW";
28868 } else {
28869 region = "SW";
28870 }
28871 } else {
28872 // in NE or SE
28873 if (range.maxY > node.y) {
28874 region = "NE";
28875 } else {
28876 region = "SE";
28877 }
28878 }
28879
28880 this._placeInRegion(parentBranch, node, region);
28881 }
28882 /**
28883 * actually place the node in a region (or branch)
28884 *
28885 * @param {object} parentBranch
28886 * @param {Node} node
28887 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
28888 * @private
28889 */
28890
28891 }, {
28892 key: "_placeInRegion",
28893 value: function _placeInRegion(parentBranch, node, region) {
28894 var children = parentBranch.children[region];
28895
28896 switch (children.childrenCount) {
28897 case 0:
28898 // place node here
28899 children.children.data = node;
28900 children.childrenCount = 1;
28901
28902 this._updateBranchMass(children, node);
28903
28904 break;
28905
28906 case 1:
28907 // convert into children
28908 // if there are two nodes exactly overlapping (on init, on opening of cluster etc.)
28909 // we move one node a little bit and we do not put it in the tree.
28910 if (children.children.data.x === node.x && children.children.data.y === node.y) {
28911 node.x += this._rng();
28912 node.y += this._rng();
28913 } else {
28914 this._splitBranch(children);
28915
28916 this._placeInTree(children, node);
28917 }
28918
28919 break;
28920
28921 case 4:
28922 // place in branch
28923 this._placeInTree(children, node);
28924
28925 break;
28926 }
28927 }
28928 /**
28929 * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch
28930 * after the split is complete.
28931 *
28932 * @param {object} parentBranch
28933 * @private
28934 */
28935
28936 }, {
28937 key: "_splitBranch",
28938 value: function _splitBranch(parentBranch) {
28939 // if the branch is shaded with a node, replace the node in the new subset.
28940 var containedNode = null;
28941
28942 if (parentBranch.childrenCount === 1) {
28943 containedNode = parentBranch.children.data;
28944 parentBranch.mass = 0;
28945 parentBranch.centerOfMass.x = 0;
28946 parentBranch.centerOfMass.y = 0;
28947 }
28948
28949 parentBranch.childrenCount = 4;
28950 parentBranch.children.data = null;
28951
28952 this._insertRegion(parentBranch, "NW");
28953
28954 this._insertRegion(parentBranch, "NE");
28955
28956 this._insertRegion(parentBranch, "SW");
28957
28958 this._insertRegion(parentBranch, "SE");
28959
28960 if (containedNode != null) {
28961 this._placeInTree(parentBranch, containedNode);
28962 }
28963 }
28964 /**
28965 * This function subdivides the region into four new segments.
28966 * Specifically, this inserts a single new segment.
28967 * It fills the children section of the parentBranch
28968 *
28969 * @param {object} parentBranch
28970 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
28971 * @private
28972 */
28973
28974 }, {
28975 key: "_insertRegion",
28976 value: function _insertRegion(parentBranch, region) {
28977 var minX, maxX, minY, maxY;
28978 var childSize = 0.5 * parentBranch.size;
28979
28980 switch (region) {
28981 case "NW":
28982 minX = parentBranch.range.minX;
28983 maxX = parentBranch.range.minX + childSize;
28984 minY = parentBranch.range.minY;
28985 maxY = parentBranch.range.minY + childSize;
28986 break;
28987
28988 case "NE":
28989 minX = parentBranch.range.minX + childSize;
28990 maxX = parentBranch.range.maxX;
28991 minY = parentBranch.range.minY;
28992 maxY = parentBranch.range.minY + childSize;
28993 break;
28994
28995 case "SW":
28996 minX = parentBranch.range.minX;
28997 maxX = parentBranch.range.minX + childSize;
28998 minY = parentBranch.range.minY + childSize;
28999 maxY = parentBranch.range.maxY;
29000 break;
29001
29002 case "SE":
29003 minX = parentBranch.range.minX + childSize;
29004 maxX = parentBranch.range.maxX;
29005 minY = parentBranch.range.minY + childSize;
29006 maxY = parentBranch.range.maxY;
29007 break;
29008 }
29009
29010 parentBranch.children[region] = {
29011 centerOfMass: {
29012 x: 0,
29013 y: 0
29014 },
29015 mass: 0,
29016 range: {
29017 minX: minX,
29018 maxX: maxX,
29019 minY: minY,
29020 maxY: maxY
29021 },
29022 size: 0.5 * parentBranch.size,
29023 calcSize: 2 * parentBranch.calcSize,
29024 children: {
29025 data: null
29026 },
29027 maxWidth: 0,
29028 level: parentBranch.level + 1,
29029 childrenCount: 0
29030 };
29031 } //--------------------------- DEBUGGING BELOW ---------------------------//
29032
29033 /**
29034 * This function is for debugging purposed, it draws the tree.
29035 *
29036 * @param {CanvasRenderingContext2D} ctx
29037 * @param {string} color
29038 * @private
29039 */
29040
29041 }, {
29042 key: "_debug",
29043 value: function _debug(ctx, color) {
29044 if (this.barnesHutTree !== undefined) {
29045 ctx.lineWidth = 1;
29046
29047 this._drawBranch(this.barnesHutTree.root, ctx, color);
29048 }
29049 }
29050 /**
29051 * This function is for debugging purposes. It draws the branches recursively.
29052 *
29053 * @param {object} branch
29054 * @param {CanvasRenderingContext2D} ctx
29055 * @param {string} color
29056 * @private
29057 */
29058
29059 }, {
29060 key: "_drawBranch",
29061 value: function _drawBranch(branch, ctx, color) {
29062 if (color === undefined) {
29063 color = "#FF0000";
29064 }
29065
29066 if (branch.childrenCount === 4) {
29067 this._drawBranch(branch.children.NW, ctx);
29068
29069 this._drawBranch(branch.children.NE, ctx);
29070
29071 this._drawBranch(branch.children.SE, ctx);
29072
29073 this._drawBranch(branch.children.SW, ctx);
29074 }
29075
29076 ctx.strokeStyle = color;
29077 ctx.beginPath();
29078 ctx.moveTo(branch.range.minX, branch.range.minY);
29079 ctx.lineTo(branch.range.maxX, branch.range.minY);
29080 ctx.stroke();
29081 ctx.beginPath();
29082 ctx.moveTo(branch.range.maxX, branch.range.minY);
29083 ctx.lineTo(branch.range.maxX, branch.range.maxY);
29084 ctx.stroke();
29085 ctx.beginPath();
29086 ctx.moveTo(branch.range.maxX, branch.range.maxY);
29087 ctx.lineTo(branch.range.minX, branch.range.maxY);
29088 ctx.stroke();
29089 ctx.beginPath();
29090 ctx.moveTo(branch.range.minX, branch.range.maxY);
29091 ctx.lineTo(branch.range.minX, branch.range.minY);
29092 ctx.stroke();
29093 /*
29094 if (branch.mass > 0) {
29095 ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass);
29096 ctx.stroke();
29097 }
29098 */
29099 }
29100 }]);
29101
29102 return BarnesHutSolver;
29103}();
29104
29105/**
29106 * Repulsion Solver
29107 */
29108
29109var RepulsionSolver = /*#__PURE__*/function () {
29110 /**
29111 * @param {object} body
29112 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
29113 * @param {object} options
29114 */
29115 function RepulsionSolver(body, physicsBody, options) {
29116 _classCallCheck(this, RepulsionSolver);
29117
29118 this._rng = Alea("REPULSION SOLVER");
29119 this.body = body;
29120 this.physicsBody = physicsBody;
29121 this.setOptions(options);
29122 }
29123 /**
29124 *
29125 * @param {object} options
29126 */
29127
29128
29129 _createClass(RepulsionSolver, [{
29130 key: "setOptions",
29131 value: function setOptions(options) {
29132 this.options = options;
29133 }
29134 /**
29135 * Calculate the forces the nodes apply on each other based on a repulsion field.
29136 * This field is linearly approximated.
29137 *
29138 * @private
29139 */
29140
29141 }, {
29142 key: "solve",
29143 value: function solve() {
29144 var dx, dy, distance, fx, fy, repulsingForce, node1, node2;
29145 var nodes = this.body.nodes;
29146 var nodeIndices = this.physicsBody.physicsNodeIndices;
29147 var forces = this.physicsBody.forces; // repulsing forces between nodes
29148
29149 var nodeDistance = this.options.nodeDistance; // approximation constants
29150
29151 var a = -2 / 3 / nodeDistance;
29152 var b = 4 / 3; // we loop from i over all but the last entree in the array
29153 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
29154
29155 for (var i = 0; i < nodeIndices.length - 1; i++) {
29156 node1 = nodes[nodeIndices[i]];
29157
29158 for (var j = i + 1; j < nodeIndices.length; j++) {
29159 node2 = nodes[nodeIndices[j]];
29160 dx = node2.x - node1.x;
29161 dy = node2.y - node1.y;
29162 distance = Math.sqrt(dx * dx + dy * dy); // same condition as BarnesHutSolver, making sure nodes are never 100% overlapping.
29163
29164 if (distance === 0) {
29165 distance = 0.1 * this._rng();
29166 dx = distance;
29167 }
29168
29169 if (distance < 2 * nodeDistance) {
29170 if (distance < 0.5 * nodeDistance) {
29171 repulsingForce = 1.0;
29172 } else {
29173 repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / nodeDistance - 1) * steepness))
29174 }
29175
29176 repulsingForce = repulsingForce / distance;
29177 fx = dx * repulsingForce;
29178 fy = dy * repulsingForce;
29179 forces[node1.id].x -= fx;
29180 forces[node1.id].y -= fy;
29181 forces[node2.id].x += fx;
29182 forces[node2.id].y += fy;
29183 }
29184 }
29185 }
29186 }
29187 }]);
29188
29189 return RepulsionSolver;
29190}();
29191
29192/**
29193 * Hierarchical Repulsion Solver
29194 */
29195var HierarchicalRepulsionSolver = /*#__PURE__*/function () {
29196 /**
29197 * @param {object} body
29198 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
29199 * @param {object} options
29200 */
29201 function HierarchicalRepulsionSolver(body, physicsBody, options) {
29202 _classCallCheck(this, HierarchicalRepulsionSolver);
29203
29204 this.body = body;
29205 this.physicsBody = physicsBody;
29206 this.setOptions(options);
29207 }
29208 /**
29209 *
29210 * @param {object} options
29211 */
29212
29213
29214 _createClass(HierarchicalRepulsionSolver, [{
29215 key: "setOptions",
29216 value: function setOptions(options) {
29217 this.options = options;
29218 this.overlapAvoidanceFactor = Math.max(0, Math.min(1, this.options.avoidOverlap || 0));
29219 }
29220 /**
29221 * Calculate the forces the nodes apply on each other based on a repulsion field.
29222 * This field is linearly approximated.
29223 *
29224 * @private
29225 */
29226
29227 }, {
29228 key: "solve",
29229 value: function solve() {
29230 var nodes = this.body.nodes;
29231 var nodeIndices = this.physicsBody.physicsNodeIndices;
29232 var forces = this.physicsBody.forces; // repulsing forces between nodes
29233
29234 var nodeDistance = this.options.nodeDistance; // we loop from i over all but the last entree in the array
29235 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
29236
29237 for (var i = 0; i < nodeIndices.length - 1; i++) {
29238 var node1 = nodes[nodeIndices[i]];
29239
29240 for (var j = i + 1; j < nodeIndices.length; j++) {
29241 var node2 = nodes[nodeIndices[j]]; // nodes only affect nodes on their level
29242
29243 if (node1.level === node2.level) {
29244 var theseNodesDistance = nodeDistance + this.overlapAvoidanceFactor * ((node1.shape.radius || 0) / 2 + (node2.shape.radius || 0) / 2);
29245 var dx = node2.x - node1.x;
29246 var dy = node2.y - node1.y;
29247 var distance = Math.sqrt(dx * dx + dy * dy);
29248 var steepness = 0.05;
29249 var repulsingForce = void 0;
29250
29251 if (distance < theseNodesDistance) {
29252 repulsingForce = -Math.pow(steepness * distance, 2) + Math.pow(steepness * theseNodesDistance, 2);
29253 } else {
29254 repulsingForce = 0;
29255 } // normalize force with
29256
29257
29258 if (distance !== 0) {
29259 repulsingForce = repulsingForce / distance;
29260 }
29261
29262 var fx = dx * repulsingForce;
29263 var fy = dy * repulsingForce;
29264 forces[node1.id].x -= fx;
29265 forces[node1.id].y -= fy;
29266 forces[node2.id].x += fx;
29267 forces[node2.id].y += fy;
29268 }
29269 }
29270 }
29271 }
29272 }]);
29273
29274 return HierarchicalRepulsionSolver;
29275}();
29276
29277/**
29278 * Spring Solver
29279 */
29280var SpringSolver = /*#__PURE__*/function () {
29281 /**
29282 * @param {object} body
29283 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
29284 * @param {object} options
29285 */
29286 function SpringSolver(body, physicsBody, options) {
29287 _classCallCheck(this, SpringSolver);
29288
29289 this.body = body;
29290 this.physicsBody = physicsBody;
29291 this.setOptions(options);
29292 }
29293 /**
29294 *
29295 * @param {object} options
29296 */
29297
29298
29299 _createClass(SpringSolver, [{
29300 key: "setOptions",
29301 value: function setOptions(options) {
29302 this.options = options;
29303 }
29304 /**
29305 * This function calculates the springforces on the nodes, accounting for the support nodes.
29306 *
29307 * @private
29308 */
29309
29310 }, {
29311 key: "solve",
29312 value: function solve() {
29313 var edgeLength, edge;
29314 var edgeIndices = this.physicsBody.physicsEdgeIndices;
29315 var edges = this.body.edges;
29316 var node1, node2, node3; // forces caused by the edges, modelled as springs
29317
29318 for (var i = 0; i < edgeIndices.length; i++) {
29319 edge = edges[edgeIndices[i]];
29320
29321 if (edge.connected === true && edge.toId !== edge.fromId) {
29322 // only calculate forces if nodes are in the same sector
29323 if (this.body.nodes[edge.toId] !== undefined && this.body.nodes[edge.fromId] !== undefined) {
29324 if (edge.edgeType.via !== undefined) {
29325 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
29326 node1 = edge.to;
29327 node2 = edge.edgeType.via;
29328 node3 = edge.from;
29329
29330 this._calculateSpringForce(node1, node2, 0.5 * edgeLength);
29331
29332 this._calculateSpringForce(node2, node3, 0.5 * edgeLength);
29333 } else {
29334 // the * 1.5 is here so the edge looks as large as a smooth edge. It does not initially because the smooth edges use
29335 // the support nodes which exert a repulsive force on the to and from nodes, making the edge appear larger.
29336 edgeLength = edge.options.length === undefined ? this.options.springLength * 1.5 : edge.options.length;
29337
29338 this._calculateSpringForce(edge.from, edge.to, edgeLength);
29339 }
29340 }
29341 }
29342 }
29343 }
29344 /**
29345 * This is the code actually performing the calculation for the function above.
29346 *
29347 * @param {Node} node1
29348 * @param {Node} node2
29349 * @param {number} edgeLength
29350 * @private
29351 */
29352
29353 }, {
29354 key: "_calculateSpringForce",
29355 value: function _calculateSpringForce(node1, node2, edgeLength) {
29356 var dx = node1.x - node2.x;
29357 var dy = node1.y - node2.y;
29358 var distance = Math.max(Math.sqrt(dx * dx + dy * dy), 0.01); // the 1/distance is so the fx and fy can be calculated without sine or cosine.
29359
29360 var springForce = this.options.springConstant * (edgeLength - distance) / distance;
29361 var fx = dx * springForce;
29362 var fy = dy * springForce; // handle the case where one node is not part of the physcis
29363
29364 if (this.physicsBody.forces[node1.id] !== undefined) {
29365 this.physicsBody.forces[node1.id].x += fx;
29366 this.physicsBody.forces[node1.id].y += fy;
29367 }
29368
29369 if (this.physicsBody.forces[node2.id] !== undefined) {
29370 this.physicsBody.forces[node2.id].x -= fx;
29371 this.physicsBody.forces[node2.id].y -= fy;
29372 }
29373 }
29374 }]);
29375
29376 return SpringSolver;
29377}();
29378
29379/**
29380 * Hierarchical Spring Solver
29381 */
29382var HierarchicalSpringSolver = /*#__PURE__*/function () {
29383 /**
29384 * @param {object} body
29385 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
29386 * @param {object} options
29387 */
29388 function HierarchicalSpringSolver(body, physicsBody, options) {
29389 _classCallCheck(this, HierarchicalSpringSolver);
29390
29391 this.body = body;
29392 this.physicsBody = physicsBody;
29393 this.setOptions(options);
29394 }
29395 /**
29396 *
29397 * @param {object} options
29398 */
29399
29400
29401 _createClass(HierarchicalSpringSolver, [{
29402 key: "setOptions",
29403 value: function setOptions(options) {
29404 this.options = options;
29405 }
29406 /**
29407 * This function calculates the springforces on the nodes, accounting for the support nodes.
29408 *
29409 * @private
29410 */
29411
29412 }, {
29413 key: "solve",
29414 value: function solve() {
29415 var edgeLength, edge;
29416 var dx, dy, fx, fy, springForce, distance;
29417 var edges = this.body.edges;
29418 var factor = 0.5;
29419 var edgeIndices = this.physicsBody.physicsEdgeIndices;
29420 var nodeIndices = this.physicsBody.physicsNodeIndices;
29421 var forces = this.physicsBody.forces; // initialize the spring force counters
29422
29423 for (var i = 0; i < nodeIndices.length; i++) {
29424 var nodeId = nodeIndices[i];
29425 forces[nodeId].springFx = 0;
29426 forces[nodeId].springFy = 0;
29427 } // forces caused by the edges, modelled as springs
29428
29429
29430 for (var _i = 0; _i < edgeIndices.length; _i++) {
29431 edge = edges[edgeIndices[_i]];
29432
29433 if (edge.connected === true) {
29434 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
29435 dx = edge.from.x - edge.to.x;
29436 dy = edge.from.y - edge.to.y;
29437 distance = Math.sqrt(dx * dx + dy * dy);
29438 distance = distance === 0 ? 0.01 : distance; // the 1/distance is so the fx and fy can be calculated without sine or cosine.
29439
29440 springForce = this.options.springConstant * (edgeLength - distance) / distance;
29441 fx = dx * springForce;
29442 fy = dy * springForce;
29443
29444 if (edge.to.level != edge.from.level) {
29445 if (forces[edge.toId] !== undefined) {
29446 forces[edge.toId].springFx -= fx;
29447 forces[edge.toId].springFy -= fy;
29448 }
29449
29450 if (forces[edge.fromId] !== undefined) {
29451 forces[edge.fromId].springFx += fx;
29452 forces[edge.fromId].springFy += fy;
29453 }
29454 } else {
29455 if (forces[edge.toId] !== undefined) {
29456 forces[edge.toId].x -= factor * fx;
29457 forces[edge.toId].y -= factor * fy;
29458 }
29459
29460 if (forces[edge.fromId] !== undefined) {
29461 forces[edge.fromId].x += factor * fx;
29462 forces[edge.fromId].y += factor * fy;
29463 }
29464 }
29465 }
29466 } // normalize spring forces
29467
29468
29469 springForce = 1;
29470 var springFx, springFy;
29471
29472 for (var _i2 = 0; _i2 < nodeIndices.length; _i2++) {
29473 var _nodeId = nodeIndices[_i2];
29474 springFx = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFx));
29475 springFy = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFy));
29476 forces[_nodeId].x += springFx;
29477 forces[_nodeId].y += springFy;
29478 } // retain energy balance
29479
29480
29481 var totalFx = 0;
29482 var totalFy = 0;
29483
29484 for (var _i3 = 0; _i3 < nodeIndices.length; _i3++) {
29485 var _nodeId2 = nodeIndices[_i3];
29486 totalFx += forces[_nodeId2].x;
29487 totalFy += forces[_nodeId2].y;
29488 }
29489
29490 var correctionFx = totalFx / nodeIndices.length;
29491 var correctionFy = totalFy / nodeIndices.length;
29492
29493 for (var _i4 = 0; _i4 < nodeIndices.length; _i4++) {
29494 var _nodeId3 = nodeIndices[_i4];
29495 forces[_nodeId3].x -= correctionFx;
29496 forces[_nodeId3].y -= correctionFy;
29497 }
29498 }
29499 }]);
29500
29501 return HierarchicalSpringSolver;
29502}();
29503
29504/**
29505 * Central Gravity Solver
29506 */
29507var CentralGravitySolver = /*#__PURE__*/function () {
29508 /**
29509 * @param {object} body
29510 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
29511 * @param {object} options
29512 */
29513 function CentralGravitySolver(body, physicsBody, options) {
29514 _classCallCheck(this, CentralGravitySolver);
29515
29516 this.body = body;
29517 this.physicsBody = physicsBody;
29518 this.setOptions(options);
29519 }
29520 /**
29521 *
29522 * @param {object} options
29523 */
29524
29525
29526 _createClass(CentralGravitySolver, [{
29527 key: "setOptions",
29528 value: function setOptions(options) {
29529 this.options = options;
29530 }
29531 /**
29532 * Calculates forces for each node
29533 */
29534
29535 }, {
29536 key: "solve",
29537 value: function solve() {
29538 var dx, dy, distance, node;
29539 var nodes = this.body.nodes;
29540 var nodeIndices = this.physicsBody.physicsNodeIndices;
29541 var forces = this.physicsBody.forces;
29542
29543 for (var i = 0; i < nodeIndices.length; i++) {
29544 var nodeId = nodeIndices[i];
29545 node = nodes[nodeId];
29546 dx = -node.x;
29547 dy = -node.y;
29548 distance = Math.sqrt(dx * dx + dy * dy);
29549
29550 this._calculateForces(distance, dx, dy, forces, node);
29551 }
29552 }
29553 /**
29554 * Calculate the forces based on the distance.
29555 *
29556 * @param {number} distance
29557 * @param {number} dx
29558 * @param {number} dy
29559 * @param {object<Node.id, vis.Node>} forces
29560 * @param {Node} node
29561 * @private
29562 */
29563
29564 }, {
29565 key: "_calculateForces",
29566 value: function _calculateForces(distance, dx, dy, forces, node) {
29567 var gravityForce = distance === 0 ? 0 : this.options.centralGravity / distance;
29568 forces[node.id].x = dx * gravityForce;
29569 forces[node.id].y = dy * gravityForce;
29570 }
29571 }]);
29572
29573 return CentralGravitySolver;
29574}();
29575
29576function _createSuper$3(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$3(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
29577
29578function _isNativeReflectConstruct$3() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
29579/**
29580 * @augments BarnesHutSolver
29581 */
29582
29583var ForceAtlas2BasedRepulsionSolver = /*#__PURE__*/function (_BarnesHutSolver) {
29584 _inherits(ForceAtlas2BasedRepulsionSolver, _BarnesHutSolver);
29585
29586 var _super = _createSuper$3(ForceAtlas2BasedRepulsionSolver);
29587
29588 /**
29589 * @param {object} body
29590 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
29591 * @param {object} options
29592 */
29593 function ForceAtlas2BasedRepulsionSolver(body, physicsBody, options) {
29594 var _this;
29595
29596 _classCallCheck(this, ForceAtlas2BasedRepulsionSolver);
29597
29598 _this = _super.call(this, body, physicsBody, options);
29599 _this._rng = Alea("FORCE ATLAS 2 BASED REPULSION SOLVER");
29600 return _this;
29601 }
29602 /**
29603 * Calculate the forces based on the distance.
29604 *
29605 * @param {number} distance
29606 * @param {number} dx
29607 * @param {number} dy
29608 * @param {Node} node
29609 * @param {object} parentBranch
29610 * @private
29611 */
29612
29613
29614 _createClass(ForceAtlas2BasedRepulsionSolver, [{
29615 key: "_calculateForces",
29616 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
29617 if (distance === 0) {
29618 distance = 0.1 * this._rng();
29619 dx = distance;
29620 }
29621
29622 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
29623 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
29624 }
29625
29626 var degree = node.edges.length + 1; // the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
29627 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
29628
29629 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass * degree / Math.pow(distance, 2);
29630 var fx = dx * gravityForce;
29631 var fy = dy * gravityForce;
29632 this.physicsBody.forces[node.id].x += fx;
29633 this.physicsBody.forces[node.id].y += fy;
29634 }
29635 }]);
29636
29637 return ForceAtlas2BasedRepulsionSolver;
29638}(BarnesHutSolver);
29639
29640function _createSuper$2(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$2(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
29641
29642function _isNativeReflectConstruct$2() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
29643/**
29644 * @augments CentralGravitySolver
29645 */
29646
29647var ForceAtlas2BasedCentralGravitySolver = /*#__PURE__*/function (_CentralGravitySolver) {
29648 _inherits(ForceAtlas2BasedCentralGravitySolver, _CentralGravitySolver);
29649
29650 var _super = _createSuper$2(ForceAtlas2BasedCentralGravitySolver);
29651
29652 /**
29653 * @param {object} body
29654 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
29655 * @param {object} options
29656 */
29657 function ForceAtlas2BasedCentralGravitySolver(body, physicsBody, options) {
29658 _classCallCheck(this, ForceAtlas2BasedCentralGravitySolver);
29659
29660 return _super.call(this, body, physicsBody, options);
29661 }
29662 /**
29663 * Calculate the forces based on the distance.
29664 *
29665 * @param {number} distance
29666 * @param {number} dx
29667 * @param {number} dy
29668 * @param {object<Node.id, Node>} forces
29669 * @param {Node} node
29670 * @private
29671 */
29672
29673
29674 _createClass(ForceAtlas2BasedCentralGravitySolver, [{
29675 key: "_calculateForces",
29676 value: function _calculateForces(distance, dx, dy, forces, node) {
29677 if (distance > 0) {
29678 var degree = node.edges.length + 1;
29679 var gravityForce = this.options.centralGravity * degree * node.options.mass;
29680 forces[node.id].x = dx * gravityForce;
29681 forces[node.id].y = dy * gravityForce;
29682 }
29683 }
29684 }]);
29685
29686 return ForceAtlas2BasedCentralGravitySolver;
29687}(CentralGravitySolver);
29688
29689/**
29690 * The physics engine
29691 */
29692
29693var PhysicsEngine = /*#__PURE__*/function () {
29694 /**
29695 * @param {object} body
29696 */
29697 function PhysicsEngine(body) {
29698 _classCallCheck(this, PhysicsEngine);
29699
29700 this.body = body;
29701 this.physicsBody = {
29702 physicsNodeIndices: [],
29703 physicsEdgeIndices: [],
29704 forces: {},
29705 velocities: {}
29706 };
29707 this.physicsEnabled = true;
29708 this.simulationInterval = 1000 / 60;
29709 this.requiresTimeout = true;
29710 this.previousStates = {};
29711 this.referenceState = {};
29712 this.freezeCache = {};
29713 this.renderTimer = undefined; // parameters for the adaptive timestep
29714
29715 this.adaptiveTimestep = false;
29716 this.adaptiveTimestepEnabled = false;
29717 this.adaptiveCounter = 0;
29718 this.adaptiveInterval = 3;
29719 this.stabilized = false;
29720 this.startedStabilization = false;
29721 this.stabilizationIterations = 0;
29722 this.ready = false; // will be set to true if the stabilize
29723 // default options
29724
29725 this.options = {};
29726 this.defaultOptions = {
29727 enabled: true,
29728 barnesHut: {
29729 theta: 0.5,
29730 gravitationalConstant: -2000,
29731 centralGravity: 0.3,
29732 springLength: 95,
29733 springConstant: 0.04,
29734 damping: 0.09,
29735 avoidOverlap: 0
29736 },
29737 forceAtlas2Based: {
29738 theta: 0.5,
29739 gravitationalConstant: -50,
29740 centralGravity: 0.01,
29741 springConstant: 0.08,
29742 springLength: 100,
29743 damping: 0.4,
29744 avoidOverlap: 0
29745 },
29746 repulsion: {
29747 centralGravity: 0.2,
29748 springLength: 200,
29749 springConstant: 0.05,
29750 nodeDistance: 100,
29751 damping: 0.09,
29752 avoidOverlap: 0
29753 },
29754 hierarchicalRepulsion: {
29755 centralGravity: 0.0,
29756 springLength: 100,
29757 springConstant: 0.01,
29758 nodeDistance: 120,
29759 damping: 0.09
29760 },
29761 maxVelocity: 50,
29762 minVelocity: 0.75,
29763 // px/s
29764 solver: "barnesHut",
29765 stabilization: {
29766 enabled: true,
29767 iterations: 1000,
29768 // maximum number of iteration to stabilize
29769 updateInterval: 50,
29770 onlyDynamicEdges: false,
29771 fit: true
29772 },
29773 timestep: 0.5,
29774 adaptiveTimestep: true,
29775 wind: {
29776 x: 0,
29777 y: 0
29778 }
29779 };
29780
29781 assign$2(this.options, this.defaultOptions);
29782
29783 this.timestep = 0.5;
29784 this.layoutFailed = false;
29785 this.bindEventListeners();
29786 }
29787 /**
29788 * Binds event listeners
29789 */
29790
29791
29792 _createClass(PhysicsEngine, [{
29793 key: "bindEventListeners",
29794 value: function bindEventListeners() {
29795 var _this = this;
29796
29797 this.body.emitter.on("initPhysics", function () {
29798 _this.initPhysics();
29799 });
29800 this.body.emitter.on("_layoutFailed", function () {
29801 _this.layoutFailed = true;
29802 });
29803 this.body.emitter.on("resetPhysics", function () {
29804 _this.stopSimulation();
29805
29806 _this.ready = false;
29807 });
29808 this.body.emitter.on("disablePhysics", function () {
29809 _this.physicsEnabled = false;
29810
29811 _this.stopSimulation();
29812 });
29813 this.body.emitter.on("restorePhysics", function () {
29814 _this.setOptions(_this.options);
29815
29816 if (_this.ready === true) {
29817 _this.startSimulation();
29818 }
29819 });
29820 this.body.emitter.on("startSimulation", function () {
29821 if (_this.ready === true) {
29822 _this.startSimulation();
29823 }
29824 });
29825 this.body.emitter.on("stopSimulation", function () {
29826 _this.stopSimulation();
29827 });
29828 this.body.emitter.on("destroy", function () {
29829 _this.stopSimulation(false);
29830
29831 _this.body.emitter.off();
29832 });
29833 this.body.emitter.on("_dataChanged", function () {
29834 // Nodes and/or edges have been added or removed, update shortcut lists.
29835 _this.updatePhysicsData();
29836 }); // debug: show forces
29837 // this.body.emitter.on("afterDrawing", (ctx) => {this._drawForces(ctx);});
29838 }
29839 /**
29840 * set the physics options
29841 *
29842 * @param {object} options
29843 */
29844
29845 }, {
29846 key: "setOptions",
29847 value: function setOptions(options) {
29848 if (options !== undefined) {
29849 if (options === false) {
29850 this.options.enabled = false;
29851 this.physicsEnabled = false;
29852 this.stopSimulation();
29853 } else if (options === true) {
29854 this.options.enabled = true;
29855 this.physicsEnabled = true;
29856 this.startSimulation();
29857 } else {
29858 this.physicsEnabled = true;
29859 selectiveNotDeepExtend(["stabilization"], this.options, options);
29860 mergeOptions(this.options, options, "stabilization");
29861
29862 if (options.enabled === undefined) {
29863 this.options.enabled = true;
29864 }
29865
29866 if (this.options.enabled === false) {
29867 this.physicsEnabled = false;
29868 this.stopSimulation();
29869 }
29870
29871 var wind = this.options.wind;
29872
29873 if (wind) {
29874 if (typeof wind.x !== "number" || isNan(wind.x)) {
29875 wind.x = 0;
29876 }
29877
29878 if (typeof wind.y !== "number" || isNan(wind.y)) {
29879 wind.y = 0;
29880 }
29881 } // set the timestep
29882
29883
29884 this.timestep = this.options.timestep;
29885 }
29886 }
29887
29888 this.init();
29889 }
29890 /**
29891 * configure the engine.
29892 */
29893
29894 }, {
29895 key: "init",
29896 value: function init() {
29897 var options;
29898
29899 if (this.options.solver === "forceAtlas2Based") {
29900 options = this.options.forceAtlas2Based;
29901 this.nodesSolver = new ForceAtlas2BasedRepulsionSolver(this.body, this.physicsBody, options);
29902 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
29903 this.gravitySolver = new ForceAtlas2BasedCentralGravitySolver(this.body, this.physicsBody, options);
29904 } else if (this.options.solver === "repulsion") {
29905 options = this.options.repulsion;
29906 this.nodesSolver = new RepulsionSolver(this.body, this.physicsBody, options);
29907 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
29908 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
29909 } else if (this.options.solver === "hierarchicalRepulsion") {
29910 options = this.options.hierarchicalRepulsion;
29911 this.nodesSolver = new HierarchicalRepulsionSolver(this.body, this.physicsBody, options);
29912 this.edgesSolver = new HierarchicalSpringSolver(this.body, this.physicsBody, options);
29913 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
29914 } else {
29915 // barnesHut
29916 options = this.options.barnesHut;
29917 this.nodesSolver = new BarnesHutSolver(this.body, this.physicsBody, options);
29918 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
29919 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
29920 }
29921
29922 this.modelOptions = options;
29923 }
29924 /**
29925 * initialize the engine
29926 */
29927
29928 }, {
29929 key: "initPhysics",
29930 value: function initPhysics() {
29931 if (this.physicsEnabled === true && this.options.enabled === true) {
29932 if (this.options.stabilization.enabled === true) {
29933 this.stabilize();
29934 } else {
29935 this.stabilized = false;
29936 this.ready = true;
29937 this.body.emitter.emit("fit", {}, this.layoutFailed); // if the layout failed, we use the approximation for the zoom
29938
29939 this.startSimulation();
29940 }
29941 } else {
29942 this.ready = true;
29943 this.body.emitter.emit("fit");
29944 }
29945 }
29946 /**
29947 * Start the simulation
29948 */
29949
29950 }, {
29951 key: "startSimulation",
29952 value: function startSimulation() {
29953 if (this.physicsEnabled === true && this.options.enabled === true) {
29954 this.stabilized = false; // when visible, adaptivity is disabled.
29955
29956 this.adaptiveTimestep = false; // this sets the width of all nodes initially which could be required for the avoidOverlap
29957
29958 this.body.emitter.emit("_resizeNodes");
29959
29960 if (this.viewFunction === undefined) {
29961 var _context;
29962
29963 this.viewFunction = bind(_context = this.simulationStep).call(_context, this);
29964 this.body.emitter.on("initRedraw", this.viewFunction);
29965 this.body.emitter.emit("_startRendering");
29966 }
29967 } else {
29968 this.body.emitter.emit("_redraw");
29969 }
29970 }
29971 /**
29972 * Stop the simulation, force stabilization.
29973 *
29974 * @param {boolean} [emit=true]
29975 */
29976
29977 }, {
29978 key: "stopSimulation",
29979 value: function stopSimulation() {
29980 var emit = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
29981 this.stabilized = true;
29982
29983 if (emit === true) {
29984 this._emitStabilized();
29985 }
29986
29987 if (this.viewFunction !== undefined) {
29988 this.body.emitter.off("initRedraw", this.viewFunction);
29989 this.viewFunction = undefined;
29990
29991 if (emit === true) {
29992 this.body.emitter.emit("_stopRendering");
29993 }
29994 }
29995 }
29996 /**
29997 * The viewFunction inserts this step into each render loop. It calls the physics tick and handles the cleanup at stabilized.
29998 *
29999 */
30000
30001 }, {
30002 key: "simulationStep",
30003 value: function simulationStep() {
30004 // check if the physics have settled
30005 var startTime = now$1();
30006
30007 this.physicsTick();
30008 var physicsTime = now$1() - startTime; // run double speed if it is a little graph
30009
30010 if ((physicsTime < 0.4 * this.simulationInterval || this.runDoubleSpeed === true) && this.stabilized === false) {
30011 this.physicsTick(); // this makes sure there is no jitter. The decision is taken once to run it at double speed.
30012
30013 this.runDoubleSpeed = true;
30014 }
30015
30016 if (this.stabilized === true) {
30017 this.stopSimulation();
30018 }
30019 }
30020 /**
30021 * trigger the stabilized event.
30022 *
30023 * @param {number} [amountOfIterations=this.stabilizationIterations]
30024 * @private
30025 */
30026
30027 }, {
30028 key: "_emitStabilized",
30029 value: function _emitStabilized() {
30030 var _this2 = this;
30031
30032 var amountOfIterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.stabilizationIterations;
30033
30034 if (this.stabilizationIterations > 1 || this.startedStabilization === true) {
30035 setTimeout$1(function () {
30036 _this2.body.emitter.emit("stabilized", {
30037 iterations: amountOfIterations
30038 });
30039
30040 _this2.startedStabilization = false;
30041 _this2.stabilizationIterations = 0;
30042 }, 0);
30043 }
30044 }
30045 /**
30046 * Calculate the forces for one physics iteration and move the nodes.
30047 *
30048 * @private
30049 */
30050
30051 }, {
30052 key: "physicsStep",
30053 value: function physicsStep() {
30054 this.gravitySolver.solve();
30055 this.nodesSolver.solve();
30056 this.edgesSolver.solve();
30057 this.moveNodes();
30058 }
30059 /**
30060 * Make dynamic adjustments to the timestep, based on current state.
30061 *
30062 * Helper function for physicsTick().
30063 *
30064 * @private
30065 */
30066
30067 }, {
30068 key: "adjustTimeStep",
30069 value: function adjustTimeStep() {
30070 var factor = 1.2; // Factor for increasing the timestep on success.
30071 // we compare the two steps. if it is acceptable we double the step.
30072
30073 if (this._evaluateStepQuality() === true) {
30074 this.timestep = factor * this.timestep;
30075 } else {
30076 // if not, we decrease the step to a minimum of the options timestep.
30077 // if the decreased timestep is smaller than the options step, we do not reset the counter
30078 // we assume that the options timestep is stable enough.
30079 if (this.timestep / factor < this.options.timestep) {
30080 this.timestep = this.options.timestep;
30081 } else {
30082 // if the timestep was larger than 2 times the option one we check the adaptivity again to ensure
30083 // that large instabilities do not form.
30084 this.adaptiveCounter = -1; // check again next iteration
30085
30086 this.timestep = Math.max(this.options.timestep, this.timestep / factor);
30087 }
30088 }
30089 }
30090 /**
30091 * A single simulation step (or 'tick') in the physics simulation
30092 *
30093 * @private
30094 */
30095
30096 }, {
30097 key: "physicsTick",
30098 value: function physicsTick() {
30099 this._startStabilizing(); // this ensures that there is no start event when the network is already stable.
30100
30101
30102 if (this.stabilized === true) return; // adaptivity means the timestep adapts to the situation, only applicable for stabilization
30103
30104 if (this.adaptiveTimestep === true && this.adaptiveTimestepEnabled === true) {
30105 // timestep remains stable for "interval" iterations.
30106 var doAdaptive = this.adaptiveCounter % this.adaptiveInterval === 0;
30107
30108 if (doAdaptive) {
30109 // first the big step and revert.
30110 this.timestep = 2 * this.timestep;
30111 this.physicsStep();
30112 this.revert(); // saves the reference state
30113 // now the normal step. Since this is the last step, it is the more stable one and we will take this.
30114
30115 this.timestep = 0.5 * this.timestep; // since it's half the step, we do it twice.
30116
30117 this.physicsStep();
30118 this.physicsStep();
30119 this.adjustTimeStep();
30120 } else {
30121 this.physicsStep(); // normal step, keeping timestep constant
30122 }
30123
30124 this.adaptiveCounter += 1;
30125 } else {
30126 // case for the static timestep, we reset it to the one in options and take a normal step.
30127 this.timestep = this.options.timestep;
30128 this.physicsStep();
30129 }
30130
30131 if (this.stabilized === true) this.revert();
30132 this.stabilizationIterations++;
30133 }
30134 /**
30135 * Nodes and edges can have the physics toggles on or off. A collection of indices is created here so we can skip the check all the time.
30136 *
30137 * @private
30138 */
30139
30140 }, {
30141 key: "updatePhysicsData",
30142 value: function updatePhysicsData() {
30143 this.physicsBody.forces = {};
30144 this.physicsBody.physicsNodeIndices = [];
30145 this.physicsBody.physicsEdgeIndices = [];
30146 var nodes = this.body.nodes;
30147 var edges = this.body.edges; // get node indices for physics
30148
30149 for (var nodeId in nodes) {
30150 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
30151 if (nodes[nodeId].options.physics === true) {
30152 this.physicsBody.physicsNodeIndices.push(nodes[nodeId].id);
30153 }
30154 }
30155 } // get edge indices for physics
30156
30157
30158 for (var edgeId in edges) {
30159 if (Object.prototype.hasOwnProperty.call(edges, edgeId)) {
30160 if (edges[edgeId].options.physics === true) {
30161 this.physicsBody.physicsEdgeIndices.push(edges[edgeId].id);
30162 }
30163 }
30164 } // get the velocity and the forces vector
30165
30166
30167 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
30168 var _nodeId = this.physicsBody.physicsNodeIndices[i];
30169 this.physicsBody.forces[_nodeId] = {
30170 x: 0,
30171 y: 0
30172 }; // forces can be reset because they are recalculated. Velocities have to persist.
30173
30174 if (this.physicsBody.velocities[_nodeId] === undefined) {
30175 this.physicsBody.velocities[_nodeId] = {
30176 x: 0,
30177 y: 0
30178 };
30179 }
30180 } // clean deleted nodes from the velocity vector
30181
30182
30183 for (var _nodeId2 in this.physicsBody.velocities) {
30184 if (nodes[_nodeId2] === undefined) {
30185 delete this.physicsBody.velocities[_nodeId2];
30186 }
30187 }
30188 }
30189 /**
30190 * Revert the simulation one step. This is done so after stabilization, every new start of the simulation will also say stabilized.
30191 */
30192
30193 }, {
30194 key: "revert",
30195 value: function revert() {
30196 var nodeIds = keys$3(this.previousStates);
30197
30198 var nodes = this.body.nodes;
30199 var velocities = this.physicsBody.velocities;
30200 this.referenceState = {};
30201
30202 for (var i = 0; i < nodeIds.length; i++) {
30203 var nodeId = nodeIds[i];
30204
30205 if (nodes[nodeId] !== undefined) {
30206 if (nodes[nodeId].options.physics === true) {
30207 this.referenceState[nodeId] = {
30208 positions: {
30209 x: nodes[nodeId].x,
30210 y: nodes[nodeId].y
30211 }
30212 };
30213 velocities[nodeId].x = this.previousStates[nodeId].vx;
30214 velocities[nodeId].y = this.previousStates[nodeId].vy;
30215 nodes[nodeId].x = this.previousStates[nodeId].x;
30216 nodes[nodeId].y = this.previousStates[nodeId].y;
30217 }
30218 } else {
30219 delete this.previousStates[nodeId];
30220 }
30221 }
30222 }
30223 /**
30224 * This compares the reference state to the current state
30225 *
30226 * @returns {boolean}
30227 * @private
30228 */
30229
30230 }, {
30231 key: "_evaluateStepQuality",
30232 value: function _evaluateStepQuality() {
30233 var dx, dy, dpos;
30234 var nodes = this.body.nodes;
30235 var reference = this.referenceState;
30236 var posThreshold = 0.3;
30237
30238 for (var nodeId in this.referenceState) {
30239 if (Object.prototype.hasOwnProperty.call(this.referenceState, nodeId) && nodes[nodeId] !== undefined) {
30240 dx = nodes[nodeId].x - reference[nodeId].positions.x;
30241 dy = nodes[nodeId].y - reference[nodeId].positions.y;
30242 dpos = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
30243
30244 if (dpos > posThreshold) {
30245 return false;
30246 }
30247 }
30248 }
30249
30250 return true;
30251 }
30252 /**
30253 * move the nodes one timestep and check if they are stabilized
30254 */
30255
30256 }, {
30257 key: "moveNodes",
30258 value: function moveNodes() {
30259 var nodeIndices = this.physicsBody.physicsNodeIndices;
30260 var maxNodeVelocity = 0;
30261 var averageNodeVelocity = 0; // the velocity threshold (energy in the system) for the adaptivity toggle
30262
30263 var velocityAdaptiveThreshold = 5;
30264
30265 for (var i = 0; i < nodeIndices.length; i++) {
30266 var nodeId = nodeIndices[i];
30267
30268 var nodeVelocity = this._performStep(nodeId); // stabilized is true if stabilized is true and velocity is smaller than vmin --> all nodes must be stabilized
30269
30270
30271 maxNodeVelocity = Math.max(maxNodeVelocity, nodeVelocity);
30272 averageNodeVelocity += nodeVelocity;
30273 } // evaluating the stabilized and adaptiveTimestepEnabled conditions
30274
30275
30276 this.adaptiveTimestepEnabled = averageNodeVelocity / nodeIndices.length < velocityAdaptiveThreshold;
30277 this.stabilized = maxNodeVelocity < this.options.minVelocity;
30278 }
30279 /**
30280 * Calculate new velocity for a coordinate direction
30281 *
30282 * @param {number} v velocity for current coordinate
30283 * @param {number} f regular force for current coordinate
30284 * @param {number} m mass of current node
30285 * @returns {number} new velocity for current coordinate
30286 * @private
30287 */
30288
30289 }, {
30290 key: "calculateComponentVelocity",
30291 value: function calculateComponentVelocity(v, f, m) {
30292 var df = this.modelOptions.damping * v; // damping force
30293
30294 var a = (f - df) / m; // acceleration
30295
30296 v += a * this.timestep; // Put a limit on the velocities if it is really high
30297
30298 var maxV = this.options.maxVelocity || 1e9;
30299
30300 if (Math.abs(v) > maxV) {
30301 v = v > 0 ? maxV : -maxV;
30302 }
30303
30304 return v;
30305 }
30306 /**
30307 * Perform the actual step
30308 *
30309 * @param {Node.id} nodeId
30310 * @returns {number} the new velocity of given node
30311 * @private
30312 */
30313
30314 }, {
30315 key: "_performStep",
30316 value: function _performStep(nodeId) {
30317 var node = this.body.nodes[nodeId];
30318 var force = this.physicsBody.forces[nodeId];
30319
30320 if (this.options.wind) {
30321 force.x += this.options.wind.x;
30322 force.y += this.options.wind.y;
30323 }
30324
30325 var velocity = this.physicsBody.velocities[nodeId]; // store the state so we can revert
30326
30327 this.previousStates[nodeId] = {
30328 x: node.x,
30329 y: node.y,
30330 vx: velocity.x,
30331 vy: velocity.y
30332 };
30333
30334 if (node.options.fixed.x === false) {
30335 velocity.x = this.calculateComponentVelocity(velocity.x, force.x, node.options.mass);
30336 node.x += velocity.x * this.timestep;
30337 } else {
30338 force.x = 0;
30339 velocity.x = 0;
30340 }
30341
30342 if (node.options.fixed.y === false) {
30343 velocity.y = this.calculateComponentVelocity(velocity.y, force.y, node.options.mass);
30344 node.y += velocity.y * this.timestep;
30345 } else {
30346 force.y = 0;
30347 velocity.y = 0;
30348 }
30349
30350 var totalVelocity = Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(velocity.y, 2));
30351 return totalVelocity;
30352 }
30353 /**
30354 * When initializing and stabilizing, we can freeze nodes with a predefined position.
30355 * This greatly speeds up stabilization because only the supportnodes for the smoothCurves have to settle.
30356 *
30357 * @private
30358 */
30359
30360 }, {
30361 key: "_freezeNodes",
30362 value: function _freezeNodes() {
30363 var nodes = this.body.nodes;
30364
30365 for (var id in nodes) {
30366 if (Object.prototype.hasOwnProperty.call(nodes, id)) {
30367 if (nodes[id].x && nodes[id].y) {
30368 var fixed = nodes[id].options.fixed;
30369 this.freezeCache[id] = {
30370 x: fixed.x,
30371 y: fixed.y
30372 };
30373 fixed.x = true;
30374 fixed.y = true;
30375 }
30376 }
30377 }
30378 }
30379 /**
30380 * Unfreezes the nodes that have been frozen by _freezeDefinedNodes.
30381 *
30382 * @private
30383 */
30384
30385 }, {
30386 key: "_restoreFrozenNodes",
30387 value: function _restoreFrozenNodes() {
30388 var nodes = this.body.nodes;
30389
30390 for (var id in nodes) {
30391 if (Object.prototype.hasOwnProperty.call(nodes, id)) {
30392 if (this.freezeCache[id] !== undefined) {
30393 nodes[id].options.fixed.x = this.freezeCache[id].x;
30394 nodes[id].options.fixed.y = this.freezeCache[id].y;
30395 }
30396 }
30397 }
30398
30399 this.freezeCache = {};
30400 }
30401 /**
30402 * Find a stable position for all nodes
30403 *
30404 * @param {number} [iterations=this.options.stabilization.iterations]
30405 */
30406
30407 }, {
30408 key: "stabilize",
30409 value: function stabilize() {
30410 var _this3 = this;
30411
30412 var iterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.stabilization.iterations;
30413
30414 if (typeof iterations !== "number") {
30415 iterations = this.options.stabilization.iterations;
30416 console.error("The stabilize method needs a numeric amount of iterations. Switching to default: ", iterations);
30417 }
30418
30419 if (this.physicsBody.physicsNodeIndices.length === 0) {
30420 this.ready = true;
30421 return;
30422 } // enable adaptive timesteps
30423
30424
30425 this.adaptiveTimestep = this.options.adaptiveTimestep; // this sets the width of all nodes initially which could be required for the avoidOverlap
30426
30427 this.body.emitter.emit("_resizeNodes");
30428 this.stopSimulation(); // stop the render loop
30429
30430 this.stabilized = false; // block redraw requests
30431
30432 this.body.emitter.emit("_blockRedraw");
30433 this.targetIterations = iterations; // start the stabilization
30434
30435 if (this.options.stabilization.onlyDynamicEdges === true) {
30436 this._freezeNodes();
30437 }
30438
30439 this.stabilizationIterations = 0;
30440
30441 setTimeout$1(function () {
30442 return _this3._stabilizationBatch();
30443 }, 0);
30444 }
30445 /**
30446 * If not already stabilizing, start it and emit a start event.
30447 *
30448 * @returns {boolean} true if stabilization started with this call
30449 * @private
30450 */
30451
30452 }, {
30453 key: "_startStabilizing",
30454 value: function _startStabilizing() {
30455 if (this.startedStabilization === true) return false;
30456 this.body.emitter.emit("startStabilizing");
30457 this.startedStabilization = true;
30458 return true;
30459 }
30460 /**
30461 * One batch of stabilization
30462 *
30463 * @private
30464 */
30465
30466 }, {
30467 key: "_stabilizationBatch",
30468 value: function _stabilizationBatch() {
30469 var _this4 = this;
30470
30471 var running = function running() {
30472 return _this4.stabilized === false && _this4.stabilizationIterations < _this4.targetIterations;
30473 };
30474
30475 var sendProgress = function sendProgress() {
30476 _this4.body.emitter.emit("stabilizationProgress", {
30477 iterations: _this4.stabilizationIterations,
30478 total: _this4.targetIterations
30479 });
30480 };
30481
30482 if (this._startStabilizing()) {
30483 sendProgress(); // Ensure that there is at least one start event.
30484 }
30485
30486 var count = 0;
30487
30488 while (running() && count < this.options.stabilization.updateInterval) {
30489 this.physicsTick();
30490 count++;
30491 }
30492
30493 sendProgress();
30494
30495 if (running()) {
30496 var _context2;
30497
30498 setTimeout$1(bind(_context2 = this._stabilizationBatch).call(_context2, this), 0);
30499 } else {
30500 this._finalizeStabilization();
30501 }
30502 }
30503 /**
30504 * Wrap up the stabilization, fit and emit the events.
30505 *
30506 * @private
30507 */
30508
30509 }, {
30510 key: "_finalizeStabilization",
30511 value: function _finalizeStabilization() {
30512 this.body.emitter.emit("_allowRedraw");
30513
30514 if (this.options.stabilization.fit === true) {
30515 this.body.emitter.emit("fit");
30516 }
30517
30518 if (this.options.stabilization.onlyDynamicEdges === true) {
30519 this._restoreFrozenNodes();
30520 }
30521
30522 this.body.emitter.emit("stabilizationIterationsDone");
30523 this.body.emitter.emit("_requestRedraw");
30524
30525 if (this.stabilized === true) {
30526 this._emitStabilized();
30527 } else {
30528 this.startSimulation();
30529 }
30530
30531 this.ready = true;
30532 } //--------------------------- DEBUGGING BELOW ---------------------------//
30533
30534 /**
30535 * Debug function that display arrows for the forces currently active in the network.
30536 *
30537 * Use this when debugging only.
30538 *
30539 * @param {CanvasRenderingContext2D} ctx
30540 * @private
30541 */
30542
30543 }, {
30544 key: "_drawForces",
30545 value: function _drawForces(ctx) {
30546 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
30547 var index = this.physicsBody.physicsNodeIndices[i];
30548 var node = this.body.nodes[index];
30549 var force = this.physicsBody.forces[index];
30550 var factor = 20;
30551 var colorFactor = 0.03;
30552 var forceSize = Math.sqrt(Math.pow(force.x, 2) + Math.pow(force.x, 2));
30553 var size = Math.min(Math.max(5, forceSize), 15);
30554 var arrowSize = 3 * size;
30555 var color = HSVToHex((180 - Math.min(1, Math.max(0, colorFactor * forceSize)) * 180) / 360, 1, 1);
30556 var point = {
30557 x: node.x + factor * force.x,
30558 y: node.y + factor * force.y
30559 };
30560 ctx.lineWidth = size;
30561 ctx.strokeStyle = color;
30562 ctx.beginPath();
30563 ctx.moveTo(node.x, node.y);
30564 ctx.lineTo(point.x, point.y);
30565 ctx.stroke();
30566 var angle = Math.atan2(force.y, force.x);
30567 ctx.fillStyle = color;
30568 EndPoints.draw(ctx, {
30569 type: "arrow",
30570 point: point,
30571 angle: angle,
30572 length: arrowSize
30573 });
30574
30575 fill(ctx).call(ctx);
30576 }
30577 }
30578 }]);
30579
30580 return PhysicsEngine;
30581}();
30582
30583/**
30584 * Utility Class
30585 */
30586
30587var NetworkUtil = /*#__PURE__*/function () {
30588 /**
30589 * @ignore
30590 */
30591 function NetworkUtil() {
30592 _classCallCheck(this, NetworkUtil);
30593 }
30594 /**
30595 * Find the center position of the network considering the bounding boxes
30596 *
30597 * @param {Array.<Node>} allNodes
30598 * @param {Array.<Node>} [specificNodes=[]]
30599 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
30600 * @static
30601 */
30602
30603
30604 _createClass(NetworkUtil, null, [{
30605 key: "getRange",
30606 value: function getRange(allNodes) {
30607 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
30608 var minY = 1e9,
30609 maxY = -1e9,
30610 minX = 1e9,
30611 maxX = -1e9,
30612 node;
30613
30614 if (specificNodes.length > 0) {
30615 for (var i = 0; i < specificNodes.length; i++) {
30616 node = allNodes[specificNodes[i]];
30617
30618 if (minX > node.shape.boundingBox.left) {
30619 minX = node.shape.boundingBox.left;
30620 }
30621
30622 if (maxX < node.shape.boundingBox.right) {
30623 maxX = node.shape.boundingBox.right;
30624 }
30625
30626 if (minY > node.shape.boundingBox.top) {
30627 minY = node.shape.boundingBox.top;
30628 } // top is negative, bottom is positive
30629
30630
30631 if (maxY < node.shape.boundingBox.bottom) {
30632 maxY = node.shape.boundingBox.bottom;
30633 } // top is negative, bottom is positive
30634
30635 }
30636 }
30637
30638 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
30639 minY = 0, maxY = 0, minX = 0, maxX = 0;
30640 }
30641
30642 return {
30643 minX: minX,
30644 maxX: maxX,
30645 minY: minY,
30646 maxY: maxY
30647 };
30648 }
30649 /**
30650 * Find the center position of the network
30651 *
30652 * @param {Array.<Node>} allNodes
30653 * @param {Array.<Node>} [specificNodes=[]]
30654 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
30655 * @static
30656 */
30657
30658 }, {
30659 key: "getRangeCore",
30660 value: function getRangeCore(allNodes) {
30661 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
30662 var minY = 1e9,
30663 maxY = -1e9,
30664 minX = 1e9,
30665 maxX = -1e9,
30666 node;
30667
30668 if (specificNodes.length > 0) {
30669 for (var i = 0; i < specificNodes.length; i++) {
30670 node = allNodes[specificNodes[i]];
30671
30672 if (minX > node.x) {
30673 minX = node.x;
30674 }
30675
30676 if (maxX < node.x) {
30677 maxX = node.x;
30678 }
30679
30680 if (minY > node.y) {
30681 minY = node.y;
30682 } // top is negative, bottom is positive
30683
30684
30685 if (maxY < node.y) {
30686 maxY = node.y;
30687 } // top is negative, bottom is positive
30688
30689 }
30690 }
30691
30692 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
30693 minY = 0, maxY = 0, minX = 0, maxX = 0;
30694 }
30695
30696 return {
30697 minX: minX,
30698 maxX: maxX,
30699 minY: minY,
30700 maxY: maxY
30701 };
30702 }
30703 /**
30704 * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY};
30705 * @returns {{x: number, y: number}}
30706 * @static
30707 */
30708
30709 }, {
30710 key: "findCenter",
30711 value: function findCenter(range) {
30712 return {
30713 x: 0.5 * (range.maxX + range.minX),
30714 y: 0.5 * (range.maxY + range.minY)
30715 };
30716 }
30717 /**
30718 * This returns a clone of the options or options of the edge or node to be used for construction of new edges or check functions for new nodes.
30719 *
30720 * @param {vis.Item} item
30721 * @param {'node'|undefined} type
30722 * @returns {{}}
30723 * @static
30724 */
30725
30726 }, {
30727 key: "cloneOptions",
30728 value: function cloneOptions(item, type) {
30729 var clonedOptions = {};
30730
30731 if (type === undefined || type === "node") {
30732 deepExtend(clonedOptions, item.options, true);
30733 clonedOptions.x = item.x;
30734 clonedOptions.y = item.y;
30735 clonedOptions.amountOfConnections = item.edges.length;
30736 } else {
30737 deepExtend(clonedOptions, item.options, true);
30738 }
30739
30740 return clonedOptions;
30741 }
30742 }]);
30743
30744 return NetworkUtil;
30745}();
30746
30747function _createSuper$1(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
30748
30749function _isNativeReflectConstruct$1() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
30750/**
30751 * A Cluster is a special Node that allows a group of Nodes positioned closely together
30752 * to be represented by a single Cluster Node.
30753 *
30754 * @augments Node
30755 */
30756
30757var Cluster = /*#__PURE__*/function (_Node) {
30758 _inherits(Cluster, _Node);
30759
30760 var _super = _createSuper$1(Cluster);
30761
30762 /**
30763 * @param {object} options
30764 * @param {object} body
30765 * @param {Array.<HTMLImageElement>}imagelist
30766 * @param {Array} grouplist
30767 * @param {object} globalOptions
30768 * @param {object} defaultOptions Global default options for nodes
30769 */
30770 function Cluster(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
30771 var _this;
30772
30773 _classCallCheck(this, Cluster);
30774
30775 _this = _super.call(this, options, body, imagelist, grouplist, globalOptions, defaultOptions);
30776 _this.isCluster = true;
30777 _this.containedNodes = {};
30778 _this.containedEdges = {};
30779 return _this;
30780 }
30781 /**
30782 * Transfer child cluster data to current and disconnect the child cluster.
30783 *
30784 * Please consult the header comment in 'Clustering.js' for the fields set here.
30785 *
30786 * @param {string|number} childClusterId id of child cluster to open
30787 */
30788
30789
30790 _createClass(Cluster, [{
30791 key: "_openChildCluster",
30792 value: function _openChildCluster(childClusterId) {
30793 var _this2 = this;
30794
30795 var childCluster = this.body.nodes[childClusterId];
30796
30797 if (this.containedNodes[childClusterId] === undefined) {
30798 throw new Error("node with id: " + childClusterId + " not in current cluster");
30799 }
30800
30801 if (!childCluster.isCluster) {
30802 throw new Error("node with id: " + childClusterId + " is not a cluster");
30803 } // Disconnect child cluster from current cluster
30804
30805
30806 delete this.containedNodes[childClusterId];
30807 forEach$1(childCluster.edges, function (edge) {
30808 delete _this2.containedEdges[edge.id];
30809 }); // Transfer nodes and edges
30810
30811 forEach$1(childCluster.containedNodes, function (node, nodeId) {
30812 _this2.containedNodes[nodeId] = node;
30813 });
30814 childCluster.containedNodes = {};
30815 forEach$1(childCluster.containedEdges, function (edge, edgeId) {
30816 _this2.containedEdges[edgeId] = edge;
30817 });
30818 childCluster.containedEdges = {}; // Transfer edges within cluster edges which are clustered
30819
30820 forEach$1(childCluster.edges, function (clusterEdge) {
30821 forEach$1(_this2.edges, function (parentClusterEdge) {
30822 var _context, _context2;
30823
30824 // Assumption: a clustered edge can only be present in a single clustering edge
30825 // Not tested here
30826 var index = indexOf(_context = parentClusterEdge.clusteringEdgeReplacingIds).call(_context, clusterEdge.id);
30827
30828 if (index === -1) return;
30829 forEach$1(clusterEdge.clusteringEdgeReplacingIds, function (srcId) {
30830 parentClusterEdge.clusteringEdgeReplacingIds.push(srcId); // Maintain correct bookkeeping for transferred edge
30831
30832 _this2.body.edges[srcId].edgeReplacedById = parentClusterEdge.id;
30833 }); // Remove cluster edge from parent cluster edge
30834
30835 splice(_context2 = parentClusterEdge.clusteringEdgeReplacingIds).call(_context2, index, 1);
30836 });
30837 });
30838 childCluster.edges = [];
30839 }
30840 }]);
30841
30842 return Cluster;
30843}(Node);
30844
30845/**
30846 * The clustering engine
30847 */
30848
30849var ClusterEngine = /*#__PURE__*/function () {
30850 /**
30851 * @param {object} body
30852 */
30853 function ClusterEngine(body) {
30854 var _this = this;
30855
30856 _classCallCheck(this, ClusterEngine);
30857
30858 this.body = body;
30859 this.clusteredNodes = {}; // key: node id, value: { clusterId: <id of cluster>, node: <node instance>}
30860
30861 this.clusteredEdges = {}; // key: edge id, value: restore information for given edge
30862
30863 this.options = {};
30864 this.defaultOptions = {};
30865
30866 assign$2(this.options, this.defaultOptions);
30867
30868 this.body.emitter.on("_resetData", function () {
30869 _this.clusteredNodes = {};
30870 _this.clusteredEdges = {};
30871 });
30872 }
30873 /**
30874 *
30875 * @param {number} hubsize
30876 * @param {object} options
30877 */
30878
30879
30880 _createClass(ClusterEngine, [{
30881 key: "clusterByHubsize",
30882 value: function clusterByHubsize(hubsize, options) {
30883 if (hubsize === undefined) {
30884 hubsize = this._getHubSize();
30885 } else if (_typeof(hubsize) === "object") {
30886 options = this._checkOptions(hubsize);
30887 hubsize = this._getHubSize();
30888 }
30889
30890 var nodesToCluster = [];
30891
30892 for (var i = 0; i < this.body.nodeIndices.length; i++) {
30893 var node = this.body.nodes[this.body.nodeIndices[i]];
30894
30895 if (node.edges.length >= hubsize) {
30896 nodesToCluster.push(node.id);
30897 }
30898 }
30899
30900 for (var _i = 0; _i < nodesToCluster.length; _i++) {
30901 this.clusterByConnection(nodesToCluster[_i], options, true);
30902 }
30903
30904 this.body.emitter.emit("_dataChanged");
30905 }
30906 /**
30907 * loop over all nodes, check if they adhere to the condition and cluster if needed.
30908 *
30909 * @param {object} options
30910 * @param {boolean} [refreshData=true]
30911 */
30912
30913 }, {
30914 key: "cluster",
30915 value: function cluster() {
30916 var _this2 = this;
30917
30918 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
30919 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
30920
30921 if (options.joinCondition === undefined) {
30922 throw new Error("Cannot call clusterByNodeData without a joinCondition function in the options.");
30923 } // check if the options object is fine, append if needed
30924
30925
30926 options = this._checkOptions(options);
30927 var childNodesObj = {};
30928 var childEdgesObj = {}; // collect the nodes that will be in the cluster
30929
30930 forEach$1(this.body.nodes, function (node, nodeId) {
30931 if (node.options && options.joinCondition(node.options) === true) {
30932 childNodesObj[nodeId] = node; // collect the edges that will be in the cluster
30933
30934 forEach$1(node.edges, function (edge) {
30935 if (_this2.clusteredEdges[edge.id] === undefined) {
30936 childEdgesObj[edge.id] = edge;
30937 }
30938 });
30939 }
30940 });
30941
30942 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
30943 }
30944 /**
30945 * Cluster all nodes in the network that have only X edges
30946 *
30947 * @param {number} edgeCount
30948 * @param {object} options
30949 * @param {boolean} [refreshData=true]
30950 */
30951
30952 }, {
30953 key: "clusterByEdgeCount",
30954 value: function clusterByEdgeCount(edgeCount, options) {
30955 var _this3 = this;
30956
30957 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
30958 options = this._checkOptions(options);
30959 var clusters = [];
30960 var usedNodes = {};
30961 var edge, edges, relevantEdgeCount; // collect the nodes that will be in the cluster
30962
30963 var _loop = function _loop(i) {
30964 var childNodesObj = {};
30965 var childEdgesObj = {};
30966 var nodeId = _this3.body.nodeIndices[i];
30967 var node = _this3.body.nodes[nodeId]; // if this node is already used in another cluster this session, we do not have to re-evaluate it.
30968
30969 if (usedNodes[nodeId] === undefined) {
30970 relevantEdgeCount = 0;
30971 edges = [];
30972
30973 for (var j = 0; j < node.edges.length; j++) {
30974 edge = node.edges[j];
30975
30976 if (_this3.clusteredEdges[edge.id] === undefined) {
30977 if (edge.toId !== edge.fromId) {
30978 relevantEdgeCount++;
30979 }
30980
30981 edges.push(edge);
30982 }
30983 } // this node qualifies, we collect its neighbours to start the clustering process.
30984
30985
30986 if (relevantEdgeCount === edgeCount) {
30987 var checkJoinCondition = function checkJoinCondition(node) {
30988 if (options.joinCondition === undefined || options.joinCondition === null) {
30989 return true;
30990 }
30991
30992 var clonedOptions = NetworkUtil.cloneOptions(node);
30993 return options.joinCondition(clonedOptions);
30994 };
30995
30996 var gatheringSuccessful = true;
30997
30998 for (var _j = 0; _j < edges.length; _j++) {
30999 edge = edges[_j];
31000
31001 var childNodeId = _this3._getConnectedId(edge, nodeId); // add the nodes to the list by the join condition.
31002
31003
31004 if (checkJoinCondition(node)) {
31005 childEdgesObj[edge.id] = edge;
31006 childNodesObj[nodeId] = node;
31007 childNodesObj[childNodeId] = _this3.body.nodes[childNodeId];
31008 usedNodes[nodeId] = true;
31009 } else {
31010 // this node does not qualify after all.
31011 gatheringSuccessful = false;
31012 break;
31013 }
31014 } // add to the cluster queue
31015
31016
31017 if (keys$3(childNodesObj).length > 0 && keys$3(childEdgesObj).length > 0 && gatheringSuccessful === true) {
31018 /**
31019 * Search for cluster data that contains any of the node id's
31020 *
31021 * @returns {boolean} true if no joinCondition, otherwise return value of joinCondition
31022 */
31023 var findClusterData = function findClusterData() {
31024 for (var n = 0; n < clusters.length; ++n) {
31025 // Search for a cluster containing any of the node id's
31026 for (var m in childNodesObj) {
31027 if (clusters[n].nodes[m] !== undefined) {
31028 return clusters[n];
31029 }
31030 }
31031 }
31032
31033 return undefined;
31034 }; // If any of the found nodes is part of a cluster found in this method,
31035 // add the current values to that cluster
31036
31037
31038 var foundCluster = findClusterData();
31039
31040 if (foundCluster !== undefined) {
31041 // Add nodes to found cluster if not present
31042 for (var m in childNodesObj) {
31043 if (foundCluster.nodes[m] === undefined) {
31044 foundCluster.nodes[m] = childNodesObj[m];
31045 }
31046 } // Add edges to found cluster, if not present
31047
31048
31049 for (var _m in childEdgesObj) {
31050 if (foundCluster.edges[_m] === undefined) {
31051 foundCluster.edges[_m] = childEdgesObj[_m];
31052 }
31053 }
31054 } else {
31055 // Create a new cluster group
31056 clusters.push({
31057 nodes: childNodesObj,
31058 edges: childEdgesObj
31059 });
31060 }
31061 }
31062 }
31063 }
31064 };
31065
31066 for (var i = 0; i < this.body.nodeIndices.length; i++) {
31067 _loop(i);
31068 }
31069
31070 for (var _i2 = 0; _i2 < clusters.length; _i2++) {
31071 this._cluster(clusters[_i2].nodes, clusters[_i2].edges, options, false);
31072 }
31073
31074 if (refreshData === true) {
31075 this.body.emitter.emit("_dataChanged");
31076 }
31077 }
31078 /**
31079 * Cluster all nodes in the network that have only 1 edge
31080 *
31081 * @param {object} options
31082 * @param {boolean} [refreshData=true]
31083 */
31084
31085 }, {
31086 key: "clusterOutliers",
31087 value: function clusterOutliers(options) {
31088 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
31089 this.clusterByEdgeCount(1, options, refreshData);
31090 }
31091 /**
31092 * Cluster all nodes in the network that have only 2 edge
31093 *
31094 * @param {object} options
31095 * @param {boolean} [refreshData=true]
31096 */
31097
31098 }, {
31099 key: "clusterBridges",
31100 value: function clusterBridges(options) {
31101 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
31102 this.clusterByEdgeCount(2, options, refreshData);
31103 }
31104 /**
31105 * suck all connected nodes of a node into the node.
31106 *
31107 * @param {Node.id} nodeId
31108 * @param {object} options
31109 * @param {boolean} [refreshData=true]
31110 */
31111
31112 }, {
31113 key: "clusterByConnection",
31114 value: function clusterByConnection(nodeId, options) {
31115 var _context;
31116
31117 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
31118
31119 // kill conditions
31120 if (nodeId === undefined) {
31121 throw new Error("No nodeId supplied to clusterByConnection!");
31122 }
31123
31124 if (this.body.nodes[nodeId] === undefined) {
31125 throw new Error("The nodeId given to clusterByConnection does not exist!");
31126 }
31127
31128 var node = this.body.nodes[nodeId];
31129 options = this._checkOptions(options, node);
31130
31131 if (options.clusterNodeProperties.x === undefined) {
31132 options.clusterNodeProperties.x = node.x;
31133 }
31134
31135 if (options.clusterNodeProperties.y === undefined) {
31136 options.clusterNodeProperties.y = node.y;
31137 }
31138
31139 if (options.clusterNodeProperties.fixed === undefined) {
31140 options.clusterNodeProperties.fixed = {};
31141 options.clusterNodeProperties.fixed.x = node.options.fixed.x;
31142 options.clusterNodeProperties.fixed.y = node.options.fixed.y;
31143 }
31144
31145 var childNodesObj = {};
31146 var childEdgesObj = {};
31147 var parentNodeId = node.id;
31148 var parentClonedOptions = NetworkUtil.cloneOptions(node);
31149 childNodesObj[parentNodeId] = node; // collect the nodes that will be in the cluster
31150
31151 for (var i = 0; i < node.edges.length; i++) {
31152 var edge = node.edges[i];
31153
31154 if (this.clusteredEdges[edge.id] === undefined) {
31155 var childNodeId = this._getConnectedId(edge, parentNodeId); // if the child node is not in a cluster
31156
31157
31158 if (this.clusteredNodes[childNodeId] === undefined) {
31159 if (childNodeId !== parentNodeId) {
31160 if (options.joinCondition === undefined) {
31161 childEdgesObj[edge.id] = edge;
31162 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
31163 } else {
31164 // clone the options and insert some additional parameters that could be interesting.
31165 var childClonedOptions = NetworkUtil.cloneOptions(this.body.nodes[childNodeId]);
31166
31167 if (options.joinCondition(parentClonedOptions, childClonedOptions) === true) {
31168 childEdgesObj[edge.id] = edge;
31169 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
31170 }
31171 }
31172 } else {
31173 // swallow the edge if it is self-referencing.
31174 childEdgesObj[edge.id] = edge;
31175 }
31176 }
31177 }
31178 }
31179
31180 var childNodeIDs = map$3(_context = keys$3(childNodesObj)).call(_context, function (childNode) {
31181 return childNodesObj[childNode].id;
31182 });
31183
31184 for (var childNodeKey in childNodesObj) {
31185 if (!Object.prototype.hasOwnProperty.call(childNodesObj, childNodeKey)) continue;
31186 var childNode = childNodesObj[childNodeKey];
31187
31188 for (var y = 0; y < childNode.edges.length; y++) {
31189 var childEdge = childNode.edges[y];
31190
31191 if (indexOf(childNodeIDs).call(childNodeIDs, this._getConnectedId(childEdge, childNode.id)) > -1) {
31192 childEdgesObj[childEdge.id] = childEdge;
31193 }
31194 }
31195 }
31196
31197 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
31198 }
31199 /**
31200 * This function creates the edges that will be attached to the cluster
31201 * It looks for edges that are connected to the nodes from the "outside' of the cluster.
31202 *
31203 * @param {{Node.id: vis.Node}} childNodesObj
31204 * @param {{vis.Edge.id: vis.Edge}} childEdgesObj
31205 * @param {object} clusterNodeProperties
31206 * @param {object} clusterEdgeProperties
31207 * @private
31208 */
31209
31210 }, {
31211 key: "_createClusterEdges",
31212 value: function _createClusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, clusterEdgeProperties) {
31213 var edge, childNodeId, childNode, toId, fromId, otherNodeId; // loop over all child nodes and their edges to find edges going out of the cluster
31214 // these edges will be replaced by clusterEdges.
31215
31216 var childKeys = keys$3(childNodesObj);
31217
31218 var createEdges = [];
31219
31220 for (var i = 0; i < childKeys.length; i++) {
31221 childNodeId = childKeys[i];
31222 childNode = childNodesObj[childNodeId]; // construct new edges from the cluster to others
31223
31224 for (var j = 0; j < childNode.edges.length; j++) {
31225 edge = childNode.edges[j]; // we only handle edges that are visible to the system, not the disabled ones from the clustering process.
31226
31227 if (this.clusteredEdges[edge.id] === undefined) {
31228 // self-referencing edges will be added to the "hidden" list
31229 if (edge.toId == edge.fromId) {
31230 childEdgesObj[edge.id] = edge;
31231 } else {
31232 // set up the from and to.
31233 if (edge.toId == childNodeId) {
31234 // this is a double equals because ints and strings can be interchanged here.
31235 toId = clusterNodeProperties.id;
31236 fromId = edge.fromId;
31237 otherNodeId = fromId;
31238 } else {
31239 toId = edge.toId;
31240 fromId = clusterNodeProperties.id;
31241 otherNodeId = toId;
31242 }
31243 } // Only edges from the cluster outwards are being replaced.
31244
31245
31246 if (childNodesObj[otherNodeId] === undefined) {
31247 createEdges.push({
31248 edge: edge,
31249 fromId: fromId,
31250 toId: toId
31251 });
31252 }
31253 }
31254 }
31255 } //
31256 // Here we actually create the replacement edges.
31257 //
31258 // We could not do this in the loop above as the creation process
31259 // would add an edge to the edges array we are iterating over.
31260 //
31261 // NOTE: a clustered edge can have multiple base edges!
31262 //
31263
31264
31265 var newEdges = [];
31266 /**
31267 * Find a cluster edge which matches the given created edge.
31268 *
31269 * @param {vis.Edge} createdEdge
31270 * @returns {vis.Edge}
31271 */
31272
31273 var getNewEdge = function getNewEdge(createdEdge) {
31274 for (var _j2 = 0; _j2 < newEdges.length; _j2++) {
31275 var newEdge = newEdges[_j2]; // We replace both to and from edges with a single cluster edge
31276
31277 var matchToDirection = createdEdge.fromId === newEdge.fromId && createdEdge.toId === newEdge.toId;
31278 var matchFromDirection = createdEdge.fromId === newEdge.toId && createdEdge.toId === newEdge.fromId;
31279
31280 if (matchToDirection || matchFromDirection) {
31281 return newEdge;
31282 }
31283 }
31284
31285 return null;
31286 };
31287
31288 for (var _j3 = 0; _j3 < createEdges.length; _j3++) {
31289 var createdEdge = createEdges[_j3];
31290 var _edge = createdEdge.edge;
31291 var newEdge = getNewEdge(createdEdge);
31292
31293 if (newEdge === null) {
31294 // Create a clustered edge for this connection
31295 newEdge = this._createClusteredEdge(createdEdge.fromId, createdEdge.toId, _edge, clusterEdgeProperties);
31296 newEdges.push(newEdge);
31297 } else {
31298 newEdge.clusteringEdgeReplacingIds.push(_edge.id);
31299 } // also reference the new edge in the old edge
31300
31301
31302 this.body.edges[_edge.id].edgeReplacedById = newEdge.id; // hide the replaced edge
31303
31304 this._backupEdgeOptions(_edge);
31305
31306 _edge.setOptions({
31307 physics: false
31308 });
31309 }
31310 }
31311 /**
31312 * This function checks the options that can be supplied to the different cluster functions
31313 * for certain fields and inserts defaults if needed
31314 *
31315 * @param {object} options
31316 * @returns {*}
31317 * @private
31318 */
31319
31320 }, {
31321 key: "_checkOptions",
31322 value: function _checkOptions() {
31323 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
31324
31325 if (options.clusterEdgeProperties === undefined) {
31326 options.clusterEdgeProperties = {};
31327 }
31328
31329 if (options.clusterNodeProperties === undefined) {
31330 options.clusterNodeProperties = {};
31331 }
31332
31333 return options;
31334 }
31335 /**
31336 *
31337 * @param {object} childNodesObj | object with node objects, id as keys, same as childNodes except it also contains a source node
31338 * @param {object} childEdgesObj | object with edge objects, id as keys
31339 * @param {Array} options | object with {clusterNodeProperties, clusterEdgeProperties, processProperties}
31340 * @param {boolean} refreshData | when true, do not wrap up
31341 * @private
31342 */
31343
31344 }, {
31345 key: "_cluster",
31346 value: function _cluster(childNodesObj, childEdgesObj, options) {
31347 var refreshData = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
31348 // Remove nodes which are already clustered
31349 var tmpNodesToRemove = [];
31350
31351 for (var nodeId in childNodesObj) {
31352 if (Object.prototype.hasOwnProperty.call(childNodesObj, nodeId)) {
31353 if (this.clusteredNodes[nodeId] !== undefined) {
31354 tmpNodesToRemove.push(nodeId);
31355 }
31356 }
31357 }
31358
31359 for (var n = 0; n < tmpNodesToRemove.length; ++n) {
31360 delete childNodesObj[tmpNodesToRemove[n]];
31361 } // kill condition: no nodes don't bother
31362
31363
31364 if (keys$3(childNodesObj).length == 0) {
31365 return;
31366 } // allow clusters of 1 if options allow
31367
31368
31369 if (keys$3(childNodesObj).length == 1 && options.clusterNodeProperties.allowSingleNodeCluster != true) {
31370 return;
31371 }
31372
31373 var clusterNodeProperties = deepExtend({}, options.clusterNodeProperties); // construct the clusterNodeProperties
31374
31375 if (options.processProperties !== undefined) {
31376 // get the childNode options
31377 var childNodesOptions = [];
31378
31379 for (var _nodeId in childNodesObj) {
31380 if (Object.prototype.hasOwnProperty.call(childNodesObj, _nodeId)) {
31381 var clonedOptions = NetworkUtil.cloneOptions(childNodesObj[_nodeId]);
31382 childNodesOptions.push(clonedOptions);
31383 }
31384 } // get cluster properties based on childNodes
31385
31386
31387 var childEdgesOptions = [];
31388
31389 for (var edgeId in childEdgesObj) {
31390 if (Object.prototype.hasOwnProperty.call(childEdgesObj, edgeId)) {
31391 // these cluster edges will be removed on creation of the cluster.
31392 if (edgeId.substr(0, 12) !== "clusterEdge:") {
31393 var _clonedOptions = NetworkUtil.cloneOptions(childEdgesObj[edgeId], "edge");
31394
31395 childEdgesOptions.push(_clonedOptions);
31396 }
31397 }
31398 }
31399
31400 clusterNodeProperties = options.processProperties(clusterNodeProperties, childNodesOptions, childEdgesOptions);
31401
31402 if (!clusterNodeProperties) {
31403 throw new Error("The processProperties function does not return properties!");
31404 }
31405 } // check if we have an unique id;
31406
31407
31408 if (clusterNodeProperties.id === undefined) {
31409 clusterNodeProperties.id = "cluster:" + v4();
31410 }
31411
31412 var clusterId = clusterNodeProperties.id;
31413
31414 if (clusterNodeProperties.label === undefined) {
31415 clusterNodeProperties.label = "cluster";
31416 } // give the clusterNode a position if it does not have one.
31417
31418
31419 var pos = undefined;
31420
31421 if (clusterNodeProperties.x === undefined) {
31422 pos = this._getClusterPosition(childNodesObj);
31423 clusterNodeProperties.x = pos.x;
31424 }
31425
31426 if (clusterNodeProperties.y === undefined) {
31427 if (pos === undefined) {
31428 pos = this._getClusterPosition(childNodesObj);
31429 }
31430
31431 clusterNodeProperties.y = pos.y;
31432 } // force the ID to remain the same
31433
31434
31435 clusterNodeProperties.id = clusterId; // create the cluster Node
31436 // Note that allowSingleNodeCluster, if present, is stored in the options as well
31437
31438 var clusterNode = this.body.functions.createNode(clusterNodeProperties, Cluster);
31439 clusterNode.containedNodes = childNodesObj;
31440 clusterNode.containedEdges = childEdgesObj; // cache a copy from the cluster edge properties if we have to reconnect others later on
31441
31442 clusterNode.clusterEdgeProperties = options.clusterEdgeProperties; // finally put the cluster node into global
31443
31444 this.body.nodes[clusterNodeProperties.id] = clusterNode;
31445
31446 this._clusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, options.clusterEdgeProperties); // set ID to undefined so no duplicates arise
31447
31448
31449 clusterNodeProperties.id = undefined; // wrap up
31450
31451 if (refreshData === true) {
31452 this.body.emitter.emit("_dataChanged");
31453 }
31454 }
31455 /**
31456 *
31457 * @param {Edge} edge
31458 * @private
31459 */
31460
31461 }, {
31462 key: "_backupEdgeOptions",
31463 value: function _backupEdgeOptions(edge) {
31464 if (this.clusteredEdges[edge.id] === undefined) {
31465 this.clusteredEdges[edge.id] = {
31466 physics: edge.options.physics
31467 };
31468 }
31469 }
31470 /**
31471 *
31472 * @param {Edge} edge
31473 * @private
31474 */
31475
31476 }, {
31477 key: "_restoreEdge",
31478 value: function _restoreEdge(edge) {
31479 var originalOptions = this.clusteredEdges[edge.id];
31480
31481 if (originalOptions !== undefined) {
31482 edge.setOptions({
31483 physics: originalOptions.physics
31484 });
31485 delete this.clusteredEdges[edge.id];
31486 }
31487 }
31488 /**
31489 * Check if a node is a cluster.
31490 *
31491 * @param {Node.id} nodeId
31492 * @returns {*}
31493 */
31494
31495 }, {
31496 key: "isCluster",
31497 value: function isCluster(nodeId) {
31498 if (this.body.nodes[nodeId] !== undefined) {
31499 return this.body.nodes[nodeId].isCluster === true;
31500 } else {
31501 console.error("Node does not exist.");
31502 return false;
31503 }
31504 }
31505 /**
31506 * get the position of the cluster node based on what's inside
31507 *
31508 * @param {object} childNodesObj | object with node objects, id as keys
31509 * @returns {{x: number, y: number}}
31510 * @private
31511 */
31512
31513 }, {
31514 key: "_getClusterPosition",
31515 value: function _getClusterPosition(childNodesObj) {
31516 var childKeys = keys$3(childNodesObj);
31517
31518 var minX = childNodesObj[childKeys[0]].x;
31519 var maxX = childNodesObj[childKeys[0]].x;
31520 var minY = childNodesObj[childKeys[0]].y;
31521 var maxY = childNodesObj[childKeys[0]].y;
31522 var node;
31523
31524 for (var i = 1; i < childKeys.length; i++) {
31525 node = childNodesObj[childKeys[i]];
31526 minX = node.x < minX ? node.x : minX;
31527 maxX = node.x > maxX ? node.x : maxX;
31528 minY = node.y < minY ? node.y : minY;
31529 maxY = node.y > maxY ? node.y : maxY;
31530 }
31531
31532 return {
31533 x: 0.5 * (minX + maxX),
31534 y: 0.5 * (minY + maxY)
31535 };
31536 }
31537 /**
31538 * Open a cluster by calling this function.
31539 *
31540 * @param {vis.Edge.id} clusterNodeId | the ID of the cluster node
31541 * @param {object} options
31542 * @param {boolean} refreshData | wrap up afterwards if not true
31543 */
31544
31545 }, {
31546 key: "openCluster",
31547 value: function openCluster(clusterNodeId, options) {
31548 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
31549
31550 // kill conditions
31551 if (clusterNodeId === undefined) {
31552 throw new Error("No clusterNodeId supplied to openCluster.");
31553 }
31554
31555 var clusterNode = this.body.nodes[clusterNodeId];
31556
31557 if (clusterNode === undefined) {
31558 throw new Error("The clusterNodeId supplied to openCluster does not exist.");
31559 }
31560
31561 if (clusterNode.isCluster !== true || clusterNode.containedNodes === undefined || clusterNode.containedEdges === undefined) {
31562 throw new Error("The node:" + clusterNodeId + " is not a valid cluster.");
31563 } // Check if current cluster is clustered itself
31564
31565
31566 var stack = this.findNode(clusterNodeId);
31567 var parentIndex = indexOf(stack).call(stack, clusterNodeId) - 1;
31568
31569 if (parentIndex >= 0) {
31570 // Current cluster is clustered; transfer contained nodes and edges to parent
31571 var parentClusterNodeId = stack[parentIndex];
31572 var parentClusterNode = this.body.nodes[parentClusterNodeId]; // clustering.clusteredNodes and clustering.clusteredEdges remain unchanged
31573
31574 parentClusterNode._openChildCluster(clusterNodeId); // All components of child cluster node have been transferred. It can die now.
31575
31576
31577 delete this.body.nodes[clusterNodeId];
31578
31579 if (refreshData === true) {
31580 this.body.emitter.emit("_dataChanged");
31581 }
31582
31583 return;
31584 } // main body
31585
31586
31587 var containedNodes = clusterNode.containedNodes;
31588 var containedEdges = clusterNode.containedEdges; // allow the user to position the nodes after release.
31589
31590 if (options !== undefined && options.releaseFunction !== undefined && typeof options.releaseFunction === "function") {
31591 var positions = {};
31592 var clusterPosition = {
31593 x: clusterNode.x,
31594 y: clusterNode.y
31595 };
31596
31597 for (var nodeId in containedNodes) {
31598 if (Object.prototype.hasOwnProperty.call(containedNodes, nodeId)) {
31599 var containedNode = this.body.nodes[nodeId];
31600 positions[nodeId] = {
31601 x: containedNode.x,
31602 y: containedNode.y
31603 };
31604 }
31605 }
31606
31607 var newPositions = options.releaseFunction(clusterPosition, positions);
31608
31609 for (var _nodeId2 in containedNodes) {
31610 if (Object.prototype.hasOwnProperty.call(containedNodes, _nodeId2)) {
31611 var _containedNode = this.body.nodes[_nodeId2];
31612
31613 if (newPositions[_nodeId2] !== undefined) {
31614 _containedNode.x = newPositions[_nodeId2].x === undefined ? clusterNode.x : newPositions[_nodeId2].x;
31615 _containedNode.y = newPositions[_nodeId2].y === undefined ? clusterNode.y : newPositions[_nodeId2].y;
31616 }
31617 }
31618 }
31619 } else {
31620 // copy the position from the cluster
31621 forEach$1(containedNodes, function (containedNode) {
31622 // inherit position
31623 if (containedNode.options.fixed.x === false) {
31624 containedNode.x = clusterNode.x;
31625 }
31626
31627 if (containedNode.options.fixed.y === false) {
31628 containedNode.y = clusterNode.y;
31629 }
31630 });
31631 } // release nodes
31632
31633
31634 for (var _nodeId3 in containedNodes) {
31635 if (Object.prototype.hasOwnProperty.call(containedNodes, _nodeId3)) {
31636 var _containedNode2 = this.body.nodes[_nodeId3]; // inherit speed
31637
31638 _containedNode2.vx = clusterNode.vx;
31639 _containedNode2.vy = clusterNode.vy;
31640
31641 _containedNode2.setOptions({
31642 physics: true
31643 });
31644
31645 delete this.clusteredNodes[_nodeId3];
31646 }
31647 } // copy the clusterNode edges because we cannot iterate over an object that we add or remove from.
31648
31649
31650 var edgesToBeDeleted = [];
31651
31652 for (var i = 0; i < clusterNode.edges.length; i++) {
31653 edgesToBeDeleted.push(clusterNode.edges[i]);
31654 } // actually handling the deleting.
31655
31656
31657 for (var _i3 = 0; _i3 < edgesToBeDeleted.length; _i3++) {
31658 var edge = edgesToBeDeleted[_i3];
31659
31660 var otherNodeId = this._getConnectedId(edge, clusterNodeId);
31661
31662 var otherNode = this.clusteredNodes[otherNodeId];
31663
31664 for (var j = 0; j < edge.clusteringEdgeReplacingIds.length; j++) {
31665 var transferId = edge.clusteringEdgeReplacingIds[j];
31666 var transferEdge = this.body.edges[transferId];
31667 if (transferEdge === undefined) continue; // if the other node is in another cluster, we transfer ownership of this edge to the other cluster
31668
31669 if (otherNode !== undefined) {
31670 // transfer ownership:
31671 var otherCluster = this.body.nodes[otherNode.clusterId];
31672 otherCluster.containedEdges[transferEdge.id] = transferEdge; // delete local reference
31673
31674 delete containedEdges[transferEdge.id]; // get to and from
31675
31676 var fromId = transferEdge.fromId;
31677 var toId = transferEdge.toId;
31678
31679 if (transferEdge.toId == otherNodeId) {
31680 toId = otherNode.clusterId;
31681 } else {
31682 fromId = otherNode.clusterId;
31683 } // create new cluster edge from the otherCluster
31684
31685
31686 this._createClusteredEdge(fromId, toId, transferEdge, otherCluster.clusterEdgeProperties, {
31687 hidden: false,
31688 physics: true
31689 });
31690 } else {
31691 this._restoreEdge(transferEdge);
31692 }
31693 }
31694
31695 edge.remove();
31696 } // handle the releasing of the edges
31697
31698
31699 for (var edgeId in containedEdges) {
31700 if (Object.prototype.hasOwnProperty.call(containedEdges, edgeId)) {
31701 this._restoreEdge(containedEdges[edgeId]);
31702 }
31703 } // remove clusterNode
31704
31705
31706 delete this.body.nodes[clusterNodeId];
31707
31708 if (refreshData === true) {
31709 this.body.emitter.emit("_dataChanged");
31710 }
31711 }
31712 /**
31713 *
31714 * @param {Cluster.id} clusterId
31715 * @returns {Array.<Node.id>}
31716 */
31717
31718 }, {
31719 key: "getNodesInCluster",
31720 value: function getNodesInCluster(clusterId) {
31721 var nodesArray = [];
31722
31723 if (this.isCluster(clusterId) === true) {
31724 var containedNodes = this.body.nodes[clusterId].containedNodes;
31725
31726 for (var nodeId in containedNodes) {
31727 if (Object.prototype.hasOwnProperty.call(containedNodes, nodeId)) {
31728 nodesArray.push(this.body.nodes[nodeId].id);
31729 }
31730 }
31731 }
31732
31733 return nodesArray;
31734 }
31735 /**
31736 * Get the stack clusterId's that a certain node resides in. cluster A -> cluster B -> cluster C -> node
31737 *
31738 * If a node can't be found in the chain, return an empty array.
31739 *
31740 * @param {string|number} nodeId
31741 * @returns {Array}
31742 */
31743
31744 }, {
31745 key: "findNode",
31746 value: function findNode(nodeId) {
31747 var stack = [];
31748 var max = 100;
31749 var counter = 0;
31750 var node;
31751
31752 while (this.clusteredNodes[nodeId] !== undefined && counter < max) {
31753 node = this.body.nodes[nodeId];
31754 if (node === undefined) return [];
31755 stack.push(node.id);
31756 nodeId = this.clusteredNodes[nodeId].clusterId;
31757 counter++;
31758 }
31759
31760 node = this.body.nodes[nodeId];
31761 if (node === undefined) return [];
31762 stack.push(node.id);
31763
31764 reverse(stack).call(stack);
31765
31766 return stack;
31767 }
31768 /**
31769 * Using a clustered nodeId, update with the new options
31770 *
31771 * @param {Node.id} clusteredNodeId
31772 * @param {object} newOptions
31773 */
31774
31775 }, {
31776 key: "updateClusteredNode",
31777 value: function updateClusteredNode(clusteredNodeId, newOptions) {
31778 if (clusteredNodeId === undefined) {
31779 throw new Error("No clusteredNodeId supplied to updateClusteredNode.");
31780 }
31781
31782 if (newOptions === undefined) {
31783 throw new Error("No newOptions supplied to updateClusteredNode.");
31784 }
31785
31786 if (this.body.nodes[clusteredNodeId] === undefined) {
31787 throw new Error("The clusteredNodeId supplied to updateClusteredNode does not exist.");
31788 }
31789
31790 this.body.nodes[clusteredNodeId].setOptions(newOptions);
31791 this.body.emitter.emit("_dataChanged");
31792 }
31793 /**
31794 * Using a base edgeId, update all related clustered edges with the new options
31795 *
31796 * @param {vis.Edge.id} startEdgeId
31797 * @param {object} newOptions
31798 */
31799
31800 }, {
31801 key: "updateEdge",
31802 value: function updateEdge(startEdgeId, newOptions) {
31803 if (startEdgeId === undefined) {
31804 throw new Error("No startEdgeId supplied to updateEdge.");
31805 }
31806
31807 if (newOptions === undefined) {
31808 throw new Error("No newOptions supplied to updateEdge.");
31809 }
31810
31811 if (this.body.edges[startEdgeId] === undefined) {
31812 throw new Error("The startEdgeId supplied to updateEdge does not exist.");
31813 }
31814
31815 var allEdgeIds = this.getClusteredEdges(startEdgeId);
31816
31817 for (var i = 0; i < allEdgeIds.length; i++) {
31818 var edge = this.body.edges[allEdgeIds[i]];
31819 edge.setOptions(newOptions);
31820 }
31821
31822 this.body.emitter.emit("_dataChanged");
31823 }
31824 /**
31825 * Get a stack of clusterEdgeId's (+base edgeid) that a base edge is the same as. cluster edge C -> cluster edge B -> cluster edge A -> base edge(edgeId)
31826 *
31827 * @param {vis.Edge.id} edgeId
31828 * @returns {Array.<vis.Edge.id>}
31829 */
31830
31831 }, {
31832 key: "getClusteredEdges",
31833 value: function getClusteredEdges(edgeId) {
31834 var stack = [];
31835 var max = 100;
31836 var counter = 0;
31837
31838 while (edgeId !== undefined && this.body.edges[edgeId] !== undefined && counter < max) {
31839 stack.push(this.body.edges[edgeId].id);
31840 edgeId = this.body.edges[edgeId].edgeReplacedById;
31841 counter++;
31842 }
31843
31844 reverse(stack).call(stack);
31845
31846 return stack;
31847 }
31848 /**
31849 * Get the base edge id of clusterEdgeId. cluster edge (clusteredEdgeId) -> cluster edge B -> cluster edge C -> base edge
31850 *
31851 * @param {vis.Edge.id} clusteredEdgeId
31852 * @returns {vis.Edge.id} baseEdgeId
31853 *
31854 * TODO: deprecate in 5.0.0. Method getBaseEdges() is the correct one to use.
31855 */
31856
31857 }, {
31858 key: "getBaseEdge",
31859 value: function getBaseEdge(clusteredEdgeId) {
31860 // Just kludge this by returning the first base edge id found
31861 return this.getBaseEdges(clusteredEdgeId)[0];
31862 }
31863 /**
31864 * Get all regular edges for this clustered edge id.
31865 *
31866 * @param {vis.Edge.id} clusteredEdgeId
31867 * @returns {Array.<vis.Edge.id>} all baseEdgeId's under this clustered edge
31868 */
31869
31870 }, {
31871 key: "getBaseEdges",
31872 value: function getBaseEdges(clusteredEdgeId) {
31873 var IdsToHandle = [clusteredEdgeId];
31874 var doneIds = [];
31875 var foundIds = [];
31876 var max = 100;
31877 var counter = 0;
31878
31879 while (IdsToHandle.length > 0 && counter < max) {
31880 var nextId = IdsToHandle.pop();
31881 if (nextId === undefined) continue; // Paranoia here and onwards
31882
31883 var nextEdge = this.body.edges[nextId];
31884 if (nextEdge === undefined) continue;
31885 counter++;
31886 var replacingIds = nextEdge.clusteringEdgeReplacingIds;
31887
31888 if (replacingIds === undefined) {
31889 // nextId is a base id
31890 foundIds.push(nextId);
31891 } else {
31892 // Another cluster edge, unravel this one as well
31893 for (var i = 0; i < replacingIds.length; ++i) {
31894 var replacingId = replacingIds[i]; // Don't add if already handled
31895 // TODO: never triggers; find a test-case which does
31896
31897 if (indexOf(IdsToHandle).call(IdsToHandle, replacingIds) !== -1 || indexOf(doneIds).call(doneIds, replacingIds) !== -1) {
31898 continue;
31899 }
31900
31901 IdsToHandle.push(replacingId);
31902 }
31903 }
31904
31905 doneIds.push(nextId);
31906 }
31907
31908 return foundIds;
31909 }
31910 /**
31911 * Get the Id the node is connected to
31912 *
31913 * @param {vis.Edge} edge
31914 * @param {Node.id} nodeId
31915 * @returns {*}
31916 * @private
31917 */
31918
31919 }, {
31920 key: "_getConnectedId",
31921 value: function _getConnectedId(edge, nodeId) {
31922 if (edge.toId != nodeId) {
31923 return edge.toId;
31924 } else if (edge.fromId != nodeId) {
31925 return edge.fromId;
31926 } else {
31927 return edge.fromId;
31928 }
31929 }
31930 /**
31931 * We determine how many connections denote an important hub.
31932 * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%)
31933 *
31934 * @returns {number}
31935 * @private
31936 */
31937
31938 }, {
31939 key: "_getHubSize",
31940 value: function _getHubSize() {
31941 var average = 0;
31942 var averageSquared = 0;
31943 var hubCounter = 0;
31944 var largestHub = 0;
31945
31946 for (var i = 0; i < this.body.nodeIndices.length; i++) {
31947 var node = this.body.nodes[this.body.nodeIndices[i]];
31948
31949 if (node.edges.length > largestHub) {
31950 largestHub = node.edges.length;
31951 }
31952
31953 average += node.edges.length;
31954 averageSquared += Math.pow(node.edges.length, 2);
31955 hubCounter += 1;
31956 }
31957
31958 average = average / hubCounter;
31959 averageSquared = averageSquared / hubCounter;
31960 var variance = averageSquared - Math.pow(average, 2);
31961 var standardDeviation = Math.sqrt(variance);
31962 var hubThreshold = Math.floor(average + 2 * standardDeviation); // always have at least one to cluster
31963
31964 if (hubThreshold > largestHub) {
31965 hubThreshold = largestHub;
31966 }
31967
31968 return hubThreshold;
31969 }
31970 /**
31971 * Create an edge for the cluster representation.
31972 *
31973 * @param {Node.id} fromId
31974 * @param {Node.id} toId
31975 * @param {vis.Edge} baseEdge
31976 * @param {object} clusterEdgeProperties
31977 * @param {object} extraOptions
31978 * @returns {Edge} newly created clustered edge
31979 * @private
31980 */
31981
31982 }, {
31983 key: "_createClusteredEdge",
31984 value: function _createClusteredEdge(fromId, toId, baseEdge, clusterEdgeProperties, extraOptions) {
31985 // copy the options of the edge we will replace
31986 var clonedOptions = NetworkUtil.cloneOptions(baseEdge, "edge"); // make sure the properties of clusterEdges are superimposed on it
31987
31988 deepExtend(clonedOptions, clusterEdgeProperties); // set up the edge
31989
31990 clonedOptions.from = fromId;
31991 clonedOptions.to = toId;
31992 clonedOptions.id = "clusterEdge:" + v4(); // apply the edge specific options to it if specified
31993
31994 if (extraOptions !== undefined) {
31995 deepExtend(clonedOptions, extraOptions);
31996 }
31997
31998 var newEdge = this.body.functions.createEdge(clonedOptions);
31999 newEdge.clusteringEdgeReplacingIds = [baseEdge.id];
32000 newEdge.connect(); // Register the new edge
32001
32002 this.body.edges[newEdge.id] = newEdge;
32003 return newEdge;
32004 }
32005 /**
32006 * Add the passed child nodes and edges to the given cluster node.
32007 *
32008 * @param {object | Node} childNodes hash of nodes or single node to add in cluster
32009 * @param {object | Edge} childEdges hash of edges or single edge to take into account when clustering
32010 * @param {Node} clusterNode cluster node to add nodes and edges to
32011 * @param {object} [clusterEdgeProperties]
32012 * @private
32013 */
32014
32015 }, {
32016 key: "_clusterEdges",
32017 value: function _clusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties) {
32018 if (childEdges instanceof Edge) {
32019 var edge = childEdges;
32020 var obj = {};
32021 obj[edge.id] = edge;
32022 childEdges = obj;
32023 }
32024
32025 if (childNodes instanceof Node) {
32026 var node = childNodes;
32027 var _obj = {};
32028 _obj[node.id] = node;
32029 childNodes = _obj;
32030 }
32031
32032 if (clusterNode === undefined || clusterNode === null) {
32033 throw new Error("_clusterEdges: parameter clusterNode required");
32034 }
32035
32036 if (clusterEdgeProperties === undefined) {
32037 // Take the required properties from the cluster node
32038 clusterEdgeProperties = clusterNode.clusterEdgeProperties;
32039 } // create the new edges that will connect to the cluster.
32040 // All self-referencing edges will be added to childEdges here.
32041
32042
32043 this._createClusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties); // disable the childEdges
32044
32045
32046 for (var edgeId in childEdges) {
32047 if (Object.prototype.hasOwnProperty.call(childEdges, edgeId)) {
32048 if (this.body.edges[edgeId] !== undefined) {
32049 var _edge2 = this.body.edges[edgeId]; // cache the options before changing
32050
32051 this._backupEdgeOptions(_edge2); // disable physics and hide the edge
32052
32053
32054 _edge2.setOptions({
32055 physics: false
32056 });
32057 }
32058 }
32059 } // disable the childNodes
32060
32061
32062 for (var nodeId in childNodes) {
32063 if (Object.prototype.hasOwnProperty.call(childNodes, nodeId)) {
32064 this.clusteredNodes[nodeId] = {
32065 clusterId: clusterNode.id,
32066 node: this.body.nodes[nodeId]
32067 };
32068 this.body.nodes[nodeId].setOptions({
32069 physics: false
32070 });
32071 }
32072 }
32073 }
32074 /**
32075 * Determine in which cluster given nodeId resides.
32076 *
32077 * If not in cluster, return undefined.
32078 *
32079 * NOTE: If you know a cleaner way to do this, please enlighten me (wimrijnders).
32080 *
32081 * @param {Node.id} nodeId
32082 * @returns {Node|undefined} Node instance for cluster, if present
32083 * @private
32084 */
32085
32086 }, {
32087 key: "_getClusterNodeForNode",
32088 value: function _getClusterNodeForNode(nodeId) {
32089 if (nodeId === undefined) return undefined;
32090 var clusteredNode = this.clusteredNodes[nodeId]; // NOTE: If no cluster info found, it should actually be an error
32091
32092 if (clusteredNode === undefined) return undefined;
32093 var clusterId = clusteredNode.clusterId;
32094 if (clusterId === undefined) return undefined;
32095 return this.body.nodes[clusterId];
32096 }
32097 /**
32098 * Internal helper function for conditionally removing items in array
32099 *
32100 * Done like this because Array.filter() is not fully supported by all IE's.
32101 *
32102 * @param {Array} arr
32103 * @param {Function} callback
32104 * @returns {Array}
32105 * @private
32106 */
32107
32108 }, {
32109 key: "_filter",
32110 value: function _filter(arr, callback) {
32111 var ret = [];
32112 forEach$1(arr, function (item) {
32113 if (callback(item)) {
32114 ret.push(item);
32115 }
32116 });
32117 return ret;
32118 }
32119 /**
32120 * Scan all edges for changes in clustering and adjust this if necessary.
32121 *
32122 * Call this (internally) after there has been a change in node or edge data.
32123 *
32124 * Pre: States of this.body.nodes and this.body.edges consistent
32125 * Pre: this.clusteredNodes and this.clusteredEdge consistent with containedNodes and containedEdges
32126 * of cluster nodes.
32127 */
32128
32129 }, {
32130 key: "_updateState",
32131 value: function _updateState() {
32132 var _this4 = this;
32133
32134 var nodeId;
32135 var deletedNodeIds = [];
32136 var deletedEdgeIds = {};
32137 /**
32138 * Utility function to iterate over clustering nodes only
32139 *
32140 * @param {Function} callback function to call for each cluster node
32141 */
32142
32143 var eachClusterNode = function eachClusterNode(callback) {
32144 forEach$1(_this4.body.nodes, function (node) {
32145 if (node.isCluster === true) {
32146 callback(node);
32147 }
32148 });
32149 }; //
32150 // Remove deleted regular nodes from clustering
32151 //
32152 // Determine the deleted nodes
32153
32154
32155 for (nodeId in this.clusteredNodes) {
32156 if (!Object.prototype.hasOwnProperty.call(this.clusteredNodes, nodeId)) continue;
32157 var node = this.body.nodes[nodeId];
32158
32159 if (node === undefined) {
32160 deletedNodeIds.push(nodeId);
32161 }
32162 } // Remove nodes from cluster nodes
32163
32164
32165 eachClusterNode(function (clusterNode) {
32166 for (var n = 0; n < deletedNodeIds.length; n++) {
32167 delete clusterNode.containedNodes[deletedNodeIds[n]];
32168 }
32169 }); // Remove nodes from cluster list
32170
32171 for (var n = 0; n < deletedNodeIds.length; n++) {
32172 delete this.clusteredNodes[deletedNodeIds[n]];
32173 } //
32174 // Remove deleted edges from clustering
32175 //
32176 // Add the deleted clustered edges to the list
32177
32178
32179 forEach$1(this.clusteredEdges, function (edgeId) {
32180 var edge = _this4.body.edges[edgeId];
32181
32182 if (edge === undefined || !edge.endPointsValid()) {
32183 deletedEdgeIds[edgeId] = edgeId;
32184 }
32185 }); // Cluster nodes can also contain edges which are not clustered,
32186 // i.e. nodes 1-2 within cluster with an edge in between.
32187 // So the cluster nodes also need to be scanned for invalid edges
32188
32189 eachClusterNode(function (clusterNode) {
32190 forEach$1(clusterNode.containedEdges, function (edge, edgeId) {
32191 if (!edge.endPointsValid() && !deletedEdgeIds[edgeId]) {
32192 deletedEdgeIds[edgeId] = edgeId;
32193 }
32194 });
32195 }); // Also scan for cluster edges which need to be removed in the active list.
32196 // Regular edges have been removed beforehand, so this only picks up the cluster edges.
32197
32198 forEach$1(this.body.edges, function (edge, edgeId) {
32199 // Explicitly scan the contained edges for validity
32200 var isValid = true;
32201 var replacedIds = edge.clusteringEdgeReplacingIds;
32202
32203 if (replacedIds !== undefined) {
32204 var numValid = 0;
32205 forEach$1(replacedIds, function (containedEdgeId) {
32206 var containedEdge = _this4.body.edges[containedEdgeId];
32207
32208 if (containedEdge !== undefined && containedEdge.endPointsValid()) {
32209 numValid += 1;
32210 }
32211 });
32212 isValid = numValid > 0;
32213 }
32214
32215 if (!edge.endPointsValid() || !isValid) {
32216 deletedEdgeIds[edgeId] = edgeId;
32217 }
32218 }); // Remove edges from cluster nodes
32219
32220 eachClusterNode(function (clusterNode) {
32221 forEach$1(deletedEdgeIds, function (deletedEdgeId) {
32222 delete clusterNode.containedEdges[deletedEdgeId];
32223 forEach$1(clusterNode.edges, function (edge, m) {
32224 if (edge.id === deletedEdgeId) {
32225 clusterNode.edges[m] = null; // Don't want to directly delete here, because in the loop
32226
32227 return;
32228 }
32229
32230 edge.clusteringEdgeReplacingIds = _this4._filter(edge.clusteringEdgeReplacingIds, function (id) {
32231 return !deletedEdgeIds[id];
32232 });
32233 }); // Clean up the nulls
32234
32235 clusterNode.edges = _this4._filter(clusterNode.edges, function (item) {
32236 return item !== null;
32237 });
32238 });
32239 }); // Remove from cluster list
32240
32241 forEach$1(deletedEdgeIds, function (edgeId) {
32242 delete _this4.clusteredEdges[edgeId];
32243 }); // Remove cluster edges from active list (this.body.edges).
32244 // deletedEdgeIds still contains id of regular edges, but these should all
32245 // be gone when you reach here.
32246
32247 forEach$1(deletedEdgeIds, function (edgeId) {
32248 delete _this4.body.edges[edgeId];
32249 }); //
32250 // Check changed cluster state of edges
32251 //
32252 // Iterating over keys here, because edges may be removed in the loop
32253
32254 var ids = keys$3(this.body.edges);
32255
32256 forEach$1(ids, function (edgeId) {
32257 var edge = _this4.body.edges[edgeId];
32258
32259 var shouldBeClustered = _this4._isClusteredNode(edge.fromId) || _this4._isClusteredNode(edge.toId);
32260
32261 if (shouldBeClustered === _this4._isClusteredEdge(edge.id)) {
32262 return; // all is well
32263 }
32264
32265 if (shouldBeClustered) {
32266 // add edge to clustering
32267 var clusterFrom = _this4._getClusterNodeForNode(edge.fromId);
32268
32269 if (clusterFrom !== undefined) {
32270 _this4._clusterEdges(_this4.body.nodes[edge.fromId], edge, clusterFrom);
32271 }
32272
32273 var clusterTo = _this4._getClusterNodeForNode(edge.toId);
32274
32275 if (clusterTo !== undefined) {
32276 _this4._clusterEdges(_this4.body.nodes[edge.toId], edge, clusterTo);
32277 } // TODO: check that it works for both edges clustered
32278 // (This might be paranoia)
32279
32280 } else {
32281 delete _this4._clusterEdges[edgeId];
32282
32283 _this4._restoreEdge(edge); // This should not be happening, the state should
32284 // be properly updated at this point.
32285 //
32286 // If it *is* reached during normal operation, then we have to implement
32287 // undo clustering for this edge here.
32288 // throw new Error('remove edge from clustering not implemented!')
32289
32290 }
32291 }); // Clusters may be nested to any level. Keep on opening until nothing to open
32292
32293 var changed = false;
32294 var continueLoop = true;
32295
32296 var _loop2 = function _loop2() {
32297 var clustersToOpen = []; // Determine the id's of clusters that need opening
32298
32299 eachClusterNode(function (clusterNode) {
32300 var numNodes = keys$3(clusterNode.containedNodes).length;
32301
32302 var allowSingle = clusterNode.options.allowSingleNodeCluster === true;
32303
32304 if (allowSingle && numNodes < 1 || !allowSingle && numNodes < 2) {
32305 clustersToOpen.push(clusterNode.id);
32306 }
32307 }); // Open them
32308
32309 for (var _n = 0; _n < clustersToOpen.length; ++_n) {
32310 _this4.openCluster(clustersToOpen[_n], {}, false
32311 /* Don't refresh, we're in an refresh/update already */
32312 );
32313 }
32314
32315 continueLoop = clustersToOpen.length > 0;
32316 changed = changed || continueLoop;
32317 };
32318
32319 while (continueLoop) {
32320 _loop2();
32321 }
32322
32323 if (changed) {
32324 this._updateState(); // Redo this method (recursion possible! should be safe)
32325
32326 }
32327 }
32328 /**
32329 * Determine if node with given id is part of a cluster.
32330 *
32331 * @param {Node.id} nodeId
32332 * @returns {boolean} true if part of a cluster.
32333 */
32334
32335 }, {
32336 key: "_isClusteredNode",
32337 value: function _isClusteredNode(nodeId) {
32338 return this.clusteredNodes[nodeId] !== undefined;
32339 }
32340 /**
32341 * Determine if edge with given id is not visible due to clustering.
32342 *
32343 * An edge is considered clustered if:
32344 * - it is directly replaced by a clustering edge
32345 * - any of its connecting nodes is in a cluster
32346 *
32347 * @param {vis.Edge.id} edgeId
32348 * @returns {boolean} true if part of a cluster.
32349 */
32350
32351 }, {
32352 key: "_isClusteredEdge",
32353 value: function _isClusteredEdge(edgeId) {
32354 return this.clusteredEdges[edgeId] !== undefined;
32355 }
32356 }]);
32357
32358 return ClusterEngine;
32359}();
32360
32361function _createForOfIteratorHelper$5(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (isArray(o) || (it = _unsupportedIterableToArray$5(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
32362
32363function _unsupportedIterableToArray$5(o, minLen) { var _context4; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$5(o, minLen); var n = slice$1(_context4 = Object.prototype.toString.call(o)).call(_context4, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from_1$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$5(o, minLen); }
32364
32365function _arrayLikeToArray$5(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
32366/**
32367 * Initializes window.requestAnimationFrame() to a usable form.
32368 *
32369 * Specifically, set up this method for the case of running on node.js with jsdom enabled.
32370 *
32371 * NOTES:
32372 *
32373 * * On node.js, when calling this directly outside of this class, `window` is not defined.
32374 * This happens even if jsdom is used.
32375 * * For node.js + jsdom, `window` is available at the moment the constructor is called.
32376 * For this reason, the called is placed within the constructor.
32377 * * Even then, `window.requestAnimationFrame()` is not defined, so it still needs to be added.
32378 * * During unit testing, it happens that the window object is reset during execution, causing
32379 * a runtime error due to missing `requestAnimationFrame()`. This needs to be compensated for,
32380 * see `_requestNextFrame()`.
32381 * * Since this is a global object, it may affect other modules besides `Network`. With normal
32382 * usage, this does not cause any problems. During unit testing, errors may occur. These have
32383 * been compensated for, see comment block in _requestNextFrame().
32384 *
32385 * @private
32386 */
32387
32388function _initRequestAnimationFrame() {
32389 var func;
32390
32391 if (window !== undefined) {
32392 func = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
32393 }
32394
32395 if (func === undefined) {
32396 // window or method not present, setting mock requestAnimationFrame
32397 window.requestAnimationFrame = function (callback) {
32398 //console.log("Called mock requestAnimationFrame");
32399 callback();
32400 };
32401 } else {
32402 window.requestAnimationFrame = func;
32403 }
32404}
32405/**
32406 * The canvas renderer
32407 */
32408
32409
32410var CanvasRenderer = /*#__PURE__*/function () {
32411 /**
32412 * @param {object} body
32413 * @param {Canvas} canvas
32414 */
32415 function CanvasRenderer(body, canvas) {
32416 _classCallCheck(this, CanvasRenderer);
32417
32418 _initRequestAnimationFrame();
32419
32420 this.body = body;
32421 this.canvas = canvas;
32422 this.redrawRequested = false;
32423 this.renderTimer = undefined;
32424 this.requiresTimeout = true;
32425 this.renderingActive = false;
32426 this.renderRequests = 0;
32427 this.allowRedraw = true;
32428 this.dragging = false;
32429 this.zooming = false;
32430 this.options = {};
32431 this.defaultOptions = {
32432 hideEdgesOnDrag: false,
32433 hideEdgesOnZoom: false,
32434 hideNodesOnDrag: false
32435 };
32436
32437 assign$2(this.options, this.defaultOptions);
32438
32439 this._determineBrowserMethod();
32440
32441 this.bindEventListeners();
32442 }
32443 /**
32444 * Binds event listeners
32445 */
32446
32447
32448 _createClass(CanvasRenderer, [{
32449 key: "bindEventListeners",
32450 value: function bindEventListeners() {
32451 var _this = this,
32452 _context2;
32453
32454 this.body.emitter.on("dragStart", function () {
32455 _this.dragging = true;
32456 });
32457 this.body.emitter.on("dragEnd", function () {
32458 _this.dragging = false;
32459 });
32460 this.body.emitter.on("zoom", function () {
32461 _this.zooming = true;
32462 window.clearTimeout(_this.zoomTimeoutId);
32463 _this.zoomTimeoutId = setTimeout$1(function () {
32464 var _context;
32465
32466 _this.zooming = false;
32467
32468 bind(_context = _this._requestRedraw).call(_context, _this)();
32469 }, 250);
32470 });
32471 this.body.emitter.on("_resizeNodes", function () {
32472 _this._resizeNodes();
32473 });
32474 this.body.emitter.on("_redraw", function () {
32475 if (_this.renderingActive === false) {
32476 _this._redraw();
32477 }
32478 });
32479 this.body.emitter.on("_blockRedraw", function () {
32480 _this.allowRedraw = false;
32481 });
32482 this.body.emitter.on("_allowRedraw", function () {
32483 _this.allowRedraw = true;
32484 _this.redrawRequested = false;
32485 });
32486 this.body.emitter.on("_requestRedraw", bind(_context2 = this._requestRedraw).call(_context2, this));
32487 this.body.emitter.on("_startRendering", function () {
32488 _this.renderRequests += 1;
32489 _this.renderingActive = true;
32490
32491 _this._startRendering();
32492 });
32493 this.body.emitter.on("_stopRendering", function () {
32494 _this.renderRequests -= 1;
32495 _this.renderingActive = _this.renderRequests > 0;
32496 _this.renderTimer = undefined;
32497 });
32498 this.body.emitter.on("destroy", function () {
32499 _this.renderRequests = 0;
32500 _this.allowRedraw = false;
32501 _this.renderingActive = false;
32502
32503 if (_this.requiresTimeout === true) {
32504 clearTimeout(_this.renderTimer);
32505 } else {
32506 window.cancelAnimationFrame(_this.renderTimer);
32507 }
32508
32509 _this.body.emitter.off();
32510 });
32511 }
32512 /**
32513 *
32514 * @param {object} options
32515 */
32516
32517 }, {
32518 key: "setOptions",
32519 value: function setOptions(options) {
32520 if (options !== undefined) {
32521 var fields = ["hideEdgesOnDrag", "hideEdgesOnZoom", "hideNodesOnDrag"];
32522 selectiveDeepExtend(fields, this.options, options);
32523 }
32524 }
32525 /**
32526 * Prepare the drawing of the next frame.
32527 *
32528 * Calls the callback when the next frame can or will be drawn.
32529 *
32530 * @param {Function} callback
32531 * @param {number} delay - timeout case only, wait this number of milliseconds
32532 * @returns {Function | undefined}
32533 * @private
32534 */
32535
32536 }, {
32537 key: "_requestNextFrame",
32538 value: function _requestNextFrame(callback, delay) {
32539 // During unit testing, it happens that the mock window object is reset while
32540 // the next frame is still pending. Then, either 'window' is not present, or
32541 // 'requestAnimationFrame()' is not present because it is not defined on the
32542 // mock window object.
32543 //
32544 // As a consequence, unrelated unit tests may appear to fail, even if the problem
32545 // described happens in the current unit test.
32546 //
32547 // This is not something that will happen in normal operation, but we still need
32548 // to take it into account.
32549 //
32550 if (typeof window === "undefined") return; // Doing `if (window === undefined)` does not work here!
32551
32552 var timer;
32553 var myWindow = window; // Grab a reference to reduce the possibility that 'window' is reset
32554 // while running this method.
32555
32556 if (this.requiresTimeout === true) {
32557 // wait given number of milliseconds and perform the animation step function
32558 timer = setTimeout$1(callback, delay);
32559 } else {
32560 if (myWindow.requestAnimationFrame) {
32561 timer = myWindow.requestAnimationFrame(callback);
32562 }
32563 }
32564
32565 return timer;
32566 }
32567 /**
32568 *
32569 * @private
32570 */
32571
32572 }, {
32573 key: "_startRendering",
32574 value: function _startRendering() {
32575 if (this.renderingActive === true) {
32576 if (this.renderTimer === undefined) {
32577 var _context3;
32578
32579 this.renderTimer = this._requestNextFrame(bind(_context3 = this._renderStep).call(_context3, this), this.simulationInterval);
32580 }
32581 }
32582 }
32583 /**
32584 *
32585 * @private
32586 */
32587
32588 }, {
32589 key: "_renderStep",
32590 value: function _renderStep() {
32591 if (this.renderingActive === true) {
32592 // reset the renderTimer so a new scheduled animation step can be set
32593 this.renderTimer = undefined;
32594
32595 if (this.requiresTimeout === true) {
32596 // this schedules a new simulation step
32597 this._startRendering();
32598 }
32599
32600 this._redraw();
32601
32602 if (this.requiresTimeout === false) {
32603 // this schedules a new simulation step
32604 this._startRendering();
32605 }
32606 }
32607 }
32608 /**
32609 * Redraw the network with the current data
32610 * chart will be resized too.
32611 */
32612
32613 }, {
32614 key: "redraw",
32615 value: function redraw() {
32616 this.body.emitter.emit("setSize");
32617
32618 this._redraw();
32619 }
32620 /**
32621 * Redraw the network with the current data
32622 *
32623 * @private
32624 */
32625
32626 }, {
32627 key: "_requestRedraw",
32628 value: function _requestRedraw() {
32629 var _this2 = this;
32630
32631 if (this.redrawRequested !== true && this.renderingActive === false && this.allowRedraw === true) {
32632 this.redrawRequested = true;
32633
32634 this._requestNextFrame(function () {
32635 _this2._redraw(false);
32636 }, 0);
32637 }
32638 }
32639 /**
32640 * Redraw the network with the current data
32641 *
32642 * @param {boolean} [hidden=false] | Used to get the first estimate of the node sizes.
32643 * Only the nodes are drawn after which they are quickly drawn over.
32644 * @private
32645 */
32646
32647 }, {
32648 key: "_redraw",
32649 value: function _redraw() {
32650 var hidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
32651
32652 if (this.allowRedraw === true) {
32653 this.body.emitter.emit("initRedraw");
32654 this.redrawRequested = false;
32655 var drawLater = {
32656 drawExternalLabels: null
32657 }; // when the container div was hidden, this fixes it back up!
32658
32659 if (this.canvas.frame.canvas.width === 0 || this.canvas.frame.canvas.height === 0) {
32660 this.canvas.setSize();
32661 }
32662
32663 this.canvas.setTransform();
32664 var ctx = this.canvas.getContext(); // clear the canvas
32665
32666 var w = this.canvas.frame.canvas.clientWidth;
32667 var h = this.canvas.frame.canvas.clientHeight;
32668 ctx.clearRect(0, 0, w, h); // if the div is hidden, we stop the redraw here for performance.
32669
32670 if (this.canvas.frame.clientWidth === 0) {
32671 return;
32672 } // set scaling and translation
32673
32674
32675 ctx.save();
32676 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
32677 ctx.scale(this.body.view.scale, this.body.view.scale);
32678 ctx.beginPath();
32679 this.body.emitter.emit("beforeDrawing", ctx);
32680 ctx.closePath();
32681
32682 if (hidden === false) {
32683 if ((this.dragging === false || this.dragging === true && this.options.hideEdgesOnDrag === false) && (this.zooming === false || this.zooming === true && this.options.hideEdgesOnZoom === false)) {
32684 this._drawEdges(ctx);
32685 }
32686 }
32687
32688 if (this.dragging === false || this.dragging === true && this.options.hideNodesOnDrag === false) {
32689 var _this$_drawNodes = this._drawNodes(ctx, hidden),
32690 drawExternalLabels = _this$_drawNodes.drawExternalLabels;
32691
32692 drawLater.drawExternalLabels = drawExternalLabels;
32693 } // draw the arrows last so they will be at the top
32694
32695
32696 if (hidden === false) {
32697 if ((this.dragging === false || this.dragging === true && this.options.hideEdgesOnDrag === false) && (this.zooming === false || this.zooming === true && this.options.hideEdgesOnZoom === false)) {
32698 this._drawArrows(ctx);
32699 }
32700 }
32701
32702 if (drawLater.drawExternalLabels != null) {
32703 drawLater.drawExternalLabels();
32704 }
32705
32706 if (hidden === false) {
32707 this._drawSelectionBox(ctx);
32708 }
32709
32710 ctx.beginPath();
32711 this.body.emitter.emit("afterDrawing", ctx);
32712 ctx.closePath(); // restore original scaling and translation
32713
32714 ctx.restore();
32715
32716 if (hidden === true) {
32717 ctx.clearRect(0, 0, w, h);
32718 }
32719 }
32720 }
32721 /**
32722 * Redraw all nodes
32723 *
32724 * @param {CanvasRenderingContext2D} ctx
32725 * @param {boolean} [alwaysShow]
32726 * @private
32727 */
32728
32729 }, {
32730 key: "_resizeNodes",
32731 value: function _resizeNodes() {
32732 this.canvas.setTransform();
32733 var ctx = this.canvas.getContext();
32734 ctx.save();
32735 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
32736 ctx.scale(this.body.view.scale, this.body.view.scale);
32737 var nodes = this.body.nodes;
32738 var node; // resize all nodes
32739
32740 for (var nodeId in nodes) {
32741 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
32742 node = nodes[nodeId];
32743 node.resize(ctx);
32744 node.updateBoundingBox(ctx, node.selected);
32745 }
32746 } // restore original scaling and translation
32747
32748
32749 ctx.restore();
32750 }
32751 /**
32752 * Redraw all nodes
32753 *
32754 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
32755 * @param {boolean} [alwaysShow]
32756 * @private
32757 *
32758 * @returns {object} Callbacks to draw later on higher layers.
32759 */
32760
32761 }, {
32762 key: "_drawNodes",
32763 value: function _drawNodes(ctx) {
32764 var alwaysShow = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
32765 var nodes = this.body.nodes;
32766 var nodeIndices = this.body.nodeIndices;
32767 var node;
32768 var selected = [];
32769 var hovered = [];
32770 var margin = 20;
32771 var topLeft = this.canvas.DOMtoCanvas({
32772 x: -margin,
32773 y: -margin
32774 });
32775 var bottomRight = this.canvas.DOMtoCanvas({
32776 x: this.canvas.frame.canvas.clientWidth + margin,
32777 y: this.canvas.frame.canvas.clientHeight + margin
32778 });
32779 var viewableArea = {
32780 top: topLeft.y,
32781 left: topLeft.x,
32782 bottom: bottomRight.y,
32783 right: bottomRight.x
32784 };
32785 var _drawExternalLabels = []; // draw unselected nodes;
32786
32787 for (var _i = 0; _i < nodeIndices.length; _i++) {
32788 node = nodes[nodeIndices[_i]]; // set selected and hovered nodes aside
32789
32790 if (node.hover) {
32791 hovered.push(nodeIndices[_i]);
32792 } else if (node.isSelected()) {
32793 selected.push(nodeIndices[_i]);
32794 } else {
32795 if (alwaysShow === true) {
32796 var drawLater = node.draw(ctx);
32797
32798 if (drawLater.drawExternalLabel != null) {
32799 _drawExternalLabels.push(drawLater.drawExternalLabel);
32800 }
32801 } else if (node.isBoundingBoxOverlappingWith(viewableArea) === true) {
32802 var _drawLater = node.draw(ctx);
32803
32804 if (_drawLater.drawExternalLabel != null) {
32805 _drawExternalLabels.push(_drawLater.drawExternalLabel);
32806 }
32807 } else {
32808 node.updateBoundingBox(ctx, node.selected);
32809 }
32810 }
32811 }
32812
32813 var i;
32814 var selectedLength = selected.length;
32815 var hoveredLength = hovered.length; // draw the selected nodes on top
32816
32817 for (i = 0; i < selectedLength; i++) {
32818 node = nodes[selected[i]];
32819
32820 var _drawLater2 = node.draw(ctx);
32821
32822 if (_drawLater2.drawExternalLabel != null) {
32823 _drawExternalLabels.push(_drawLater2.drawExternalLabel);
32824 }
32825 } // draw hovered nodes above everything else: fixes https://github.com/visjs/vis-network/issues/226
32826
32827
32828 for (i = 0; i < hoveredLength; i++) {
32829 node = nodes[hovered[i]];
32830
32831 var _drawLater3 = node.draw(ctx);
32832
32833 if (_drawLater3.drawExternalLabel != null) {
32834 _drawExternalLabels.push(_drawLater3.drawExternalLabel);
32835 }
32836 }
32837
32838 return {
32839 drawExternalLabels: function drawExternalLabels() {
32840 var _iterator = _createForOfIteratorHelper$5(_drawExternalLabels),
32841 _step;
32842
32843 try {
32844 for (_iterator.s(); !(_step = _iterator.n()).done;) {
32845 var draw = _step.value;
32846 draw();
32847 }
32848 } catch (err) {
32849 _iterator.e(err);
32850 } finally {
32851 _iterator.f();
32852 }
32853 }
32854 };
32855 }
32856 /**
32857 * Redraw all edges
32858 *
32859 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
32860 * @private
32861 */
32862
32863 }, {
32864 key: "_drawEdges",
32865 value: function _drawEdges(ctx) {
32866 var edges = this.body.edges;
32867 var edgeIndices = this.body.edgeIndices;
32868
32869 for (var i = 0; i < edgeIndices.length; i++) {
32870 var edge = edges[edgeIndices[i]];
32871
32872 if (edge.connected === true) {
32873 edge.draw(ctx);
32874 }
32875 }
32876 }
32877 /**
32878 * Redraw all arrows
32879 *
32880 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
32881 * @private
32882 */
32883
32884 }, {
32885 key: "_drawArrows",
32886 value: function _drawArrows(ctx) {
32887 var edges = this.body.edges;
32888 var edgeIndices = this.body.edgeIndices;
32889
32890 for (var i = 0; i < edgeIndices.length; i++) {
32891 var edge = edges[edgeIndices[i]];
32892
32893 if (edge.connected === true) {
32894 edge.drawArrows(ctx);
32895 }
32896 }
32897 }
32898 /**
32899 * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because
32900 * some implementations (safari and IE9) did not support requestAnimationFrame
32901 *
32902 * @private
32903 */
32904
32905 }, {
32906 key: "_determineBrowserMethod",
32907 value: function _determineBrowserMethod() {
32908 if (typeof window !== "undefined") {
32909 var browserType = navigator.userAgent.toLowerCase();
32910 this.requiresTimeout = false;
32911
32912 if (indexOf(browserType).call(browserType, "msie 9.0") != -1) {
32913 // IE 9
32914 this.requiresTimeout = true;
32915 } else if (indexOf(browserType).call(browserType, "safari") != -1) {
32916 // safari
32917 if (indexOf(browserType).call(browserType, "chrome") <= -1) {
32918 this.requiresTimeout = true;
32919 }
32920 }
32921 } else {
32922 this.requiresTimeout = true;
32923 }
32924 }
32925 /**
32926 * Redraw selection box
32927 *
32928 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
32929 * @private
32930 */
32931
32932 }, {
32933 key: "_drawSelectionBox",
32934 value: function _drawSelectionBox(ctx) {
32935 if (this.body.selectionBox.show) {
32936 ctx.beginPath();
32937 var width = this.body.selectionBox.position.end.x - this.body.selectionBox.position.start.x;
32938 var height = this.body.selectionBox.position.end.y - this.body.selectionBox.position.start.y;
32939 ctx.rect(this.body.selectionBox.position.start.x, this.body.selectionBox.position.start.y, width, height);
32940 ctx.fillStyle = "rgba(151, 194, 252, 0.2)";
32941 ctx.fillRect(this.body.selectionBox.position.start.x, this.body.selectionBox.position.start.y, width, height);
32942 ctx.strokeStyle = "rgba(151, 194, 252, 1)";
32943 ctx.stroke();
32944 } else {
32945 ctx.closePath();
32946 }
32947 }
32948 }]);
32949
32950 return CanvasRenderer;
32951}();
32952
32953var setInterval$1 = path.setInterval;
32954
32955var setInterval = setInterval$1;
32956
32957/**
32958 * Register a touch event, taking place before a gesture
32959 *
32960 * @param {Hammer} hammer A hammer instance
32961 * @param {Function} callback Callback, called as callback(event)
32962 */
32963function onTouch(hammer, callback) {
32964 callback.inputHandler = function (event) {
32965 if (event.isFirst) {
32966 callback(event);
32967 }
32968 };
32969
32970 hammer.on("hammer.input", callback.inputHandler);
32971}
32972/**
32973 * Register a release event, taking place after a gesture
32974 *
32975 * @param {Hammer} hammer A hammer instance
32976 * @param {Function} callback Callback, called as callback(event)
32977 * @returns {*}
32978 */
32979
32980function onRelease(hammer, callback) {
32981 callback.inputHandler = function (event) {
32982 if (event.isFinal) {
32983 callback(event);
32984 }
32985 };
32986
32987 return hammer.on("hammer.input", callback.inputHandler);
32988}
32989
32990/**
32991 * Create the main frame for the Network.
32992 * This function is executed once when a Network object is created. The frame
32993 * contains a canvas, and this canvas contains all objects like the axis and
32994 * nodes.
32995 */
32996
32997var Canvas = /*#__PURE__*/function () {
32998 /**
32999 * @param {object} body
33000 */
33001 function Canvas(body) {
33002 _classCallCheck(this, Canvas);
33003
33004 this.body = body;
33005 this.pixelRatio = 1;
33006 this.cameraState = {};
33007 this.initialized = false;
33008 this.canvasViewCenter = {};
33009 this._cleanupCallbacks = [];
33010 this.options = {};
33011 this.defaultOptions = {
33012 autoResize: true,
33013 height: "100%",
33014 width: "100%"
33015 };
33016
33017 assign$2(this.options, this.defaultOptions);
33018
33019 this.bindEventListeners();
33020 }
33021 /**
33022 * Binds event listeners
33023 */
33024
33025
33026 _createClass(Canvas, [{
33027 key: "bindEventListeners",
33028 value: function bindEventListeners() {
33029 var _this = this,
33030 _context;
33031
33032 // bind the events
33033 this.body.emitter.once("resize", function (obj) {
33034 if (obj.width !== 0) {
33035 _this.body.view.translation.x = obj.width * 0.5;
33036 }
33037
33038 if (obj.height !== 0) {
33039 _this.body.view.translation.y = obj.height * 0.5;
33040 }
33041 });
33042 this.body.emitter.on("setSize", bind(_context = this.setSize).call(_context, this));
33043 this.body.emitter.on("destroy", function () {
33044 _this.hammerFrame.destroy();
33045
33046 _this.hammer.destroy();
33047
33048 _this._cleanUp();
33049 });
33050 }
33051 /**
33052 * @param {object} options
33053 */
33054
33055 }, {
33056 key: "setOptions",
33057 value: function setOptions(options) {
33058 var _this2 = this;
33059
33060 if (options !== undefined) {
33061 var fields = ["width", "height", "autoResize"];
33062 selectiveDeepExtend(fields, this.options, options);
33063 } // Automatically adapt to changing size of the container element.
33064
33065
33066 this._cleanUp();
33067
33068 if (this.options.autoResize === true) {
33069 var _context2;
33070
33071 if (window.ResizeObserver) {
33072 // decent browsers, immediate reactions
33073 var observer = new ResizeObserver(function () {
33074 var changed = _this2.setSize();
33075
33076 if (changed === true) {
33077 _this2.body.emitter.emit("_requestRedraw");
33078 }
33079 });
33080 var frame = this.frame;
33081 observer.observe(frame);
33082
33083 this._cleanupCallbacks.push(function () {
33084 observer.unobserve(frame);
33085 });
33086 } else {
33087 // IE11, continous polling
33088 var resizeTimer = setInterval(function () {
33089 var changed = _this2.setSize();
33090
33091 if (changed === true) {
33092 _this2.body.emitter.emit("_requestRedraw");
33093 }
33094 }, 1000);
33095
33096 this._cleanupCallbacks.push(function () {
33097 clearInterval(resizeTimer);
33098 });
33099 } // Automatically adapt to changing size of the browser.
33100
33101
33102 var resizeFunction = bind(_context2 = this._onResize).call(_context2, this);
33103
33104 addEventListener(window, "resize", resizeFunction);
33105
33106 this._cleanupCallbacks.push(function () {
33107 removeEventListener(window, "resize", resizeFunction);
33108 });
33109 }
33110 }
33111 /**
33112 * @private
33113 */
33114
33115 }, {
33116 key: "_cleanUp",
33117 value: function _cleanUp() {
33118 var _context3, _context4, _context5;
33119
33120 forEach$2(_context3 = reverse(_context4 = splice(_context5 = this._cleanupCallbacks).call(_context5, 0)).call(_context4)).call(_context3, function (callback) {
33121 try {
33122 callback();
33123 } catch (error) {
33124 console.error(error);
33125 }
33126 });
33127 }
33128 /**
33129 * @private
33130 */
33131
33132 }, {
33133 key: "_onResize",
33134 value: function _onResize() {
33135 this.setSize();
33136 this.body.emitter.emit("_redraw");
33137 }
33138 /**
33139 * Get and store the cameraState
33140 *
33141 * @param {number} [pixelRatio=this.pixelRatio]
33142 * @private
33143 */
33144
33145 }, {
33146 key: "_getCameraState",
33147 value: function _getCameraState() {
33148 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.pixelRatio;
33149
33150 if (this.initialized === true) {
33151 this.cameraState.previousWidth = this.frame.canvas.width / pixelRatio;
33152 this.cameraState.previousHeight = this.frame.canvas.height / pixelRatio;
33153 this.cameraState.scale = this.body.view.scale;
33154 this.cameraState.position = this.DOMtoCanvas({
33155 x: 0.5 * this.frame.canvas.width / pixelRatio,
33156 y: 0.5 * this.frame.canvas.height / pixelRatio
33157 });
33158 }
33159 }
33160 /**
33161 * Set the cameraState
33162 *
33163 * @private
33164 */
33165
33166 }, {
33167 key: "_setCameraState",
33168 value: function _setCameraState() {
33169 if (this.cameraState.scale !== undefined && this.frame.canvas.clientWidth !== 0 && this.frame.canvas.clientHeight !== 0 && this.pixelRatio !== 0 && this.cameraState.previousWidth > 0 && this.cameraState.previousHeight > 0) {
33170 var widthRatio = this.frame.canvas.width / this.pixelRatio / this.cameraState.previousWidth;
33171 var heightRatio = this.frame.canvas.height / this.pixelRatio / this.cameraState.previousHeight;
33172 var newScale = this.cameraState.scale;
33173
33174 if (widthRatio != 1 && heightRatio != 1) {
33175 newScale = this.cameraState.scale * 0.5 * (widthRatio + heightRatio);
33176 } else if (widthRatio != 1) {
33177 newScale = this.cameraState.scale * widthRatio;
33178 } else if (heightRatio != 1) {
33179 newScale = this.cameraState.scale * heightRatio;
33180 }
33181
33182 this.body.view.scale = newScale; // this comes from the view module.
33183
33184 var currentViewCenter = this.DOMtoCanvas({
33185 x: 0.5 * this.frame.canvas.clientWidth,
33186 y: 0.5 * this.frame.canvas.clientHeight
33187 });
33188 var distanceFromCenter = {
33189 // offset from view, distance view has to change by these x and y to center the node
33190 x: currentViewCenter.x - this.cameraState.position.x,
33191 y: currentViewCenter.y - this.cameraState.position.y
33192 };
33193 this.body.view.translation.x += distanceFromCenter.x * this.body.view.scale;
33194 this.body.view.translation.y += distanceFromCenter.y * this.body.view.scale;
33195 }
33196 }
33197 /**
33198 *
33199 * @param {number|string} value
33200 * @returns {string}
33201 * @private
33202 */
33203
33204 }, {
33205 key: "_prepareValue",
33206 value: function _prepareValue(value) {
33207 if (typeof value === "number") {
33208 return value + "px";
33209 } else if (typeof value === "string") {
33210 if (indexOf(value).call(value, "%") !== -1 || indexOf(value).call(value, "px") !== -1) {
33211 return value;
33212 } else if (indexOf(value).call(value, "%") === -1) {
33213 return value + "px";
33214 }
33215 }
33216
33217 throw new Error("Could not use the value supplied for width or height:" + value);
33218 }
33219 /**
33220 * Create the HTML
33221 */
33222
33223 }, {
33224 key: "_create",
33225 value: function _create() {
33226 // remove all elements from the container element.
33227 while (this.body.container.hasChildNodes()) {
33228 this.body.container.removeChild(this.body.container.firstChild);
33229 }
33230
33231 this.frame = document.createElement("div");
33232 this.frame.className = "vis-network";
33233 this.frame.style.position = "relative";
33234 this.frame.style.overflow = "hidden";
33235 this.frame.tabIndex = 0; // tab index is required for keycharm to bind keystrokes to the div instead of the window
33236 //////////////////////////////////////////////////////////////////
33237
33238 this.frame.canvas = document.createElement("canvas");
33239 this.frame.canvas.style.position = "relative";
33240 this.frame.appendChild(this.frame.canvas);
33241
33242 if (!this.frame.canvas.getContext) {
33243 var noCanvas = document.createElement("DIV");
33244 noCanvas.style.color = "red";
33245 noCanvas.style.fontWeight = "bold";
33246 noCanvas.style.padding = "10px";
33247 noCanvas.innerText = "Error: your browser does not support HTML canvas";
33248 this.frame.canvas.appendChild(noCanvas);
33249 } else {
33250 this._setPixelRatio();
33251
33252 this.setTransform();
33253 } // add the frame to the container element
33254
33255
33256 this.body.container.appendChild(this.frame);
33257 this.body.view.scale = 1;
33258 this.body.view.translation = {
33259 x: 0.5 * this.frame.canvas.clientWidth,
33260 y: 0.5 * this.frame.canvas.clientHeight
33261 };
33262
33263 this._bindHammer();
33264 }
33265 /**
33266 * This function binds hammer, it can be repeated over and over due to the uniqueness check.
33267 *
33268 * @private
33269 */
33270
33271 }, {
33272 key: "_bindHammer",
33273 value: function _bindHammer() {
33274 var _this3 = this;
33275
33276 if (this.hammer !== undefined) {
33277 this.hammer.destroy();
33278 }
33279
33280 this.drag = {};
33281 this.pinch = {}; // init hammer
33282
33283 this.hammer = new Hammer$1(this.frame.canvas);
33284 this.hammer.get("pinch").set({
33285 enable: true
33286 }); // enable to get better response, todo: test on mobile.
33287
33288 this.hammer.get("pan").set({
33289 threshold: 5,
33290 direction: Hammer$1.DIRECTION_ALL
33291 });
33292 onTouch(this.hammer, function (event) {
33293 _this3.body.eventListeners.onTouch(event);
33294 });
33295 this.hammer.on("tap", function (event) {
33296 _this3.body.eventListeners.onTap(event);
33297 });
33298 this.hammer.on("doubletap", function (event) {
33299 _this3.body.eventListeners.onDoubleTap(event);
33300 });
33301 this.hammer.on("press", function (event) {
33302 _this3.body.eventListeners.onHold(event);
33303 });
33304 this.hammer.on("panstart", function (event) {
33305 _this3.body.eventListeners.onDragStart(event);
33306 });
33307 this.hammer.on("panmove", function (event) {
33308 _this3.body.eventListeners.onDrag(event);
33309 });
33310 this.hammer.on("panend", function (event) {
33311 _this3.body.eventListeners.onDragEnd(event);
33312 });
33313 this.hammer.on("pinch", function (event) {
33314 _this3.body.eventListeners.onPinch(event);
33315 }); // TODO: neatly cleanup these handlers when re-creating the Canvas, IF these are done with hammer, event.stopPropagation will not work?
33316
33317 this.frame.canvas.addEventListener("wheel", function (event) {
33318 _this3.body.eventListeners.onMouseWheel(event);
33319 });
33320 this.frame.canvas.addEventListener("mousemove", function (event) {
33321 _this3.body.eventListeners.onMouseMove(event);
33322 });
33323 this.frame.canvas.addEventListener("contextmenu", function (event) {
33324 _this3.body.eventListeners.onContext(event);
33325 });
33326 this.hammerFrame = new Hammer$1(this.frame);
33327 onRelease(this.hammerFrame, function (event) {
33328 _this3.body.eventListeners.onRelease(event);
33329 });
33330 }
33331 /**
33332 * Set a new size for the network
33333 *
33334 * @param {string} width Width in pixels or percentage (for example '800px'
33335 * or '50%')
33336 * @param {string} height Height in pixels or percentage (for example '400px'
33337 * or '30%')
33338 * @returns {boolean}
33339 */
33340
33341 }, {
33342 key: "setSize",
33343 value: function setSize() {
33344 var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.width;
33345 var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.height;
33346 width = this._prepareValue(width);
33347 height = this._prepareValue(height);
33348 var emitEvent = false;
33349 var oldWidth = this.frame.canvas.width;
33350 var oldHeight = this.frame.canvas.height; // update the pixel ratio
33351 //
33352 // NOTE: Comment in following is rather inconsistent; this is the ONLY place in the code
33353 // where it is assumed that the pixel ratio could change at runtime.
33354 // The only way I can think of this happening is a rotating screen or tablet; but then
33355 // there should be a mechanism for reloading the data (TODO: check if this is present).
33356 //
33357 // If the assumption is true (i.e. pixel ratio can change at runtime), then *all* usage
33358 // of pixel ratio must be overhauled for this.
33359 //
33360 // For the time being, I will humor the assumption here, and in the rest of the code assume it is
33361 // constant.
33362
33363 var previousRatio = this.pixelRatio; // we cache this because the camera state storage needs the old value
33364
33365 this._setPixelRatio();
33366
33367 if (width != this.options.width || height != this.options.height || this.frame.style.width != width || this.frame.style.height != height) {
33368 this._getCameraState(previousRatio);
33369
33370 this.frame.style.width = width;
33371 this.frame.style.height = height;
33372 this.frame.canvas.style.width = "100%";
33373 this.frame.canvas.style.height = "100%";
33374 this.frame.canvas.width = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
33375 this.frame.canvas.height = Math.round(this.frame.canvas.clientHeight * this.pixelRatio);
33376 this.options.width = width;
33377 this.options.height = height;
33378 this.canvasViewCenter = {
33379 x: 0.5 * this.frame.clientWidth,
33380 y: 0.5 * this.frame.clientHeight
33381 };
33382 emitEvent = true;
33383 } else {
33384 // this would adapt the width of the canvas to the width from 100% if and only if
33385 // there is a change.
33386 var newWidth = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
33387 var newHeight = Math.round(this.frame.canvas.clientHeight * this.pixelRatio); // store the camera if there is a change in size.
33388
33389 if (this.frame.canvas.width !== newWidth || this.frame.canvas.height !== newHeight) {
33390 this._getCameraState(previousRatio);
33391 }
33392
33393 if (this.frame.canvas.width !== newWidth) {
33394 this.frame.canvas.width = newWidth;
33395 emitEvent = true;
33396 }
33397
33398 if (this.frame.canvas.height !== newHeight) {
33399 this.frame.canvas.height = newHeight;
33400 emitEvent = true;
33401 }
33402 }
33403
33404 if (emitEvent === true) {
33405 this.body.emitter.emit("resize", {
33406 width: Math.round(this.frame.canvas.width / this.pixelRatio),
33407 height: Math.round(this.frame.canvas.height / this.pixelRatio),
33408 oldWidth: Math.round(oldWidth / this.pixelRatio),
33409 oldHeight: Math.round(oldHeight / this.pixelRatio)
33410 }); // restore the camera on change.
33411
33412 this._setCameraState();
33413 } // set initialized so the get and set camera will work from now on.
33414
33415
33416 this.initialized = true;
33417 return emitEvent;
33418 }
33419 /**
33420 *
33421 * @returns {CanvasRenderingContext2D}
33422 */
33423
33424 }, {
33425 key: "getContext",
33426 value: function getContext() {
33427 return this.frame.canvas.getContext("2d");
33428 }
33429 /**
33430 * Determine the pixel ratio for various browsers.
33431 *
33432 * @returns {number}
33433 * @private
33434 */
33435
33436 }, {
33437 key: "_determinePixelRatio",
33438 value: function _determinePixelRatio() {
33439 var ctx = this.getContext();
33440
33441 if (ctx === undefined) {
33442 throw new Error("Could not get canvax context");
33443 }
33444
33445 var numerator = 1;
33446
33447 if (typeof window !== "undefined") {
33448 // (window !== undefined) doesn't work here!
33449 // Protection during unit tests, where 'window' can be missing
33450 numerator = window.devicePixelRatio || 1;
33451 }
33452
33453 var denominator = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
33454 return numerator / denominator;
33455 }
33456 /**
33457 * Lazy determination of pixel ratio.
33458 *
33459 * @private
33460 */
33461
33462 }, {
33463 key: "_setPixelRatio",
33464 value: function _setPixelRatio() {
33465 this.pixelRatio = this._determinePixelRatio();
33466 }
33467 /**
33468 * Set the transform in the contained context, based on its pixelRatio
33469 */
33470
33471 }, {
33472 key: "setTransform",
33473 value: function setTransform() {
33474 var ctx = this.getContext();
33475
33476 if (ctx === undefined) {
33477 throw new Error("Could not get canvax context");
33478 }
33479
33480 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
33481 }
33482 /**
33483 * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
33484 * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
33485 *
33486 * @param {number} x
33487 * @returns {number}
33488 * @private
33489 */
33490
33491 }, {
33492 key: "_XconvertDOMtoCanvas",
33493 value: function _XconvertDOMtoCanvas(x) {
33494 return (x - this.body.view.translation.x) / this.body.view.scale;
33495 }
33496 /**
33497 * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
33498 * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
33499 *
33500 * @param {number} x
33501 * @returns {number}
33502 * @private
33503 */
33504
33505 }, {
33506 key: "_XconvertCanvasToDOM",
33507 value: function _XconvertCanvasToDOM(x) {
33508 return x * this.body.view.scale + this.body.view.translation.x;
33509 }
33510 /**
33511 * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
33512 * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
33513 *
33514 * @param {number} y
33515 * @returns {number}
33516 * @private
33517 */
33518
33519 }, {
33520 key: "_YconvertDOMtoCanvas",
33521 value: function _YconvertDOMtoCanvas(y) {
33522 return (y - this.body.view.translation.y) / this.body.view.scale;
33523 }
33524 /**
33525 * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
33526 * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
33527 *
33528 * @param {number} y
33529 * @returns {number}
33530 * @private
33531 */
33532
33533 }, {
33534 key: "_YconvertCanvasToDOM",
33535 value: function _YconvertCanvasToDOM(y) {
33536 return y * this.body.view.scale + this.body.view.translation.y;
33537 }
33538 /**
33539 * @param {point} pos
33540 * @returns {point}
33541 */
33542
33543 }, {
33544 key: "canvasToDOM",
33545 value: function canvasToDOM(pos) {
33546 return {
33547 x: this._XconvertCanvasToDOM(pos.x),
33548 y: this._YconvertCanvasToDOM(pos.y)
33549 };
33550 }
33551 /**
33552 *
33553 * @param {point} pos
33554 * @returns {point}
33555 */
33556
33557 }, {
33558 key: "DOMtoCanvas",
33559 value: function DOMtoCanvas(pos) {
33560 return {
33561 x: this._XconvertDOMtoCanvas(pos.x),
33562 y: this._YconvertDOMtoCanvas(pos.y)
33563 };
33564 }
33565 }]);
33566
33567 return Canvas;
33568}();
33569
33570/**
33571 * Validate the fit options, replace missing optional values by defaults etc.
33572 *
33573 * @param rawOptions - The raw options.
33574 * @param allNodeIds - All node ids that will be used if nodes are omitted in
33575 * the raw options.
33576 *
33577 * @returns Options with everything filled in and validated.
33578 */
33579function normalizeFitOptions(rawOptions, allNodeIds) {
33580 var options = assign$2({
33581 nodes: allNodeIds,
33582 minZoomLevel: Number.MIN_VALUE,
33583 maxZoomLevel: 1
33584 }, rawOptions !== null && rawOptions !== void 0 ? rawOptions : {});
33585
33586 if (!isArray(options.nodes)) {
33587 throw new TypeError("Nodes has to be an array of ids.");
33588 }
33589
33590 if (options.nodes.length === 0) {
33591 options.nodes = allNodeIds;
33592 }
33593
33594 if (!(typeof options.minZoomLevel === "number" && options.minZoomLevel > 0)) {
33595 throw new TypeError("Min zoom level has to be a number higher than zero.");
33596 }
33597
33598 if (!(typeof options.maxZoomLevel === "number" && options.minZoomLevel <= options.maxZoomLevel)) {
33599 throw new TypeError("Max zoom level has to be a number higher than min zoom level.");
33600 }
33601
33602 return options;
33603}
33604
33605/**
33606 * The view
33607 */
33608
33609var View = /*#__PURE__*/function () {
33610 /**
33611 * @param {object} body
33612 * @param {Canvas} canvas
33613 */
33614 function View(body, canvas) {
33615 var _context,
33616 _this = this,
33617 _context2;
33618
33619 _classCallCheck(this, View);
33620
33621 this.body = body;
33622 this.canvas = canvas;
33623 this.animationSpeed = 1 / this.renderRefreshRate;
33624 this.animationEasingFunction = "easeInOutQuint";
33625 this.easingTime = 0;
33626 this.sourceScale = 0;
33627 this.targetScale = 0;
33628 this.sourceTranslation = 0;
33629 this.targetTranslation = 0;
33630 this.lockedOnNodeId = undefined;
33631 this.lockedOnNodeOffset = undefined;
33632 this.touchTime = 0;
33633 this.viewFunction = undefined;
33634 this.body.emitter.on("fit", bind(_context = this.fit).call(_context, this));
33635 this.body.emitter.on("animationFinished", function () {
33636 _this.body.emitter.emit("_stopRendering");
33637 });
33638 this.body.emitter.on("unlockNode", bind(_context2 = this.releaseNode).call(_context2, this));
33639 }
33640 /**
33641 *
33642 * @param {object} [options={}]
33643 */
33644
33645
33646 _createClass(View, [{
33647 key: "setOptions",
33648 value: function setOptions() {
33649 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
33650 this.options = options;
33651 }
33652 /**
33653 * This function zooms out to fit all data on screen based on amount of nodes
33654 *
33655 * @param {object} [options={{nodes=Array}}]
33656 * @param options
33657 * @param {boolean} [initialZoom=false] | zoom based on fitted formula or range, true = fitted, default = false;
33658 */
33659
33660 }, {
33661 key: "fit",
33662 value: function fit(options) {
33663 var initialZoom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
33664 options = normalizeFitOptions(options, this.body.nodeIndices);
33665 var canvasWidth = this.canvas.frame.canvas.clientWidth;
33666 var canvasHeight = this.canvas.frame.canvas.clientHeight;
33667 var range;
33668 var zoomLevel;
33669
33670 if (canvasWidth === 0 || canvasHeight === 0) {
33671 // There's no point in trying to fit into zero sized canvas. This could
33672 // potentially even result in invalid values being computed. For example
33673 // for network without nodes and zero sized canvas the zoom level would
33674 // end up being computed as 0/0 which results in NaN. In any other case
33675 // this would be 0/something which is again pointless to compute.
33676 zoomLevel = 1;
33677 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
33678 } else if (initialZoom === true) {
33679 // check if more than half of the nodes have a predefined position. If so, we use the range, not the approximation.
33680 var positionDefined = 0;
33681
33682 for (var nodeId in this.body.nodes) {
33683 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
33684 var node = this.body.nodes[nodeId];
33685
33686 if (node.predefinedPosition === true) {
33687 positionDefined += 1;
33688 }
33689 }
33690 }
33691
33692 if (positionDefined > 0.5 * this.body.nodeIndices.length) {
33693 this.fit(options, false);
33694 return;
33695 }
33696
33697 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
33698 var numberOfNodes = this.body.nodeIndices.length;
33699 zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
33700 // correct for larger canvasses.
33701
33702 var factor = Math.min(canvasWidth / 600, canvasHeight / 600);
33703 zoomLevel *= factor;
33704 } else {
33705 this.body.emitter.emit("_resizeNodes");
33706 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
33707 var xDistance = Math.abs(range.maxX - range.minX) * 1.1;
33708 var yDistance = Math.abs(range.maxY - range.minY) * 1.1;
33709 var xZoomLevel = canvasWidth / xDistance;
33710 var yZoomLevel = canvasHeight / yDistance;
33711 zoomLevel = xZoomLevel <= yZoomLevel ? xZoomLevel : yZoomLevel;
33712 }
33713
33714 if (zoomLevel > options.maxZoomLevel) {
33715 zoomLevel = options.maxZoomLevel;
33716 } else if (zoomLevel < options.minZoomLevel) {
33717 zoomLevel = options.minZoomLevel;
33718 }
33719
33720 var center = NetworkUtil.findCenter(range);
33721 var animationOptions = {
33722 position: center,
33723 scale: zoomLevel,
33724 animation: options.animation
33725 };
33726 this.moveTo(animationOptions);
33727 } // animation
33728
33729 /**
33730 * Center a node in view.
33731 *
33732 * @param {number} nodeId
33733 * @param {number} [options]
33734 */
33735
33736 }, {
33737 key: "focus",
33738 value: function focus(nodeId) {
33739 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
33740
33741 if (this.body.nodes[nodeId] !== undefined) {
33742 var nodePosition = {
33743 x: this.body.nodes[nodeId].x,
33744 y: this.body.nodes[nodeId].y
33745 };
33746 options.position = nodePosition;
33747 options.lockedOnNode = nodeId;
33748 this.moveTo(options);
33749 } else {
33750 console.error("Node: " + nodeId + " cannot be found.");
33751 }
33752 }
33753 /**
33754 *
33755 * @param {object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
33756 * | options.scale = number // scale to move to
33757 * | options.position = {x:number, y:number} // position to move to
33758 * | options.animation = {duration:number, easingFunction:String} || Boolean // position to move to
33759 */
33760
33761 }, {
33762 key: "moveTo",
33763 value: function moveTo(options) {
33764 if (options === undefined) {
33765 options = {};
33766 return;
33767 }
33768
33769 if (options.offset != null) {
33770 if (options.offset.x != null) {
33771 // Coerce and verify that x is valid.
33772 options.offset.x = +options.offset.x;
33773
33774 if (!_isFinite(options.offset.x)) {
33775 throw new TypeError('The option "offset.x" has to be a finite number.');
33776 }
33777 } else {
33778 options.offset.x = 0;
33779 }
33780
33781 if (options.offset.y != null) {
33782 // Coerce and verify that y is valid.
33783 options.offset.y = +options.offset.y;
33784
33785 if (!_isFinite(options.offset.y)) {
33786 throw new TypeError('The option "offset.y" has to be a finite number.');
33787 }
33788 } else {
33789 options.offset.x = 0;
33790 }
33791 } else {
33792 options.offset = {
33793 x: 0,
33794 y: 0
33795 };
33796 }
33797
33798 if (options.position != null) {
33799 if (options.position.x != null) {
33800 // Coerce and verify that x is valid.
33801 options.position.x = +options.position.x;
33802
33803 if (!_isFinite(options.position.x)) {
33804 throw new TypeError('The option "position.x" has to be a finite number.');
33805 }
33806 } else {
33807 options.position.x = 0;
33808 }
33809
33810 if (options.position.y != null) {
33811 // Coerce and verify that y is valid.
33812 options.position.y = +options.position.y;
33813
33814 if (!_isFinite(options.position.y)) {
33815 throw new TypeError('The option "position.y" has to be a finite number.');
33816 }
33817 } else {
33818 options.position.x = 0;
33819 }
33820 } else {
33821 options.position = this.getViewPosition();
33822 }
33823
33824 if (options.scale != null) {
33825 // Coerce and verify that the scale is valid.
33826 options.scale = +options.scale;
33827
33828 if (!(options.scale > 0)) {
33829 throw new TypeError('The option "scale" has to be a number greater than zero.');
33830 }
33831 } else {
33832 options.scale = this.body.view.scale;
33833 }
33834
33835 if (options.animation === undefined) {
33836 options.animation = {
33837 duration: 0
33838 };
33839 }
33840
33841 if (options.animation === false) {
33842 options.animation = {
33843 duration: 0
33844 };
33845 }
33846
33847 if (options.animation === true) {
33848 options.animation = {};
33849 }
33850
33851 if (options.animation.duration === undefined) {
33852 options.animation.duration = 1000;
33853 } // default duration
33854
33855
33856 if (options.animation.easingFunction === undefined) {
33857 options.animation.easingFunction = "easeInOutQuad";
33858 } // default easing function
33859
33860
33861 this.animateView(options);
33862 }
33863 /**
33864 *
33865 * @param {object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
33866 * | options.time = number // animation time in milliseconds
33867 * | options.scale = number // scale to animate to
33868 * | options.position = {x:number, y:number} // position to animate to
33869 * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad,
33870 * // easeInCubic, easeOutCubic, easeInOutCubic,
33871 * // easeInQuart, easeOutQuart, easeInOutQuart,
33872 * // easeInQuint, easeOutQuint, easeInOutQuint
33873 */
33874
33875 }, {
33876 key: "animateView",
33877 value: function animateView(options) {
33878 if (options === undefined) {
33879 return;
33880 }
33881
33882 this.animationEasingFunction = options.animation.easingFunction; // release if something focussed on the node
33883
33884 this.releaseNode();
33885
33886 if (options.locked === true) {
33887 this.lockedOnNodeId = options.lockedOnNode;
33888 this.lockedOnNodeOffset = options.offset;
33889 } // forcefully complete the old animation if it was still running
33890
33891
33892 if (this.easingTime != 0) {
33893 this._transitionRedraw(true); // by setting easingtime to 1, we finish the animation.
33894
33895 }
33896
33897 this.sourceScale = this.body.view.scale;
33898 this.sourceTranslation = this.body.view.translation;
33899 this.targetScale = options.scale; // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw
33900 // but at least then we'll have the target transition
33901
33902 this.body.view.scale = this.targetScale;
33903 var viewCenter = this.canvas.DOMtoCanvas({
33904 x: 0.5 * this.canvas.frame.canvas.clientWidth,
33905 y: 0.5 * this.canvas.frame.canvas.clientHeight
33906 });
33907 var distanceFromCenter = {
33908 // offset from view, distance view has to change by these x and y to center the node
33909 x: viewCenter.x - options.position.x,
33910 y: viewCenter.y - options.position.y
33911 };
33912 this.targetTranslation = {
33913 x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x,
33914 y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y
33915 }; // if the time is set to 0, don't do an animation
33916
33917 if (options.animation.duration === 0) {
33918 if (this.lockedOnNodeId != undefined) {
33919 var _context3;
33920
33921 this.viewFunction = bind(_context3 = this._lockedRedraw).call(_context3, this);
33922 this.body.emitter.on("initRedraw", this.viewFunction);
33923 } else {
33924 this.body.view.scale = this.targetScale;
33925 this.body.view.translation = this.targetTranslation;
33926 this.body.emitter.emit("_requestRedraw");
33927 }
33928 } else {
33929 var _context4;
33930
33931 this.animationSpeed = 1 / (60 * options.animation.duration * 0.001) || 1 / 60; // 60 for 60 seconds, 0.001 for milli's
33932
33933 this.animationEasingFunction = options.animation.easingFunction;
33934 this.viewFunction = bind(_context4 = this._transitionRedraw).call(_context4, this);
33935 this.body.emitter.on("initRedraw", this.viewFunction);
33936 this.body.emitter.emit("_startRendering");
33937 }
33938 }
33939 /**
33940 * used to animate smoothly by hijacking the redraw function.
33941 *
33942 * @private
33943 */
33944
33945 }, {
33946 key: "_lockedRedraw",
33947 value: function _lockedRedraw() {
33948 var nodePosition = {
33949 x: this.body.nodes[this.lockedOnNodeId].x,
33950 y: this.body.nodes[this.lockedOnNodeId].y
33951 };
33952 var viewCenter = this.canvas.DOMtoCanvas({
33953 x: 0.5 * this.canvas.frame.canvas.clientWidth,
33954 y: 0.5 * this.canvas.frame.canvas.clientHeight
33955 });
33956 var distanceFromCenter = {
33957 // offset from view, distance view has to change by these x and y to center the node
33958 x: viewCenter.x - nodePosition.x,
33959 y: viewCenter.y - nodePosition.y
33960 };
33961 var sourceTranslation = this.body.view.translation;
33962 var targetTranslation = {
33963 x: sourceTranslation.x + distanceFromCenter.x * this.body.view.scale + this.lockedOnNodeOffset.x,
33964 y: sourceTranslation.y + distanceFromCenter.y * this.body.view.scale + this.lockedOnNodeOffset.y
33965 };
33966 this.body.view.translation = targetTranslation;
33967 }
33968 /**
33969 * Resets state of a locked on Node
33970 */
33971
33972 }, {
33973 key: "releaseNode",
33974 value: function releaseNode() {
33975 if (this.lockedOnNodeId !== undefined && this.viewFunction !== undefined) {
33976 this.body.emitter.off("initRedraw", this.viewFunction);
33977 this.lockedOnNodeId = undefined;
33978 this.lockedOnNodeOffset = undefined;
33979 }
33980 }
33981 /**
33982 * @param {boolean} [finished=false]
33983 * @private
33984 */
33985
33986 }, {
33987 key: "_transitionRedraw",
33988 value: function _transitionRedraw() {
33989 var finished = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
33990 this.easingTime += this.animationSpeed;
33991 this.easingTime = finished === true ? 1.0 : this.easingTime;
33992 var progress = easingFunctions[this.animationEasingFunction](this.easingTime);
33993 this.body.view.scale = this.sourceScale + (this.targetScale - this.sourceScale) * progress;
33994 this.body.view.translation = {
33995 x: this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress,
33996 y: this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress
33997 }; // cleanup
33998
33999 if (this.easingTime >= 1.0) {
34000 this.body.emitter.off("initRedraw", this.viewFunction);
34001 this.easingTime = 0;
34002
34003 if (this.lockedOnNodeId != undefined) {
34004 var _context5;
34005
34006 this.viewFunction = bind(_context5 = this._lockedRedraw).call(_context5, this);
34007 this.body.emitter.on("initRedraw", this.viewFunction);
34008 }
34009
34010 this.body.emitter.emit("animationFinished");
34011 }
34012 }
34013 /**
34014 *
34015 * @returns {number}
34016 */
34017
34018 }, {
34019 key: "getScale",
34020 value: function getScale() {
34021 return this.body.view.scale;
34022 }
34023 /**
34024 *
34025 * @returns {{x: number, y: number}}
34026 */
34027
34028 }, {
34029 key: "getViewPosition",
34030 value: function getViewPosition() {
34031 return this.canvas.DOMtoCanvas({
34032 x: 0.5 * this.canvas.frame.canvas.clientWidth,
34033 y: 0.5 * this.canvas.frame.canvas.clientHeight
34034 });
34035 }
34036 }]);
34037
34038 return View;
34039}();
34040
34041/**
34042 * Created by Alex on 11/6/2014.
34043 */
34044function keycharm(options) {
34045 var preventDefault = options && options.preventDefault || false;
34046 var container = options && options.container || window;
34047 var _exportFunctions = {};
34048 var _bound = {
34049 keydown: {},
34050 keyup: {}
34051 };
34052 var _keys = {};
34053 var i; // a - z
34054
34055 for (i = 97; i <= 122; i++) {
34056 _keys[String.fromCharCode(i)] = {
34057 code: 65 + (i - 97),
34058 shift: false
34059 };
34060 } // A - Z
34061
34062
34063 for (i = 65; i <= 90; i++) {
34064 _keys[String.fromCharCode(i)] = {
34065 code: i,
34066 shift: true
34067 };
34068 } // 0 - 9
34069
34070
34071 for (i = 0; i <= 9; i++) {
34072 _keys['' + i] = {
34073 code: 48 + i,
34074 shift: false
34075 };
34076 } // F1 - F12
34077
34078
34079 for (i = 1; i <= 12; i++) {
34080 _keys['F' + i] = {
34081 code: 111 + i,
34082 shift: false
34083 };
34084 } // num0 - num9
34085
34086
34087 for (i = 0; i <= 9; i++) {
34088 _keys['num' + i] = {
34089 code: 96 + i,
34090 shift: false
34091 };
34092 } // numpad misc
34093
34094
34095 _keys['num*'] = {
34096 code: 106,
34097 shift: false
34098 };
34099 _keys['num+'] = {
34100 code: 107,
34101 shift: false
34102 };
34103 _keys['num-'] = {
34104 code: 109,
34105 shift: false
34106 };
34107 _keys['num/'] = {
34108 code: 111,
34109 shift: false
34110 };
34111 _keys['num.'] = {
34112 code: 110,
34113 shift: false
34114 }; // arrows
34115
34116 _keys['left'] = {
34117 code: 37,
34118 shift: false
34119 };
34120 _keys['up'] = {
34121 code: 38,
34122 shift: false
34123 };
34124 _keys['right'] = {
34125 code: 39,
34126 shift: false
34127 };
34128 _keys['down'] = {
34129 code: 40,
34130 shift: false
34131 }; // extra keys
34132
34133 _keys['space'] = {
34134 code: 32,
34135 shift: false
34136 };
34137 _keys['enter'] = {
34138 code: 13,
34139 shift: false
34140 };
34141 _keys['shift'] = {
34142 code: 16,
34143 shift: undefined
34144 };
34145 _keys['esc'] = {
34146 code: 27,
34147 shift: false
34148 };
34149 _keys['backspace'] = {
34150 code: 8,
34151 shift: false
34152 };
34153 _keys['tab'] = {
34154 code: 9,
34155 shift: false
34156 };
34157 _keys['ctrl'] = {
34158 code: 17,
34159 shift: false
34160 };
34161 _keys['alt'] = {
34162 code: 18,
34163 shift: false
34164 };
34165 _keys['delete'] = {
34166 code: 46,
34167 shift: false
34168 };
34169 _keys['pageup'] = {
34170 code: 33,
34171 shift: false
34172 };
34173 _keys['pagedown'] = {
34174 code: 34,
34175 shift: false
34176 }; // symbols
34177
34178 _keys['='] = {
34179 code: 187,
34180 shift: false
34181 };
34182 _keys['-'] = {
34183 code: 189,
34184 shift: false
34185 };
34186 _keys[']'] = {
34187 code: 221,
34188 shift: false
34189 };
34190 _keys['['] = {
34191 code: 219,
34192 shift: false
34193 };
34194
34195 var down = function (event) {
34196 handleEvent(event, 'keydown');
34197 };
34198
34199 var up = function (event) {
34200 handleEvent(event, 'keyup');
34201 }; // handle the actualy bound key with the event
34202
34203
34204 var handleEvent = function (event, type) {
34205 if (_bound[type][event.keyCode] !== undefined) {
34206 var bound = _bound[type][event.keyCode];
34207
34208 for (var i = 0; i < bound.length; i++) {
34209 if (bound[i].shift === undefined) {
34210 bound[i].fn(event);
34211 } else if (bound[i].shift == true && event.shiftKey == true) {
34212 bound[i].fn(event);
34213 } else if (bound[i].shift == false && event.shiftKey == false) {
34214 bound[i].fn(event);
34215 }
34216 }
34217
34218 if (preventDefault == true) {
34219 event.preventDefault();
34220 }
34221 }
34222 }; // bind a key to a callback
34223
34224
34225 _exportFunctions.bind = function (key, callback, type) {
34226 if (type === undefined) {
34227 type = 'keydown';
34228 }
34229
34230 if (_keys[key] === undefined) {
34231 throw new Error("unsupported key: " + key);
34232 }
34233
34234 if (_bound[type][_keys[key].code] === undefined) {
34235 _bound[type][_keys[key].code] = [];
34236 }
34237
34238 _bound[type][_keys[key].code].push({
34239 fn: callback,
34240 shift: _keys[key].shift
34241 });
34242 }; // bind all keys to a call back (demo purposes)
34243
34244
34245 _exportFunctions.bindAll = function (callback, type) {
34246 if (type === undefined) {
34247 type = 'keydown';
34248 }
34249
34250 for (var key in _keys) {
34251 if (_keys.hasOwnProperty(key)) {
34252 _exportFunctions.bind(key, callback, type);
34253 }
34254 }
34255 }; // get the key label from an event
34256
34257
34258 _exportFunctions.getKey = function (event) {
34259 for (var key in _keys) {
34260 if (_keys.hasOwnProperty(key)) {
34261 if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) {
34262 return key;
34263 } else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) {
34264 return key;
34265 } else if (event.keyCode == _keys[key].code && key == 'shift') {
34266 return key;
34267 }
34268 }
34269 }
34270
34271 return "unknown key, currently not supported";
34272 }; // unbind either a specific callback from a key or all of them (by leaving callback undefined)
34273
34274
34275 _exportFunctions.unbind = function (key, callback, type) {
34276 if (type === undefined) {
34277 type = 'keydown';
34278 }
34279
34280 if (_keys[key] === undefined) {
34281 throw new Error("unsupported key: " + key);
34282 }
34283
34284 if (callback !== undefined) {
34285 var newBindings = [];
34286 var bound = _bound[type][_keys[key].code];
34287
34288 if (bound !== undefined) {
34289 for (var i = 0; i < bound.length; i++) {
34290 if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) {
34291 newBindings.push(_bound[type][_keys[key].code][i]);
34292 }
34293 }
34294 }
34295
34296 _bound[type][_keys[key].code] = newBindings;
34297 } else {
34298 _bound[type][_keys[key].code] = [];
34299 }
34300 }; // reset all bound variables.
34301
34302
34303 _exportFunctions.reset = function () {
34304 _bound = {
34305 keydown: {},
34306 keyup: {}
34307 };
34308 }; // unbind all listeners and reset all variables.
34309
34310
34311 _exportFunctions.destroy = function () {
34312 _bound = {
34313 keydown: {},
34314 keyup: {}
34315 };
34316 container.removeEventListener('keydown', down, true);
34317 container.removeEventListener('keyup', up, true);
34318 }; // create listeners.
34319
34320
34321 container.addEventListener('keydown', down, true);
34322 container.addEventListener('keyup', up, true); // return the public functions.
34323
34324 return _exportFunctions;
34325}
34326
34327var keycharm$1 = /*#__PURE__*/Object.freeze({
34328 __proto__: null,
34329 'default': keycharm
34330});
34331
34332/**
34333 * Navigation Handler
34334 */
34335
34336var NavigationHandler = /*#__PURE__*/function () {
34337 /**
34338 * @param {object} body
34339 * @param {Canvas} canvas
34340 */
34341 function NavigationHandler(body, canvas) {
34342 var _this = this;
34343
34344 _classCallCheck(this, NavigationHandler);
34345
34346 this.body = body;
34347 this.canvas = canvas;
34348 this.iconsCreated = false;
34349 this.navigationHammers = [];
34350 this.boundFunctions = {};
34351 this.touchTime = 0;
34352 this.activated = false;
34353 this.body.emitter.on("activate", function () {
34354 _this.activated = true;
34355
34356 _this.configureKeyboardBindings();
34357 });
34358 this.body.emitter.on("deactivate", function () {
34359 _this.activated = false;
34360
34361 _this.configureKeyboardBindings();
34362 });
34363 this.body.emitter.on("destroy", function () {
34364 if (_this.keycharm !== undefined) {
34365 _this.keycharm.destroy();
34366 }
34367 });
34368 this.options = {};
34369 }
34370 /**
34371 *
34372 * @param {object} options
34373 */
34374
34375
34376 _createClass(NavigationHandler, [{
34377 key: "setOptions",
34378 value: function setOptions(options) {
34379 if (options !== undefined) {
34380 this.options = options;
34381 this.create();
34382 }
34383 }
34384 /**
34385 * Creates or refreshes navigation and sets key bindings
34386 */
34387
34388 }, {
34389 key: "create",
34390 value: function create() {
34391 if (this.options.navigationButtons === true) {
34392 if (this.iconsCreated === false) {
34393 this.loadNavigationElements();
34394 }
34395 } else if (this.iconsCreated === true) {
34396 this.cleanNavigation();
34397 }
34398
34399 this.configureKeyboardBindings();
34400 }
34401 /**
34402 * Cleans up previous navigation items
34403 */
34404
34405 }, {
34406 key: "cleanNavigation",
34407 value: function cleanNavigation() {
34408 // clean hammer bindings
34409 if (this.navigationHammers.length != 0) {
34410 for (var i = 0; i < this.navigationHammers.length; i++) {
34411 this.navigationHammers[i].destroy();
34412 }
34413
34414 this.navigationHammers = [];
34415 } // clean up previous navigation items
34416
34417
34418 if (this.navigationDOM && this.navigationDOM["wrapper"] && this.navigationDOM["wrapper"].parentNode) {
34419 this.navigationDOM["wrapper"].parentNode.removeChild(this.navigationDOM["wrapper"]);
34420 }
34421
34422 this.iconsCreated = false;
34423 }
34424 /**
34425 * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation
34426 * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent
34427 * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false.
34428 * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas.
34429 *
34430 * @private
34431 */
34432
34433 }, {
34434 key: "loadNavigationElements",
34435 value: function loadNavigationElements() {
34436 var _this2 = this;
34437
34438 this.cleanNavigation();
34439 this.navigationDOM = {};
34440 var navigationDivs = ["up", "down", "left", "right", "zoomIn", "zoomOut", "zoomExtends"];
34441 var navigationDivActions = ["_moveUp", "_moveDown", "_moveLeft", "_moveRight", "_zoomIn", "_zoomOut", "_fit"];
34442 this.navigationDOM["wrapper"] = document.createElement("div");
34443 this.navigationDOM["wrapper"].className = "vis-navigation";
34444 this.canvas.frame.appendChild(this.navigationDOM["wrapper"]);
34445
34446 for (var i = 0; i < navigationDivs.length; i++) {
34447 this.navigationDOM[navigationDivs[i]] = document.createElement("div");
34448 this.navigationDOM[navigationDivs[i]].className = "vis-button vis-" + navigationDivs[i];
34449 this.navigationDOM["wrapper"].appendChild(this.navigationDOM[navigationDivs[i]]);
34450 var hammer = new Hammer$1(this.navigationDOM[navigationDivs[i]]);
34451
34452 if (navigationDivActions[i] === "_fit") {
34453 var _context;
34454
34455 onTouch(hammer, bind(_context = this._fit).call(_context, this));
34456 } else {
34457 var _context2;
34458
34459 onTouch(hammer, bind(_context2 = this.bindToRedraw).call(_context2, this, navigationDivActions[i]));
34460 }
34461
34462 this.navigationHammers.push(hammer);
34463 } // use a hammer for the release so we do not require the one used in the rest of the network
34464 // the one the rest uses can be overloaded by the manipulation system.
34465
34466
34467 var hammerFrame = new Hammer$1(this.canvas.frame);
34468 onRelease(hammerFrame, function () {
34469 _this2._stopMovement();
34470 });
34471 this.navigationHammers.push(hammerFrame);
34472 this.iconsCreated = true;
34473 }
34474 /**
34475 *
34476 * @param {string} action
34477 */
34478
34479 }, {
34480 key: "bindToRedraw",
34481 value: function bindToRedraw(action) {
34482 if (this.boundFunctions[action] === undefined) {
34483 var _context3;
34484
34485 this.boundFunctions[action] = bind(_context3 = this[action]).call(_context3, this);
34486 this.body.emitter.on("initRedraw", this.boundFunctions[action]);
34487 this.body.emitter.emit("_startRendering");
34488 }
34489 }
34490 /**
34491 *
34492 * @param {string} action
34493 */
34494
34495 }, {
34496 key: "unbindFromRedraw",
34497 value: function unbindFromRedraw(action) {
34498 if (this.boundFunctions[action] !== undefined) {
34499 this.body.emitter.off("initRedraw", this.boundFunctions[action]);
34500 this.body.emitter.emit("_stopRendering");
34501 delete this.boundFunctions[action];
34502 }
34503 }
34504 /**
34505 * this stops all movement induced by the navigation buttons
34506 *
34507 * @private
34508 */
34509
34510 }, {
34511 key: "_fit",
34512 value: function _fit() {
34513 if (new Date().valueOf() - this.touchTime > 700) {
34514 // TODO: fix ugly hack to avoid hammer's double fireing of event (because we use release?)
34515 this.body.emitter.emit("fit", {
34516 duration: 700
34517 });
34518 this.touchTime = new Date().valueOf();
34519 }
34520 }
34521 /**
34522 * this stops all movement induced by the navigation buttons
34523 *
34524 * @private
34525 */
34526
34527 }, {
34528 key: "_stopMovement",
34529 value: function _stopMovement() {
34530 for (var boundAction in this.boundFunctions) {
34531 if (Object.prototype.hasOwnProperty.call(this.boundFunctions, boundAction)) {
34532 this.body.emitter.off("initRedraw", this.boundFunctions[boundAction]);
34533 this.body.emitter.emit("_stopRendering");
34534 }
34535 }
34536
34537 this.boundFunctions = {};
34538 }
34539 /**
34540 *
34541 * @private
34542 */
34543
34544 }, {
34545 key: "_moveUp",
34546 value: function _moveUp() {
34547 this.body.view.translation.y += this.options.keyboard.speed.y;
34548 }
34549 /**
34550 *
34551 * @private
34552 */
34553
34554 }, {
34555 key: "_moveDown",
34556 value: function _moveDown() {
34557 this.body.view.translation.y -= this.options.keyboard.speed.y;
34558 }
34559 /**
34560 *
34561 * @private
34562 */
34563
34564 }, {
34565 key: "_moveLeft",
34566 value: function _moveLeft() {
34567 this.body.view.translation.x += this.options.keyboard.speed.x;
34568 }
34569 /**
34570 *
34571 * @private
34572 */
34573
34574 }, {
34575 key: "_moveRight",
34576 value: function _moveRight() {
34577 this.body.view.translation.x -= this.options.keyboard.speed.x;
34578 }
34579 /**
34580 *
34581 * @private
34582 */
34583
34584 }, {
34585 key: "_zoomIn",
34586 value: function _zoomIn() {
34587 var scaleOld = this.body.view.scale;
34588 var scale = this.body.view.scale * (1 + this.options.keyboard.speed.zoom);
34589 var translation = this.body.view.translation;
34590 var scaleFrac = scale / scaleOld;
34591 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
34592 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
34593 this.body.view.scale = scale;
34594 this.body.view.translation = {
34595 x: tx,
34596 y: ty
34597 };
34598 this.body.emitter.emit("zoom", {
34599 direction: "+",
34600 scale: this.body.view.scale,
34601 pointer: null
34602 });
34603 }
34604 /**
34605 *
34606 * @private
34607 */
34608
34609 }, {
34610 key: "_zoomOut",
34611 value: function _zoomOut() {
34612 var scaleOld = this.body.view.scale;
34613 var scale = this.body.view.scale / (1 + this.options.keyboard.speed.zoom);
34614 var translation = this.body.view.translation;
34615 var scaleFrac = scale / scaleOld;
34616 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
34617 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
34618 this.body.view.scale = scale;
34619 this.body.view.translation = {
34620 x: tx,
34621 y: ty
34622 };
34623 this.body.emitter.emit("zoom", {
34624 direction: "-",
34625 scale: this.body.view.scale,
34626 pointer: null
34627 });
34628 }
34629 /**
34630 * bind all keys using keycharm.
34631 */
34632
34633 }, {
34634 key: "configureKeyboardBindings",
34635 value: function configureKeyboardBindings() {
34636 var _this3 = this;
34637
34638 if (this.keycharm !== undefined) {
34639 this.keycharm.destroy();
34640 }
34641
34642 if (this.options.keyboard.enabled === true) {
34643 if (this.options.keyboard.bindToWindow === true) {
34644 this.keycharm = keycharm({
34645 container: window,
34646 preventDefault: true
34647 });
34648 } else {
34649 this.keycharm = keycharm({
34650 container: this.canvas.frame,
34651 preventDefault: true
34652 });
34653 }
34654
34655 this.keycharm.reset();
34656
34657 if (this.activated === true) {
34658 var _context4, _context5, _context6, _context7, _context8, _context9, _context10, _context11, _context12, _context13, _context14, _context15, _context16, _context17, _context18, _context19, _context20, _context21, _context22, _context23, _context24, _context25, _context26, _context27;
34659
34660 bind(_context4 = this.keycharm).call(_context4, "up", function () {
34661 _this3.bindToRedraw("_moveUp");
34662 }, "keydown");
34663
34664 bind(_context5 = this.keycharm).call(_context5, "down", function () {
34665 _this3.bindToRedraw("_moveDown");
34666 }, "keydown");
34667
34668 bind(_context6 = this.keycharm).call(_context6, "left", function () {
34669 _this3.bindToRedraw("_moveLeft");
34670 }, "keydown");
34671
34672 bind(_context7 = this.keycharm).call(_context7, "right", function () {
34673 _this3.bindToRedraw("_moveRight");
34674 }, "keydown");
34675
34676 bind(_context8 = this.keycharm).call(_context8, "=", function () {
34677 _this3.bindToRedraw("_zoomIn");
34678 }, "keydown");
34679
34680 bind(_context9 = this.keycharm).call(_context9, "num+", function () {
34681 _this3.bindToRedraw("_zoomIn");
34682 }, "keydown");
34683
34684 bind(_context10 = this.keycharm).call(_context10, "num-", function () {
34685 _this3.bindToRedraw("_zoomOut");
34686 }, "keydown");
34687
34688 bind(_context11 = this.keycharm).call(_context11, "-", function () {
34689 _this3.bindToRedraw("_zoomOut");
34690 }, "keydown");
34691
34692 bind(_context12 = this.keycharm).call(_context12, "[", function () {
34693 _this3.bindToRedraw("_zoomOut");
34694 }, "keydown");
34695
34696 bind(_context13 = this.keycharm).call(_context13, "]", function () {
34697 _this3.bindToRedraw("_zoomIn");
34698 }, "keydown");
34699
34700 bind(_context14 = this.keycharm).call(_context14, "pageup", function () {
34701 _this3.bindToRedraw("_zoomIn");
34702 }, "keydown");
34703
34704 bind(_context15 = this.keycharm).call(_context15, "pagedown", function () {
34705 _this3.bindToRedraw("_zoomOut");
34706 }, "keydown");
34707
34708 bind(_context16 = this.keycharm).call(_context16, "up", function () {
34709 _this3.unbindFromRedraw("_moveUp");
34710 }, "keyup");
34711
34712 bind(_context17 = this.keycharm).call(_context17, "down", function () {
34713 _this3.unbindFromRedraw("_moveDown");
34714 }, "keyup");
34715
34716 bind(_context18 = this.keycharm).call(_context18, "left", function () {
34717 _this3.unbindFromRedraw("_moveLeft");
34718 }, "keyup");
34719
34720 bind(_context19 = this.keycharm).call(_context19, "right", function () {
34721 _this3.unbindFromRedraw("_moveRight");
34722 }, "keyup");
34723
34724 bind(_context20 = this.keycharm).call(_context20, "=", function () {
34725 _this3.unbindFromRedraw("_zoomIn");
34726 }, "keyup");
34727
34728 bind(_context21 = this.keycharm).call(_context21, "num+", function () {
34729 _this3.unbindFromRedraw("_zoomIn");
34730 }, "keyup");
34731
34732 bind(_context22 = this.keycharm).call(_context22, "num-", function () {
34733 _this3.unbindFromRedraw("_zoomOut");
34734 }, "keyup");
34735
34736 bind(_context23 = this.keycharm).call(_context23, "-", function () {
34737 _this3.unbindFromRedraw("_zoomOut");
34738 }, "keyup");
34739
34740 bind(_context24 = this.keycharm).call(_context24, "[", function () {
34741 _this3.unbindFromRedraw("_zoomOut");
34742 }, "keyup");
34743
34744 bind(_context25 = this.keycharm).call(_context25, "]", function () {
34745 _this3.unbindFromRedraw("_zoomIn");
34746 }, "keyup");
34747
34748 bind(_context26 = this.keycharm).call(_context26, "pageup", function () {
34749 _this3.unbindFromRedraw("_zoomIn");
34750 }, "keyup");
34751
34752 bind(_context27 = this.keycharm).call(_context27, "pagedown", function () {
34753 _this3.unbindFromRedraw("_zoomOut");
34754 }, "keyup");
34755 }
34756 }
34757 }
34758 }]);
34759
34760 return NavigationHandler;
34761}();
34762
34763function _createForOfIteratorHelper$4(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (isArray(o) || (it = _unsupportedIterableToArray$4(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
34764
34765function _unsupportedIterableToArray$4(o, minLen) { var _context15; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$4(o, minLen); var n = slice$1(_context15 = Object.prototype.toString.call(o)).call(_context15, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from_1$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$4(o, minLen); }
34766
34767function _arrayLikeToArray$4(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
34768/**
34769 * Handler for interactions
34770 */
34771
34772var InteractionHandler = /*#__PURE__*/function () {
34773 /**
34774 * @param {object} body
34775 * @param {Canvas} canvas
34776 * @param {SelectionHandler} selectionHandler
34777 */
34778 function InteractionHandler(body, canvas, selectionHandler) {
34779 var _context, _context2, _context3, _context4, _context5, _context6, _context7, _context8, _context9, _context10, _context11, _context12, _context13;
34780
34781 _classCallCheck(this, InteractionHandler);
34782
34783 this.body = body;
34784 this.canvas = canvas;
34785 this.selectionHandler = selectionHandler;
34786 this.navigationHandler = new NavigationHandler(body, canvas); // bind the events from hammer to functions in this object
34787
34788 this.body.eventListeners.onTap = bind(_context = this.onTap).call(_context, this);
34789 this.body.eventListeners.onTouch = bind(_context2 = this.onTouch).call(_context2, this);
34790 this.body.eventListeners.onDoubleTap = bind(_context3 = this.onDoubleTap).call(_context3, this);
34791 this.body.eventListeners.onHold = bind(_context4 = this.onHold).call(_context4, this);
34792 this.body.eventListeners.onDragStart = bind(_context5 = this.onDragStart).call(_context5, this);
34793 this.body.eventListeners.onDrag = bind(_context6 = this.onDrag).call(_context6, this);
34794 this.body.eventListeners.onDragEnd = bind(_context7 = this.onDragEnd).call(_context7, this);
34795 this.body.eventListeners.onMouseWheel = bind(_context8 = this.onMouseWheel).call(_context8, this);
34796 this.body.eventListeners.onPinch = bind(_context9 = this.onPinch).call(_context9, this);
34797 this.body.eventListeners.onMouseMove = bind(_context10 = this.onMouseMove).call(_context10, this);
34798 this.body.eventListeners.onRelease = bind(_context11 = this.onRelease).call(_context11, this);
34799 this.body.eventListeners.onContext = bind(_context12 = this.onContext).call(_context12, this);
34800 this.touchTime = 0;
34801 this.drag = {};
34802 this.pinch = {};
34803 this.popup = undefined;
34804 this.popupObj = undefined;
34805 this.popupTimer = undefined;
34806 this.body.functions.getPointer = bind(_context13 = this.getPointer).call(_context13, this);
34807 this.options = {};
34808 this.defaultOptions = {
34809 dragNodes: true,
34810 dragView: true,
34811 hover: false,
34812 keyboard: {
34813 enabled: false,
34814 speed: {
34815 x: 10,
34816 y: 10,
34817 zoom: 0.02
34818 },
34819 bindToWindow: true,
34820 autoFocus: true
34821 },
34822 navigationButtons: false,
34823 tooltipDelay: 300,
34824 zoomView: true,
34825 zoomSpeed: 1
34826 };
34827
34828 assign$2(this.options, this.defaultOptions);
34829
34830 this.bindEventListeners();
34831 }
34832 /**
34833 * Binds event listeners
34834 */
34835
34836
34837 _createClass(InteractionHandler, [{
34838 key: "bindEventListeners",
34839 value: function bindEventListeners() {
34840 var _this = this;
34841
34842 this.body.emitter.on("destroy", function () {
34843 clearTimeout(_this.popupTimer);
34844 delete _this.body.functions.getPointer;
34845 });
34846 }
34847 /**
34848 *
34849 * @param {object} options
34850 */
34851
34852 }, {
34853 key: "setOptions",
34854 value: function setOptions(options) {
34855 if (options !== undefined) {
34856 // extend all but the values in fields
34857 var fields = ["hideEdgesOnDrag", "hideEdgesOnZoom", "hideNodesOnDrag", "keyboard", "multiselect", "selectable", "selectConnectedEdges"];
34858 selectiveNotDeepExtend(fields, this.options, options); // merge the keyboard options in.
34859
34860 mergeOptions(this.options, options, "keyboard");
34861
34862 if (options.tooltip) {
34863 assign$2(this.options.tooltip, options.tooltip);
34864
34865 if (options.tooltip.color) {
34866 this.options.tooltip.color = parseColor(options.tooltip.color);
34867 }
34868 }
34869 }
34870
34871 this.navigationHandler.setOptions(this.options);
34872 }
34873 /**
34874 * Get the pointer location from a touch location
34875 *
34876 * @param {{x: number, y: number}} touch
34877 * @returns {{x: number, y: number}} pointer
34878 * @private
34879 */
34880
34881 }, {
34882 key: "getPointer",
34883 value: function getPointer(touch) {
34884 return {
34885 x: touch.x - getAbsoluteLeft(this.canvas.frame.canvas),
34886 y: touch.y - getAbsoluteTop(this.canvas.frame.canvas)
34887 };
34888 }
34889 /**
34890 * On start of a touch gesture, store the pointer
34891 *
34892 * @param {Event} event The event
34893 * @private
34894 */
34895
34896 }, {
34897 key: "onTouch",
34898 value: function onTouch(event) {
34899 if (new Date().valueOf() - this.touchTime > 50) {
34900 this.drag.pointer = this.getPointer(event.center);
34901 this.drag.pinched = false;
34902 this.pinch.scale = this.body.view.scale; // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
34903
34904 this.touchTime = new Date().valueOf();
34905 }
34906 }
34907 /**
34908 * handle tap/click event: select/unselect a node
34909 *
34910 * @param {Event} event
34911 * @private
34912 */
34913
34914 }, {
34915 key: "onTap",
34916 value: function onTap(event) {
34917 var pointer = this.getPointer(event.center);
34918 var multiselect = this.selectionHandler.options.multiselect && (event.changedPointers[0].ctrlKey || event.changedPointers[0].metaKey);
34919 this.checkSelectionChanges(pointer, multiselect);
34920 this.selectionHandler.commitAndEmit(pointer, event);
34921 this.selectionHandler.generateClickEvent("click", event, pointer);
34922 }
34923 /**
34924 * handle doubletap event
34925 *
34926 * @param {Event} event
34927 * @private
34928 */
34929
34930 }, {
34931 key: "onDoubleTap",
34932 value: function onDoubleTap(event) {
34933 var pointer = this.getPointer(event.center);
34934 this.selectionHandler.generateClickEvent("doubleClick", event, pointer);
34935 }
34936 /**
34937 * handle long tap event: multi select nodes
34938 *
34939 * @param {Event} event
34940 * @private
34941 */
34942
34943 }, {
34944 key: "onHold",
34945 value: function onHold(event) {
34946 var pointer = this.getPointer(event.center);
34947 var multiselect = this.selectionHandler.options.multiselect;
34948 this.checkSelectionChanges(pointer, multiselect);
34949 this.selectionHandler.commitAndEmit(pointer, event);
34950 this.selectionHandler.generateClickEvent("click", event, pointer);
34951 this.selectionHandler.generateClickEvent("hold", event, pointer);
34952 }
34953 /**
34954 * handle the release of the screen
34955 *
34956 * @param {Event} event
34957 * @private
34958 */
34959
34960 }, {
34961 key: "onRelease",
34962 value: function onRelease(event) {
34963 if (new Date().valueOf() - this.touchTime > 10) {
34964 var pointer = this.getPointer(event.center);
34965 this.selectionHandler.generateClickEvent("release", event, pointer); // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
34966
34967 this.touchTime = new Date().valueOf();
34968 }
34969 }
34970 /**
34971 *
34972 * @param {Event} event
34973 */
34974
34975 }, {
34976 key: "onContext",
34977 value: function onContext(event) {
34978 var pointer = this.getPointer({
34979 x: event.clientX,
34980 y: event.clientY
34981 });
34982 this.selectionHandler.generateClickEvent("oncontext", event, pointer);
34983 }
34984 /**
34985 * Select and deselect nodes depending current selection change.
34986 *
34987 * @param {{x: number, y: number}} pointer
34988 * @param {boolean} [add=false]
34989 */
34990
34991 }, {
34992 key: "checkSelectionChanges",
34993 value: function checkSelectionChanges(pointer) {
34994 var add = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
34995
34996 if (add === true) {
34997 this.selectionHandler.selectAdditionalOnPoint(pointer);
34998 } else {
34999 this.selectionHandler.selectOnPoint(pointer);
35000 }
35001 }
35002 /**
35003 * Remove all node and edge id's from the first set that are present in the second one.
35004 *
35005 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} firstSet
35006 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} secondSet
35007 * @returns {{nodes: Array.<Node>, edges: Array.<vis.Edge>}}
35008 * @private
35009 */
35010
35011 }, {
35012 key: "_determineDifference",
35013 value: function _determineDifference(firstSet, secondSet) {
35014 var arrayDiff = function arrayDiff(firstArr, secondArr) {
35015 var result = [];
35016
35017 for (var i = 0; i < firstArr.length; i++) {
35018 var value = firstArr[i];
35019
35020 if (indexOf(secondArr).call(secondArr, value) === -1) {
35021 result.push(value);
35022 }
35023 }
35024
35025 return result;
35026 };
35027
35028 return {
35029 nodes: arrayDiff(firstSet.nodes, secondSet.nodes),
35030 edges: arrayDiff(firstSet.edges, secondSet.edges)
35031 };
35032 }
35033 /**
35034 * This function is called by onDragStart.
35035 * It is separated out because we can then overload it for the datamanipulation system.
35036 *
35037 * @param {Event} event
35038 * @private
35039 */
35040
35041 }, {
35042 key: "onDragStart",
35043 value: function onDragStart(event) {
35044 // if already dragging, do not start
35045 // this can happen on touch screens with multiple fingers
35046 if (this.drag.dragging) {
35047 return;
35048 } //in case the touch event was triggered on an external div, do the initial touch now.
35049
35050
35051 if (this.drag.pointer === undefined) {
35052 this.onTouch(event);
35053 } // note: drag.pointer is set in onTouch to get the initial touch location
35054
35055
35056 var node = this.selectionHandler.getNodeAt(this.drag.pointer);
35057 this.drag.dragging = true;
35058 this.drag.selection = [];
35059 this.drag.translation = assign$2({}, this.body.view.translation); // copy the object
35060
35061 this.drag.nodeId = undefined;
35062
35063 if (event.srcEvent.shiftKey) {
35064 this.body.selectionBox.show = true;
35065 var pointer = this.getPointer(event.center);
35066 this.body.selectionBox.position.start = {
35067 x: this.canvas._XconvertDOMtoCanvas(pointer.x),
35068 y: this.canvas._YconvertDOMtoCanvas(pointer.y)
35069 };
35070 this.body.selectionBox.position.end = {
35071 x: this.canvas._XconvertDOMtoCanvas(pointer.x),
35072 y: this.canvas._YconvertDOMtoCanvas(pointer.y)
35073 };
35074 }
35075
35076 if (node !== undefined && this.options.dragNodes === true) {
35077 this.drag.nodeId = node.id; // select the clicked node if not yet selected
35078
35079 if (node.isSelected() === false) {
35080 this.selectionHandler.unselectAll();
35081 this.selectionHandler.selectObject(node);
35082 } // after select to contain the node
35083
35084
35085 this.selectionHandler.generateClickEvent("dragStart", event, this.drag.pointer); // create an array with the selected nodes and their original location and status
35086
35087 var _iterator = _createForOfIteratorHelper$4(this.selectionHandler.getSelectedNodes()),
35088 _step;
35089
35090 try {
35091 for (_iterator.s(); !(_step = _iterator.n()).done;) {
35092 var _node = _step.value;
35093 var s = {
35094 id: _node.id,
35095 node: _node,
35096 // store original x, y, xFixed and yFixed, make the node temporarily Fixed
35097 x: _node.x,
35098 y: _node.y,
35099 xFixed: _node.options.fixed.x,
35100 yFixed: _node.options.fixed.y
35101 };
35102 _node.options.fixed.x = true;
35103 _node.options.fixed.y = true;
35104 this.drag.selection.push(s);
35105 }
35106 } catch (err) {
35107 _iterator.e(err);
35108 } finally {
35109 _iterator.f();
35110 }
35111 } else {
35112 // fallback if no node is selected and thus the view is dragged.
35113 this.selectionHandler.generateClickEvent("dragStart", event, this.drag.pointer, undefined, true);
35114 }
35115 }
35116 /**
35117 * handle drag event
35118 *
35119 * @param {Event} event
35120 * @private
35121 */
35122
35123 }, {
35124 key: "onDrag",
35125 value: function onDrag(event) {
35126 var _this2 = this;
35127
35128 if (this.drag.pinched === true) {
35129 return;
35130 } // remove the focus on node if it is focussed on by the focusOnNode
35131
35132
35133 this.body.emitter.emit("unlockNode");
35134 var pointer = this.getPointer(event.center);
35135 var selection = this.drag.selection;
35136
35137 if (selection && selection.length && this.options.dragNodes === true) {
35138 this.selectionHandler.generateClickEvent("dragging", event, pointer); // calculate delta's and new location
35139
35140 var deltaX = pointer.x - this.drag.pointer.x;
35141 var deltaY = pointer.y - this.drag.pointer.y; // update position of all selected nodes
35142
35143 forEach$2(selection).call(selection, function (selection) {
35144 var node = selection.node; // only move the node if it was not fixed initially
35145
35146 if (selection.xFixed === false) {
35147 node.x = _this2.canvas._XconvertDOMtoCanvas(_this2.canvas._XconvertCanvasToDOM(selection.x) + deltaX);
35148 } // only move the node if it was not fixed initially
35149
35150
35151 if (selection.yFixed === false) {
35152 node.y = _this2.canvas._YconvertDOMtoCanvas(_this2.canvas._YconvertCanvasToDOM(selection.y) + deltaY);
35153 }
35154 }); // start the simulation of the physics
35155
35156
35157 this.body.emitter.emit("startSimulation");
35158 } else {
35159 // create selection box
35160 if (event.srcEvent.shiftKey) {
35161 this.selectionHandler.generateClickEvent("dragging", event, pointer, undefined, true); // if the drag was not started properly because the click started outside the network div, start it now.
35162
35163 if (this.drag.pointer === undefined) {
35164 this.onDragStart(event);
35165 return;
35166 }
35167
35168 this.body.selectionBox.position.end = {
35169 x: this.canvas._XconvertDOMtoCanvas(pointer.x),
35170 y: this.canvas._YconvertDOMtoCanvas(pointer.y)
35171 };
35172 this.body.emitter.emit("_requestRedraw");
35173 } // move the network
35174
35175
35176 if (this.options.dragView === true && !event.srcEvent.shiftKey) {
35177 this.selectionHandler.generateClickEvent("dragging", event, pointer, undefined, true); // if the drag was not started properly because the click started outside the network div, start it now.
35178
35179 if (this.drag.pointer === undefined) {
35180 this.onDragStart(event);
35181 return;
35182 }
35183
35184 var diffX = pointer.x - this.drag.pointer.x;
35185 var diffY = pointer.y - this.drag.pointer.y;
35186 this.body.view.translation = {
35187 x: this.drag.translation.x + diffX,
35188 y: this.drag.translation.y + diffY
35189 };
35190 this.body.emitter.emit("_requestRedraw");
35191 }
35192 }
35193 }
35194 /**
35195 * handle drag start event
35196 *
35197 * @param {Event} event
35198 * @private
35199 */
35200
35201 }, {
35202 key: "onDragEnd",
35203 value: function onDragEnd(event) {
35204 var _this3 = this;
35205
35206 this.drag.dragging = false;
35207
35208 if (this.body.selectionBox.show) {
35209 var _context14;
35210
35211 this.body.selectionBox.show = false;
35212 var selectionBoxPosition = this.body.selectionBox.position;
35213 var selectionBoxPositionMinMax = {
35214 minX: Math.min(selectionBoxPosition.start.x, selectionBoxPosition.end.x),
35215 minY: Math.min(selectionBoxPosition.start.y, selectionBoxPosition.end.y),
35216 maxX: Math.max(selectionBoxPosition.start.x, selectionBoxPosition.end.x),
35217 maxY: Math.max(selectionBoxPosition.start.y, selectionBoxPosition.end.y)
35218 };
35219
35220 var toBeSelectedNodes = filter(_context14 = this.body.nodeIndices).call(_context14, function (nodeId) {
35221 var node = _this3.body.nodes[nodeId];
35222 return node.x >= selectionBoxPositionMinMax.minX && node.x <= selectionBoxPositionMinMax.maxX && node.y >= selectionBoxPositionMinMax.minY && node.y <= selectionBoxPositionMinMax.maxY;
35223 });
35224
35225 forEach$2(toBeSelectedNodes).call(toBeSelectedNodes, function (nodeId) {
35226 return _this3.selectionHandler.selectObject(_this3.body.nodes[nodeId]);
35227 });
35228
35229 var pointer = this.getPointer(event.center);
35230 this.selectionHandler.commitAndEmit(pointer, event);
35231 this.selectionHandler.generateClickEvent("dragEnd", event, this.getPointer(event.center), undefined, true);
35232 this.body.emitter.emit("_requestRedraw");
35233 } else {
35234 var selection = this.drag.selection;
35235
35236 if (selection && selection.length) {
35237 forEach$2(selection).call(selection, function (s) {
35238 // restore original xFixed and yFixed
35239 s.node.options.fixed.x = s.xFixed;
35240 s.node.options.fixed.y = s.yFixed;
35241 });
35242
35243 this.selectionHandler.generateClickEvent("dragEnd", event, this.getPointer(event.center));
35244 this.body.emitter.emit("startSimulation");
35245 } else {
35246 this.selectionHandler.generateClickEvent("dragEnd", event, this.getPointer(event.center), undefined, true);
35247 this.body.emitter.emit("_requestRedraw");
35248 }
35249 }
35250 }
35251 /**
35252 * Handle pinch event
35253 *
35254 * @param {Event} event The event
35255 * @private
35256 */
35257
35258 }, {
35259 key: "onPinch",
35260 value: function onPinch(event) {
35261 var pointer = this.getPointer(event.center);
35262 this.drag.pinched = true;
35263
35264 if (this.pinch["scale"] === undefined) {
35265 this.pinch.scale = 1;
35266 } // TODO: enabled moving while pinching?
35267
35268
35269 var scale = this.pinch.scale * event.scale;
35270 this.zoom(scale, pointer);
35271 }
35272 /**
35273 * Zoom the network in or out
35274 *
35275 * @param {number} scale a number around 1, and between 0.01 and 10
35276 * @param {{x: number, y: number}} pointer Position on screen
35277 * @private
35278 */
35279
35280 }, {
35281 key: "zoom",
35282 value: function zoom(scale, pointer) {
35283 if (this.options.zoomView === true) {
35284 var scaleOld = this.body.view.scale;
35285
35286 if (scale < 0.00001) {
35287 scale = 0.00001;
35288 }
35289
35290 if (scale > 10) {
35291 scale = 10;
35292 }
35293
35294 var preScaleDragPointer = undefined;
35295
35296 if (this.drag !== undefined) {
35297 if (this.drag.dragging === true) {
35298 preScaleDragPointer = this.canvas.DOMtoCanvas(this.drag.pointer);
35299 }
35300 } // + this.canvas.frame.canvas.clientHeight / 2
35301
35302
35303 var translation = this.body.view.translation;
35304 var scaleFrac = scale / scaleOld;
35305 var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
35306 var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
35307 this.body.view.scale = scale;
35308 this.body.view.translation = {
35309 x: tx,
35310 y: ty
35311 };
35312
35313 if (preScaleDragPointer != undefined) {
35314 var postScaleDragPointer = this.canvas.canvasToDOM(preScaleDragPointer);
35315 this.drag.pointer.x = postScaleDragPointer.x;
35316 this.drag.pointer.y = postScaleDragPointer.y;
35317 }
35318
35319 this.body.emitter.emit("_requestRedraw");
35320
35321 if (scaleOld < scale) {
35322 this.body.emitter.emit("zoom", {
35323 direction: "+",
35324 scale: this.body.view.scale,
35325 pointer: pointer
35326 });
35327 } else {
35328 this.body.emitter.emit("zoom", {
35329 direction: "-",
35330 scale: this.body.view.scale,
35331 pointer: pointer
35332 });
35333 }
35334 }
35335 }
35336 /**
35337 * Event handler for mouse wheel event, used to zoom the timeline
35338 * See http://adomas.org/javascript-mouse-wheel/
35339 * https://github.com/EightMedia/hammer.js/issues/256
35340 *
35341 * @param {MouseEvent} event
35342 * @private
35343 */
35344
35345 }, {
35346 key: "onMouseWheel",
35347 value: function onMouseWheel(event) {
35348 if (this.options.zoomView === true) {
35349 // If delta is nonzero, handle it.
35350 // Basically, delta is now positive if wheel was scrolled up,
35351 // and negative, if wheel was scrolled down.
35352 if (event.deltaY !== 0) {
35353 // calculate the new scale
35354 var scale = this.body.view.scale;
35355 scale *= 1 + (event.deltaY < 0 ? 1 : -1) * (this.options.zoomSpeed * 0.1); // calculate the pointer location
35356
35357 var pointer = this.getPointer({
35358 x: event.clientX,
35359 y: event.clientY
35360 }); // apply the new scale
35361
35362 this.zoom(scale, pointer);
35363 } // Prevent default actions caused by mouse wheel.
35364
35365
35366 event.preventDefault();
35367 }
35368 }
35369 /**
35370 * Mouse move handler for checking whether the title moves over a node with a title.
35371 *
35372 * @param {Event} event
35373 * @private
35374 */
35375
35376 }, {
35377 key: "onMouseMove",
35378 value: function onMouseMove(event) {
35379 var _this4 = this;
35380
35381 var pointer = this.getPointer({
35382 x: event.clientX,
35383 y: event.clientY
35384 });
35385 var popupVisible = false; // check if the previously selected node is still selected
35386
35387 if (this.popup !== undefined) {
35388 if (this.popup.hidden === false) {
35389 this._checkHidePopup(pointer);
35390 } // if the popup was not hidden above
35391
35392
35393 if (this.popup.hidden === false) {
35394 popupVisible = true;
35395 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
35396 this.popup.show();
35397 }
35398 } // if we bind the keyboard to the div, we have to highlight it to use it. This highlights it on mouse over.
35399
35400
35401 if (this.options.keyboard.autoFocus && this.options.keyboard.bindToWindow === false && this.options.keyboard.enabled === true) {
35402 this.canvas.frame.focus();
35403 } // start a timeout that will check if the mouse is positioned above an element
35404
35405
35406 if (popupVisible === false) {
35407 if (this.popupTimer !== undefined) {
35408 clearInterval(this.popupTimer); // stop any running calculationTimer
35409
35410 this.popupTimer = undefined;
35411 }
35412
35413 if (!this.drag.dragging) {
35414 this.popupTimer = setTimeout$1(function () {
35415 return _this4._checkShowPopup(pointer);
35416 }, this.options.tooltipDelay);
35417 }
35418 } // adding hover highlights
35419
35420
35421 if (this.options.hover === true) {
35422 this.selectionHandler.hoverObject(event, pointer);
35423 }
35424 }
35425 /**
35426 * Check if there is an element on the given position in the network
35427 * (a node or edge). If so, and if this element has a title,
35428 * show a popup window with its title.
35429 *
35430 * @param {{x:number, y:number}} pointer
35431 * @private
35432 */
35433
35434 }, {
35435 key: "_checkShowPopup",
35436 value: function _checkShowPopup(pointer) {
35437 var x = this.canvas._XconvertDOMtoCanvas(pointer.x);
35438
35439 var y = this.canvas._YconvertDOMtoCanvas(pointer.y);
35440
35441 var pointerObj = {
35442 left: x,
35443 top: y,
35444 right: x,
35445 bottom: y
35446 };
35447 var previousPopupObjId = this.popupObj === undefined ? undefined : this.popupObj.id;
35448 var nodeUnderCursor = false;
35449 var popupType = "node"; // check if a node is under the cursor.
35450
35451 if (this.popupObj === undefined) {
35452 // search the nodes for overlap, select the top one in case of multiple nodes
35453 var nodeIndices = this.body.nodeIndices;
35454 var nodes = this.body.nodes;
35455 var node;
35456 var overlappingNodes = [];
35457
35458 for (var i = 0; i < nodeIndices.length; i++) {
35459 node = nodes[nodeIndices[i]];
35460
35461 if (node.isOverlappingWith(pointerObj) === true) {
35462 nodeUnderCursor = true;
35463
35464 if (node.getTitle() !== undefined) {
35465 overlappingNodes.push(nodeIndices[i]);
35466 }
35467 }
35468 }
35469
35470 if (overlappingNodes.length > 0) {
35471 // if there are overlapping nodes, select the last one, this is the one which is drawn on top of the others
35472 this.popupObj = nodes[overlappingNodes[overlappingNodes.length - 1]]; // if you hover over a node, the title of the edge is not supposed to be shown.
35473
35474 nodeUnderCursor = true;
35475 }
35476 }
35477
35478 if (this.popupObj === undefined && nodeUnderCursor === false) {
35479 // search the edges for overlap
35480 var edgeIndices = this.body.edgeIndices;
35481 var edges = this.body.edges;
35482 var edge;
35483 var overlappingEdges = [];
35484
35485 for (var _i = 0; _i < edgeIndices.length; _i++) {
35486 edge = edges[edgeIndices[_i]];
35487
35488 if (edge.isOverlappingWith(pointerObj) === true) {
35489 if (edge.connected === true && edge.getTitle() !== undefined) {
35490 overlappingEdges.push(edgeIndices[_i]);
35491 }
35492 }
35493 }
35494
35495 if (overlappingEdges.length > 0) {
35496 this.popupObj = edges[overlappingEdges[overlappingEdges.length - 1]];
35497 popupType = "edge";
35498 }
35499 }
35500
35501 if (this.popupObj !== undefined) {
35502 // show popup message window
35503 if (this.popupObj.id !== previousPopupObjId) {
35504 if (this.popup === undefined) {
35505 this.popup = new Popup$1(this.canvas.frame);
35506 }
35507
35508 this.popup.popupTargetType = popupType;
35509 this.popup.popupTargetId = this.popupObj.id; // adjust a small offset such that the mouse cursor is located in the
35510 // bottom left location of the popup, and you can easily move over the
35511 // popup area
35512
35513 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
35514 this.popup.setText(this.popupObj.getTitle());
35515 this.popup.show();
35516 this.body.emitter.emit("showPopup", this.popupObj.id);
35517 }
35518 } else {
35519 if (this.popup !== undefined) {
35520 this.popup.hide();
35521 this.body.emitter.emit("hidePopup");
35522 }
35523 }
35524 }
35525 /**
35526 * Check if the popup must be hidden, which is the case when the mouse is no
35527 * longer hovering on the object
35528 *
35529 * @param {{x:number, y:number}} pointer
35530 * @private
35531 */
35532
35533 }, {
35534 key: "_checkHidePopup",
35535 value: function _checkHidePopup(pointer) {
35536 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
35537
35538 var stillOnObj = false;
35539
35540 if (this.popup.popupTargetType === "node") {
35541 if (this.body.nodes[this.popup.popupTargetId] !== undefined) {
35542 stillOnObj = this.body.nodes[this.popup.popupTargetId].isOverlappingWith(pointerObj); // if the mouse is still one the node, we have to check if it is not also on one that is drawn on top of it.
35543 // we initially only check stillOnObj because this is much faster.
35544
35545 if (stillOnObj === true) {
35546 var overNode = this.selectionHandler.getNodeAt(pointer);
35547 stillOnObj = overNode === undefined ? false : overNode.id === this.popup.popupTargetId;
35548 }
35549 }
35550 } else {
35551 if (this.selectionHandler.getNodeAt(pointer) === undefined) {
35552 if (this.body.edges[this.popup.popupTargetId] !== undefined) {
35553 stillOnObj = this.body.edges[this.popup.popupTargetId].isOverlappingWith(pointerObj);
35554 }
35555 }
35556 }
35557
35558 if (stillOnObj === false) {
35559 this.popupObj = undefined;
35560 this.popup.hide();
35561 this.body.emitter.emit("hidePopup");
35562 }
35563 }
35564 }]);
35565
35566 return InteractionHandler;
35567}();
35568
35569var getWeakData = internalMetadata.getWeakData;
35570var setInternalState = internalState.set;
35571var internalStateGetterFor = internalState.getterFor;
35572var find = arrayIteration.find;
35573var findIndex = arrayIteration.findIndex;
35574var id = 0; // fallback for uncaught frozen keys
35575
35576var uncaughtFrozenStore = function (store) {
35577 return store.frozen || (store.frozen = new UncaughtFrozenStore());
35578};
35579
35580var UncaughtFrozenStore = function () {
35581 this.entries = [];
35582};
35583
35584var findUncaughtFrozen = function (store, key) {
35585 return find(store.entries, function (it) {
35586 return it[0] === key;
35587 });
35588};
35589
35590UncaughtFrozenStore.prototype = {
35591 get: function (key) {
35592 var entry = findUncaughtFrozen(this, key);
35593 if (entry) return entry[1];
35594 },
35595 has: function (key) {
35596 return !!findUncaughtFrozen(this, key);
35597 },
35598 set: function (key, value) {
35599 var entry = findUncaughtFrozen(this, key);
35600 if (entry) entry[1] = value;else this.entries.push([key, value]);
35601 },
35602 'delete': function (key) {
35603 var index = findIndex(this.entries, function (it) {
35604 return it[0] === key;
35605 });
35606 if (~index) this.entries.splice(index, 1);
35607 return !!~index;
35608 }
35609};
35610var collectionWeak = {
35611 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
35612 var C = wrapper(function (that, iterable) {
35613 anInstance(that, C, CONSTRUCTOR_NAME);
35614 setInternalState(that, {
35615 type: CONSTRUCTOR_NAME,
35616 id: id++,
35617 frozen: undefined
35618 });
35619 if (iterable != undefined) iterate(iterable, that[ADDER], {
35620 that: that,
35621 AS_ENTRIES: IS_MAP
35622 });
35623 });
35624 var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
35625
35626 var define = function (that, key, value) {
35627 var state = getInternalState(that);
35628 var data = getWeakData(anObject(key), true);
35629 if (data === true) uncaughtFrozenStore(state).set(key, value);else data[state.id] = value;
35630 return that;
35631 };
35632
35633 redefineAll(C.prototype, {
35634 // `{ WeakMap, WeakSet }.prototype.delete(key)` methods
35635 // https://tc39.es/ecma262/#sec-weakmap.prototype.delete
35636 // https://tc39.es/ecma262/#sec-weakset.prototype.delete
35637 'delete': function (key) {
35638 var state = getInternalState(this);
35639 if (!isObject$1(key)) return false;
35640 var data = getWeakData(key);
35641 if (data === true) return uncaughtFrozenStore(state)['delete'](key);
35642 return data && has$1(data, state.id) && delete data[state.id];
35643 },
35644 // `{ WeakMap, WeakSet }.prototype.has(key)` methods
35645 // https://tc39.es/ecma262/#sec-weakmap.prototype.has
35646 // https://tc39.es/ecma262/#sec-weakset.prototype.has
35647 has: function has(key) {
35648 var state = getInternalState(this);
35649 if (!isObject$1(key)) return false;
35650 var data = getWeakData(key);
35651 if (data === true) return uncaughtFrozenStore(state).has(key);
35652 return data && has$1(data, state.id);
35653 }
35654 });
35655 redefineAll(C.prototype, IS_MAP ? {
35656 // `WeakMap.prototype.get(key)` method
35657 // https://tc39.es/ecma262/#sec-weakmap.prototype.get
35658 get: function get(key) {
35659 var state = getInternalState(this);
35660
35661 if (isObject$1(key)) {
35662 var data = getWeakData(key);
35663 if (data === true) return uncaughtFrozenStore(state).get(key);
35664 return data ? data[state.id] : undefined;
35665 }
35666 },
35667 // `WeakMap.prototype.set(key, value)` method
35668 // https://tc39.es/ecma262/#sec-weakmap.prototype.set
35669 set: function set(key, value) {
35670 return define(this, key, value);
35671 }
35672 } : {
35673 // `WeakSet.prototype.add(value)` method
35674 // https://tc39.es/ecma262/#sec-weakset.prototype.add
35675 add: function add(value) {
35676 return define(this, value, true);
35677 }
35678 });
35679 return C;
35680 }
35681};
35682collectionWeak.getConstructor;
35683
35684createCommonjsModule(function (module) {
35685
35686 var enforceIternalState = internalState.enforce;
35687 var IS_IE11 = !global_1.ActiveXObject && 'ActiveXObject' in global_1; // eslint-disable-next-line es/no-object-isextensible -- safe
35688
35689 var isExtensible = Object.isExtensible;
35690 var InternalWeakMap;
35691
35692 var wrapper = function (init) {
35693 return function WeakMap() {
35694 return init(this, arguments.length ? arguments[0] : undefined);
35695 };
35696 }; // `WeakMap` constructor
35697 // https://tc39.es/ecma262/#sec-weakmap-constructor
35698
35699
35700 var $WeakMap = module.exports = collection('WeakMap', wrapper, collectionWeak); // IE11 WeakMap frozen keys fix
35701 // We can't use feature detection because it crash some old IE builds
35702 // https://github.com/zloirock/core-js/issues/485
35703
35704 if (nativeWeakMap && IS_IE11) {
35705 InternalWeakMap = collectionWeak.getConstructor(wrapper, 'WeakMap', true);
35706 internalMetadata.enable();
35707 var WeakMapPrototype = $WeakMap.prototype;
35708 var nativeDelete = WeakMapPrototype['delete'];
35709 var nativeHas = WeakMapPrototype.has;
35710 var nativeGet = WeakMapPrototype.get;
35711 var nativeSet = WeakMapPrototype.set;
35712 redefineAll(WeakMapPrototype, {
35713 'delete': function (key) {
35714 if (isObject$1(key) && !isExtensible(key)) {
35715 var state = enforceIternalState(this);
35716 if (!state.frozen) state.frozen = new InternalWeakMap();
35717 return nativeDelete.call(this, key) || state.frozen['delete'](key);
35718 }
35719
35720 return nativeDelete.call(this, key);
35721 },
35722 has: function has(key) {
35723 if (isObject$1(key) && !isExtensible(key)) {
35724 var state = enforceIternalState(this);
35725 if (!state.frozen) state.frozen = new InternalWeakMap();
35726 return nativeHas.call(this, key) || state.frozen.has(key);
35727 }
35728
35729 return nativeHas.call(this, key);
35730 },
35731 get: function get(key) {
35732 if (isObject$1(key) && !isExtensible(key)) {
35733 var state = enforceIternalState(this);
35734 if (!state.frozen) state.frozen = new InternalWeakMap();
35735 return nativeHas.call(this, key) ? nativeGet.call(this, key) : state.frozen.get(key);
35736 }
35737
35738 return nativeGet.call(this, key);
35739 },
35740 set: function set(key, value) {
35741 if (isObject$1(key) && !isExtensible(key)) {
35742 var state = enforceIternalState(this);
35743 if (!state.frozen) state.frozen = new InternalWeakMap();
35744 nativeHas.call(this, key) ? nativeSet.call(this, key, value) : state.frozen.set(key, value);
35745 } else nativeSet.call(this, key, value);
35746
35747 return this;
35748 }
35749 });
35750 }
35751});
35752
35753var weakMap$2 = path.WeakMap;
35754
35755var weakMap$1 = weakMap$2;
35756
35757var weakMap = weakMap$1;
35758
35759/*! *****************************************************************************
35760Copyright (c) Microsoft Corporation.
35761
35762Permission to use, copy, modify, and/or distribute this software for any
35763purpose with or without fee is hereby granted.
35764
35765THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
35766REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
35767AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
35768INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
35769LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
35770OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
35771PERFORMANCE OF THIS SOFTWARE.
35772***************************************************************************** */
35773function __classPrivateFieldGet(receiver, state, kind, f) {
35774 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
35775 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
35776 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
35777}
35778function __classPrivateFieldSet(receiver, state, value, kind, f) {
35779 if (kind === "m") throw new TypeError("Private method is not writable");
35780 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
35781 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
35782 return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
35783}
35784
35785function _createForOfIteratorHelper$3(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (isArray(o) || (it = _unsupportedIterableToArray$3(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
35786
35787function _unsupportedIterableToArray$3(o, minLen) { var _context2; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$3(o, minLen); var n = slice$1(_context2 = Object.prototype.toString.call(o)).call(_context2, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from_1$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$3(o, minLen); }
35788
35789function _arrayLikeToArray$3(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
35790
35791var _SingleTypeSelectionAccumulator_previousSelection, _SingleTypeSelectionAccumulator_selection, _SelectionAccumulator_nodes, _SelectionAccumulator_edges, _SelectionAccumulator_commitHandler;
35792/**
35793 * @param prev
35794 * @param next
35795 */
35796
35797function diffSets(prev, next) {
35798 var diff = new set();
35799
35800 var _iterator = _createForOfIteratorHelper$3(next),
35801 _step;
35802
35803 try {
35804 for (_iterator.s(); !(_step = _iterator.n()).done;) {
35805 var item = _step.value;
35806
35807 if (!prev.has(item)) {
35808 diff.add(item);
35809 }
35810 }
35811 } catch (err) {
35812 _iterator.e(err);
35813 } finally {
35814 _iterator.f();
35815 }
35816
35817 return diff;
35818}
35819
35820var SingleTypeSelectionAccumulator = /*#__PURE__*/function () {
35821 function SingleTypeSelectionAccumulator() {
35822 _classCallCheck(this, SingleTypeSelectionAccumulator);
35823
35824 _SingleTypeSelectionAccumulator_previousSelection.set(this, new set());
35825
35826 _SingleTypeSelectionAccumulator_selection.set(this, new set());
35827 }
35828
35829 _createClass(SingleTypeSelectionAccumulator, [{
35830 key: "size",
35831 get: function get() {
35832 return __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").size;
35833 }
35834 }, {
35835 key: "add",
35836 value: function add() {
35837 for (var _len = arguments.length, items = new Array(_len), _key = 0; _key < _len; _key++) {
35838 items[_key] = arguments[_key];
35839 }
35840
35841 for (var _i = 0, _items = items; _i < _items.length; _i++) {
35842 var item = _items[_i];
35843
35844 __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").add(item);
35845 }
35846 }
35847 }, {
35848 key: "delete",
35849 value: function _delete() {
35850 for (var _len2 = arguments.length, items = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
35851 items[_key2] = arguments[_key2];
35852 }
35853
35854 for (var _i2 = 0, _items2 = items; _i2 < _items2.length; _i2++) {
35855 var item = _items2[_i2];
35856
35857 __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").delete(item);
35858 }
35859 }
35860 }, {
35861 key: "clear",
35862 value: function clear() {
35863 __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").clear();
35864 }
35865 }, {
35866 key: "getSelection",
35867 value: function getSelection() {
35868 return _toConsumableArray(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"));
35869 }
35870 }, {
35871 key: "getChanges",
35872 value: function getChanges() {
35873 return {
35874 added: _toConsumableArray(diffSets(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f"), __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"))),
35875 deleted: _toConsumableArray(diffSets(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"), __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f"))),
35876 previous: _toConsumableArray(new set(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f"))),
35877 current: _toConsumableArray(new set(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f")))
35878 };
35879 }
35880 }, {
35881 key: "commit",
35882 value: function commit() {
35883 var changes = this.getChanges();
35884
35885 __classPrivateFieldSet(this, _SingleTypeSelectionAccumulator_previousSelection, __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"), "f");
35886
35887 __classPrivateFieldSet(this, _SingleTypeSelectionAccumulator_selection, new set(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f")), "f");
35888
35889 var _iterator2 = _createForOfIteratorHelper$3(changes.added),
35890 _step2;
35891
35892 try {
35893 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
35894 var item = _step2.value;
35895 item.select();
35896 }
35897 } catch (err) {
35898 _iterator2.e(err);
35899 } finally {
35900 _iterator2.f();
35901 }
35902
35903 var _iterator3 = _createForOfIteratorHelper$3(changes.deleted),
35904 _step3;
35905
35906 try {
35907 for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
35908 var _item = _step3.value;
35909
35910 _item.unselect();
35911 }
35912 } catch (err) {
35913 _iterator3.e(err);
35914 } finally {
35915 _iterator3.f();
35916 }
35917
35918 return changes;
35919 }
35920 }]);
35921
35922 return SingleTypeSelectionAccumulator;
35923}();
35924
35925_SingleTypeSelectionAccumulator_previousSelection = new weakMap(), _SingleTypeSelectionAccumulator_selection = new weakMap();
35926var SelectionAccumulator = /*#__PURE__*/function () {
35927 function SelectionAccumulator() {
35928 var commitHandler = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
35929
35930 _classCallCheck(this, SelectionAccumulator);
35931
35932 _SelectionAccumulator_nodes.set(this, new SingleTypeSelectionAccumulator());
35933
35934 _SelectionAccumulator_edges.set(this, new SingleTypeSelectionAccumulator());
35935
35936 _SelectionAccumulator_commitHandler.set(this, void 0);
35937
35938 __classPrivateFieldSet(this, _SelectionAccumulator_commitHandler, commitHandler, "f");
35939 }
35940
35941 _createClass(SelectionAccumulator, [{
35942 key: "sizeNodes",
35943 get: function get() {
35944 return __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").size;
35945 }
35946 }, {
35947 key: "sizeEdges",
35948 get: function get() {
35949 return __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").size;
35950 }
35951 }, {
35952 key: "getNodes",
35953 value: function getNodes() {
35954 return __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").getSelection();
35955 }
35956 }, {
35957 key: "getEdges",
35958 value: function getEdges() {
35959 return __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").getSelection();
35960 }
35961 }, {
35962 key: "addNodes",
35963 value: function addNodes() {
35964 var _classPrivateFieldGe;
35965
35966 (_classPrivateFieldGe = __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f")).add.apply(_classPrivateFieldGe, arguments);
35967 }
35968 }, {
35969 key: "addEdges",
35970 value: function addEdges() {
35971 var _classPrivateFieldGe2;
35972
35973 (_classPrivateFieldGe2 = __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f")).add.apply(_classPrivateFieldGe2, arguments);
35974 }
35975 }, {
35976 key: "deleteNodes",
35977 value: function deleteNodes(node) {
35978 __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").delete(node);
35979 }
35980 }, {
35981 key: "deleteEdges",
35982 value: function deleteEdges(edge) {
35983 __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").delete(edge);
35984 }
35985 }, {
35986 key: "clear",
35987 value: function clear() {
35988 __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").clear();
35989
35990 __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").clear();
35991 }
35992 }, {
35993 key: "commit",
35994 value: function commit() {
35995 var _classPrivateFieldGe3, _context;
35996
35997 var summary = {
35998 nodes: __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").commit(),
35999 edges: __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").commit()
36000 };
36001
36002 for (var _len3 = arguments.length, rest = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
36003 rest[_key3] = arguments[_key3];
36004 }
36005
36006 (_classPrivateFieldGe3 = __classPrivateFieldGet(this, _SelectionAccumulator_commitHandler, "f")).call.apply(_classPrivateFieldGe3, concat(_context = [this, summary]).call(_context, rest));
36007
36008 return summary;
36009 }
36010 }]);
36011
36012 return SelectionAccumulator;
36013}();
36014_SelectionAccumulator_nodes = new weakMap(), _SelectionAccumulator_edges = new weakMap(), _SelectionAccumulator_commitHandler = new weakMap();
36015
36016function _createForOfIteratorHelper$2(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (isArray(o) || (it = _unsupportedIterableToArray$2(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
36017
36018function _unsupportedIterableToArray$2(o, minLen) { var _context3; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$2(o, minLen); var n = slice$1(_context3 = Object.prototype.toString.call(o)).call(_context3, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from_1$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$2(o, minLen); }
36019
36020function _arrayLikeToArray$2(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
36021/**
36022 * The handler for selections
36023 */
36024
36025var SelectionHandler = /*#__PURE__*/function () {
36026 /**
36027 * @param {object} body
36028 * @param {Canvas} canvas
36029 */
36030 function SelectionHandler(body, canvas) {
36031 var _this = this;
36032
36033 _classCallCheck(this, SelectionHandler);
36034
36035 this.body = body;
36036 this.canvas = canvas; // TODO: Consider firing an event on any change to the selection, not
36037 // only those caused by clicks and taps. It would be easy to implement
36038 // now and (at least to me) it seems like something that could be
36039 // quite useful.
36040
36041 this._selectionAccumulator = new SelectionAccumulator();
36042 this.hoverObj = {
36043 nodes: {},
36044 edges: {}
36045 };
36046 this.options = {};
36047 this.defaultOptions = {
36048 multiselect: false,
36049 selectable: true,
36050 selectConnectedEdges: true,
36051 hoverConnectedEdges: true
36052 };
36053
36054 assign$2(this.options, this.defaultOptions);
36055
36056 this.body.emitter.on("_dataChanged", function () {
36057 _this.updateSelection();
36058 });
36059 }
36060 /**
36061 *
36062 * @param {object} [options]
36063 */
36064
36065
36066 _createClass(SelectionHandler, [{
36067 key: "setOptions",
36068 value: function setOptions(options) {
36069 if (options !== undefined) {
36070 var fields = ["multiselect", "hoverConnectedEdges", "selectable", "selectConnectedEdges"];
36071 selectiveDeepExtend(fields, this.options, options);
36072 }
36073 }
36074 /**
36075 * handles the selection part of the tap;
36076 *
36077 * @param {{x: number, y: number}} pointer
36078 * @returns {boolean}
36079 */
36080
36081 }, {
36082 key: "selectOnPoint",
36083 value: function selectOnPoint(pointer) {
36084 var selected = false;
36085
36086 if (this.options.selectable === true) {
36087 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer); // unselect after getting the objects in order to restore width and height.
36088
36089 this.unselectAll();
36090
36091 if (obj !== undefined) {
36092 selected = this.selectObject(obj);
36093 }
36094
36095 this.body.emitter.emit("_requestRedraw");
36096 }
36097
36098 return selected;
36099 }
36100 /**
36101 *
36102 * @param {{x: number, y: number}} pointer
36103 * @returns {boolean}
36104 */
36105
36106 }, {
36107 key: "selectAdditionalOnPoint",
36108 value: function selectAdditionalOnPoint(pointer) {
36109 var selectionChanged = false;
36110
36111 if (this.options.selectable === true) {
36112 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
36113
36114 if (obj !== undefined) {
36115 selectionChanged = true;
36116
36117 if (obj.isSelected() === true) {
36118 this.deselectObject(obj);
36119 } else {
36120 this.selectObject(obj);
36121 }
36122
36123 this.body.emitter.emit("_requestRedraw");
36124 }
36125 }
36126
36127 return selectionChanged;
36128 }
36129 /**
36130 * Create an object containing the standard fields for an event.
36131 *
36132 * @param {Event} event
36133 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
36134 * @returns {{}}
36135 * @private
36136 */
36137
36138 }, {
36139 key: "_initBaseEvent",
36140 value: function _initBaseEvent(event, pointer) {
36141 var properties = {};
36142 properties["pointer"] = {
36143 DOM: {
36144 x: pointer.x,
36145 y: pointer.y
36146 },
36147 canvas: this.canvas.DOMtoCanvas(pointer)
36148 };
36149 properties["event"] = event;
36150 return properties;
36151 }
36152 /**
36153 * Generate an event which the user can catch.
36154 *
36155 * This adds some extra data to the event with respect to cursor position and
36156 * selected nodes and edges.
36157 *
36158 * @param {string} eventType Name of event to send
36159 * @param {Event} event
36160 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
36161 * @param {object | undefined} oldSelection If present, selection state before event occured
36162 * @param {boolean|undefined} [emptySelection=false] Indicate if selection data should be passed
36163 */
36164
36165 }, {
36166 key: "generateClickEvent",
36167 value: function generateClickEvent(eventType, event, pointer, oldSelection) {
36168 var emptySelection = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
36169
36170 var properties = this._initBaseEvent(event, pointer);
36171
36172 if (emptySelection === true) {
36173 properties.nodes = [];
36174 properties.edges = [];
36175 } else {
36176 var tmp = this.getSelection();
36177 properties.nodes = tmp.nodes;
36178 properties.edges = tmp.edges;
36179 }
36180
36181 if (oldSelection !== undefined) {
36182 properties["previousSelection"] = oldSelection;
36183 }
36184
36185 if (eventType == "click") {
36186 // For the time being, restrict this functionality to
36187 // just the click event.
36188 properties.items = this.getClickedItems(pointer);
36189 }
36190
36191 if (event.controlEdge !== undefined) {
36192 properties.controlEdge = event.controlEdge;
36193 }
36194
36195 this.body.emitter.emit(eventType, properties);
36196 }
36197 /**
36198 *
36199 * @param {object} obj
36200 * @param {boolean} [highlightEdges=this.options.selectConnectedEdges]
36201 * @returns {boolean}
36202 */
36203
36204 }, {
36205 key: "selectObject",
36206 value: function selectObject(obj) {
36207 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.selectConnectedEdges;
36208
36209 if (obj !== undefined) {
36210 if (obj instanceof Node) {
36211 if (highlightEdges === true) {
36212 var _this$_selectionAccum;
36213
36214 (_this$_selectionAccum = this._selectionAccumulator).addEdges.apply(_this$_selectionAccum, _toConsumableArray(obj.edges));
36215 }
36216
36217 this._selectionAccumulator.addNodes(obj);
36218 } else {
36219 this._selectionAccumulator.addEdges(obj);
36220 }
36221
36222 return true;
36223 }
36224
36225 return false;
36226 }
36227 /**
36228 *
36229 * @param {object} obj
36230 */
36231
36232 }, {
36233 key: "deselectObject",
36234 value: function deselectObject(obj) {
36235 if (obj.isSelected() === true) {
36236 obj.selected = false;
36237
36238 this._removeFromSelection(obj);
36239 }
36240 }
36241 /**
36242 * retrieve all nodes overlapping with given object
36243 *
36244 * @param {object} object An object with parameters left, top, right, bottom
36245 * @returns {number[]} An array with id's of the overlapping nodes
36246 * @private
36247 */
36248
36249 }, {
36250 key: "_getAllNodesOverlappingWith",
36251 value: function _getAllNodesOverlappingWith(object) {
36252 var overlappingNodes = [];
36253 var nodes = this.body.nodes;
36254
36255 for (var i = 0; i < this.body.nodeIndices.length; i++) {
36256 var nodeId = this.body.nodeIndices[i];
36257
36258 if (nodes[nodeId].isOverlappingWith(object)) {
36259 overlappingNodes.push(nodeId);
36260 }
36261 }
36262
36263 return overlappingNodes;
36264 }
36265 /**
36266 * Return a position object in canvasspace from a single point in screenspace
36267 *
36268 * @param {{x: number, y: number}} pointer
36269 * @returns {{left: number, top: number, right: number, bottom: number}}
36270 * @private
36271 */
36272
36273 }, {
36274 key: "_pointerToPositionObject",
36275 value: function _pointerToPositionObject(pointer) {
36276 var canvasPos = this.canvas.DOMtoCanvas(pointer);
36277 return {
36278 left: canvasPos.x - 1,
36279 top: canvasPos.y + 1,
36280 right: canvasPos.x + 1,
36281 bottom: canvasPos.y - 1
36282 };
36283 }
36284 /**
36285 * Get the top node at the passed point (like a click)
36286 *
36287 * @param {{x: number, y: number}} pointer
36288 * @param {boolean} [returnNode=true]
36289 * @returns {Node | undefined} node
36290 */
36291
36292 }, {
36293 key: "getNodeAt",
36294 value: function getNodeAt(pointer) {
36295 var returnNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
36296
36297 // we first check if this is an navigation controls element
36298 var positionObject = this._pointerToPositionObject(pointer);
36299
36300 var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); // if there are overlapping nodes, select the last one, this is the
36301 // one which is drawn on top of the others
36302
36303
36304 if (overlappingNodes.length > 0) {
36305 if (returnNode === true) {
36306 return this.body.nodes[overlappingNodes[overlappingNodes.length - 1]];
36307 } else {
36308 return overlappingNodes[overlappingNodes.length - 1];
36309 }
36310 } else {
36311 return undefined;
36312 }
36313 }
36314 /**
36315 * retrieve all edges overlapping with given object, selector is around center
36316 *
36317 * @param {object} object An object with parameters left, top, right, bottom
36318 * @param {number[]} overlappingEdges An array with id's of the overlapping nodes
36319 * @private
36320 */
36321
36322 }, {
36323 key: "_getEdgesOverlappingWith",
36324 value: function _getEdgesOverlappingWith(object, overlappingEdges) {
36325 var edges = this.body.edges;
36326
36327 for (var i = 0; i < this.body.edgeIndices.length; i++) {
36328 var edgeId = this.body.edgeIndices[i];
36329
36330 if (edges[edgeId].isOverlappingWith(object)) {
36331 overlappingEdges.push(edgeId);
36332 }
36333 }
36334 }
36335 /**
36336 * retrieve all nodes overlapping with given object
36337 *
36338 * @param {object} object An object with parameters left, top, right, bottom
36339 * @returns {number[]} An array with id's of the overlapping nodes
36340 * @private
36341 */
36342
36343 }, {
36344 key: "_getAllEdgesOverlappingWith",
36345 value: function _getAllEdgesOverlappingWith(object) {
36346 var overlappingEdges = [];
36347
36348 this._getEdgesOverlappingWith(object, overlappingEdges);
36349
36350 return overlappingEdges;
36351 }
36352 /**
36353 * Get the edges nearest to the passed point (like a click)
36354 *
36355 * @param {{x: number, y: number}} pointer
36356 * @param {boolean} [returnEdge=true]
36357 * @returns {Edge | undefined} node
36358 */
36359
36360 }, {
36361 key: "getEdgeAt",
36362 value: function getEdgeAt(pointer) {
36363 var returnEdge = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
36364 // Iterate over edges, pick closest within 10
36365 var canvasPos = this.canvas.DOMtoCanvas(pointer);
36366 var mindist = 10;
36367 var overlappingEdge = null;
36368 var edges = this.body.edges;
36369
36370 for (var i = 0; i < this.body.edgeIndices.length; i++) {
36371 var edgeId = this.body.edgeIndices[i];
36372 var edge = edges[edgeId];
36373
36374 if (edge.connected) {
36375 var xFrom = edge.from.x;
36376 var yFrom = edge.from.y;
36377 var xTo = edge.to.x;
36378 var yTo = edge.to.y;
36379 var dist = edge.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, canvasPos.x, canvasPos.y);
36380
36381 if (dist < mindist) {
36382 overlappingEdge = edgeId;
36383 mindist = dist;
36384 }
36385 }
36386 }
36387
36388 if (overlappingEdge !== null) {
36389 if (returnEdge === true) {
36390 return this.body.edges[overlappingEdge];
36391 } else {
36392 return overlappingEdge;
36393 }
36394 } else {
36395 return undefined;
36396 }
36397 }
36398 /**
36399 * Add object to the selection array.
36400 *
36401 * @param {object} obj
36402 * @private
36403 */
36404
36405 }, {
36406 key: "_addToHover",
36407 value: function _addToHover(obj) {
36408 if (obj instanceof Node) {
36409 this.hoverObj.nodes[obj.id] = obj;
36410 } else {
36411 this.hoverObj.edges[obj.id] = obj;
36412 }
36413 }
36414 /**
36415 * Remove a single option from selection.
36416 *
36417 * @param {object} obj
36418 * @private
36419 */
36420
36421 }, {
36422 key: "_removeFromSelection",
36423 value: function _removeFromSelection(obj) {
36424 if (obj instanceof Node) {
36425 var _this$_selectionAccum2;
36426
36427 this._selectionAccumulator.deleteNodes(obj);
36428
36429 (_this$_selectionAccum2 = this._selectionAccumulator).deleteEdges.apply(_this$_selectionAccum2, _toConsumableArray(obj.edges));
36430 } else {
36431 this._selectionAccumulator.deleteEdges(obj);
36432 }
36433 }
36434 /**
36435 * Unselect all nodes and edges.
36436 */
36437
36438 }, {
36439 key: "unselectAll",
36440 value: function unselectAll() {
36441 this._selectionAccumulator.clear();
36442 }
36443 /**
36444 * return the number of selected nodes
36445 *
36446 * @returns {number}
36447 */
36448
36449 }, {
36450 key: "getSelectedNodeCount",
36451 value: function getSelectedNodeCount() {
36452 return this._selectionAccumulator.sizeNodes;
36453 }
36454 /**
36455 * return the number of selected edges
36456 *
36457 * @returns {number}
36458 */
36459
36460 }, {
36461 key: "getSelectedEdgeCount",
36462 value: function getSelectedEdgeCount() {
36463 return this._selectionAccumulator.sizeEdges;
36464 }
36465 /**
36466 * select the edges connected to the node that is being selected
36467 *
36468 * @param {Node} node
36469 * @private
36470 */
36471
36472 }, {
36473 key: "_hoverConnectedEdges",
36474 value: function _hoverConnectedEdges(node) {
36475 for (var i = 0; i < node.edges.length; i++) {
36476 var edge = node.edges[i];
36477 edge.hover = true;
36478
36479 this._addToHover(edge);
36480 }
36481 }
36482 /**
36483 * Remove the highlight from a node or edge, in response to mouse movement
36484 *
36485 * @param {Event} event
36486 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
36487 * @param {Node|vis.Edge} object
36488 * @private
36489 */
36490
36491 }, {
36492 key: "emitBlurEvent",
36493 value: function emitBlurEvent(event, pointer, object) {
36494 var properties = this._initBaseEvent(event, pointer);
36495
36496 if (object.hover === true) {
36497 object.hover = false;
36498
36499 if (object instanceof Node) {
36500 properties.node = object.id;
36501 this.body.emitter.emit("blurNode", properties);
36502 } else {
36503 properties.edge = object.id;
36504 this.body.emitter.emit("blurEdge", properties);
36505 }
36506 }
36507 }
36508 /**
36509 * Create the highlight for a node or edge, in response to mouse movement
36510 *
36511 * @param {Event} event
36512 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
36513 * @param {Node|vis.Edge} object
36514 * @returns {boolean} hoverChanged
36515 * @private
36516 */
36517
36518 }, {
36519 key: "emitHoverEvent",
36520 value: function emitHoverEvent(event, pointer, object) {
36521 var properties = this._initBaseEvent(event, pointer);
36522
36523 var hoverChanged = false;
36524
36525 if (object.hover === false) {
36526 object.hover = true;
36527
36528 this._addToHover(object);
36529
36530 hoverChanged = true;
36531
36532 if (object instanceof Node) {
36533 properties.node = object.id;
36534 this.body.emitter.emit("hoverNode", properties);
36535 } else {
36536 properties.edge = object.id;
36537 this.body.emitter.emit("hoverEdge", properties);
36538 }
36539 }
36540
36541 return hoverChanged;
36542 }
36543 /**
36544 * Perform actions in response to a mouse movement.
36545 *
36546 * @param {Event} event
36547 * @param {{x: number, y: number}} pointer | object with the x and y screen coordinates of the mouse
36548 */
36549
36550 }, {
36551 key: "hoverObject",
36552 value: function hoverObject(event, pointer) {
36553 var object = this.getNodeAt(pointer);
36554
36555 if (object === undefined) {
36556 object = this.getEdgeAt(pointer);
36557 }
36558
36559 var hoverChanged = false; // remove all node hover highlights
36560
36561 for (var nodeId in this.hoverObj.nodes) {
36562 if (Object.prototype.hasOwnProperty.call(this.hoverObj.nodes, nodeId)) {
36563 if (object === undefined || object instanceof Node && object.id != nodeId || object instanceof Edge) {
36564 this.emitBlurEvent(event, pointer, this.hoverObj.nodes[nodeId]);
36565 delete this.hoverObj.nodes[nodeId];
36566 hoverChanged = true;
36567 }
36568 }
36569 } // removing all edge hover highlights
36570
36571
36572 for (var edgeId in this.hoverObj.edges) {
36573 if (Object.prototype.hasOwnProperty.call(this.hoverObj.edges, edgeId)) {
36574 // if the hover has been changed here it means that the node has been hovered over or off
36575 // we then do not use the emitBlurEvent method here.
36576 if (hoverChanged === true) {
36577 this.hoverObj.edges[edgeId].hover = false;
36578 delete this.hoverObj.edges[edgeId];
36579 } // if the blur remains the same and the object is undefined (mouse off) or another
36580 // edge has been hovered, or another node has been hovered we blur the edge.
36581 else if (object === undefined || object instanceof Edge && object.id != edgeId || object instanceof Node && !object.hover) {
36582 this.emitBlurEvent(event, pointer, this.hoverObj.edges[edgeId]);
36583 delete this.hoverObj.edges[edgeId];
36584 hoverChanged = true;
36585 }
36586 }
36587 }
36588
36589 if (object !== undefined) {
36590 var hoveredEdgesCount = keys$3(this.hoverObj.edges).length;
36591
36592 var hoveredNodesCount = keys$3(this.hoverObj.nodes).length;
36593
36594 var newOnlyHoveredEdge = object instanceof Edge && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
36595 var newOnlyHoveredNode = object instanceof Node && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
36596
36597 if (hoverChanged || newOnlyHoveredEdge || newOnlyHoveredNode) {
36598 hoverChanged = this.emitHoverEvent(event, pointer, object);
36599 }
36600
36601 if (object instanceof Node && this.options.hoverConnectedEdges === true) {
36602 this._hoverConnectedEdges(object);
36603 }
36604 }
36605
36606 if (hoverChanged === true) {
36607 this.body.emitter.emit("_requestRedraw");
36608 }
36609 }
36610 /**
36611 * Commit the selection changes but don't emit any events.
36612 */
36613
36614 }, {
36615 key: "commitWithoutEmitting",
36616 value: function commitWithoutEmitting() {
36617 this._selectionAccumulator.commit();
36618 }
36619 /**
36620 * Select and deselect nodes depending current selection change.
36621 *
36622 * For changing nodes, select/deselect events are fired.
36623 *
36624 * NOTE: For a given edge, if one connecting node is deselected and with the
36625 * same click the other node is selected, no events for the edge will fire. It
36626 * was selected and it will remain selected.
36627 *
36628 * @param {{x: number, y: number}} pointer - The x and y coordinates of the
36629 * click, tap, dragend… that triggered this.
36630 * @param {UIEvent} event - The event that triggered this.
36631 */
36632
36633 }, {
36634 key: "commitAndEmit",
36635 value: function commitAndEmit(pointer, event) {
36636 var selected = false;
36637
36638 var selectionChanges = this._selectionAccumulator.commit();
36639
36640 var previousSelection = {
36641 nodes: selectionChanges.nodes.previous,
36642 edges: selectionChanges.edges.previous
36643 };
36644
36645 if (selectionChanges.edges.deleted.length > 0) {
36646 this.generateClickEvent("deselectEdge", event, pointer, previousSelection);
36647 selected = true;
36648 }
36649
36650 if (selectionChanges.nodes.deleted.length > 0) {
36651 this.generateClickEvent("deselectNode", event, pointer, previousSelection);
36652 selected = true;
36653 }
36654
36655 if (selectionChanges.nodes.added.length > 0) {
36656 this.generateClickEvent("selectNode", event, pointer);
36657 selected = true;
36658 }
36659
36660 if (selectionChanges.edges.added.length > 0) {
36661 this.generateClickEvent("selectEdge", event, pointer);
36662 selected = true;
36663 } // fire the select event if anything has been selected or deselected
36664
36665
36666 if (selected === true) {
36667 // select or unselect
36668 this.generateClickEvent("select", event, pointer);
36669 }
36670 }
36671 /**
36672 * Retrieve the currently selected node and edge ids.
36673 *
36674 * @returns {{nodes: Array.<string>, edges: Array.<string>}} Arrays with the
36675 * ids of the selected nodes and edges.
36676 */
36677
36678 }, {
36679 key: "getSelection",
36680 value: function getSelection() {
36681 return {
36682 nodes: this.getSelectedNodeIds(),
36683 edges: this.getSelectedEdgeIds()
36684 };
36685 }
36686 /**
36687 * Retrieve the currently selected nodes.
36688 *
36689 * @returns {Array} An array with selected nodes.
36690 */
36691
36692 }, {
36693 key: "getSelectedNodes",
36694 value: function getSelectedNodes() {
36695 return this._selectionAccumulator.getNodes();
36696 }
36697 /**
36698 * Retrieve the currently selected edges.
36699 *
36700 * @returns {Array} An array with selected edges.
36701 */
36702
36703 }, {
36704 key: "getSelectedEdges",
36705 value: function getSelectedEdges() {
36706 return this._selectionAccumulator.getEdges();
36707 }
36708 /**
36709 * Retrieve the currently selected node ids.
36710 *
36711 * @returns {Array} An array with the ids of the selected nodes.
36712 */
36713
36714 }, {
36715 key: "getSelectedNodeIds",
36716 value: function getSelectedNodeIds() {
36717 var _context;
36718
36719 return map$3(_context = this._selectionAccumulator.getNodes()).call(_context, function (node) {
36720 return node.id;
36721 });
36722 }
36723 /**
36724 * Retrieve the currently selected edge ids.
36725 *
36726 * @returns {Array} An array with the ids of the selected edges.
36727 */
36728
36729 }, {
36730 key: "getSelectedEdgeIds",
36731 value: function getSelectedEdgeIds() {
36732 var _context2;
36733
36734 return map$3(_context2 = this._selectionAccumulator.getEdges()).call(_context2, function (edge) {
36735 return edge.id;
36736 });
36737 }
36738 /**
36739 * Updates the current selection
36740 *
36741 * @param {{nodes: Array.<string>, edges: Array.<string>}} selection
36742 * @param {object} options Options
36743 */
36744
36745 }, {
36746 key: "setSelection",
36747 value: function setSelection(selection) {
36748 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
36749
36750 if (!selection || !selection.nodes && !selection.edges) {
36751 throw new TypeError("Selection must be an object with nodes and/or edges properties");
36752 } // first unselect any selected node, if option is true or undefined
36753
36754
36755 if (options.unselectAll || options.unselectAll === undefined) {
36756 this.unselectAll();
36757 }
36758
36759 if (selection.nodes) {
36760 var _iterator = _createForOfIteratorHelper$2(selection.nodes),
36761 _step;
36762
36763 try {
36764 for (_iterator.s(); !(_step = _iterator.n()).done;) {
36765 var id = _step.value;
36766 var node = this.body.nodes[id];
36767
36768 if (!node) {
36769 throw new RangeError('Node with id "' + id + '" not found');
36770 } // don't select edges with it
36771
36772
36773 this.selectObject(node, options.highlightEdges);
36774 }
36775 } catch (err) {
36776 _iterator.e(err);
36777 } finally {
36778 _iterator.f();
36779 }
36780 }
36781
36782 if (selection.edges) {
36783 var _iterator2 = _createForOfIteratorHelper$2(selection.edges),
36784 _step2;
36785
36786 try {
36787 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
36788 var _id = _step2.value;
36789 var edge = this.body.edges[_id];
36790
36791 if (!edge) {
36792 throw new RangeError('Edge with id "' + _id + '" not found');
36793 }
36794
36795 this.selectObject(edge);
36796 }
36797 } catch (err) {
36798 _iterator2.e(err);
36799 } finally {
36800 _iterator2.f();
36801 }
36802 }
36803
36804 this.body.emitter.emit("_requestRedraw");
36805
36806 this._selectionAccumulator.commit();
36807 }
36808 /**
36809 * select zero or more nodes with the option to highlight edges
36810 *
36811 * @param {number[] | string[]} selection An array with the ids of the
36812 * selected nodes.
36813 * @param {boolean} [highlightEdges]
36814 */
36815
36816 }, {
36817 key: "selectNodes",
36818 value: function selectNodes(selection) {
36819 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
36820 if (!selection || selection.length === undefined) throw "Selection must be an array with ids";
36821 this.setSelection({
36822 nodes: selection
36823 }, {
36824 highlightEdges: highlightEdges
36825 });
36826 }
36827 /**
36828 * select zero or more edges
36829 *
36830 * @param {number[] | string[]} selection An array with the ids of the
36831 * selected nodes.
36832 */
36833
36834 }, {
36835 key: "selectEdges",
36836 value: function selectEdges(selection) {
36837 if (!selection || selection.length === undefined) throw "Selection must be an array with ids";
36838 this.setSelection({
36839 edges: selection
36840 });
36841 }
36842 /**
36843 * Validate the selection: remove ids of nodes which no longer exist
36844 *
36845 * @private
36846 */
36847
36848 }, {
36849 key: "updateSelection",
36850 value: function updateSelection() {
36851 for (var node in this._selectionAccumulator.getNodes()) {
36852 if (!Object.prototype.hasOwnProperty.call(this.body.nodes, node.id)) {
36853 this._selectionAccumulator.deleteNodes(node);
36854 }
36855 }
36856
36857 for (var edge in this._selectionAccumulator.getEdges()) {
36858 if (!Object.prototype.hasOwnProperty.call(this.body.edges, edge.id)) {
36859 this._selectionAccumulator.deleteEdges(edge);
36860 }
36861 }
36862 }
36863 /**
36864 * Determine all the visual elements clicked which are on the given point.
36865 *
36866 * All elements are returned; this includes nodes, edges and their labels.
36867 * The order returned is from highest to lowest, i.e. element 0 of the return
36868 * value is the topmost item clicked on.
36869 *
36870 * The return value consists of an array of the following possible elements:
36871 *
36872 * - `{nodeId:number}` - node with given id clicked on
36873 * - `{nodeId:number, labelId:0}` - label of node with given id clicked on
36874 * - `{edgeId:number}` - edge with given id clicked on
36875 * - `{edge:number, labelId:0}` - label of edge with given id clicked on
36876 *
36877 * ## NOTES
36878 *
36879 * - Currently, there is only one label associated with a node or an edge,
36880 * but this is expected to change somewhere in the future.
36881 * - Since there is no z-indexing yet, it is not really possible to set the nodes and
36882 * edges in the correct order. For the time being, nodes come first.
36883 *
36884 * @param {point} pointer mouse position in screen coordinates
36885 * @returns {Array.<nodeClickItem|nodeLabelClickItem|edgeClickItem|edgeLabelClickItem>}
36886 * @private
36887 */
36888
36889 }, {
36890 key: "getClickedItems",
36891 value: function getClickedItems(pointer) {
36892 var point = this.canvas.DOMtoCanvas(pointer);
36893 var items = []; // Note reverse order; we want the topmost clicked items to be first in the array
36894 // Also note that selected nodes are disregarded here; these normally display on top
36895
36896 var nodeIndices = this.body.nodeIndices;
36897 var nodes = this.body.nodes;
36898
36899 for (var i = nodeIndices.length - 1; i >= 0; i--) {
36900 var node = nodes[nodeIndices[i]];
36901 var ret = node.getItemsOnPoint(point);
36902 items.push.apply(items, ret); // Append the return value to the running list.
36903 }
36904
36905 var edgeIndices = this.body.edgeIndices;
36906 var edges = this.body.edges;
36907
36908 for (var _i = edgeIndices.length - 1; _i >= 0; _i--) {
36909 var edge = edges[edgeIndices[_i]];
36910
36911 var _ret = edge.getItemsOnPoint(point);
36912
36913 items.push.apply(items, _ret); // Append the return value to the running list.
36914 }
36915
36916 return items;
36917 }
36918 }]);
36919
36920 return SelectionHandler;
36921}();
36922
36923var timsort$1 = createCommonjsModule(function (module, exports) {
36924 /****
36925 * The MIT License
36926 *
36927 * Copyright (c) 2015 Marco Ziccardi
36928 *
36929 * Permission is hereby granted, free of charge, to any person obtaining a copy
36930 * of this software and associated documentation files (the "Software"), to deal
36931 * in the Software without restriction, including without limitation the rights
36932 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36933 * copies of the Software, and to permit persons to whom the Software is
36934 * furnished to do so, subject to the following conditions:
36935 *
36936 * The above copyright notice and this permission notice shall be included in
36937 * all copies or substantial portions of the Software.
36938 *
36939 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36940 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36941 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36942 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36943 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36944 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36945 * THE SOFTWARE.
36946 *
36947 ****/
36948 (function (global, factory) {
36949 {
36950 factory(exports);
36951 }
36952 })(commonjsGlobal, function (exports) {
36953
36954 exports.__esModule = true;
36955 exports.sort = sort;
36956
36957 function _classCallCheck(instance, Constructor) {
36958 if (!(instance instanceof Constructor)) {
36959 throw new TypeError('Cannot call a class as a function');
36960 }
36961 }
36962
36963 var DEFAULT_MIN_MERGE = 32;
36964 var DEFAULT_MIN_GALLOPING = 7;
36965 var DEFAULT_TMP_STORAGE_LENGTH = 256;
36966 var POWERS_OF_TEN = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9];
36967
36968 function log10(x) {
36969 if (x < 1e5) {
36970 if (x < 1e2) {
36971 return x < 1e1 ? 0 : 1;
36972 }
36973
36974 if (x < 1e4) {
36975 return x < 1e3 ? 2 : 3;
36976 }
36977
36978 return 4;
36979 }
36980
36981 if (x < 1e7) {
36982 return x < 1e6 ? 5 : 6;
36983 }
36984
36985 if (x < 1e9) {
36986 return x < 1e8 ? 7 : 8;
36987 }
36988
36989 return 9;
36990 }
36991
36992 function alphabeticalCompare(a, b) {
36993 if (a === b) {
36994 return 0;
36995 }
36996
36997 if (~~a === a && ~~b === b) {
36998 if (a === 0 || b === 0) {
36999 return a < b ? -1 : 1;
37000 }
37001
37002 if (a < 0 || b < 0) {
37003 if (b >= 0) {
37004 return -1;
37005 }
37006
37007 if (a >= 0) {
37008 return 1;
37009 }
37010
37011 a = -a;
37012 b = -b;
37013 }
37014
37015 var al = log10(a);
37016 var bl = log10(b);
37017 var t = 0;
37018
37019 if (al < bl) {
37020 a *= POWERS_OF_TEN[bl - al - 1];
37021 b /= 10;
37022 t = -1;
37023 } else if (al > bl) {
37024 b *= POWERS_OF_TEN[al - bl - 1];
37025 a /= 10;
37026 t = 1;
37027 }
37028
37029 if (a === b) {
37030 return t;
37031 }
37032
37033 return a < b ? -1 : 1;
37034 }
37035
37036 var aStr = String(a);
37037 var bStr = String(b);
37038
37039 if (aStr === bStr) {
37040 return 0;
37041 }
37042
37043 return aStr < bStr ? -1 : 1;
37044 }
37045
37046 function minRunLength(n) {
37047 var r = 0;
37048
37049 while (n >= DEFAULT_MIN_MERGE) {
37050 r |= n & 1;
37051 n >>= 1;
37052 }
37053
37054 return n + r;
37055 }
37056
37057 function makeAscendingRun(array, lo, hi, compare) {
37058 var runHi = lo + 1;
37059
37060 if (runHi === hi) {
37061 return 1;
37062 }
37063
37064 if (compare(array[runHi++], array[lo]) < 0) {
37065 while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
37066 runHi++;
37067 }
37068
37069 reverseRun(array, lo, runHi);
37070 } else {
37071 while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
37072 runHi++;
37073 }
37074 }
37075
37076 return runHi - lo;
37077 }
37078
37079 function reverseRun(array, lo, hi) {
37080 hi--;
37081
37082 while (lo < hi) {
37083 var t = array[lo];
37084 array[lo++] = array[hi];
37085 array[hi--] = t;
37086 }
37087 }
37088
37089 function binaryInsertionSort(array, lo, hi, start, compare) {
37090 if (start === lo) {
37091 start++;
37092 }
37093
37094 for (; start < hi; start++) {
37095 var pivot = array[start];
37096 var left = lo;
37097 var right = start;
37098
37099 while (left < right) {
37100 var mid = left + right >>> 1;
37101
37102 if (compare(pivot, array[mid]) < 0) {
37103 right = mid;
37104 } else {
37105 left = mid + 1;
37106 }
37107 }
37108
37109 var n = start - left;
37110
37111 switch (n) {
37112 case 3:
37113 array[left + 3] = array[left + 2];
37114
37115 case 2:
37116 array[left + 2] = array[left + 1];
37117
37118 case 1:
37119 array[left + 1] = array[left];
37120 break;
37121
37122 default:
37123 while (n > 0) {
37124 array[left + n] = array[left + n - 1];
37125 n--;
37126 }
37127
37128 }
37129
37130 array[left] = pivot;
37131 }
37132 }
37133
37134 function gallopLeft(value, array, start, length, hint, compare) {
37135 var lastOffset = 0;
37136 var maxOffset = 0;
37137 var offset = 1;
37138
37139 if (compare(value, array[start + hint]) > 0) {
37140 maxOffset = length - hint;
37141
37142 while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
37143 lastOffset = offset;
37144 offset = (offset << 1) + 1;
37145
37146 if (offset <= 0) {
37147 offset = maxOffset;
37148 }
37149 }
37150
37151 if (offset > maxOffset) {
37152 offset = maxOffset;
37153 }
37154
37155 lastOffset += hint;
37156 offset += hint;
37157 } else {
37158 maxOffset = hint + 1;
37159
37160 while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
37161 lastOffset = offset;
37162 offset = (offset << 1) + 1;
37163
37164 if (offset <= 0) {
37165 offset = maxOffset;
37166 }
37167 }
37168
37169 if (offset > maxOffset) {
37170 offset = maxOffset;
37171 }
37172
37173 var tmp = lastOffset;
37174 lastOffset = hint - offset;
37175 offset = hint - tmp;
37176 }
37177
37178 lastOffset++;
37179
37180 while (lastOffset < offset) {
37181 var m = lastOffset + (offset - lastOffset >>> 1);
37182
37183 if (compare(value, array[start + m]) > 0) {
37184 lastOffset = m + 1;
37185 } else {
37186 offset = m;
37187 }
37188 }
37189
37190 return offset;
37191 }
37192
37193 function gallopRight(value, array, start, length, hint, compare) {
37194 var lastOffset = 0;
37195 var maxOffset = 0;
37196 var offset = 1;
37197
37198 if (compare(value, array[start + hint]) < 0) {
37199 maxOffset = hint + 1;
37200
37201 while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
37202 lastOffset = offset;
37203 offset = (offset << 1) + 1;
37204
37205 if (offset <= 0) {
37206 offset = maxOffset;
37207 }
37208 }
37209
37210 if (offset > maxOffset) {
37211 offset = maxOffset;
37212 }
37213
37214 var tmp = lastOffset;
37215 lastOffset = hint - offset;
37216 offset = hint - tmp;
37217 } else {
37218 maxOffset = length - hint;
37219
37220 while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
37221 lastOffset = offset;
37222 offset = (offset << 1) + 1;
37223
37224 if (offset <= 0) {
37225 offset = maxOffset;
37226 }
37227 }
37228
37229 if (offset > maxOffset) {
37230 offset = maxOffset;
37231 }
37232
37233 lastOffset += hint;
37234 offset += hint;
37235 }
37236
37237 lastOffset++;
37238
37239 while (lastOffset < offset) {
37240 var m = lastOffset + (offset - lastOffset >>> 1);
37241
37242 if (compare(value, array[start + m]) < 0) {
37243 offset = m;
37244 } else {
37245 lastOffset = m + 1;
37246 }
37247 }
37248
37249 return offset;
37250 }
37251
37252 var TimSort = function () {
37253 function TimSort(array, compare) {
37254 _classCallCheck(this, TimSort);
37255
37256 this.array = null;
37257 this.compare = null;
37258 this.minGallop = DEFAULT_MIN_GALLOPING;
37259 this.length = 0;
37260 this.tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
37261 this.stackLength = 0;
37262 this.runStart = null;
37263 this.runLength = null;
37264 this.stackSize = 0;
37265 this.array = array;
37266 this.compare = compare;
37267 this.length = array.length;
37268
37269 if (this.length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
37270 this.tmpStorageLength = this.length >>> 1;
37271 }
37272
37273 this.tmp = new Array(this.tmpStorageLength);
37274 this.stackLength = this.length < 120 ? 5 : this.length < 1542 ? 10 : this.length < 119151 ? 19 : 40;
37275 this.runStart = new Array(this.stackLength);
37276 this.runLength = new Array(this.stackLength);
37277 }
37278
37279 TimSort.prototype.pushRun = function pushRun(runStart, runLength) {
37280 this.runStart[this.stackSize] = runStart;
37281 this.runLength[this.stackSize] = runLength;
37282 this.stackSize += 1;
37283 };
37284
37285 TimSort.prototype.mergeRuns = function mergeRuns() {
37286 while (this.stackSize > 1) {
37287 var n = this.stackSize - 2;
37288
37289 if (n >= 1 && this.runLength[n - 1] <= this.runLength[n] + this.runLength[n + 1] || n >= 2 && this.runLength[n - 2] <= this.runLength[n] + this.runLength[n - 1]) {
37290 if (this.runLength[n - 1] < this.runLength[n + 1]) {
37291 n--;
37292 }
37293 } else if (this.runLength[n] > this.runLength[n + 1]) {
37294 break;
37295 }
37296
37297 this.mergeAt(n);
37298 }
37299 };
37300
37301 TimSort.prototype.forceMergeRuns = function forceMergeRuns() {
37302 while (this.stackSize > 1) {
37303 var n = this.stackSize - 2;
37304
37305 if (n > 0 && this.runLength[n - 1] < this.runLength[n + 1]) {
37306 n--;
37307 }
37308
37309 this.mergeAt(n);
37310 }
37311 };
37312
37313 TimSort.prototype.mergeAt = function mergeAt(i) {
37314 var compare = this.compare;
37315 var array = this.array;
37316 var start1 = this.runStart[i];
37317 var length1 = this.runLength[i];
37318 var start2 = this.runStart[i + 1];
37319 var length2 = this.runLength[i + 1];
37320 this.runLength[i] = length1 + length2;
37321
37322 if (i === this.stackSize - 3) {
37323 this.runStart[i + 1] = this.runStart[i + 2];
37324 this.runLength[i + 1] = this.runLength[i + 2];
37325 }
37326
37327 this.stackSize--;
37328 var k = gallopRight(array[start2], array, start1, length1, 0, compare);
37329 start1 += k;
37330 length1 -= k;
37331
37332 if (length1 === 0) {
37333 return;
37334 }
37335
37336 length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
37337
37338 if (length2 === 0) {
37339 return;
37340 }
37341
37342 if (length1 <= length2) {
37343 this.mergeLow(start1, length1, start2, length2);
37344 } else {
37345 this.mergeHigh(start1, length1, start2, length2);
37346 }
37347 };
37348
37349 TimSort.prototype.mergeLow = function mergeLow(start1, length1, start2, length2) {
37350 var compare = this.compare;
37351 var array = this.array;
37352 var tmp = this.tmp;
37353 var i = 0;
37354
37355 for (i = 0; i < length1; i++) {
37356 tmp[i] = array[start1 + i];
37357 }
37358
37359 var cursor1 = 0;
37360 var cursor2 = start2;
37361 var dest = start1;
37362 array[dest++] = array[cursor2++];
37363
37364 if (--length2 === 0) {
37365 for (i = 0; i < length1; i++) {
37366 array[dest + i] = tmp[cursor1 + i];
37367 }
37368
37369 return;
37370 }
37371
37372 if (length1 === 1) {
37373 for (i = 0; i < length2; i++) {
37374 array[dest + i] = array[cursor2 + i];
37375 }
37376
37377 array[dest + length2] = tmp[cursor1];
37378 return;
37379 }
37380
37381 var minGallop = this.minGallop;
37382
37383 while (true) {
37384 var count1 = 0;
37385 var count2 = 0;
37386 var exit = false;
37387
37388 do {
37389 if (compare(array[cursor2], tmp[cursor1]) < 0) {
37390 array[dest++] = array[cursor2++];
37391 count2++;
37392 count1 = 0;
37393
37394 if (--length2 === 0) {
37395 exit = true;
37396 break;
37397 }
37398 } else {
37399 array[dest++] = tmp[cursor1++];
37400 count1++;
37401 count2 = 0;
37402
37403 if (--length1 === 1) {
37404 exit = true;
37405 break;
37406 }
37407 }
37408 } while ((count1 | count2) < minGallop);
37409
37410 if (exit) {
37411 break;
37412 }
37413
37414 do {
37415 count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
37416
37417 if (count1 !== 0) {
37418 for (i = 0; i < count1; i++) {
37419 array[dest + i] = tmp[cursor1 + i];
37420 }
37421
37422 dest += count1;
37423 cursor1 += count1;
37424 length1 -= count1;
37425
37426 if (length1 <= 1) {
37427 exit = true;
37428 break;
37429 }
37430 }
37431
37432 array[dest++] = array[cursor2++];
37433
37434 if (--length2 === 0) {
37435 exit = true;
37436 break;
37437 }
37438
37439 count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
37440
37441 if (count2 !== 0) {
37442 for (i = 0; i < count2; i++) {
37443 array[dest + i] = array[cursor2 + i];
37444 }
37445
37446 dest += count2;
37447 cursor2 += count2;
37448 length2 -= count2;
37449
37450 if (length2 === 0) {
37451 exit = true;
37452 break;
37453 }
37454 }
37455
37456 array[dest++] = tmp[cursor1++];
37457
37458 if (--length1 === 1) {
37459 exit = true;
37460 break;
37461 }
37462
37463 minGallop--;
37464 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
37465
37466 if (exit) {
37467 break;
37468 }
37469
37470 if (minGallop < 0) {
37471 minGallop = 0;
37472 }
37473
37474 minGallop += 2;
37475 }
37476
37477 this.minGallop = minGallop;
37478
37479 if (minGallop < 1) {
37480 this.minGallop = 1;
37481 }
37482
37483 if (length1 === 1) {
37484 for (i = 0; i < length2; i++) {
37485 array[dest + i] = array[cursor2 + i];
37486 }
37487
37488 array[dest + length2] = tmp[cursor1];
37489 } else if (length1 === 0) {
37490 throw new Error('mergeLow preconditions were not respected');
37491 } else {
37492 for (i = 0; i < length1; i++) {
37493 array[dest + i] = tmp[cursor1 + i];
37494 }
37495 }
37496 };
37497
37498 TimSort.prototype.mergeHigh = function mergeHigh(start1, length1, start2, length2) {
37499 var compare = this.compare;
37500 var array = this.array;
37501 var tmp = this.tmp;
37502 var i = 0;
37503
37504 for (i = 0; i < length2; i++) {
37505 tmp[i] = array[start2 + i];
37506 }
37507
37508 var cursor1 = start1 + length1 - 1;
37509 var cursor2 = length2 - 1;
37510 var dest = start2 + length2 - 1;
37511 var customCursor = 0;
37512 var customDest = 0;
37513 array[dest--] = array[cursor1--];
37514
37515 if (--length1 === 0) {
37516 customCursor = dest - (length2 - 1);
37517
37518 for (i = 0; i < length2; i++) {
37519 array[customCursor + i] = tmp[i];
37520 }
37521
37522 return;
37523 }
37524
37525 if (length2 === 1) {
37526 dest -= length1;
37527 cursor1 -= length1;
37528 customDest = dest + 1;
37529 customCursor = cursor1 + 1;
37530
37531 for (i = length1 - 1; i >= 0; i--) {
37532 array[customDest + i] = array[customCursor + i];
37533 }
37534
37535 array[dest] = tmp[cursor2];
37536 return;
37537 }
37538
37539 var minGallop = this.minGallop;
37540
37541 while (true) {
37542 var count1 = 0;
37543 var count2 = 0;
37544 var exit = false;
37545
37546 do {
37547 if (compare(tmp[cursor2], array[cursor1]) < 0) {
37548 array[dest--] = array[cursor1--];
37549 count1++;
37550 count2 = 0;
37551
37552 if (--length1 === 0) {
37553 exit = true;
37554 break;
37555 }
37556 } else {
37557 array[dest--] = tmp[cursor2--];
37558 count2++;
37559 count1 = 0;
37560
37561 if (--length2 === 1) {
37562 exit = true;
37563 break;
37564 }
37565 }
37566 } while ((count1 | count2) < minGallop);
37567
37568 if (exit) {
37569 break;
37570 }
37571
37572 do {
37573 count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
37574
37575 if (count1 !== 0) {
37576 dest -= count1;
37577 cursor1 -= count1;
37578 length1 -= count1;
37579 customDest = dest + 1;
37580 customCursor = cursor1 + 1;
37581
37582 for (i = count1 - 1; i >= 0; i--) {
37583 array[customDest + i] = array[customCursor + i];
37584 }
37585
37586 if (length1 === 0) {
37587 exit = true;
37588 break;
37589 }
37590 }
37591
37592 array[dest--] = tmp[cursor2--];
37593
37594 if (--length2 === 1) {
37595 exit = true;
37596 break;
37597 }
37598
37599 count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
37600
37601 if (count2 !== 0) {
37602 dest -= count2;
37603 cursor2 -= count2;
37604 length2 -= count2;
37605 customDest = dest + 1;
37606 customCursor = cursor2 + 1;
37607
37608 for (i = 0; i < count2; i++) {
37609 array[customDest + i] = tmp[customCursor + i];
37610 }
37611
37612 if (length2 <= 1) {
37613 exit = true;
37614 break;
37615 }
37616 }
37617
37618 array[dest--] = array[cursor1--];
37619
37620 if (--length1 === 0) {
37621 exit = true;
37622 break;
37623 }
37624
37625 minGallop--;
37626 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
37627
37628 if (exit) {
37629 break;
37630 }
37631
37632 if (minGallop < 0) {
37633 minGallop = 0;
37634 }
37635
37636 minGallop += 2;
37637 }
37638
37639 this.minGallop = minGallop;
37640
37641 if (minGallop < 1) {
37642 this.minGallop = 1;
37643 }
37644
37645 if (length2 === 1) {
37646 dest -= length1;
37647 cursor1 -= length1;
37648 customDest = dest + 1;
37649 customCursor = cursor1 + 1;
37650
37651 for (i = length1 - 1; i >= 0; i--) {
37652 array[customDest + i] = array[customCursor + i];
37653 }
37654
37655 array[dest] = tmp[cursor2];
37656 } else if (length2 === 0) {
37657 throw new Error('mergeHigh preconditions were not respected');
37658 } else {
37659 customCursor = dest - (length2 - 1);
37660
37661 for (i = 0; i < length2; i++) {
37662 array[customCursor + i] = tmp[i];
37663 }
37664 }
37665 };
37666
37667 return TimSort;
37668 }();
37669
37670 function sort(array, compare, lo, hi) {
37671 if (!Array.isArray(array)) {
37672 throw new TypeError('Can only sort arrays');
37673 }
37674
37675 if (!compare) {
37676 compare = alphabeticalCompare;
37677 } else if (typeof compare !== 'function') {
37678 hi = lo;
37679 lo = compare;
37680 compare = alphabeticalCompare;
37681 }
37682
37683 if (!lo) {
37684 lo = 0;
37685 }
37686
37687 if (!hi) {
37688 hi = array.length;
37689 }
37690
37691 var remaining = hi - lo;
37692
37693 if (remaining < 2) {
37694 return;
37695 }
37696
37697 var runLength = 0;
37698
37699 if (remaining < DEFAULT_MIN_MERGE) {
37700 runLength = makeAscendingRun(array, lo, hi, compare);
37701 binaryInsertionSort(array, lo, hi, lo + runLength, compare);
37702 return;
37703 }
37704
37705 var ts = new TimSort(array, compare);
37706 var minRun = minRunLength(remaining);
37707
37708 do {
37709 runLength = makeAscendingRun(array, lo, hi, compare);
37710
37711 if (runLength < minRun) {
37712 var force = remaining;
37713
37714 if (force > minRun) {
37715 force = minRun;
37716 }
37717
37718 binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
37719 runLength = force;
37720 }
37721
37722 ts.pushRun(lo, runLength);
37723 ts.mergeRuns();
37724 remaining -= runLength;
37725 lo += runLength;
37726 } while (remaining !== 0);
37727
37728 ts.forceMergeRuns();
37729 }
37730 });
37731});
37732unwrapExports(timsort$1);
37733
37734var timsort = timsort$1;
37735var timsort_1 = timsort.sort;
37736
37737function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
37738
37739function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
37740/**
37741 * Interface definition for direction strategy classes.
37742 *
37743 * This class describes the interface for the Strategy
37744 * pattern classes used to differentiate horizontal and vertical
37745 * direction of hierarchical results.
37746 *
37747 * For a given direction, one coordinate will be 'fixed', meaning that it is
37748 * determined by level.
37749 * The other coordinate is 'unfixed', meaning that the nodes on a given level
37750 * can still move along that coordinate. So:
37751 *
37752 * - `vertical` layout: `x` unfixed, `y` fixed per level
37753 * - `horizontal` layout: `x` fixed per level, `y` unfixed
37754 *
37755 * The local methods are stubs and should be regarded as abstract.
37756 * Derived classes **must** implement all the methods themselves.
37757 *
37758 * @private
37759 */
37760
37761var DirectionInterface = /*#__PURE__*/function () {
37762 function DirectionInterface() {
37763 _classCallCheck(this, DirectionInterface);
37764 }
37765
37766 _createClass(DirectionInterface, [{
37767 key: "abstract",
37768 value:
37769 /**
37770 * @ignore
37771 */
37772 function abstract() {
37773 throw new Error("Can't instantiate abstract class!");
37774 }
37775 /**
37776 * This is a dummy call which is used to suppress the jsdoc errors of type:
37777 *
37778 * "'param' is assigned a value but never used"
37779 *
37780 * @ignore
37781 **/
37782
37783 }, {
37784 key: "fake_use",
37785 value: function fake_use() {// Do nothing special
37786 }
37787 /**
37788 * Type to use to translate dynamic curves to, in the case of hierarchical layout.
37789 * Dynamic curves do not work for these.
37790 *
37791 * The value should be perpendicular to the actual direction of the layout.
37792 *
37793 * @returns {string} Direction, either 'vertical' or 'horizontal'
37794 */
37795
37796 }, {
37797 key: "curveType",
37798 value: function curveType() {
37799 return this.abstract();
37800 }
37801 /**
37802 * Return the value of the coordinate that is not fixed for this direction.
37803 *
37804 * @param {Node} node The node to read
37805 * @returns {number} Value of the unfixed coordinate
37806 */
37807
37808 }, {
37809 key: "getPosition",
37810 value: function getPosition(node) {
37811 this.fake_use(node);
37812 return this.abstract();
37813 }
37814 /**
37815 * Set the value of the coordinate that is not fixed for this direction.
37816 *
37817 * @param {Node} node The node to adjust
37818 * @param {number} position
37819 * @param {number} [level] if specified, the hierarchy level that this node should be fixed to
37820 */
37821
37822 }, {
37823 key: "setPosition",
37824 value: function setPosition(node, position) {
37825 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
37826 this.fake_use(node, position, level);
37827 this.abstract();
37828 }
37829 /**
37830 * Get the width of a tree.
37831 *
37832 * A `tree` here is a subset of nodes within the network which are not connected to other nodes,
37833 * only among themselves. In essence, it is a sub-network.
37834 *
37835 * @param {number} index The index number of a tree
37836 * @returns {number} the width of a tree in the view coordinates
37837 */
37838
37839 }, {
37840 key: "getTreeSize",
37841 value: function getTreeSize(index) {
37842 this.fake_use(index);
37843 return this.abstract();
37844 }
37845 /**
37846 * Sort array of nodes on the unfixed coordinates.
37847 *
37848 * **Note:** chrome has non-stable sorting implementation, which
37849 * has a tendency to change the order of the array items,
37850 * even if the custom sort function returns 0.
37851 *
37852 * For this reason, an external sort implementation is used,
37853 * which has the added benefit of being faster than the standard
37854 * platforms implementation. This has been verified on `node.js`,
37855 * `firefox` and `chrome` (all linux).
37856 *
37857 * @param {Array.<Node>} nodeArray array of nodes to sort
37858 */
37859
37860 }, {
37861 key: "sort",
37862 value: function sort(nodeArray) {
37863 this.fake_use(nodeArray);
37864 this.abstract();
37865 }
37866 /**
37867 * Assign the fixed coordinate of the node to the given level
37868 *
37869 * @param {Node} node The node to adjust
37870 * @param {number} level The level to fix to
37871 */
37872
37873 }, {
37874 key: "fix",
37875 value: function fix(node, level) {
37876 this.fake_use(node, level);
37877 this.abstract();
37878 }
37879 /**
37880 * Add an offset to the unfixed coordinate of the given node.
37881 *
37882 * @param {NodeId} nodeId Id of the node to adjust
37883 * @param {number} diff Offset to add to the unfixed coordinate
37884 */
37885
37886 }, {
37887 key: "shift",
37888 value: function shift(nodeId, diff) {
37889 this.fake_use(nodeId, diff);
37890 this.abstract();
37891 }
37892 }]);
37893
37894 return DirectionInterface;
37895}();
37896/**
37897 * Vertical Strategy
37898 *
37899 * Coordinate `y` is fixed on levels, coordinate `x` is unfixed.
37900 *
37901 * @augments DirectionInterface
37902 * @private
37903 */
37904
37905
37906var VerticalStrategy = /*#__PURE__*/function (_DirectionInterface) {
37907 _inherits(VerticalStrategy, _DirectionInterface);
37908
37909 var _super = _createSuper(VerticalStrategy);
37910
37911 /**
37912 * Constructor
37913 *
37914 * @param {object} layout reference to the parent LayoutEngine instance.
37915 */
37916 function VerticalStrategy(layout) {
37917 var _this;
37918
37919 _classCallCheck(this, VerticalStrategy);
37920
37921 _this = _super.call(this);
37922 _this.layout = layout;
37923 return _this;
37924 }
37925 /** @inheritDoc */
37926
37927
37928 _createClass(VerticalStrategy, [{
37929 key: "curveType",
37930 value: function curveType() {
37931 return "horizontal";
37932 }
37933 /** @inheritDoc */
37934
37935 }, {
37936 key: "getPosition",
37937 value: function getPosition(node) {
37938 return node.x;
37939 }
37940 /** @inheritDoc */
37941
37942 }, {
37943 key: "setPosition",
37944 value: function setPosition(node, position) {
37945 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
37946
37947 if (level !== undefined) {
37948 this.layout.hierarchical.addToOrdering(node, level);
37949 }
37950
37951 node.x = position;
37952 }
37953 /** @inheritDoc */
37954
37955 }, {
37956 key: "getTreeSize",
37957 value: function getTreeSize(index) {
37958 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
37959 return {
37960 min: res.min_x,
37961 max: res.max_x
37962 };
37963 }
37964 /** @inheritDoc */
37965
37966 }, {
37967 key: "sort",
37968 value: function sort(nodeArray) {
37969 timsort_1(nodeArray, function (a, b) {
37970 return a.x - b.x;
37971 });
37972 }
37973 /** @inheritDoc */
37974
37975 }, {
37976 key: "fix",
37977 value: function fix(node, level) {
37978 node.y = this.layout.options.hierarchical.levelSeparation * level;
37979 node.options.fixed.y = true;
37980 }
37981 /** @inheritDoc */
37982
37983 }, {
37984 key: "shift",
37985 value: function shift(nodeId, diff) {
37986 this.layout.body.nodes[nodeId].x += diff;
37987 }
37988 }]);
37989
37990 return VerticalStrategy;
37991}(DirectionInterface);
37992/**
37993 * Horizontal Strategy
37994 *
37995 * Coordinate `x` is fixed on levels, coordinate `y` is unfixed.
37996 *
37997 * @augments DirectionInterface
37998 * @private
37999 */
38000
38001
38002var HorizontalStrategy = /*#__PURE__*/function (_DirectionInterface2) {
38003 _inherits(HorizontalStrategy, _DirectionInterface2);
38004
38005 var _super2 = _createSuper(HorizontalStrategy);
38006
38007 /**
38008 * Constructor
38009 *
38010 * @param {object} layout reference to the parent LayoutEngine instance.
38011 */
38012 function HorizontalStrategy(layout) {
38013 var _this2;
38014
38015 _classCallCheck(this, HorizontalStrategy);
38016
38017 _this2 = _super2.call(this);
38018 _this2.layout = layout;
38019 return _this2;
38020 }
38021 /** @inheritDoc */
38022
38023
38024 _createClass(HorizontalStrategy, [{
38025 key: "curveType",
38026 value: function curveType() {
38027 return "vertical";
38028 }
38029 /** @inheritDoc */
38030
38031 }, {
38032 key: "getPosition",
38033 value: function getPosition(node) {
38034 return node.y;
38035 }
38036 /** @inheritDoc */
38037
38038 }, {
38039 key: "setPosition",
38040 value: function setPosition(node, position) {
38041 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
38042
38043 if (level !== undefined) {
38044 this.layout.hierarchical.addToOrdering(node, level);
38045 }
38046
38047 node.y = position;
38048 }
38049 /** @inheritDoc */
38050
38051 }, {
38052 key: "getTreeSize",
38053 value: function getTreeSize(index) {
38054 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
38055 return {
38056 min: res.min_y,
38057 max: res.max_y
38058 };
38059 }
38060 /** @inheritDoc */
38061
38062 }, {
38063 key: "sort",
38064 value: function sort(nodeArray) {
38065 timsort_1(nodeArray, function (a, b) {
38066 return a.y - b.y;
38067 });
38068 }
38069 /** @inheritDoc */
38070
38071 }, {
38072 key: "fix",
38073 value: function fix(node, level) {
38074 node.x = this.layout.options.hierarchical.levelSeparation * level;
38075 node.options.fixed.x = true;
38076 }
38077 /** @inheritDoc */
38078
38079 }, {
38080 key: "shift",
38081 value: function shift(nodeId, diff) {
38082 this.layout.body.nodes[nodeId].y += diff;
38083 }
38084 }]);
38085
38086 return HorizontalStrategy;
38087}(DirectionInterface);
38088
38089var $every = arrayIteration.every;
38090var STRICT_METHOD = arrayMethodIsStrict('every'); // `Array.prototype.every` method
38091// https://tc39.es/ecma262/#sec-array.prototype.every
38092
38093_export({
38094 target: 'Array',
38095 proto: true,
38096 forced: !STRICT_METHOD
38097}, {
38098 every: function every(callbackfn
38099 /* , thisArg */
38100 ) {
38101 return $every(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
38102 }
38103});
38104
38105var every$2 = entryVirtual('Array').every;
38106
38107var ArrayPrototype = Array.prototype;
38108
38109var every_1 = function (it) {
38110 var own = it.every;
38111 return it === ArrayPrototype || it instanceof Array && own === ArrayPrototype.every ? every$2 : own;
38112};
38113
38114var every$1 = every_1;
38115
38116var every = every$1;
38117
38118function _createForOfIteratorHelper$1(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
38119
38120function _unsupportedIterableToArray$1(o, minLen) { var _context9; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); var n = slice$1(_context9 = Object.prototype.toString.call(o)).call(_context9, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from_1$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); }
38121
38122function _arrayLikeToArray$1(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
38123
38124/**
38125 * Try to assign levels to nodes according to their positions in the cyclic “hierarchy”.
38126 *
38127 * @param nodes - Visible nodes of the graph.
38128 * @param levels - If present levels will be added to it, if not a new object will be created.
38129 *
38130 * @returns Populated node levels.
38131 */
38132function fillLevelsByDirectionCyclic(nodes, levels) {
38133 var edges = new set();
38134
38135 forEach$2(nodes).call(nodes, function (node) {
38136 var _context;
38137
38138 forEach$2(_context = node.edges).call(_context, function (edge) {
38139 if (edge.connected) {
38140 edges.add(edge);
38141 }
38142 });
38143 });
38144
38145 forEach$2(edges).call(edges, function (edge) {
38146 var fromId = edge.from.id;
38147 var toId = edge.to.id;
38148
38149 if (levels[fromId] == null) {
38150 levels[fromId] = 0;
38151 }
38152
38153 if (levels[toId] == null || levels[fromId] >= levels[toId]) {
38154 levels[toId] = levels[fromId] + 1;
38155 }
38156 });
38157
38158 return levels;
38159}
38160/**
38161 * Assign levels to nodes according to their positions in the hierarchy. Leaves will be lined up at the bottom and all other nodes as close to their children as possible.
38162 *
38163 * @param nodes - Visible nodes of the graph.
38164 *
38165 * @returns Populated node levels.
38166 */
38167
38168
38169function fillLevelsByDirectionLeaves(nodes) {
38170 return fillLevelsByDirection( // Pick only leaves (nodes without children).
38171 function (node) {
38172 var _context2, _context3;
38173
38174 return every(_context2 = filter(_context3 = node.edges // Take only visible nodes into account.
38175 ).call(_context3, function (edge) {
38176 return nodes.has(edge.toId);
38177 }) // Check that all edges lead to this node (leaf).
38178 ).call(_context2, function (edge) {
38179 return edge.to === node;
38180 });
38181 }, // Use the lowest level.
38182 function (newLevel, oldLevel) {
38183 return oldLevel > newLevel;
38184 }, // Go against the direction of the edges.
38185 "from", nodes);
38186}
38187/**
38188 * Assign levels to nodes according to their positions in the hierarchy. Roots will be lined up at the top and all nodes as close to their parents as possible.
38189 *
38190 * @param nodes - Visible nodes of the graph.
38191 *
38192 * @returns Populated node levels.
38193 */
38194
38195function fillLevelsByDirectionRoots(nodes) {
38196 return fillLevelsByDirection( // Pick only roots (nodes without parents).
38197 function (node) {
38198 var _context4, _context5;
38199
38200 return every(_context4 = filter(_context5 = node.edges // Take only visible nodes into account.
38201 ).call(_context5, function (edge) {
38202 return nodes.has(edge.toId);
38203 }) // Check that all edges lead from this node (root).
38204 ).call(_context4, function (edge) {
38205 return edge.from === node;
38206 });
38207 }, // Use the highest level.
38208 function (newLevel, oldLevel) {
38209 return oldLevel < newLevel;
38210 }, // Go in the direction of the edges.
38211 "to", nodes);
38212}
38213/**
38214 * Assign levels to nodes according to their positions in the hierarchy.
38215 *
38216 * @param isEntryNode - Checks and return true if the graph should be traversed from this node.
38217 * @param shouldLevelBeReplaced - Checks and returns true if the level of given node should be updated to the new value.
38218 * @param direction - Wheter the graph should be traversed in the direction of the edges `"to"` or in the other way `"from"`.
38219 * @param nodes - Visible nodes of the graph.
38220 *
38221 * @returns Populated node levels.
38222 */
38223
38224function fillLevelsByDirection(isEntryNode, shouldLevelBeReplaced, direction, nodes) {
38225 var _context6;
38226
38227 var levels = create$2(null); // If acyclic, the graph can be walked through with (most likely way) fewer
38228 // steps than the number bellow. The exact value isn't too important as long
38229 // as it's quick to compute (doesn't impact acyclic graphs too much), is
38230 // higher than the number of steps actually needed (doesn't cut off before
38231 // acyclic graph is walked through) and prevents infinite loops (cuts off for
38232 // cyclic graphs).
38233
38234
38235 var limit = reduce(_context6 = _toConsumableArray(values(nodes).call(nodes))).call(_context6, function (acc, node) {
38236 return acc + 1 + node.edges.length;
38237 }, 0);
38238
38239 var edgeIdProp = direction + "Id";
38240 var newLevelDiff = direction === "to" ? 1 : -1;
38241
38242 var _iterator = _createForOfIteratorHelper$1(nodes),
38243 _step;
38244
38245 try {
38246 var _loop = function _loop() {
38247 var _step$value = _slicedToArray(_step.value, 2),
38248 entryNodeId = _step$value[0],
38249 entryNode = _step$value[1];
38250
38251 if ( // Skip if the node is not visible.
38252 !nodes.has(entryNodeId) || // Skip if the node is not an entry node.
38253 !isEntryNode(entryNode)) {
38254 return "continue";
38255 } // Line up all the entry nodes on level 0.
38256
38257
38258 levels[entryNodeId] = 0;
38259 var stack = [entryNode];
38260 var done = 0;
38261 var node = void 0;
38262
38263 var _loop2 = function _loop2() {
38264 var _context7, _context8;
38265
38266 if (!nodes.has(entryNodeId)) {
38267 // Skip if the node is not visible.
38268 return "continue";
38269 }
38270
38271 var newLevel = levels[node.id] + newLevelDiff;
38272
38273 forEach$2(_context7 = filter(_context8 = node.edges).call(_context8, function (edge) {
38274 return (// Ignore disconnected edges.
38275 edge.connected && // Ignore circular edges.
38276 edge.to !== edge.from && // Ignore edges leading to the node that's currently being processed.
38277 edge[direction] !== node && // Ignore edges connecting to an invisible node.
38278 nodes.has(edge.toId) && // Ignore edges connecting from an invisible node.
38279 nodes.has(edge.fromId)
38280 );
38281 })).call(_context7, function (edge) {
38282 var targetNodeId = edge[edgeIdProp];
38283 var oldLevel = levels[targetNodeId];
38284
38285 if (oldLevel == null || shouldLevelBeReplaced(newLevel, oldLevel)) {
38286 levels[targetNodeId] = newLevel;
38287 stack.push(edge[direction]);
38288 }
38289 });
38290
38291 if (done > limit) {
38292 // This would run forever on a cyclic graph.
38293 return {
38294 v: {
38295 v: fillLevelsByDirectionCyclic(nodes, levels)
38296 }
38297 };
38298 } else {
38299 ++done;
38300 }
38301 };
38302
38303 while (node = stack.pop()) {
38304 var _ret2 = _loop2();
38305
38306 if (_ret2 === "continue") continue;
38307 if (_typeof(_ret2) === "object") return _ret2.v;
38308 }
38309 };
38310
38311 for (_iterator.s(); !(_step = _iterator.n()).done;) {
38312 var _ret = _loop();
38313
38314 if (_ret === "continue") continue;
38315 if (_typeof(_ret) === "object") return _ret.v;
38316 }
38317 } catch (err) {
38318 _iterator.e(err);
38319 } finally {
38320 _iterator.f();
38321 }
38322
38323 return levels;
38324}
38325
38326/**
38327 * There's a mix-up with terms in the code. Following are the formal definitions:
38328 *
38329 * tree - a strict hierarchical network, i.e. every node has at most one parent
38330 * forest - a collection of trees. These distinct trees are thus not connected.
38331 *
38332 * So:
38333 * - in a network that is not a tree, there exist nodes with multiple parents.
38334 * - a network consisting of unconnected sub-networks, of which at least one
38335 * is not a tree, is not a forest.
38336 *
38337 * In the code, the definitions are:
38338 *
38339 * tree - any disconnected sub-network, strict hierarchical or not.
38340 * forest - a bunch of these sub-networks
38341 *
38342 * The difference between tree and not-tree is important in the code, notably within
38343 * to the block-shifting algorithm. The algorithm assumes formal trees and fails
38344 * for not-trees, often in a spectacular manner (search for 'exploding network' in the issues).
38345 *
38346 * In order to distinguish the definitions in the following code, the adjective 'formal' is
38347 * used. If 'formal' is absent, you must assume the non-formal definition.
38348 *
38349 * ----------------------------------------------------------------------------------
38350 * NOTES
38351 * =====
38352 *
38353 * A hierarchical layout is a different thing from a hierarchical network.
38354 * The layout is a way to arrange the nodes in the view; this can be done
38355 * on non-hierarchical networks as well. The converse is also possible.
38356 */
38357/**
38358 * Container for derived data on current network, relating to hierarchy.
38359 *
38360 * @private
38361 */
38362
38363var HierarchicalStatus = /*#__PURE__*/function () {
38364 /**
38365 * @ignore
38366 */
38367 function HierarchicalStatus() {
38368 _classCallCheck(this, HierarchicalStatus);
38369
38370 this.childrenReference = {}; // child id's per node id
38371
38372 this.parentReference = {}; // parent id's per node id
38373
38374 this.trees = {}; // tree id per node id; i.e. to which tree does given node id belong
38375
38376 this.distributionOrdering = {}; // The nodes per level, in the display order
38377
38378 this.levels = {}; // hierarchy level per node id
38379
38380 this.distributionIndex = {}; // The position of the node in the level sorting order, per node id.
38381
38382 this.isTree = false; // True if current network is a formal tree
38383
38384 this.treeIndex = -1; // Highest tree id in current network.
38385 }
38386 /**
38387 * Add the relation between given nodes to the current state.
38388 *
38389 * @param {Node.id} parentNodeId
38390 * @param {Node.id} childNodeId
38391 */
38392
38393
38394 _createClass(HierarchicalStatus, [{
38395 key: "addRelation",
38396 value: function addRelation(parentNodeId, childNodeId) {
38397 if (this.childrenReference[parentNodeId] === undefined) {
38398 this.childrenReference[parentNodeId] = [];
38399 }
38400
38401 this.childrenReference[parentNodeId].push(childNodeId);
38402
38403 if (this.parentReference[childNodeId] === undefined) {
38404 this.parentReference[childNodeId] = [];
38405 }
38406
38407 this.parentReference[childNodeId].push(parentNodeId);
38408 }
38409 /**
38410 * Check if the current state is for a formal tree or formal forest.
38411 *
38412 * This is the case if every node has at most one parent.
38413 *
38414 * Pre: parentReference init'ed properly for current network
38415 */
38416
38417 }, {
38418 key: "checkIfTree",
38419 value: function checkIfTree() {
38420 for (var i in this.parentReference) {
38421 if (this.parentReference[i].length > 1) {
38422 this.isTree = false;
38423 return;
38424 }
38425 }
38426
38427 this.isTree = true;
38428 }
38429 /**
38430 * Return the number of separate trees in the current network.
38431 *
38432 * @returns {number}
38433 */
38434
38435 }, {
38436 key: "numTrees",
38437 value: function numTrees() {
38438 return this.treeIndex + 1; // This assumes the indexes are assigned consecitively
38439 }
38440 /**
38441 * Assign a tree id to a node
38442 *
38443 * @param {Node} node
38444 * @param {string|number} treeId
38445 */
38446
38447 }, {
38448 key: "setTreeIndex",
38449 value: function setTreeIndex(node, treeId) {
38450 if (treeId === undefined) return; // Don't bother
38451
38452 if (this.trees[node.id] === undefined) {
38453 this.trees[node.id] = treeId;
38454 this.treeIndex = Math.max(treeId, this.treeIndex);
38455 }
38456 }
38457 /**
38458 * Ensure level for given id is defined.
38459 *
38460 * Sets level to zero for given node id if not already present
38461 *
38462 * @param {Node.id} nodeId
38463 */
38464
38465 }, {
38466 key: "ensureLevel",
38467 value: function ensureLevel(nodeId) {
38468 if (this.levels[nodeId] === undefined) {
38469 this.levels[nodeId] = 0;
38470 }
38471 }
38472 /**
38473 * get the maximum level of a branch.
38474 *
38475 * TODO: Never entered; find a test case to test this!
38476 *
38477 * @param {Node.id} nodeId
38478 * @returns {number}
38479 */
38480
38481 }, {
38482 key: "getMaxLevel",
38483 value: function getMaxLevel(nodeId) {
38484 var _this = this;
38485
38486 var accumulator = {};
38487
38488 var _getMaxLevel = function _getMaxLevel(nodeId) {
38489 if (accumulator[nodeId] !== undefined) {
38490 return accumulator[nodeId];
38491 }
38492
38493 var level = _this.levels[nodeId];
38494
38495 if (_this.childrenReference[nodeId]) {
38496 var children = _this.childrenReference[nodeId];
38497
38498 if (children.length > 0) {
38499 for (var i = 0; i < children.length; i++) {
38500 level = Math.max(level, _getMaxLevel(children[i]));
38501 }
38502 }
38503 }
38504
38505 accumulator[nodeId] = level;
38506 return level;
38507 };
38508
38509 return _getMaxLevel(nodeId);
38510 }
38511 /**
38512 *
38513 * @param {Node} nodeA
38514 * @param {Node} nodeB
38515 */
38516
38517 }, {
38518 key: "levelDownstream",
38519 value: function levelDownstream(nodeA, nodeB) {
38520 if (this.levels[nodeB.id] === undefined) {
38521 // set initial level
38522 if (this.levels[nodeA.id] === undefined) {
38523 this.levels[nodeA.id] = 0;
38524 } // set level
38525
38526
38527 this.levels[nodeB.id] = this.levels[nodeA.id] + 1;
38528 }
38529 }
38530 /**
38531 * Small util method to set the minimum levels of the nodes to zero.
38532 *
38533 * @param {Array.<Node>} nodes
38534 */
38535
38536 }, {
38537 key: "setMinLevelToZero",
38538 value: function setMinLevelToZero(nodes) {
38539 var minLevel = 1e9; // get the minimum level
38540
38541 for (var nodeId in nodes) {
38542 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
38543 if (this.levels[nodeId] !== undefined) {
38544 minLevel = Math.min(this.levels[nodeId], minLevel);
38545 }
38546 }
38547 } // subtract the minimum from the set so we have a range starting from 0
38548
38549
38550 for (var _nodeId in nodes) {
38551 if (Object.prototype.hasOwnProperty.call(nodes, _nodeId)) {
38552 if (this.levels[_nodeId] !== undefined) {
38553 this.levels[_nodeId] -= minLevel;
38554 }
38555 }
38556 }
38557 }
38558 /**
38559 * Get the min and max xy-coordinates of a given tree
38560 *
38561 * @param {Array.<Node>} nodes
38562 * @param {number} index
38563 * @returns {{min_x: number, max_x: number, min_y: number, max_y: number}}
38564 */
38565
38566 }, {
38567 key: "getTreeSize",
38568 value: function getTreeSize(nodes, index) {
38569 var min_x = 1e9;
38570 var max_x = -1e9;
38571 var min_y = 1e9;
38572 var max_y = -1e9;
38573
38574 for (var nodeId in this.trees) {
38575 if (Object.prototype.hasOwnProperty.call(this.trees, nodeId)) {
38576 if (this.trees[nodeId] === index) {
38577 var node = nodes[nodeId];
38578 min_x = Math.min(node.x, min_x);
38579 max_x = Math.max(node.x, max_x);
38580 min_y = Math.min(node.y, min_y);
38581 max_y = Math.max(node.y, max_y);
38582 }
38583 }
38584 }
38585
38586 return {
38587 min_x: min_x,
38588 max_x: max_x,
38589 min_y: min_y,
38590 max_y: max_y
38591 };
38592 }
38593 /**
38594 * Check if two nodes have the same parent(s)
38595 *
38596 * @param {Node} node1
38597 * @param {Node} node2
38598 * @returns {boolean} true if the two nodes have a same ancestor node, false otherwise
38599 */
38600
38601 }, {
38602 key: "hasSameParent",
38603 value: function hasSameParent(node1, node2) {
38604 var parents1 = this.parentReference[node1.id];
38605 var parents2 = this.parentReference[node2.id];
38606
38607 if (parents1 === undefined || parents2 === undefined) {
38608 return false;
38609 }
38610
38611 for (var i = 0; i < parents1.length; i++) {
38612 for (var j = 0; j < parents2.length; j++) {
38613 if (parents1[i] == parents2[j]) {
38614 return true;
38615 }
38616 }
38617 }
38618
38619 return false;
38620 }
38621 /**
38622 * Check if two nodes are in the same tree.
38623 *
38624 * @param {Node} node1
38625 * @param {Node} node2
38626 * @returns {boolean} true if this is so, false otherwise
38627 */
38628
38629 }, {
38630 key: "inSameSubNetwork",
38631 value: function inSameSubNetwork(node1, node2) {
38632 return this.trees[node1.id] === this.trees[node2.id];
38633 }
38634 /**
38635 * Get a list of the distinct levels in the current network
38636 *
38637 * @returns {Array}
38638 */
38639
38640 }, {
38641 key: "getLevels",
38642 value: function getLevels() {
38643 return keys$3(this.distributionOrdering);
38644 }
38645 /**
38646 * Add a node to the ordering per level
38647 *
38648 * @param {Node} node
38649 * @param {number} level
38650 */
38651
38652 }, {
38653 key: "addToOrdering",
38654 value: function addToOrdering(node, level) {
38655 if (this.distributionOrdering[level] === undefined) {
38656 this.distributionOrdering[level] = [];
38657 }
38658
38659 var isPresent = false;
38660 var curLevel = this.distributionOrdering[level];
38661
38662 for (var n in curLevel) {
38663 //if (curLevel[n].id === node.id) {
38664 if (curLevel[n] === node) {
38665 isPresent = true;
38666 break;
38667 }
38668 }
38669
38670 if (!isPresent) {
38671 this.distributionOrdering[level].push(node);
38672 this.distributionIndex[node.id] = this.distributionOrdering[level].length - 1;
38673 }
38674 }
38675 }]);
38676
38677 return HierarchicalStatus;
38678}();
38679/**
38680 * The Layout Engine
38681 */
38682
38683
38684var LayoutEngine = /*#__PURE__*/function () {
38685 /**
38686 * @param {object} body
38687 */
38688 function LayoutEngine(body) {
38689 _classCallCheck(this, LayoutEngine);
38690
38691 this.body = body; // Make sure there always is some RNG because the setOptions method won't
38692 // set it unless there's a seed for it.
38693
38694 this._resetRNG(Math.random() + ":" + now$1());
38695
38696 this.setPhysics = false;
38697 this.options = {};
38698 this.optionsBackup = {
38699 physics: {}
38700 };
38701 this.defaultOptions = {
38702 randomSeed: undefined,
38703 improvedLayout: true,
38704 clusterThreshold: 150,
38705 hierarchical: {
38706 enabled: false,
38707 levelSeparation: 150,
38708 nodeSpacing: 100,
38709 treeSpacing: 200,
38710 blockShifting: true,
38711 edgeMinimization: true,
38712 parentCentralization: true,
38713 direction: "UD",
38714 // UD, DU, LR, RL
38715 sortMethod: "hubsize" // hubsize, directed
38716
38717 }
38718 };
38719
38720 assign$2(this.options, this.defaultOptions);
38721
38722 this.bindEventListeners();
38723 }
38724 /**
38725 * Binds event listeners
38726 */
38727
38728
38729 _createClass(LayoutEngine, [{
38730 key: "bindEventListeners",
38731 value: function bindEventListeners() {
38732 var _this2 = this;
38733
38734 this.body.emitter.on("_dataChanged", function () {
38735 _this2.setupHierarchicalLayout();
38736 });
38737 this.body.emitter.on("_dataLoaded", function () {
38738 _this2.layoutNetwork();
38739 });
38740 this.body.emitter.on("_resetHierarchicalLayout", function () {
38741 _this2.setupHierarchicalLayout();
38742 });
38743 this.body.emitter.on("_adjustEdgesForHierarchicalLayout", function () {
38744 if (_this2.options.hierarchical.enabled !== true) {
38745 return;
38746 } // get the type of static smooth curve in case it is required
38747
38748
38749 var type = _this2.direction.curveType(); // force all edges into static smooth curves.
38750
38751
38752 _this2.body.emitter.emit("_forceDisableDynamicCurves", type, false);
38753 });
38754 }
38755 /**
38756 *
38757 * @param {object} options
38758 * @param {object} allOptions
38759 * @returns {object}
38760 */
38761
38762 }, {
38763 key: "setOptions",
38764 value: function setOptions(options, allOptions) {
38765 if (options !== undefined) {
38766 var hierarchical = this.options.hierarchical;
38767 var prevHierarchicalState = hierarchical.enabled;
38768 selectiveDeepExtend(["randomSeed", "improvedLayout", "clusterThreshold"], this.options, options);
38769 mergeOptions(this.options, options, "hierarchical");
38770
38771 if (options.randomSeed !== undefined) {
38772 this._resetRNG(options.randomSeed);
38773 }
38774
38775 if (hierarchical.enabled === true) {
38776 if (prevHierarchicalState === true) {
38777 // refresh the overridden options for nodes and edges.
38778 this.body.emitter.emit("refresh", true);
38779 } // make sure the level separation is the right way up
38780
38781
38782 if (hierarchical.direction === "RL" || hierarchical.direction === "DU") {
38783 if (hierarchical.levelSeparation > 0) {
38784 hierarchical.levelSeparation *= -1;
38785 }
38786 } else {
38787 if (hierarchical.levelSeparation < 0) {
38788 hierarchical.levelSeparation *= -1;
38789 }
38790 }
38791
38792 this.setDirectionStrategy();
38793 this.body.emitter.emit("_resetHierarchicalLayout"); // because the hierarchical system needs it's own physics and smooth curve settings,
38794 // we adapt the other options if needed.
38795
38796 return this.adaptAllOptionsForHierarchicalLayout(allOptions);
38797 } else {
38798 if (prevHierarchicalState === true) {
38799 // refresh the overridden options for nodes and edges.
38800 this.body.emitter.emit("refresh");
38801 return deepExtend(allOptions, this.optionsBackup);
38802 }
38803 }
38804 }
38805
38806 return allOptions;
38807 }
38808 /**
38809 * Reset the random number generator with given seed.
38810 *
38811 * @param {any} seed - The seed that will be forwarded the the RNG.
38812 */
38813
38814 }, {
38815 key: "_resetRNG",
38816 value: function _resetRNG(seed) {
38817 this.initialRandomSeed = seed;
38818 this._rng = Alea(this.initialRandomSeed);
38819 }
38820 /**
38821 *
38822 * @param {object} allOptions
38823 * @returns {object}
38824 */
38825
38826 }, {
38827 key: "adaptAllOptionsForHierarchicalLayout",
38828 value: function adaptAllOptionsForHierarchicalLayout(allOptions) {
38829 if (this.options.hierarchical.enabled === true) {
38830 var backupPhysics = this.optionsBackup.physics; // set the physics
38831
38832 if (allOptions.physics === undefined || allOptions.physics === true) {
38833 allOptions.physics = {
38834 enabled: backupPhysics.enabled === undefined ? true : backupPhysics.enabled,
38835 solver: "hierarchicalRepulsion"
38836 };
38837 backupPhysics.enabled = backupPhysics.enabled === undefined ? true : backupPhysics.enabled;
38838 backupPhysics.solver = backupPhysics.solver || "barnesHut";
38839 } else if (_typeof(allOptions.physics) === "object") {
38840 backupPhysics.enabled = allOptions.physics.enabled === undefined ? true : allOptions.physics.enabled;
38841 backupPhysics.solver = allOptions.physics.solver || "barnesHut";
38842 allOptions.physics.solver = "hierarchicalRepulsion";
38843 } else if (allOptions.physics !== false) {
38844 backupPhysics.solver = "barnesHut";
38845 allOptions.physics = {
38846 solver: "hierarchicalRepulsion"
38847 };
38848 } // get the type of static smooth curve in case it is required
38849
38850
38851 var type = this.direction.curveType(); // disable smooth curves if nothing is defined. If smooth curves have been turned on,
38852 // turn them into static smooth curves.
38853
38854 if (allOptions.edges === undefined) {
38855 this.optionsBackup.edges = {
38856 smooth: {
38857 enabled: true,
38858 type: "dynamic"
38859 }
38860 };
38861 allOptions.edges = {
38862 smooth: false
38863 };
38864 } else if (allOptions.edges.smooth === undefined) {
38865 this.optionsBackup.edges = {
38866 smooth: {
38867 enabled: true,
38868 type: "dynamic"
38869 }
38870 };
38871 allOptions.edges.smooth = false;
38872 } else {
38873 if (typeof allOptions.edges.smooth === "boolean") {
38874 this.optionsBackup.edges = {
38875 smooth: allOptions.edges.smooth
38876 };
38877 allOptions.edges.smooth = {
38878 enabled: allOptions.edges.smooth,
38879 type: type
38880 };
38881 } else {
38882 var smooth = allOptions.edges.smooth; // allow custom types except for dynamic
38883
38884 if (smooth.type !== undefined && smooth.type !== "dynamic") {
38885 type = smooth.type;
38886 } // TODO: this is options merging; see if the standard routines can be used here.
38887
38888
38889 this.optionsBackup.edges = {
38890 smooth: {
38891 enabled: smooth.enabled === undefined ? true : smooth.enabled,
38892 type: smooth.type === undefined ? "dynamic" : smooth.type,
38893 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
38894 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
38895 }
38896 }; // NOTE: Copying an object to self; this is basically setting defaults for undefined variables
38897
38898 allOptions.edges.smooth = {
38899 enabled: smooth.enabled === undefined ? true : smooth.enabled,
38900 type: type,
38901 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
38902 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
38903 };
38904 }
38905 } // Force all edges into static smooth curves.
38906 // Only applies to edges that do not use the global options for smooth.
38907
38908
38909 this.body.emitter.emit("_forceDisableDynamicCurves", type);
38910 }
38911
38912 return allOptions;
38913 }
38914 /**
38915 *
38916 * @param {Array.<Node>} nodesArray
38917 */
38918
38919 }, {
38920 key: "positionInitially",
38921 value: function positionInitially(nodesArray) {
38922 if (this.options.hierarchical.enabled !== true) {
38923 this._resetRNG(this.initialRandomSeed);
38924
38925 var radius = nodesArray.length + 50;
38926
38927 for (var i = 0; i < nodesArray.length; i++) {
38928 var node = nodesArray[i];
38929
38930 var angle = 2 * Math.PI * this._rng();
38931
38932 if (node.x === undefined) {
38933 node.x = radius * Math.cos(angle);
38934 }
38935
38936 if (node.y === undefined) {
38937 node.y = radius * Math.sin(angle);
38938 }
38939 }
38940 }
38941 }
38942 /**
38943 * Use Kamada Kawai to position nodes. This is quite a heavy algorithm so if there are a lot of nodes we
38944 * cluster them first to reduce the amount.
38945 */
38946
38947 }, {
38948 key: "layoutNetwork",
38949 value: function layoutNetwork() {
38950 if (this.options.hierarchical.enabled !== true && this.options.improvedLayout === true) {
38951 var indices = this.body.nodeIndices; // first check if we should Kamada Kawai to layout. The threshold is if less than half of the visible
38952 // nodes have predefined positions we use this.
38953
38954 var positionDefined = 0;
38955
38956 for (var i = 0; i < indices.length; i++) {
38957 var node = this.body.nodes[indices[i]];
38958
38959 if (node.predefinedPosition === true) {
38960 positionDefined += 1;
38961 }
38962 } // if less than half of the nodes have a predefined position we continue
38963
38964
38965 if (positionDefined < 0.5 * indices.length) {
38966 var MAX_LEVELS = 10;
38967 var level = 0;
38968 var clusterThreshold = this.options.clusterThreshold; //
38969 // Define the options for the hidden cluster nodes
38970 // These options don't propagate outside the clustering phase.
38971 //
38972 // Some options are explicitly disabled, because they may be set in group or default node options.
38973 // The clusters are never displayed, so most explicit settings here serve as performance optimizations.
38974 //
38975 // The explicit setting of 'shape' is to avoid `shape: 'image'`; images are not passed to the hidden
38976 // cluster nodes, leading to an exception on creation.
38977 //
38978 // All settings here are performance related, except when noted otherwise.
38979 //
38980
38981 var clusterOptions = {
38982 clusterNodeProperties: {
38983 shape: "ellipse",
38984 // Bugfix: avoid type 'image', no images supplied
38985 label: "",
38986 // avoid label handling
38987 group: "",
38988 // avoid group handling
38989 font: {
38990 multi: false
38991 } // avoid font propagation
38992
38993 },
38994 clusterEdgeProperties: {
38995 label: "",
38996 // avoid label handling
38997 font: {
38998 multi: false
38999 },
39000 // avoid font propagation
39001 smooth: {
39002 enabled: false // avoid drawing penalty for complex edges
39003
39004 }
39005 }
39006 }; // if there are a lot of nodes, we cluster before we run the algorithm.
39007 // NOTE: this part fails to find clusters for large scale-free networks, which should
39008 // be easily clusterable.
39009 // TODO: examine why this is so
39010
39011 if (indices.length > clusterThreshold) {
39012 var startLength = indices.length;
39013
39014 while (indices.length > clusterThreshold && level <= MAX_LEVELS) {
39015 //console.time("clustering")
39016 level += 1;
39017 var before = indices.length; // if there are many nodes we do a hubsize cluster
39018
39019 if (level % 3 === 0) {
39020 this.body.modules.clustering.clusterBridges(clusterOptions);
39021 } else {
39022 this.body.modules.clustering.clusterOutliers(clusterOptions);
39023 }
39024
39025 var after = indices.length;
39026
39027 if (before == after && level % 3 !== 0) {
39028 this._declusterAll();
39029
39030 this.body.emitter.emit("_layoutFailed");
39031 console.info("This network could not be positioned by this version of the improved layout algorithm." + " Please disable improvedLayout for better performance.");
39032 return;
39033 } //console.timeEnd("clustering")
39034 //console.log(before,level,after);
39035
39036 } // increase the size of the edges
39037
39038
39039 this.body.modules.kamadaKawai.setOptions({
39040 springLength: Math.max(150, 2 * startLength)
39041 });
39042 }
39043
39044 if (level > MAX_LEVELS) {
39045 console.info("The clustering didn't succeed within the amount of interations allowed," + " progressing with partial result.");
39046 } // position the system for these nodes and edges
39047
39048
39049 this.body.modules.kamadaKawai.solve(indices, this.body.edgeIndices, true); // shift to center point
39050
39051 this._shiftToCenter(); // perturb the nodes a little bit to force the physics to kick in
39052
39053
39054 var offset = 70;
39055
39056 for (var _i = 0; _i < indices.length; _i++) {
39057 // Only perturb the nodes that aren't fixed
39058 var _node = this.body.nodes[indices[_i]];
39059
39060 if (_node.predefinedPosition === false) {
39061 _node.x += (0.5 - this._rng()) * offset;
39062 _node.y += (0.5 - this._rng()) * offset;
39063 }
39064 } // uncluster all clusters
39065
39066
39067 this._declusterAll(); // reposition all bezier nodes.
39068
39069
39070 this.body.emitter.emit("_repositionBezierNodes");
39071 }
39072 }
39073 }
39074 /**
39075 * Move all the nodes towards to the center so gravitational pull wil not move the nodes away from view
39076 *
39077 * @private
39078 */
39079
39080 }, {
39081 key: "_shiftToCenter",
39082 value: function _shiftToCenter() {
39083 var range = NetworkUtil.getRangeCore(this.body.nodes, this.body.nodeIndices);
39084 var center = NetworkUtil.findCenter(range);
39085
39086 for (var i = 0; i < this.body.nodeIndices.length; i++) {
39087 var node = this.body.nodes[this.body.nodeIndices[i]];
39088 node.x -= center.x;
39089 node.y -= center.y;
39090 }
39091 }
39092 /**
39093 * Expands all clusters
39094 *
39095 * @private
39096 */
39097
39098 }, {
39099 key: "_declusterAll",
39100 value: function _declusterAll() {
39101 var clustersPresent = true;
39102
39103 while (clustersPresent === true) {
39104 clustersPresent = false;
39105
39106 for (var i = 0; i < this.body.nodeIndices.length; i++) {
39107 if (this.body.nodes[this.body.nodeIndices[i]].isCluster === true) {
39108 clustersPresent = true;
39109 this.body.modules.clustering.openCluster(this.body.nodeIndices[i], {}, false);
39110 }
39111 }
39112
39113 if (clustersPresent === true) {
39114 this.body.emitter.emit("_dataChanged");
39115 }
39116 }
39117 }
39118 /**
39119 *
39120 * @returns {number|*}
39121 */
39122
39123 }, {
39124 key: "getSeed",
39125 value: function getSeed() {
39126 return this.initialRandomSeed;
39127 }
39128 /**
39129 * This is the main function to layout the nodes in a hierarchical way.
39130 * It checks if the node details are supplied correctly
39131 *
39132 * @private
39133 */
39134
39135 }, {
39136 key: "setupHierarchicalLayout",
39137 value: function setupHierarchicalLayout() {
39138 if (this.options.hierarchical.enabled === true && this.body.nodeIndices.length > 0) {
39139 // get the size of the largest hubs and check if the user has defined a level for a node.
39140 var node, nodeId;
39141 var definedLevel = false;
39142 var undefinedLevel = false;
39143 this.lastNodeOnLevel = {};
39144 this.hierarchical = new HierarchicalStatus();
39145
39146 for (nodeId in this.body.nodes) {
39147 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
39148 node = this.body.nodes[nodeId];
39149
39150 if (node.options.level !== undefined) {
39151 definedLevel = true;
39152 this.hierarchical.levels[nodeId] = node.options.level;
39153 } else {
39154 undefinedLevel = true;
39155 }
39156 }
39157 } // if the user defined some levels but not all, alert and run without hierarchical layout
39158
39159
39160 if (undefinedLevel === true && definedLevel === true) {
39161 throw new Error("To use the hierarchical layout, nodes require either no predefined levels" + " or levels have to be defined for all nodes.");
39162 } else {
39163 // define levels if undefined by the users. Based on hubsize.
39164 if (undefinedLevel === true) {
39165 var sortMethod = this.options.hierarchical.sortMethod;
39166
39167 if (sortMethod === "hubsize") {
39168 this._determineLevelsByHubsize();
39169 } else if (sortMethod === "directed") {
39170 this._determineLevelsDirected();
39171 } else if (sortMethod === "custom") {
39172 this._determineLevelsCustomCallback();
39173 }
39174 } // fallback for cases where there are nodes but no edges
39175
39176
39177 for (var _nodeId2 in this.body.nodes) {
39178 if (Object.prototype.hasOwnProperty.call(this.body.nodes, _nodeId2)) {
39179 this.hierarchical.ensureLevel(_nodeId2);
39180 }
39181 } // check the distribution of the nodes per level.
39182
39183
39184 var distribution = this._getDistribution(); // get the parent children relations.
39185
39186
39187 this._generateMap(); // place the nodes on the canvas.
39188
39189
39190 this._placeNodesByHierarchy(distribution); // condense the whitespace.
39191
39192
39193 this._condenseHierarchy(); // shift to center so gravity does not have to do much
39194
39195
39196 this._shiftToCenter();
39197 }
39198 }
39199 }
39200 /**
39201 * @private
39202 */
39203
39204 }, {
39205 key: "_condenseHierarchy",
39206 value: function _condenseHierarchy() {
39207 var _this3 = this;
39208
39209 // Global var in this scope to define when the movement has stopped.
39210 var stillShifting = false;
39211 var branches = {}; // first we have some methods to help shifting trees around.
39212 // the main method to shift the trees
39213
39214 var shiftTrees = function shiftTrees() {
39215 var treeSizes = getTreeSizes();
39216 var shiftBy = 0;
39217
39218 for (var i = 0; i < treeSizes.length - 1; i++) {
39219 var diff = treeSizes[i].max - treeSizes[i + 1].min;
39220 shiftBy += diff + _this3.options.hierarchical.treeSpacing;
39221 shiftTree(i + 1, shiftBy);
39222 }
39223 }; // shift a single tree by an offset
39224
39225
39226 var shiftTree = function shiftTree(index, offset) {
39227 var trees = _this3.hierarchical.trees;
39228
39229 for (var nodeId in trees) {
39230 if (Object.prototype.hasOwnProperty.call(trees, nodeId)) {
39231 if (trees[nodeId] === index) {
39232 _this3.direction.shift(nodeId, offset);
39233 }
39234 }
39235 }
39236 }; // get the width of all trees
39237
39238
39239 var getTreeSizes = function getTreeSizes() {
39240 var treeWidths = [];
39241
39242 for (var i = 0; i < _this3.hierarchical.numTrees(); i++) {
39243 treeWidths.push(_this3.direction.getTreeSize(i));
39244 }
39245
39246 return treeWidths;
39247 }; // get a map of all nodes in this branch
39248
39249
39250 var getBranchNodes = function getBranchNodes(source, map) {
39251 if (map[source.id]) {
39252 return;
39253 }
39254
39255 map[source.id] = true;
39256
39257 if (_this3.hierarchical.childrenReference[source.id]) {
39258 var children = _this3.hierarchical.childrenReference[source.id];
39259
39260 if (children.length > 0) {
39261 for (var i = 0; i < children.length; i++) {
39262 getBranchNodes(_this3.body.nodes[children[i]], map);
39263 }
39264 }
39265 }
39266 }; // get a min max width as well as the maximum movement space it has on either sides
39267 // we use min max terminology because width and height can interchange depending on the direction of the layout
39268
39269
39270 var getBranchBoundary = function getBranchBoundary(branchMap) {
39271 var maxLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1e9;
39272 var minSpace = 1e9;
39273 var maxSpace = 1e9;
39274 var min = 1e9;
39275 var max = -1e9;
39276
39277 for (var branchNode in branchMap) {
39278 if (Object.prototype.hasOwnProperty.call(branchMap, branchNode)) {
39279 var node = _this3.body.nodes[branchNode];
39280 var level = _this3.hierarchical.levels[node.id];
39281
39282 var position = _this3.direction.getPosition(node); // get the space around the node.
39283
39284
39285 var _this3$_getSpaceAroun = _this3._getSpaceAroundNode(node, branchMap),
39286 _this3$_getSpaceAroun2 = _slicedToArray(_this3$_getSpaceAroun, 2),
39287 minSpaceNode = _this3$_getSpaceAroun2[0],
39288 maxSpaceNode = _this3$_getSpaceAroun2[1];
39289
39290 minSpace = Math.min(minSpaceNode, minSpace);
39291 maxSpace = Math.min(maxSpaceNode, maxSpace); // the width is only relevant for the levels two nodes have in common. This is why we filter on this.
39292
39293 if (level <= maxLevel) {
39294 min = Math.min(position, min);
39295 max = Math.max(position, max);
39296 }
39297 }
39298 }
39299
39300 return [min, max, minSpace, maxSpace];
39301 }; // check what the maximum level is these nodes have in common.
39302
39303
39304 var getCollisionLevel = function getCollisionLevel(node1, node2) {
39305 var maxLevel1 = _this3.hierarchical.getMaxLevel(node1.id);
39306
39307 var maxLevel2 = _this3.hierarchical.getMaxLevel(node2.id);
39308
39309 return Math.min(maxLevel1, maxLevel2);
39310 };
39311 /**
39312 * Condense elements. These can be nodes or branches depending on the callback.
39313 *
39314 * @param {Function} callback
39315 * @param {Array.<number>} levels
39316 * @param {*} centerParents
39317 */
39318
39319
39320 var shiftElementsCloser = function shiftElementsCloser(callback, levels, centerParents) {
39321 var hier = _this3.hierarchical;
39322
39323 for (var i = 0; i < levels.length; i++) {
39324 var level = levels[i];
39325 var levelNodes = hier.distributionOrdering[level];
39326
39327 if (levelNodes.length > 1) {
39328 for (var j = 0; j < levelNodes.length - 1; j++) {
39329 var node1 = levelNodes[j];
39330 var node2 = levelNodes[j + 1]; // NOTE: logic maintained as it was; if nodes have same ancestor,
39331 // then of course they are in the same sub-network.
39332
39333 if (hier.hasSameParent(node1, node2) && hier.inSameSubNetwork(node1, node2)) {
39334 callback(node1, node2, centerParents);
39335 }
39336 }
39337 }
39338 }
39339 }; // callback for shifting branches
39340
39341
39342 var branchShiftCallback = function branchShiftCallback(node1, node2) {
39343 var centerParent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
39344
39345 //window.CALLBACKS.push(() => {
39346 var pos1 = _this3.direction.getPosition(node1);
39347
39348 var pos2 = _this3.direction.getPosition(node2);
39349
39350 var diffAbs = Math.abs(pos2 - pos1);
39351 var nodeSpacing = _this3.options.hierarchical.nodeSpacing; //console.log("NOW CHECKING:", node1.id, node2.id, diffAbs);
39352
39353 if (diffAbs > nodeSpacing) {
39354 var branchNodes1 = {};
39355 var branchNodes2 = {};
39356 getBranchNodes(node1, branchNodes1);
39357 getBranchNodes(node2, branchNodes2); // check the largest distance between the branches
39358
39359 var maxLevel = getCollisionLevel(node1, node2);
39360 var branchNodeBoundary1 = getBranchBoundary(branchNodes1, maxLevel);
39361 var branchNodeBoundary2 = getBranchBoundary(branchNodes2, maxLevel);
39362 var max1 = branchNodeBoundary1[1];
39363 var min2 = branchNodeBoundary2[0];
39364 var minSpace2 = branchNodeBoundary2[2]; //console.log(node1.id, getBranchBoundary(branchNodes1, maxLevel), node2.id,
39365 // getBranchBoundary(branchNodes2, maxLevel), maxLevel);
39366
39367 var diffBranch = Math.abs(max1 - min2);
39368
39369 if (diffBranch > nodeSpacing) {
39370 var offset = max1 - min2 + nodeSpacing;
39371
39372 if (offset < -minSpace2 + nodeSpacing) {
39373 offset = -minSpace2 + nodeSpacing; //console.log("RESETTING OFFSET", max1 - min2 + this.options.hierarchical.nodeSpacing, -minSpace2, offset);
39374 }
39375
39376 if (offset < 0) {
39377 //console.log("SHIFTING", node2.id, offset);
39378 _this3._shiftBlock(node2.id, offset);
39379
39380 stillShifting = true;
39381 if (centerParent === true) _this3._centerParent(node2);
39382 }
39383 }
39384 } //this.body.emitter.emit("_redraw");})
39385
39386 };
39387
39388 var minimizeEdgeLength = function minimizeEdgeLength(iterations, node) {
39389 //window.CALLBACKS.push(() => {
39390 // console.log("ts",node.id);
39391 var nodeId = node.id;
39392 var allEdges = node.edges;
39393 var nodeLevel = _this3.hierarchical.levels[node.id]; // gather constants
39394
39395 var C2 = _this3.options.hierarchical.levelSeparation * _this3.options.hierarchical.levelSeparation;
39396 var referenceNodes = {};
39397 var aboveEdges = [];
39398
39399 for (var i = 0; i < allEdges.length; i++) {
39400 var edge = allEdges[i];
39401
39402 if (edge.toId != edge.fromId) {
39403 var otherNode = edge.toId == nodeId ? edge.from : edge.to;
39404 referenceNodes[allEdges[i].id] = otherNode;
39405
39406 if (_this3.hierarchical.levels[otherNode.id] < nodeLevel) {
39407 aboveEdges.push(edge);
39408 }
39409 }
39410 } // differentiated sum of lengths based on only moving one node over one axis
39411
39412
39413 var getFx = function getFx(point, edges) {
39414 var sum = 0;
39415
39416 for (var _i2 = 0; _i2 < edges.length; _i2++) {
39417 if (referenceNodes[edges[_i2].id] !== undefined) {
39418 var a = _this3.direction.getPosition(referenceNodes[edges[_i2].id]) - point;
39419 sum += a / Math.sqrt(a * a + C2);
39420 }
39421 }
39422
39423 return sum;
39424 }; // doubly differentiated sum of lengths based on only moving one node over one axis
39425
39426
39427 var getDFx = function getDFx(point, edges) {
39428 var sum = 0;
39429
39430 for (var _i3 = 0; _i3 < edges.length; _i3++) {
39431 if (referenceNodes[edges[_i3].id] !== undefined) {
39432 var a = _this3.direction.getPosition(referenceNodes[edges[_i3].id]) - point;
39433 sum -= C2 * Math.pow(a * a + C2, -1.5);
39434 }
39435 }
39436
39437 return sum;
39438 };
39439
39440 var getGuess = function getGuess(iterations, edges) {
39441 var guess = _this3.direction.getPosition(node); // Newton's method for optimization
39442
39443
39444 var guessMap = {};
39445
39446 for (var _i4 = 0; _i4 < iterations; _i4++) {
39447 var fx = getFx(guess, edges);
39448 var dfx = getDFx(guess, edges); // we limit the movement to avoid instability.
39449
39450 var limit = 40;
39451 var ratio = Math.max(-limit, Math.min(limit, Math.round(fx / dfx)));
39452 guess = guess - ratio; // reduce duplicates
39453
39454 if (guessMap[guess] !== undefined) {
39455 break;
39456 }
39457
39458 guessMap[guess] = _i4;
39459 }
39460
39461 return guess;
39462 };
39463
39464 var moveBranch = function moveBranch(guess) {
39465 // position node if there is space
39466 var nodePosition = _this3.direction.getPosition(node); // check movable area of the branch
39467
39468
39469 if (branches[node.id] === undefined) {
39470 var branchNodes = {};
39471 getBranchNodes(node, branchNodes);
39472 branches[node.id] = branchNodes;
39473 }
39474
39475 var branchBoundary = getBranchBoundary(branches[node.id]);
39476 var minSpaceBranch = branchBoundary[2];
39477 var maxSpaceBranch = branchBoundary[3];
39478 var diff = guess - nodePosition; // check if we are allowed to move the node:
39479
39480 var branchOffset = 0;
39481
39482 if (diff > 0) {
39483 branchOffset = Math.min(diff, maxSpaceBranch - _this3.options.hierarchical.nodeSpacing);
39484 } else if (diff < 0) {
39485 branchOffset = -Math.min(-diff, minSpaceBranch - _this3.options.hierarchical.nodeSpacing);
39486 }
39487
39488 if (branchOffset != 0) {
39489 //console.log("moving branch:",branchOffset, maxSpaceBranch, minSpaceBranch)
39490 _this3._shiftBlock(node.id, branchOffset); //this.body.emitter.emit("_redraw");
39491
39492
39493 stillShifting = true;
39494 }
39495 };
39496
39497 var moveNode = function moveNode(guess) {
39498 var nodePosition = _this3.direction.getPosition(node); // position node if there is space
39499
39500
39501 var _this3$_getSpaceAroun3 = _this3._getSpaceAroundNode(node),
39502 _this3$_getSpaceAroun4 = _slicedToArray(_this3$_getSpaceAroun3, 2),
39503 minSpace = _this3$_getSpaceAroun4[0],
39504 maxSpace = _this3$_getSpaceAroun4[1];
39505
39506 var diff = guess - nodePosition; // check if we are allowed to move the node:
39507
39508 var newPosition = nodePosition;
39509
39510 if (diff > 0) {
39511 newPosition = Math.min(nodePosition + (maxSpace - _this3.options.hierarchical.nodeSpacing), guess);
39512 } else if (diff < 0) {
39513 newPosition = Math.max(nodePosition - (minSpace - _this3.options.hierarchical.nodeSpacing), guess);
39514 }
39515
39516 if (newPosition !== nodePosition) {
39517 //console.log("moving Node:",diff, minSpace, maxSpace);
39518 _this3.direction.setPosition(node, newPosition); //this.body.emitter.emit("_redraw");
39519
39520
39521 stillShifting = true;
39522 }
39523 };
39524
39525 var guess = getGuess(iterations, aboveEdges);
39526 moveBranch(guess);
39527 guess = getGuess(iterations, allEdges);
39528 moveNode(guess); //})
39529 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
39530
39531
39532 var minimizeEdgeLengthBottomUp = function minimizeEdgeLengthBottomUp(iterations) {
39533 var levels = _this3.hierarchical.getLevels();
39534
39535 levels = reverse(levels).call(levels);
39536
39537 for (var i = 0; i < iterations; i++) {
39538 stillShifting = false;
39539
39540 for (var j = 0; j < levels.length; j++) {
39541 var level = levels[j];
39542 var levelNodes = _this3.hierarchical.distributionOrdering[level];
39543
39544 for (var k = 0; k < levelNodes.length; k++) {
39545 minimizeEdgeLength(1000, levelNodes[k]);
39546 }
39547 }
39548
39549 if (stillShifting !== true) {
39550 //console.log("FINISHED minimizeEdgeLengthBottomUp IN " + i);
39551 break;
39552 }
39553 }
39554 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
39555
39556
39557 var shiftBranchesCloserBottomUp = function shiftBranchesCloserBottomUp(iterations) {
39558 var levels = _this3.hierarchical.getLevels();
39559
39560 levels = reverse(levels).call(levels);
39561
39562 for (var i = 0; i < iterations; i++) {
39563 stillShifting = false;
39564 shiftElementsCloser(branchShiftCallback, levels, true);
39565
39566 if (stillShifting !== true) {
39567 //console.log("FINISHED shiftBranchesCloserBottomUp IN " + (i+1));
39568 break;
39569 }
39570 }
39571 }; // center all parents
39572
39573
39574 var centerAllParents = function centerAllParents() {
39575 for (var nodeId in _this3.body.nodes) {
39576 if (Object.prototype.hasOwnProperty.call(_this3.body.nodes, nodeId)) _this3._centerParent(_this3.body.nodes[nodeId]);
39577 }
39578 }; // center all parents
39579
39580
39581 var centerAllParentsBottomUp = function centerAllParentsBottomUp() {
39582 var levels = _this3.hierarchical.getLevels();
39583
39584 levels = reverse(levels).call(levels);
39585
39586 for (var i = 0; i < levels.length; i++) {
39587 var level = levels[i];
39588 var levelNodes = _this3.hierarchical.distributionOrdering[level];
39589
39590 for (var j = 0; j < levelNodes.length; j++) {
39591 _this3._centerParent(levelNodes[j]);
39592 }
39593 }
39594 }; // the actual work is done here.
39595
39596
39597 if (this.options.hierarchical.blockShifting === true) {
39598 shiftBranchesCloserBottomUp(5);
39599 centerAllParents();
39600 } // minimize edge length
39601
39602
39603 if (this.options.hierarchical.edgeMinimization === true) {
39604 minimizeEdgeLengthBottomUp(20);
39605 }
39606
39607 if (this.options.hierarchical.parentCentralization === true) {
39608 centerAllParentsBottomUp();
39609 }
39610
39611 shiftTrees();
39612 }
39613 /**
39614 * This gives the space around the node. IF a map is supplied, it will only check against nodes NOT in the map.
39615 * This is used to only get the distances to nodes outside of a branch.
39616 *
39617 * @param {Node} node
39618 * @param {{Node.id: vis.Node}} map
39619 * @returns {number[]}
39620 * @private
39621 */
39622
39623 }, {
39624 key: "_getSpaceAroundNode",
39625 value: function _getSpaceAroundNode(node, map) {
39626 var useMap = true;
39627
39628 if (map === undefined) {
39629 useMap = false;
39630 }
39631
39632 var level = this.hierarchical.levels[node.id];
39633
39634 if (level !== undefined) {
39635 var index = this.hierarchical.distributionIndex[node.id];
39636 var position = this.direction.getPosition(node);
39637 var ordering = this.hierarchical.distributionOrdering[level];
39638 var minSpace = 1e9;
39639 var maxSpace = 1e9;
39640
39641 if (index !== 0) {
39642 var prevNode = ordering[index - 1];
39643
39644 if (useMap === true && map[prevNode.id] === undefined || useMap === false) {
39645 var prevPos = this.direction.getPosition(prevNode);
39646 minSpace = position - prevPos;
39647 }
39648 }
39649
39650 if (index != ordering.length - 1) {
39651 var nextNode = ordering[index + 1];
39652
39653 if (useMap === true && map[nextNode.id] === undefined || useMap === false) {
39654 var nextPos = this.direction.getPosition(nextNode);
39655 maxSpace = Math.min(maxSpace, nextPos - position);
39656 }
39657 }
39658
39659 return [minSpace, maxSpace];
39660 } else {
39661 return [0, 0];
39662 }
39663 }
39664 /**
39665 * We use this method to center a parent node and check if it does not cross other nodes when it does.
39666 *
39667 * @param {Node} node
39668 * @private
39669 */
39670
39671 }, {
39672 key: "_centerParent",
39673 value: function _centerParent(node) {
39674 if (this.hierarchical.parentReference[node.id]) {
39675 var parents = this.hierarchical.parentReference[node.id];
39676
39677 for (var i = 0; i < parents.length; i++) {
39678 var parentId = parents[i];
39679 var parentNode = this.body.nodes[parentId];
39680 var children = this.hierarchical.childrenReference[parentId];
39681
39682 if (children !== undefined) {
39683 // get the range of the children
39684 var newPosition = this._getCenterPosition(children);
39685
39686 var position = this.direction.getPosition(parentNode);
39687
39688 var _this$_getSpaceAround = this._getSpaceAroundNode(parentNode),
39689 _this$_getSpaceAround2 = _slicedToArray(_this$_getSpaceAround, 2),
39690 minSpace = _this$_getSpaceAround2[0],
39691 maxSpace = _this$_getSpaceAround2[1];
39692
39693 var diff = position - newPosition;
39694
39695 if (diff < 0 && Math.abs(diff) < maxSpace - this.options.hierarchical.nodeSpacing || diff > 0 && Math.abs(diff) < minSpace - this.options.hierarchical.nodeSpacing) {
39696 this.direction.setPosition(parentNode, newPosition);
39697 }
39698 }
39699 }
39700 }
39701 }
39702 /**
39703 * This function places the nodes on the canvas based on the hierarchial distribution.
39704 *
39705 * @param {object} distribution | obtained by the function this._getDistribution()
39706 * @private
39707 */
39708
39709 }, {
39710 key: "_placeNodesByHierarchy",
39711 value: function _placeNodesByHierarchy(distribution) {
39712 this.positionedNodes = {}; // start placing all the level 0 nodes first. Then recursively position their branches.
39713
39714 for (var level in distribution) {
39715 if (Object.prototype.hasOwnProperty.call(distribution, level)) {
39716 var _context;
39717
39718 // sort nodes in level by position:
39719 var nodeArray = keys$3(distribution[level]);
39720
39721 nodeArray = this._indexArrayToNodes(nodeArray);
39722
39723 sort(_context = this.direction).call(_context, nodeArray);
39724
39725 var handledNodeCount = 0;
39726
39727 for (var i = 0; i < nodeArray.length; i++) {
39728 var node = nodeArray[i];
39729
39730 if (this.positionedNodes[node.id] === undefined) {
39731 var spacing = this.options.hierarchical.nodeSpacing;
39732 var pos = spacing * handledNodeCount; // We get the X or Y values we need and store them in pos and previousPos.
39733 // The get and set make sure we get X or Y
39734
39735 if (handledNodeCount > 0) {
39736 pos = this.direction.getPosition(nodeArray[i - 1]) + spacing;
39737 }
39738
39739 this.direction.setPosition(node, pos, level);
39740
39741 this._validatePositionAndContinue(node, level, pos);
39742
39743 handledNodeCount++;
39744 }
39745 }
39746 }
39747 }
39748 }
39749 /**
39750 * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes
39751 * on a X position that ensures there will be no overlap.
39752 *
39753 * @param {Node.id} parentId
39754 * @param {number} parentLevel
39755 * @private
39756 */
39757
39758 }, {
39759 key: "_placeBranchNodes",
39760 value: function _placeBranchNodes(parentId, parentLevel) {
39761 var _context2;
39762
39763 var childRef = this.hierarchical.childrenReference[parentId]; // if this is not a parent, cancel the placing. This can happen with multiple parents to one child.
39764
39765 if (childRef === undefined) {
39766 return;
39767 } // get a list of childNodes
39768
39769
39770 var childNodes = [];
39771
39772 for (var i = 0; i < childRef.length; i++) {
39773 childNodes.push(this.body.nodes[childRef[i]]);
39774 } // use the positions to order the nodes.
39775
39776
39777 sort(_context2 = this.direction).call(_context2, childNodes); // position the childNodes
39778
39779
39780 for (var _i5 = 0; _i5 < childNodes.length; _i5++) {
39781 var childNode = childNodes[_i5];
39782 var childNodeLevel = this.hierarchical.levels[childNode.id]; // check if the child node is below the parent node and if it has already been positioned.
39783
39784 if (childNodeLevel > parentLevel && this.positionedNodes[childNode.id] === undefined) {
39785 // get the amount of space required for this node. If parent the width is based on the amount of children.
39786 var spacing = this.options.hierarchical.nodeSpacing;
39787 var pos = void 0; // we get the X or Y values we need and store them in pos and previousPos.
39788 // The get and set make sure we get X or Y
39789
39790 if (_i5 === 0) {
39791 pos = this.direction.getPosition(this.body.nodes[parentId]);
39792 } else {
39793 pos = this.direction.getPosition(childNodes[_i5 - 1]) + spacing;
39794 }
39795
39796 this.direction.setPosition(childNode, pos, childNodeLevel);
39797
39798 this._validatePositionAndContinue(childNode, childNodeLevel, pos);
39799 } else {
39800 return;
39801 }
39802 } // center the parent nodes.
39803
39804
39805 var center = this._getCenterPosition(childNodes);
39806
39807 this.direction.setPosition(this.body.nodes[parentId], center, parentLevel);
39808 }
39809 /**
39810 * This method checks for overlap and if required shifts the branch. It also keeps records of positioned nodes.
39811 * Finally it will call _placeBranchNodes to place the branch nodes.
39812 *
39813 * @param {Node} node
39814 * @param {number} level
39815 * @param {number} pos
39816 * @private
39817 */
39818
39819 }, {
39820 key: "_validatePositionAndContinue",
39821 value: function _validatePositionAndContinue(node, level, pos) {
39822 // This method only works for formal trees and formal forests
39823 // Early exit if this is not the case
39824 if (!this.hierarchical.isTree) return; // if overlap has been detected, we shift the branch
39825
39826 if (this.lastNodeOnLevel[level] !== undefined) {
39827 var previousPos = this.direction.getPosition(this.body.nodes[this.lastNodeOnLevel[level]]);
39828
39829 if (pos - previousPos < this.options.hierarchical.nodeSpacing) {
39830 var diff = previousPos + this.options.hierarchical.nodeSpacing - pos;
39831
39832 var sharedParent = this._findCommonParent(this.lastNodeOnLevel[level], node.id);
39833
39834 this._shiftBlock(sharedParent.withChild, diff);
39835 }
39836 }
39837
39838 this.lastNodeOnLevel[level] = node.id; // store change in position.
39839
39840 this.positionedNodes[node.id] = true;
39841
39842 this._placeBranchNodes(node.id, level);
39843 }
39844 /**
39845 * Receives an array with node indices and returns an array with the actual node references.
39846 * Used for sorting based on node properties.
39847 *
39848 * @param {Array.<Node.id>} idArray
39849 * @returns {Array.<Node>}
39850 */
39851
39852 }, {
39853 key: "_indexArrayToNodes",
39854 value: function _indexArrayToNodes(idArray) {
39855 var array = [];
39856
39857 for (var i = 0; i < idArray.length; i++) {
39858 array.push(this.body.nodes[idArray[i]]);
39859 }
39860
39861 return array;
39862 }
39863 /**
39864 * This function get the distribution of levels based on hubsize
39865 *
39866 * @returns {object}
39867 * @private
39868 */
39869
39870 }, {
39871 key: "_getDistribution",
39872 value: function _getDistribution() {
39873 var distribution = {};
39874 var nodeId, node; // we fix Y because the hierarchy is vertical,
39875 // we fix X so we do not give a node an x position for a second time.
39876 // the fix of X is removed after the x value has been set.
39877
39878 for (nodeId in this.body.nodes) {
39879 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
39880 node = this.body.nodes[nodeId];
39881 var level = this.hierarchical.levels[nodeId] === undefined ? 0 : this.hierarchical.levels[nodeId];
39882 this.direction.fix(node, level);
39883
39884 if (distribution[level] === undefined) {
39885 distribution[level] = {};
39886 }
39887
39888 distribution[level][nodeId] = node;
39889 }
39890 }
39891
39892 return distribution;
39893 }
39894 /**
39895 * Return the active (i.e. visible) edges for this node
39896 *
39897 * @param {Node} node
39898 * @returns {Array.<vis.Edge>} Array of edge instances
39899 * @private
39900 */
39901
39902 }, {
39903 key: "_getActiveEdges",
39904 value: function _getActiveEdges(node) {
39905 var _this4 = this;
39906
39907 var result = [];
39908 forEach$1(node.edges, function (edge) {
39909 var _context3;
39910
39911 if (indexOf(_context3 = _this4.body.edgeIndices).call(_context3, edge.id) !== -1) {
39912 result.push(edge);
39913 }
39914 });
39915 return result;
39916 }
39917 /**
39918 * Get the hubsizes for all active nodes.
39919 *
39920 * @returns {number}
39921 * @private
39922 */
39923
39924 }, {
39925 key: "_getHubSizes",
39926 value: function _getHubSizes() {
39927 var _this5 = this;
39928
39929 var hubSizes = {};
39930 var nodeIds = this.body.nodeIndices;
39931 forEach$1(nodeIds, function (nodeId) {
39932 var node = _this5.body.nodes[nodeId];
39933
39934 var hubSize = _this5._getActiveEdges(node).length;
39935
39936 hubSizes[hubSize] = true;
39937 }); // Make an array of the size sorted descending
39938
39939 var result = [];
39940 forEach$1(hubSizes, function (size) {
39941 result.push(Number(size));
39942 });
39943
39944 sort(timsort).call(timsort, result, function (a, b) {
39945 return b - a;
39946 });
39947
39948 return result;
39949 }
39950 /**
39951 * this function allocates nodes in levels based on the recursive branching from the largest hubs.
39952 *
39953 * @private
39954 */
39955
39956 }, {
39957 key: "_determineLevelsByHubsize",
39958 value: function _determineLevelsByHubsize() {
39959 var _this6 = this;
39960
39961 var levelDownstream = function levelDownstream(nodeA, nodeB) {
39962 _this6.hierarchical.levelDownstream(nodeA, nodeB);
39963 };
39964
39965 var hubSizes = this._getHubSizes();
39966
39967 var _loop = function _loop(i) {
39968 var hubSize = hubSizes[i];
39969 if (hubSize === 0) return "break";
39970 forEach$1(_this6.body.nodeIndices, function (nodeId) {
39971 var node = _this6.body.nodes[nodeId];
39972
39973 if (hubSize === _this6._getActiveEdges(node).length) {
39974 _this6._crawlNetwork(levelDownstream, nodeId);
39975 }
39976 });
39977 };
39978
39979 for (var i = 0; i < hubSizes.length; ++i) {
39980 var _ret = _loop(i);
39981
39982 if (_ret === "break") break;
39983 }
39984 }
39985 /**
39986 * TODO: release feature
39987 * TODO: Determine if this feature is needed at all
39988 *
39989 * @private
39990 */
39991
39992 }, {
39993 key: "_determineLevelsCustomCallback",
39994 value: function _determineLevelsCustomCallback() {
39995 var _this7 = this;
39996
39997 var minLevel = 100000; // TODO: this should come from options.
39998 // eslint-disable-next-line no-unused-vars -- This should eventually be implemented with these parameters used.
39999
40000 var customCallback = function customCallback(nodeA, nodeB, edge) {}; // TODO: perhaps move to HierarchicalStatus.
40001 // But I currently don't see the point, this method is not used.
40002
40003
40004 var levelByDirection = function levelByDirection(nodeA, nodeB, edge) {
40005 var levelA = _this7.hierarchical.levels[nodeA.id]; // set initial level
40006
40007 if (levelA === undefined) {
40008 levelA = _this7.hierarchical.levels[nodeA.id] = minLevel;
40009 }
40010
40011 var diff = customCallback(NetworkUtil.cloneOptions(nodeA, "node"), NetworkUtil.cloneOptions(nodeB, "node"), NetworkUtil.cloneOptions(edge, "edge"));
40012 _this7.hierarchical.levels[nodeB.id] = levelA + diff;
40013 };
40014
40015 this._crawlNetwork(levelByDirection);
40016
40017 this.hierarchical.setMinLevelToZero(this.body.nodes);
40018 }
40019 /**
40020 * Allocate nodes in levels based on the direction of the edges.
40021 *
40022 * @private
40023 */
40024
40025 }, {
40026 key: "_determineLevelsDirected",
40027 value: function _determineLevelsDirected() {
40028 var _context4,
40029 _this8 = this;
40030
40031 var nodes = reduce(_context4 = this.body.nodeIndices).call(_context4, function (acc, id) {
40032 acc.set(id, _this8.body.nodes[id]);
40033 return acc;
40034 }, new map());
40035
40036 if (this.options.hierarchical.shakeTowards === "roots") {
40037 this.hierarchical.levels = fillLevelsByDirectionRoots(nodes);
40038 } else {
40039 this.hierarchical.levels = fillLevelsByDirectionLeaves(nodes);
40040 }
40041
40042 this.hierarchical.setMinLevelToZero(this.body.nodes);
40043 }
40044 /**
40045 * Update the bookkeeping of parent and child.
40046 *
40047 * @private
40048 */
40049
40050 }, {
40051 key: "_generateMap",
40052 value: function _generateMap() {
40053 var _this9 = this;
40054
40055 var fillInRelations = function fillInRelations(parentNode, childNode) {
40056 if (_this9.hierarchical.levels[childNode.id] > _this9.hierarchical.levels[parentNode.id]) {
40057 _this9.hierarchical.addRelation(parentNode.id, childNode.id);
40058 }
40059 };
40060
40061 this._crawlNetwork(fillInRelations);
40062
40063 this.hierarchical.checkIfTree();
40064 }
40065 /**
40066 * Crawl over the entire network and use a callback on each node couple that is connected to each other.
40067 *
40068 * @param {Function} [callback=function(){}] | will receive nodeA, nodeB and the connecting edge. A and B are distinct.
40069 * @param {Node.id} startingNodeId
40070 * @private
40071 */
40072
40073 }, {
40074 key: "_crawlNetwork",
40075 value: function _crawlNetwork() {
40076 var _this10 = this;
40077
40078 var callback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
40079 var startingNodeId = arguments.length > 1 ? arguments[1] : undefined;
40080 var progress = {};
40081
40082 var crawler = function crawler(node, tree) {
40083 if (progress[node.id] === undefined) {
40084 _this10.hierarchical.setTreeIndex(node, tree);
40085
40086 progress[node.id] = true;
40087 var childNode;
40088
40089 var edges = _this10._getActiveEdges(node);
40090
40091 for (var i = 0; i < edges.length; i++) {
40092 var edge = edges[i];
40093
40094 if (edge.connected === true) {
40095 if (edge.toId == node.id) {
40096 // Not '===' because id's can be string and numeric
40097 childNode = edge.from;
40098 } else {
40099 childNode = edge.to;
40100 }
40101
40102 if (node.id != childNode.id) {
40103 // Not '!==' because id's can be string and numeric
40104 callback(node, childNode, edge);
40105 crawler(childNode, tree);
40106 }
40107 }
40108 }
40109 }
40110 };
40111
40112 if (startingNodeId === undefined) {
40113 // Crawl over all nodes
40114 var treeIndex = 0; // Serves to pass a unique id for the current distinct tree
40115
40116 for (var i = 0; i < this.body.nodeIndices.length; i++) {
40117 var nodeId = this.body.nodeIndices[i];
40118
40119 if (progress[nodeId] === undefined) {
40120 var node = this.body.nodes[nodeId];
40121 crawler(node, treeIndex);
40122 treeIndex += 1;
40123 }
40124 }
40125 } else {
40126 // Crawl from the given starting node
40127 var _node2 = this.body.nodes[startingNodeId];
40128
40129 if (_node2 === undefined) {
40130 console.error("Node not found:", startingNodeId);
40131 return;
40132 }
40133
40134 crawler(_node2);
40135 }
40136 }
40137 /**
40138 * Shift a branch a certain distance
40139 *
40140 * @param {Node.id} parentId
40141 * @param {number} diff
40142 * @private
40143 */
40144
40145 }, {
40146 key: "_shiftBlock",
40147 value: function _shiftBlock(parentId, diff) {
40148 var _this11 = this;
40149
40150 var progress = {};
40151
40152 var shifter = function shifter(parentId) {
40153 if (progress[parentId]) {
40154 return;
40155 }
40156
40157 progress[parentId] = true;
40158
40159 _this11.direction.shift(parentId, diff);
40160
40161 var childRef = _this11.hierarchical.childrenReference[parentId];
40162
40163 if (childRef !== undefined) {
40164 for (var i = 0; i < childRef.length; i++) {
40165 shifter(childRef[i]);
40166 }
40167 }
40168 };
40169
40170 shifter(parentId);
40171 }
40172 /**
40173 * Find a common parent between branches.
40174 *
40175 * @param {Node.id} childA
40176 * @param {Node.id} childB
40177 * @returns {{foundParent, withChild}}
40178 * @private
40179 */
40180
40181 }, {
40182 key: "_findCommonParent",
40183 value: function _findCommonParent(childA, childB) {
40184 var _this12 = this;
40185
40186 var parents = {};
40187
40188 var iterateParents = function iterateParents(parents, child) {
40189 var parentRef = _this12.hierarchical.parentReference[child];
40190
40191 if (parentRef !== undefined) {
40192 for (var i = 0; i < parentRef.length; i++) {
40193 var parent = parentRef[i];
40194 parents[parent] = true;
40195 iterateParents(parents, parent);
40196 }
40197 }
40198 };
40199
40200 var findParent = function findParent(parents, child) {
40201 var parentRef = _this12.hierarchical.parentReference[child];
40202
40203 if (parentRef !== undefined) {
40204 for (var i = 0; i < parentRef.length; i++) {
40205 var parent = parentRef[i];
40206
40207 if (parents[parent] !== undefined) {
40208 return {
40209 foundParent: parent,
40210 withChild: child
40211 };
40212 }
40213
40214 var branch = findParent(parents, parent);
40215
40216 if (branch.foundParent !== null) {
40217 return branch;
40218 }
40219 }
40220 }
40221
40222 return {
40223 foundParent: null,
40224 withChild: child
40225 };
40226 };
40227
40228 iterateParents(parents, childA);
40229 return findParent(parents, childB);
40230 }
40231 /**
40232 * Set the strategy pattern for handling the coordinates given the current direction.
40233 *
40234 * The individual instances contain all the operations and data specific to a layout direction.
40235 *
40236 * @param {Node} node
40237 * @param {{x: number, y: number}} position
40238 * @param {number} level
40239 * @param {boolean} [doNotUpdate=false]
40240 * @private
40241 */
40242
40243 }, {
40244 key: "setDirectionStrategy",
40245 value: function setDirectionStrategy() {
40246 var isVertical = this.options.hierarchical.direction === "UD" || this.options.hierarchical.direction === "DU";
40247
40248 if (isVertical) {
40249 this.direction = new VerticalStrategy(this);
40250 } else {
40251 this.direction = new HorizontalStrategy(this);
40252 }
40253 }
40254 /**
40255 * Determine the center position of a branch from the passed list of child nodes
40256 *
40257 * This takes into account the positions of all the child nodes.
40258 *
40259 * @param {Array.<Node|vis.Node.id>} childNodes Array of either child nodes or node id's
40260 * @returns {number}
40261 * @private
40262 */
40263
40264 }, {
40265 key: "_getCenterPosition",
40266 value: function _getCenterPosition(childNodes) {
40267 var minPos = 1e9;
40268 var maxPos = -1e9;
40269
40270 for (var i = 0; i < childNodes.length; i++) {
40271 var childNode = void 0;
40272
40273 if (childNodes[i].id !== undefined) {
40274 childNode = childNodes[i];
40275 } else {
40276 var childNodeId = childNodes[i];
40277 childNode = this.body.nodes[childNodeId];
40278 }
40279
40280 var position = this.direction.getPosition(childNode);
40281 minPos = Math.min(minPos, position);
40282 maxPos = Math.max(maxPos, position);
40283 }
40284
40285 return 0.5 * (minPos + maxPos);
40286 }
40287 }]);
40288
40289 return LayoutEngine;
40290}();
40291
40292function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
40293
40294function _unsupportedIterableToArray(o, minLen) { var _context32; if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = slice$1(_context32 = Object.prototype.toString.call(o)).call(_context32, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from_1$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
40295
40296function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
40297/**
40298 * Clears the toolbar div element of children
40299 *
40300 * @private
40301 */
40302
40303var ManipulationSystem = /*#__PURE__*/function () {
40304 /**
40305 * @param {object} body
40306 * @param {Canvas} canvas
40307 * @param {SelectionHandler} selectionHandler
40308 * @param {InteractionHandler} interactionHandler
40309 */
40310 function ManipulationSystem(body, canvas, selectionHandler, interactionHandler) {
40311 var _this = this,
40312 _context,
40313 _context2;
40314
40315 _classCallCheck(this, ManipulationSystem);
40316
40317 this.body = body;
40318 this.canvas = canvas;
40319 this.selectionHandler = selectionHandler;
40320 this.interactionHandler = interactionHandler;
40321 this.editMode = false;
40322 this.manipulationDiv = undefined;
40323 this.editModeDiv = undefined;
40324 this.closeDiv = undefined;
40325 this._domEventListenerCleanupQueue = [];
40326 this.temporaryUIFunctions = {};
40327 this.temporaryEventFunctions = [];
40328 this.touchTime = 0;
40329 this.temporaryIds = {
40330 nodes: [],
40331 edges: []
40332 };
40333 this.guiEnabled = false;
40334 this.inMode = false;
40335 this.selectedControlNode = undefined;
40336 this.options = {};
40337 this.defaultOptions = {
40338 enabled: false,
40339 initiallyActive: false,
40340 addNode: true,
40341 addEdge: true,
40342 editNode: undefined,
40343 editEdge: true,
40344 deleteNode: true,
40345 deleteEdge: true,
40346 controlNodeStyle: {
40347 shape: "dot",
40348 size: 6,
40349 color: {
40350 background: "#ff0000",
40351 border: "#3c3c3c",
40352 highlight: {
40353 background: "#07f968",
40354 border: "#3c3c3c"
40355 }
40356 },
40357 borderWidth: 2,
40358 borderWidthSelected: 2
40359 }
40360 };
40361
40362 assign$2(this.options, this.defaultOptions);
40363
40364 this.body.emitter.on("destroy", function () {
40365 _this._clean();
40366 });
40367 this.body.emitter.on("_dataChanged", bind(_context = this._restore).call(_context, this));
40368 this.body.emitter.on("_resetData", bind(_context2 = this._restore).call(_context2, this));
40369 }
40370 /**
40371 * If something changes in the data during editing, switch back to the initial datamanipulation state and close all edit modes.
40372 *
40373 * @private
40374 */
40375
40376
40377 _createClass(ManipulationSystem, [{
40378 key: "_restore",
40379 value: function _restore() {
40380 if (this.inMode !== false) {
40381 if (this.options.initiallyActive === true) {
40382 this.enableEditMode();
40383 } else {
40384 this.disableEditMode();
40385 }
40386 }
40387 }
40388 /**
40389 * Set the Options
40390 *
40391 * @param {object} options
40392 * @param {object} allOptions
40393 * @param {object} globalOptions
40394 */
40395
40396 }, {
40397 key: "setOptions",
40398 value: function setOptions(options, allOptions, globalOptions) {
40399 if (allOptions !== undefined) {
40400 if (allOptions.locale !== undefined) {
40401 this.options.locale = allOptions.locale;
40402 } else {
40403 this.options.locale = globalOptions.locale;
40404 }
40405
40406 if (allOptions.locales !== undefined) {
40407 this.options.locales = allOptions.locales;
40408 } else {
40409 this.options.locales = globalOptions.locales;
40410 }
40411 }
40412
40413 if (options !== undefined) {
40414 if (typeof options === "boolean") {
40415 this.options.enabled = options;
40416 } else {
40417 this.options.enabled = true;
40418 deepExtend(this.options, options);
40419 }
40420
40421 if (this.options.initiallyActive === true) {
40422 this.editMode = true;
40423 }
40424
40425 this._setup();
40426 }
40427 }
40428 /**
40429 * Enable or disable edit-mode. Draws the DOM required and cleans up after itself.
40430 *
40431 * @private
40432 */
40433
40434 }, {
40435 key: "toggleEditMode",
40436 value: function toggleEditMode() {
40437 if (this.editMode === true) {
40438 this.disableEditMode();
40439 } else {
40440 this.enableEditMode();
40441 }
40442 }
40443 /**
40444 * Enables Edit Mode
40445 */
40446
40447 }, {
40448 key: "enableEditMode",
40449 value: function enableEditMode() {
40450 this.editMode = true;
40451
40452 this._clean();
40453
40454 if (this.guiEnabled === true) {
40455 this.manipulationDiv.style.display = "block";
40456 this.closeDiv.style.display = "block";
40457 this.editModeDiv.style.display = "none";
40458 this.showManipulatorToolbar();
40459 }
40460 }
40461 /**
40462 * Disables Edit Mode
40463 */
40464
40465 }, {
40466 key: "disableEditMode",
40467 value: function disableEditMode() {
40468 this.editMode = false;
40469
40470 this._clean();
40471
40472 if (this.guiEnabled === true) {
40473 this.manipulationDiv.style.display = "none";
40474 this.closeDiv.style.display = "none";
40475 this.editModeDiv.style.display = "block";
40476
40477 this._createEditButton();
40478 }
40479 }
40480 /**
40481 * Creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar.
40482 *
40483 * @private
40484 */
40485
40486 }, {
40487 key: "showManipulatorToolbar",
40488 value: function showManipulatorToolbar() {
40489 // restore the state of any bound functions or events, remove control nodes, restore physics
40490 this._clean(); // reset global variables
40491
40492
40493 this.manipulationDOM = {}; // if the gui is enabled, draw all elements.
40494
40495 if (this.guiEnabled === true) {
40496 var _context3, _context4;
40497
40498 // a _restore will hide these menus
40499 this.editMode = true;
40500 this.manipulationDiv.style.display = "block";
40501 this.closeDiv.style.display = "block";
40502 var selectedNodeCount = this.selectionHandler.getSelectedNodeCount();
40503 var selectedEdgeCount = this.selectionHandler.getSelectedEdgeCount();
40504 var selectedTotalCount = selectedNodeCount + selectedEdgeCount;
40505 var locale = this.options.locales[this.options.locale];
40506 var needSeperator = false;
40507
40508 if (this.options.addNode !== false) {
40509 this._createAddNodeButton(locale);
40510
40511 needSeperator = true;
40512 }
40513
40514 if (this.options.addEdge !== false) {
40515 if (needSeperator === true) {
40516 this._createSeperator(1);
40517 } else {
40518 needSeperator = true;
40519 }
40520
40521 this._createAddEdgeButton(locale);
40522 }
40523
40524 if (selectedNodeCount === 1 && typeof this.options.editNode === "function") {
40525 if (needSeperator === true) {
40526 this._createSeperator(2);
40527 } else {
40528 needSeperator = true;
40529 }
40530
40531 this._createEditNodeButton(locale);
40532 } else if (selectedEdgeCount === 1 && selectedNodeCount === 0 && this.options.editEdge !== false) {
40533 if (needSeperator === true) {
40534 this._createSeperator(3);
40535 } else {
40536 needSeperator = true;
40537 }
40538
40539 this._createEditEdgeButton(locale);
40540 } // remove buttons
40541
40542
40543 if (selectedTotalCount !== 0) {
40544 if (selectedNodeCount > 0 && this.options.deleteNode !== false) {
40545 if (needSeperator === true) {
40546 this._createSeperator(4);
40547 }
40548
40549 this._createDeleteButton(locale);
40550 } else if (selectedNodeCount === 0 && this.options.deleteEdge !== false) {
40551 if (needSeperator === true) {
40552 this._createSeperator(4);
40553 }
40554
40555 this._createDeleteButton(locale);
40556 }
40557 } // bind the close button
40558
40559
40560 this._bindElementEvents(this.closeDiv, bind(_context3 = this.toggleEditMode).call(_context3, this)); // refresh this bar based on what has been selected
40561
40562
40563 this._temporaryBindEvent("select", bind(_context4 = this.showManipulatorToolbar).call(_context4, this));
40564 } // redraw to show any possible changes
40565
40566
40567 this.body.emitter.emit("_redraw");
40568 }
40569 /**
40570 * Create the toolbar for adding Nodes
40571 */
40572
40573 }, {
40574 key: "addNodeMode",
40575 value: function addNodeMode() {
40576 var _context6;
40577
40578 // when using the gui, enable edit mode if it wasnt already.
40579 if (this.editMode !== true) {
40580 this.enableEditMode();
40581 } // restore the state of any bound functions or events, remove control nodes, restore physics
40582
40583
40584 this._clean();
40585
40586 this.inMode = "addNode";
40587
40588 if (this.guiEnabled === true) {
40589 var _context5;
40590
40591 var locale = this.options.locales[this.options.locale];
40592 this.manipulationDOM = {};
40593
40594 this._createBackButton(locale);
40595
40596 this._createSeperator();
40597
40598 this._createDescription(locale["addDescription"] || this.options.locales["en"]["addDescription"]); // bind the close button
40599
40600
40601 this._bindElementEvents(this.closeDiv, bind(_context5 = this.toggleEditMode).call(_context5, this));
40602 }
40603
40604 this._temporaryBindEvent("click", bind(_context6 = this._performAddNode).call(_context6, this));
40605 }
40606 /**
40607 * call the bound function to handle the editing of the node. The node has to be selected.
40608 */
40609
40610 }, {
40611 key: "editNode",
40612 value: function editNode() {
40613 var _this2 = this;
40614
40615 // when using the gui, enable edit mode if it wasnt already.
40616 if (this.editMode !== true) {
40617 this.enableEditMode();
40618 } // restore the state of any bound functions or events, remove control nodes, restore physics
40619
40620
40621 this._clean();
40622
40623 var node = this.selectionHandler.getSelectedNodes()[0];
40624
40625 if (node !== undefined) {
40626 this.inMode = "editNode";
40627
40628 if (typeof this.options.editNode === "function") {
40629 if (node.isCluster !== true) {
40630 var data = deepExtend({}, node.options, false);
40631 data.x = node.x;
40632 data.y = node.y;
40633
40634 if (this.options.editNode.length === 2) {
40635 this.options.editNode(data, function (finalizedData) {
40636 if (finalizedData !== null && finalizedData !== undefined && _this2.inMode === "editNode") {
40637 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
40638 _this2.body.data.nodes.getDataSet().update(finalizedData);
40639 }
40640
40641 _this2.showManipulatorToolbar();
40642 });
40643 } else {
40644 throw new Error("The function for edit does not support two arguments (data, callback)");
40645 }
40646 } else {
40647 alert(this.options.locales[this.options.locale]["editClusterError"] || this.options.locales["en"]["editClusterError"]);
40648 }
40649 } else {
40650 throw new Error("No function has been configured to handle the editing of nodes.");
40651 }
40652 } else {
40653 this.showManipulatorToolbar();
40654 }
40655 }
40656 /**
40657 * create the toolbar to connect nodes
40658 */
40659
40660 }, {
40661 key: "addEdgeMode",
40662 value: function addEdgeMode() {
40663 var _context8, _context9, _context10, _context11, _context12;
40664
40665 // when using the gui, enable edit mode if it wasnt already.
40666 if (this.editMode !== true) {
40667 this.enableEditMode();
40668 } // restore the state of any bound functions or events, remove control nodes, restore physics
40669
40670
40671 this._clean();
40672
40673 this.inMode = "addEdge";
40674
40675 if (this.guiEnabled === true) {
40676 var _context7;
40677
40678 var locale = this.options.locales[this.options.locale];
40679 this.manipulationDOM = {};
40680
40681 this._createBackButton(locale);
40682
40683 this._createSeperator();
40684
40685 this._createDescription(locale["edgeDescription"] || this.options.locales["en"]["edgeDescription"]); // bind the close button
40686
40687
40688 this._bindElementEvents(this.closeDiv, bind(_context7 = this.toggleEditMode).call(_context7, this));
40689 } // temporarily overload functions
40690
40691
40692 this._temporaryBindUI("onTouch", bind(_context8 = this._handleConnect).call(_context8, this));
40693
40694 this._temporaryBindUI("onDragEnd", bind(_context9 = this._finishConnect).call(_context9, this));
40695
40696 this._temporaryBindUI("onDrag", bind(_context10 = this._dragControlNode).call(_context10, this));
40697
40698 this._temporaryBindUI("onRelease", bind(_context11 = this._finishConnect).call(_context11, this));
40699
40700 this._temporaryBindUI("onDragStart", bind(_context12 = this._dragStartEdge).call(_context12, this));
40701
40702 this._temporaryBindUI("onHold", function () {});
40703 }
40704 /**
40705 * create the toolbar to edit edges
40706 */
40707
40708 }, {
40709 key: "editEdgeMode",
40710 value: function editEdgeMode() {
40711 // when using the gui, enable edit mode if it wasn't already.
40712 if (this.editMode !== true) {
40713 this.enableEditMode();
40714 } // restore the state of any bound functions or events, remove control nodes, restore physics
40715
40716
40717 this._clean();
40718
40719 this.inMode = "editEdge";
40720
40721 if (_typeof(this.options.editEdge) === "object" && typeof this.options.editEdge.editWithoutDrag === "function") {
40722 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdgeIds()[0];
40723
40724 if (this.edgeBeingEditedId !== undefined) {
40725 var edge = this.body.edges[this.edgeBeingEditedId];
40726
40727 this._performEditEdge(edge.from.id, edge.to.id);
40728
40729 return;
40730 }
40731 }
40732
40733 if (this.guiEnabled === true) {
40734 var _context13;
40735
40736 var locale = this.options.locales[this.options.locale];
40737 this.manipulationDOM = {};
40738
40739 this._createBackButton(locale);
40740
40741 this._createSeperator();
40742
40743 this._createDescription(locale["editEdgeDescription"] || this.options.locales["en"]["editEdgeDescription"]); // bind the close button
40744
40745
40746 this._bindElementEvents(this.closeDiv, bind(_context13 = this.toggleEditMode).call(_context13, this));
40747 }
40748
40749 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdgeIds()[0];
40750
40751 if (this.edgeBeingEditedId !== undefined) {
40752 var _context14, _context15, _context16, _context17;
40753
40754 var _edge = this.body.edges[this.edgeBeingEditedId]; // create control nodes
40755
40756 var controlNodeFrom = this._getNewTargetNode(_edge.from.x, _edge.from.y);
40757
40758 var controlNodeTo = this._getNewTargetNode(_edge.to.x, _edge.to.y);
40759
40760 this.temporaryIds.nodes.push(controlNodeFrom.id);
40761 this.temporaryIds.nodes.push(controlNodeTo.id);
40762 this.body.nodes[controlNodeFrom.id] = controlNodeFrom;
40763 this.body.nodeIndices.push(controlNodeFrom.id);
40764 this.body.nodes[controlNodeTo.id] = controlNodeTo;
40765 this.body.nodeIndices.push(controlNodeTo.id); // temporarily overload UI functions, cleaned up automatically because of _temporaryBindUI
40766
40767 this._temporaryBindUI("onTouch", bind(_context14 = this._controlNodeTouch).call(_context14, this)); // used to get the position
40768
40769
40770 this._temporaryBindUI("onTap", function () {}); // disabled
40771
40772
40773 this._temporaryBindUI("onHold", function () {}); // disabled
40774
40775
40776 this._temporaryBindUI("onDragStart", bind(_context15 = this._controlNodeDragStart).call(_context15, this)); // used to select control node
40777
40778
40779 this._temporaryBindUI("onDrag", bind(_context16 = this._controlNodeDrag).call(_context16, this)); // used to drag control node
40780
40781
40782 this._temporaryBindUI("onDragEnd", bind(_context17 = this._controlNodeDragEnd).call(_context17, this)); // used to connect or revert control nodes
40783
40784
40785 this._temporaryBindUI("onMouseMove", function () {}); // disabled
40786 // create function to position control nodes correctly on movement
40787 // automatically cleaned up because we use the temporary bind
40788
40789
40790 this._temporaryBindEvent("beforeDrawing", function (ctx) {
40791 var positions = _edge.edgeType.findBorderPositions(ctx);
40792
40793 if (controlNodeFrom.selected === false) {
40794 controlNodeFrom.x = positions.from.x;
40795 controlNodeFrom.y = positions.from.y;
40796 }
40797
40798 if (controlNodeTo.selected === false) {
40799 controlNodeTo.x = positions.to.x;
40800 controlNodeTo.y = positions.to.y;
40801 }
40802 });
40803
40804 this.body.emitter.emit("_redraw");
40805 } else {
40806 this.showManipulatorToolbar();
40807 }
40808 }
40809 /**
40810 * delete everything in the selection
40811 */
40812
40813 }, {
40814 key: "deleteSelected",
40815 value: function deleteSelected() {
40816 var _this3 = this;
40817
40818 // when using the gui, enable edit mode if it wasnt already.
40819 if (this.editMode !== true) {
40820 this.enableEditMode();
40821 } // restore the state of any bound functions or events, remove control nodes, restore physics
40822
40823
40824 this._clean();
40825
40826 this.inMode = "delete";
40827 var selectedNodes = this.selectionHandler.getSelectedNodeIds();
40828 var selectedEdges = this.selectionHandler.getSelectedEdgeIds();
40829 var deleteFunction = undefined;
40830
40831 if (selectedNodes.length > 0) {
40832 for (var i = 0; i < selectedNodes.length; i++) {
40833 if (this.body.nodes[selectedNodes[i]].isCluster === true) {
40834 alert(this.options.locales[this.options.locale]["deleteClusterError"] || this.options.locales["en"]["deleteClusterError"]);
40835 return;
40836 }
40837 }
40838
40839 if (typeof this.options.deleteNode === "function") {
40840 deleteFunction = this.options.deleteNode;
40841 }
40842 } else if (selectedEdges.length > 0) {
40843 if (typeof this.options.deleteEdge === "function") {
40844 deleteFunction = this.options.deleteEdge;
40845 }
40846 }
40847
40848 if (typeof deleteFunction === "function") {
40849 var data = {
40850 nodes: selectedNodes,
40851 edges: selectedEdges
40852 };
40853
40854 if (deleteFunction.length === 2) {
40855 deleteFunction(data, function (finalizedData) {
40856 if (finalizedData !== null && finalizedData !== undefined && _this3.inMode === "delete") {
40857 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
40858 _this3.body.data.edges.getDataSet().remove(finalizedData.edges);
40859
40860 _this3.body.data.nodes.getDataSet().remove(finalizedData.nodes);
40861
40862 _this3.body.emitter.emit("startSimulation");
40863
40864 _this3.showManipulatorToolbar();
40865 } else {
40866 _this3.body.emitter.emit("startSimulation");
40867
40868 _this3.showManipulatorToolbar();
40869 }
40870 });
40871 } else {
40872 throw new Error("The function for delete does not support two arguments (data, callback)");
40873 }
40874 } else {
40875 this.body.data.edges.getDataSet().remove(selectedEdges);
40876 this.body.data.nodes.getDataSet().remove(selectedNodes);
40877 this.body.emitter.emit("startSimulation");
40878 this.showManipulatorToolbar();
40879 }
40880 } //********************************************** PRIVATE ***************************************//
40881
40882 /**
40883 * draw or remove the DOM
40884 *
40885 * @private
40886 */
40887
40888 }, {
40889 key: "_setup",
40890 value: function _setup() {
40891 if (this.options.enabled === true) {
40892 // Enable the GUI
40893 this.guiEnabled = true;
40894
40895 this._createWrappers();
40896
40897 if (this.editMode === false) {
40898 this._createEditButton();
40899 } else {
40900 this.showManipulatorToolbar();
40901 }
40902 } else {
40903 this._removeManipulationDOM(); // disable the gui
40904
40905
40906 this.guiEnabled = false;
40907 }
40908 }
40909 /**
40910 * create the div overlays that contain the DOM
40911 *
40912 * @private
40913 */
40914
40915 }, {
40916 key: "_createWrappers",
40917 value: function _createWrappers() {
40918 // load the manipulator HTML elements. All styling done in css.
40919 if (this.manipulationDiv === undefined) {
40920 this.manipulationDiv = document.createElement("div");
40921 this.manipulationDiv.className = "vis-manipulation";
40922
40923 if (this.editMode === true) {
40924 this.manipulationDiv.style.display = "block";
40925 } else {
40926 this.manipulationDiv.style.display = "none";
40927 }
40928
40929 this.canvas.frame.appendChild(this.manipulationDiv);
40930 } // container for the edit button.
40931
40932
40933 if (this.editModeDiv === undefined) {
40934 this.editModeDiv = document.createElement("div");
40935 this.editModeDiv.className = "vis-edit-mode";
40936
40937 if (this.editMode === true) {
40938 this.editModeDiv.style.display = "none";
40939 } else {
40940 this.editModeDiv.style.display = "block";
40941 }
40942
40943 this.canvas.frame.appendChild(this.editModeDiv);
40944 } // container for the close div button
40945
40946
40947 if (this.closeDiv === undefined) {
40948 var _this$options$locales, _this$options$locales2;
40949
40950 this.closeDiv = document.createElement("button");
40951 this.closeDiv.className = "vis-close";
40952 this.closeDiv.setAttribute("aria-label", (_this$options$locales = (_this$options$locales2 = this.options.locales[this.options.locale]) === null || _this$options$locales2 === void 0 ? void 0 : _this$options$locales2["close"]) !== null && _this$options$locales !== void 0 ? _this$options$locales : this.options.locales["en"]["close"]);
40953 this.closeDiv.style.display = this.manipulationDiv.style.display;
40954 this.canvas.frame.appendChild(this.closeDiv);
40955 }
40956 }
40957 /**
40958 * generate a new target node. Used for creating new edges and editing edges
40959 *
40960 * @param {number} x
40961 * @param {number} y
40962 * @returns {Node}
40963 * @private
40964 */
40965
40966 }, {
40967 key: "_getNewTargetNode",
40968 value: function _getNewTargetNode(x, y) {
40969 var controlNodeStyle = deepExtend({}, this.options.controlNodeStyle);
40970 controlNodeStyle.id = "targetNode" + v4();
40971 controlNodeStyle.hidden = false;
40972 controlNodeStyle.physics = false;
40973 controlNodeStyle.x = x;
40974 controlNodeStyle.y = y; // we have to define the bounding box in order for the nodes to be drawn immediately
40975
40976 var node = this.body.functions.createNode(controlNodeStyle);
40977 node.shape.boundingBox = {
40978 left: x,
40979 right: x,
40980 top: y,
40981 bottom: y
40982 };
40983 return node;
40984 }
40985 /**
40986 * Create the edit button
40987 */
40988
40989 }, {
40990 key: "_createEditButton",
40991 value: function _createEditButton() {
40992 var _context18;
40993
40994 // restore everything to it's original state (if applicable)
40995 this._clean(); // reset the manipulationDOM
40996
40997
40998 this.manipulationDOM = {}; // empty the editModeDiv
40999
41000 recursiveDOMDelete(this.editModeDiv); // create the contents for the editMode button
41001
41002 var locale = this.options.locales[this.options.locale];
41003
41004 var button = this._createButton("editMode", "vis-edit vis-edit-mode", locale["edit"] || this.options.locales["en"]["edit"]);
41005
41006 this.editModeDiv.appendChild(button); // bind a hammer listener to the button, calling the function toggleEditMode.
41007
41008 this._bindElementEvents(button, bind(_context18 = this.toggleEditMode).call(_context18, this));
41009 }
41010 /**
41011 * this function cleans up after everything this module does. Temporary elements, functions and events are removed, physics restored, hammers removed.
41012 *
41013 * @private
41014 */
41015
41016 }, {
41017 key: "_clean",
41018 value: function _clean() {
41019 // not in mode
41020 this.inMode = false; // _clean the divs
41021
41022 if (this.guiEnabled === true) {
41023 recursiveDOMDelete(this.editModeDiv);
41024 recursiveDOMDelete(this.manipulationDiv); // removes all the bindings and overloads
41025
41026 this._cleanupDOMEventListeners();
41027 } // remove temporary nodes and edges
41028
41029
41030 this._cleanupTemporaryNodesAndEdges(); // restore overloaded UI functions
41031
41032
41033 this._unbindTemporaryUIs(); // remove the temporaryEventFunctions
41034
41035
41036 this._unbindTemporaryEvents(); // restore the physics if required
41037
41038
41039 this.body.emitter.emit("restorePhysics");
41040 }
41041 /**
41042 * Each dom element has it's own hammer. They are stored in this.manipulationHammers. This cleans them up.
41043 *
41044 * @private
41045 */
41046
41047 }, {
41048 key: "_cleanupDOMEventListeners",
41049 value: function _cleanupDOMEventListeners() {
41050 var _context19;
41051
41052 // _clean DOM event listener bindings
41053 var _iterator = _createForOfIteratorHelper(splice(_context19 = this._domEventListenerCleanupQueue).call(_context19, 0)),
41054 _step;
41055
41056 try {
41057 for (_iterator.s(); !(_step = _iterator.n()).done;) {
41058 var callback = _step.value;
41059 callback();
41060 }
41061 } catch (err) {
41062 _iterator.e(err);
41063 } finally {
41064 _iterator.f();
41065 }
41066 }
41067 /**
41068 * Remove all DOM elements created by this module.
41069 *
41070 * @private
41071 */
41072
41073 }, {
41074 key: "_removeManipulationDOM",
41075 value: function _removeManipulationDOM() {
41076 // removes all the bindings and overloads
41077 this._clean(); // empty the manipulation divs
41078
41079
41080 recursiveDOMDelete(this.manipulationDiv);
41081 recursiveDOMDelete(this.editModeDiv);
41082 recursiveDOMDelete(this.closeDiv); // remove the manipulation divs
41083
41084 if (this.manipulationDiv) {
41085 this.canvas.frame.removeChild(this.manipulationDiv);
41086 }
41087
41088 if (this.editModeDiv) {
41089 this.canvas.frame.removeChild(this.editModeDiv);
41090 }
41091
41092 if (this.closeDiv) {
41093 this.canvas.frame.removeChild(this.closeDiv);
41094 } // set the references to undefined
41095
41096
41097 this.manipulationDiv = undefined;
41098 this.editModeDiv = undefined;
41099 this.closeDiv = undefined;
41100 }
41101 /**
41102 * create a seperator line. the index is to differentiate in the manipulation dom
41103 *
41104 * @param {number} [index=1]
41105 * @private
41106 */
41107
41108 }, {
41109 key: "_createSeperator",
41110 value: function _createSeperator() {
41111 var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
41112 this.manipulationDOM["seperatorLineDiv" + index] = document.createElement("div");
41113 this.manipulationDOM["seperatorLineDiv" + index].className = "vis-separator-line";
41114 this.manipulationDiv.appendChild(this.manipulationDOM["seperatorLineDiv" + index]);
41115 } // ---------------------- DOM functions for buttons --------------------------//
41116
41117 /**
41118 *
41119 * @param {Locale} locale
41120 * @private
41121 */
41122
41123 }, {
41124 key: "_createAddNodeButton",
41125 value: function _createAddNodeButton(locale) {
41126 var _context20;
41127
41128 var button = this._createButton("addNode", "vis-add", locale["addNode"] || this.options.locales["en"]["addNode"]);
41129
41130 this.manipulationDiv.appendChild(button);
41131
41132 this._bindElementEvents(button, bind(_context20 = this.addNodeMode).call(_context20, this));
41133 }
41134 /**
41135 *
41136 * @param {Locale} locale
41137 * @private
41138 */
41139
41140 }, {
41141 key: "_createAddEdgeButton",
41142 value: function _createAddEdgeButton(locale) {
41143 var _context21;
41144
41145 var button = this._createButton("addEdge", "vis-connect", locale["addEdge"] || this.options.locales["en"]["addEdge"]);
41146
41147 this.manipulationDiv.appendChild(button);
41148
41149 this._bindElementEvents(button, bind(_context21 = this.addEdgeMode).call(_context21, this));
41150 }
41151 /**
41152 *
41153 * @param {Locale} locale
41154 * @private
41155 */
41156
41157 }, {
41158 key: "_createEditNodeButton",
41159 value: function _createEditNodeButton(locale) {
41160 var _context22;
41161
41162 var button = this._createButton("editNode", "vis-edit", locale["editNode"] || this.options.locales["en"]["editNode"]);
41163
41164 this.manipulationDiv.appendChild(button);
41165
41166 this._bindElementEvents(button, bind(_context22 = this.editNode).call(_context22, this));
41167 }
41168 /**
41169 *
41170 * @param {Locale} locale
41171 * @private
41172 */
41173
41174 }, {
41175 key: "_createEditEdgeButton",
41176 value: function _createEditEdgeButton(locale) {
41177 var _context23;
41178
41179 var button = this._createButton("editEdge", "vis-edit", locale["editEdge"] || this.options.locales["en"]["editEdge"]);
41180
41181 this.manipulationDiv.appendChild(button);
41182
41183 this._bindElementEvents(button, bind(_context23 = this.editEdgeMode).call(_context23, this));
41184 }
41185 /**
41186 *
41187 * @param {Locale} locale
41188 * @private
41189 */
41190
41191 }, {
41192 key: "_createDeleteButton",
41193 value: function _createDeleteButton(locale) {
41194 var _context24;
41195
41196 var deleteBtnClass;
41197
41198 if (this.options.rtl) {
41199 deleteBtnClass = "vis-delete-rtl";
41200 } else {
41201 deleteBtnClass = "vis-delete";
41202 }
41203
41204 var button = this._createButton("delete", deleteBtnClass, locale["del"] || this.options.locales["en"]["del"]);
41205
41206 this.manipulationDiv.appendChild(button);
41207
41208 this._bindElementEvents(button, bind(_context24 = this.deleteSelected).call(_context24, this));
41209 }
41210 /**
41211 *
41212 * @param {Locale} locale
41213 * @private
41214 */
41215
41216 }, {
41217 key: "_createBackButton",
41218 value: function _createBackButton(locale) {
41219 var _context25;
41220
41221 var button = this._createButton("back", "vis-back", locale["back"] || this.options.locales["en"]["back"]);
41222
41223 this.manipulationDiv.appendChild(button);
41224
41225 this._bindElementEvents(button, bind(_context25 = this.showManipulatorToolbar).call(_context25, this));
41226 }
41227 /**
41228 *
41229 * @param {number|string} id
41230 * @param {string} className
41231 * @param {label} label
41232 * @param {string} labelClassName
41233 * @returns {HTMLElement}
41234 * @private
41235 */
41236
41237 }, {
41238 key: "_createButton",
41239 value: function _createButton(id, className, label) {
41240 var labelClassName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "vis-label";
41241 this.manipulationDOM[id + "Div"] = document.createElement("button");
41242 this.manipulationDOM[id + "Div"].className = "vis-button " + className;
41243 this.manipulationDOM[id + "Label"] = document.createElement("div");
41244 this.manipulationDOM[id + "Label"].className = labelClassName;
41245 this.manipulationDOM[id + "Label"].innerText = label;
41246 this.manipulationDOM[id + "Div"].appendChild(this.manipulationDOM[id + "Label"]);
41247 return this.manipulationDOM[id + "Div"];
41248 }
41249 /**
41250 *
41251 * @param {Label} label
41252 * @private
41253 */
41254
41255 }, {
41256 key: "_createDescription",
41257 value: function _createDescription(label) {
41258 this.manipulationDOM["descriptionLabel"] = document.createElement("div");
41259 this.manipulationDOM["descriptionLabel"].className = "vis-none";
41260 this.manipulationDOM["descriptionLabel"].innerText = label;
41261 this.manipulationDiv.appendChild(this.manipulationDOM["descriptionLabel"]);
41262 } // -------------------------- End of DOM functions for buttons ------------------------------//
41263
41264 /**
41265 * this binds an event until cleanup by the clean functions.
41266 *
41267 * @param {Event} event The event
41268 * @param {Function} newFunction
41269 * @private
41270 */
41271
41272 }, {
41273 key: "_temporaryBindEvent",
41274 value: function _temporaryBindEvent(event, newFunction) {
41275 this.temporaryEventFunctions.push({
41276 event: event,
41277 boundFunction: newFunction
41278 });
41279 this.body.emitter.on(event, newFunction);
41280 }
41281 /**
41282 * this overrides an UI function until cleanup by the clean function
41283 *
41284 * @param {string} UIfunctionName
41285 * @param {Function} newFunction
41286 * @private
41287 */
41288
41289 }, {
41290 key: "_temporaryBindUI",
41291 value: function _temporaryBindUI(UIfunctionName, newFunction) {
41292 if (this.body.eventListeners[UIfunctionName] !== undefined) {
41293 this.temporaryUIFunctions[UIfunctionName] = this.body.eventListeners[UIfunctionName];
41294 this.body.eventListeners[UIfunctionName] = newFunction;
41295 } else {
41296 throw new Error("This UI function does not exist. Typo? You tried: " + UIfunctionName + " possible are: " + stringify$1(keys$3(this.body.eventListeners)));
41297 }
41298 }
41299 /**
41300 * Restore the overridden UI functions to their original state.
41301 *
41302 * @private
41303 */
41304
41305 }, {
41306 key: "_unbindTemporaryUIs",
41307 value: function _unbindTemporaryUIs() {
41308 for (var functionName in this.temporaryUIFunctions) {
41309 if (Object.prototype.hasOwnProperty.call(this.temporaryUIFunctions, functionName)) {
41310 this.body.eventListeners[functionName] = this.temporaryUIFunctions[functionName];
41311 delete this.temporaryUIFunctions[functionName];
41312 }
41313 }
41314
41315 this.temporaryUIFunctions = {};
41316 }
41317 /**
41318 * Unbind the events created by _temporaryBindEvent
41319 *
41320 * @private
41321 */
41322
41323 }, {
41324 key: "_unbindTemporaryEvents",
41325 value: function _unbindTemporaryEvents() {
41326 for (var i = 0; i < this.temporaryEventFunctions.length; i++) {
41327 var eventName = this.temporaryEventFunctions[i].event;
41328 var boundFunction = this.temporaryEventFunctions[i].boundFunction;
41329 this.body.emitter.off(eventName, boundFunction);
41330 }
41331
41332 this.temporaryEventFunctions = [];
41333 }
41334 /**
41335 * Bind an hammer instance to a DOM element.
41336 *
41337 * @param {Element} domElement
41338 * @param {Function} boundFunction
41339 */
41340
41341 }, {
41342 key: "_bindElementEvents",
41343 value: function _bindElementEvents(domElement, boundFunction) {
41344 // Bind touch events.
41345 var hammer = new Hammer$1(domElement, {});
41346 onTouch(hammer, boundFunction);
41347
41348 this._domEventListenerCleanupQueue.push(function () {
41349 hammer.destroy();
41350 }); // Bind keyboard events.
41351
41352
41353 var keyupListener = function keyupListener(_ref) {
41354 var keyCode = _ref.keyCode,
41355 key = _ref.key;
41356
41357 if (key === "Enter" || key === " " || keyCode === 13 || keyCode === 32) {
41358 boundFunction();
41359 }
41360 };
41361
41362 domElement.addEventListener("keyup", keyupListener, false);
41363
41364 this._domEventListenerCleanupQueue.push(function () {
41365 domElement.removeEventListener("keyup", keyupListener, false);
41366 });
41367 }
41368 /**
41369 * Neatly clean up temporary edges and nodes
41370 *
41371 * @private
41372 */
41373
41374 }, {
41375 key: "_cleanupTemporaryNodesAndEdges",
41376 value: function _cleanupTemporaryNodesAndEdges() {
41377 // _clean temporary edges
41378 for (var i = 0; i < this.temporaryIds.edges.length; i++) {
41379 var _context26;
41380
41381 this.body.edges[this.temporaryIds.edges[i]].disconnect();
41382 delete this.body.edges[this.temporaryIds.edges[i]];
41383
41384 var indexTempEdge = indexOf(_context26 = this.body.edgeIndices).call(_context26, this.temporaryIds.edges[i]);
41385
41386 if (indexTempEdge !== -1) {
41387 var _context27;
41388
41389 splice(_context27 = this.body.edgeIndices).call(_context27, indexTempEdge, 1);
41390 }
41391 } // _clean temporary nodes
41392
41393
41394 for (var _i = 0; _i < this.temporaryIds.nodes.length; _i++) {
41395 var _context28;
41396
41397 delete this.body.nodes[this.temporaryIds.nodes[_i]];
41398
41399 var indexTempNode = indexOf(_context28 = this.body.nodeIndices).call(_context28, this.temporaryIds.nodes[_i]);
41400
41401 if (indexTempNode !== -1) {
41402 var _context29;
41403
41404 splice(_context29 = this.body.nodeIndices).call(_context29, indexTempNode, 1);
41405 }
41406 }
41407
41408 this.temporaryIds = {
41409 nodes: [],
41410 edges: []
41411 };
41412 } // ------------------------------------------ EDIT EDGE FUNCTIONS -----------------------------------------//
41413
41414 /**
41415 * the touch is used to get the position of the initial click
41416 *
41417 * @param {Event} event The event
41418 * @private
41419 */
41420
41421 }, {
41422 key: "_controlNodeTouch",
41423 value: function _controlNodeTouch(event) {
41424 this.selectionHandler.unselectAll();
41425 this.lastTouch = this.body.functions.getPointer(event.center);
41426 this.lastTouch.translation = assign$2({}, this.body.view.translation); // copy the object
41427 }
41428 /**
41429 * the drag start is used to mark one of the control nodes as selected.
41430 *
41431 * @private
41432 */
41433
41434 }, {
41435 key: "_controlNodeDragStart",
41436 value: function _controlNodeDragStart() {
41437 var pointer = this.lastTouch;
41438
41439 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
41440
41441 var from = this.body.nodes[this.temporaryIds.nodes[0]];
41442 var to = this.body.nodes[this.temporaryIds.nodes[1]];
41443 var edge = this.body.edges[this.edgeBeingEditedId];
41444 this.selectedControlNode = undefined;
41445 var fromSelect = from.isOverlappingWith(pointerObj);
41446 var toSelect = to.isOverlappingWith(pointerObj);
41447
41448 if (fromSelect === true) {
41449 this.selectedControlNode = from;
41450 edge.edgeType.from = from;
41451 } else if (toSelect === true) {
41452 this.selectedControlNode = to;
41453 edge.edgeType.to = to;
41454 } // we use the selection to find the node that is being dragged. We explicitly select it here.
41455
41456
41457 if (this.selectedControlNode !== undefined) {
41458 this.selectionHandler.selectObject(this.selectedControlNode);
41459 }
41460
41461 this.body.emitter.emit("_redraw");
41462 }
41463 /**
41464 * dragging the control nodes or the canvas
41465 *
41466 * @param {Event} event The event
41467 * @private
41468 */
41469
41470 }, {
41471 key: "_controlNodeDrag",
41472 value: function _controlNodeDrag(event) {
41473 this.body.emitter.emit("disablePhysics");
41474 var pointer = this.body.functions.getPointer(event.center);
41475 var pos = this.canvas.DOMtoCanvas(pointer);
41476
41477 if (this.selectedControlNode !== undefined) {
41478 this.selectedControlNode.x = pos.x;
41479 this.selectedControlNode.y = pos.y;
41480 } else {
41481 this.interactionHandler.onDrag(event);
41482 }
41483
41484 this.body.emitter.emit("_redraw");
41485 }
41486 /**
41487 * connecting or restoring the control nodes.
41488 *
41489 * @param {Event} event The event
41490 * @private
41491 */
41492
41493 }, {
41494 key: "_controlNodeDragEnd",
41495 value: function _controlNodeDragEnd(event) {
41496 var pointer = this.body.functions.getPointer(event.center);
41497
41498 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
41499
41500 var edge = this.body.edges[this.edgeBeingEditedId]; // if the node that was dragged is not a control node, return
41501
41502 if (this.selectedControlNode === undefined) {
41503 return;
41504 } // we use the selection to find the node that is being dragged. We explicitly DEselect the control node here.
41505
41506
41507 this.selectionHandler.unselectAll();
41508
41509 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
41510
41511 var node = undefined;
41512
41513 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
41514 if (overlappingNodeIds[i] !== this.selectedControlNode.id) {
41515 node = this.body.nodes[overlappingNodeIds[i]];
41516 break;
41517 }
41518 } // perform the connection
41519
41520
41521 if (node !== undefined && this.selectedControlNode !== undefined) {
41522 if (node.isCluster === true) {
41523 alert(this.options.locales[this.options.locale]["createEdgeError"] || this.options.locales["en"]["createEdgeError"]);
41524 } else {
41525 var from = this.body.nodes[this.temporaryIds.nodes[0]];
41526
41527 if (this.selectedControlNode.id === from.id) {
41528 this._performEditEdge(node.id, edge.to.id);
41529 } else {
41530 this._performEditEdge(edge.from.id, node.id);
41531 }
41532 }
41533 } else {
41534 edge.updateEdgeType();
41535 this.body.emitter.emit("restorePhysics");
41536 }
41537
41538 this.body.emitter.emit("_redraw");
41539 } // ------------------------------------ END OF EDIT EDGE FUNCTIONS -----------------------------------------//
41540 // ------------------------------------------- ADD EDGE FUNCTIONS -----------------------------------------//
41541
41542 /**
41543 * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
41544 * to walk the user through the process.
41545 *
41546 * @param {Event} event
41547 * @private
41548 */
41549
41550 }, {
41551 key: "_handleConnect",
41552 value: function _handleConnect(event) {
41553 // check to avoid double fireing of this function.
41554 if (new Date().valueOf() - this.touchTime > 100) {
41555 this.lastTouch = this.body.functions.getPointer(event.center);
41556 this.lastTouch.translation = assign$2({}, this.body.view.translation); // copy the object
41557
41558 this.interactionHandler.drag.pointer = this.lastTouch; // Drag pointer is not updated when adding edges
41559
41560 this.interactionHandler.drag.translation = this.lastTouch.translation;
41561 var pointer = this.lastTouch;
41562 var node = this.selectionHandler.getNodeAt(pointer);
41563
41564 if (node !== undefined) {
41565 if (node.isCluster === true) {
41566 alert(this.options.locales[this.options.locale]["createEdgeError"] || this.options.locales["en"]["createEdgeError"]);
41567 } else {
41568 // create a node the temporary line can look at
41569 var targetNode = this._getNewTargetNode(node.x, node.y);
41570
41571 this.body.nodes[targetNode.id] = targetNode;
41572 this.body.nodeIndices.push(targetNode.id); // create a temporary edge
41573
41574 var connectionEdge = this.body.functions.createEdge({
41575 id: "connectionEdge" + v4(),
41576 from: node.id,
41577 to: targetNode.id,
41578 physics: false,
41579 smooth: {
41580 enabled: true,
41581 type: "continuous",
41582 roundness: 0.5
41583 }
41584 });
41585 this.body.edges[connectionEdge.id] = connectionEdge;
41586 this.body.edgeIndices.push(connectionEdge.id);
41587 this.temporaryIds.nodes.push(targetNode.id);
41588 this.temporaryIds.edges.push(connectionEdge.id);
41589 }
41590 }
41591
41592 this.touchTime = new Date().valueOf();
41593 }
41594 }
41595 /**
41596 *
41597 * @param {Event} event
41598 * @private
41599 */
41600
41601 }, {
41602 key: "_dragControlNode",
41603 value: function _dragControlNode(event) {
41604 var pointer = this.body.functions.getPointer(event.center);
41605
41606 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
41607
41608
41609 var connectFromId = undefined;
41610
41611 if (this.temporaryIds.edges[0] !== undefined) {
41612 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
41613 } // get the overlapping node but NOT the temporary node;
41614
41615
41616 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
41617
41618 var node = undefined;
41619
41620 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
41621 var _context30;
41622
41623 // if the node id is NOT a temporary node, accept the node.
41624 if (indexOf(_context30 = this.temporaryIds.nodes).call(_context30, overlappingNodeIds[i]) === -1) {
41625 node = this.body.nodes[overlappingNodeIds[i]];
41626 break;
41627 }
41628 }
41629
41630 event.controlEdge = {
41631 from: connectFromId,
41632 to: node ? node.id : undefined
41633 };
41634 this.selectionHandler.generateClickEvent("controlNodeDragging", event, pointer);
41635
41636 if (this.temporaryIds.nodes[0] !== undefined) {
41637 var targetNode = this.body.nodes[this.temporaryIds.nodes[0]]; // there is only one temp node in the add edge mode.
41638
41639 targetNode.x = this.canvas._XconvertDOMtoCanvas(pointer.x);
41640 targetNode.y = this.canvas._YconvertDOMtoCanvas(pointer.y);
41641 this.body.emitter.emit("_redraw");
41642 } else {
41643 this.interactionHandler.onDrag(event);
41644 }
41645 }
41646 /**
41647 * Connect the new edge to the target if one exists, otherwise remove temp line
41648 *
41649 * @param {Event} event The event
41650 * @private
41651 */
41652
41653 }, {
41654 key: "_finishConnect",
41655 value: function _finishConnect(event) {
41656 var pointer = this.body.functions.getPointer(event.center);
41657
41658 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
41659
41660
41661 var connectFromId = undefined;
41662
41663 if (this.temporaryIds.edges[0] !== undefined) {
41664 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
41665 } // get the overlapping node but NOT the temporary node;
41666
41667
41668 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
41669
41670 var node = undefined;
41671
41672 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
41673 var _context31;
41674
41675 // if the node id is NOT a temporary node, accept the node.
41676 if (indexOf(_context31 = this.temporaryIds.nodes).call(_context31, overlappingNodeIds[i]) === -1) {
41677 node = this.body.nodes[overlappingNodeIds[i]];
41678 break;
41679 }
41680 } // clean temporary nodes and edges.
41681
41682
41683 this._cleanupTemporaryNodesAndEdges(); // perform the connection
41684
41685
41686 if (node !== undefined) {
41687 if (node.isCluster === true) {
41688 alert(this.options.locales[this.options.locale]["createEdgeError"] || this.options.locales["en"]["createEdgeError"]);
41689 } else {
41690 if (this.body.nodes[connectFromId] !== undefined && this.body.nodes[node.id] !== undefined) {
41691 this._performAddEdge(connectFromId, node.id);
41692 }
41693 }
41694 }
41695
41696 event.controlEdge = {
41697 from: connectFromId,
41698 to: node ? node.id : undefined
41699 };
41700 this.selectionHandler.generateClickEvent("controlNodeDragEnd", event, pointer); // No need to do _generateclickevent('dragEnd') here, the regular dragEnd event fires.
41701
41702 this.body.emitter.emit("_redraw");
41703 }
41704 /**
41705 *
41706 * @param {Event} event
41707 * @private
41708 */
41709
41710 }, {
41711 key: "_dragStartEdge",
41712 value: function _dragStartEdge(event) {
41713 var pointer = this.lastTouch;
41714 this.selectionHandler.generateClickEvent("dragStart", event, pointer, undefined, true);
41715 } // --------------------------------------- END OF ADD EDGE FUNCTIONS -------------------------------------//
41716 // ------------------------------ Performing all the actual data manipulation ------------------------//
41717
41718 /**
41719 * Adds a node on the specified location
41720 *
41721 * @param {object} clickData
41722 * @private
41723 */
41724
41725 }, {
41726 key: "_performAddNode",
41727 value: function _performAddNode(clickData) {
41728 var _this4 = this;
41729
41730 var defaultData = {
41731 id: v4(),
41732 x: clickData.pointer.canvas.x,
41733 y: clickData.pointer.canvas.y,
41734 label: "new"
41735 };
41736
41737 if (typeof this.options.addNode === "function") {
41738 if (this.options.addNode.length === 2) {
41739 this.options.addNode(defaultData, function (finalizedData) {
41740 if (finalizedData !== null && finalizedData !== undefined && _this4.inMode === "addNode") {
41741 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
41742 _this4.body.data.nodes.getDataSet().add(finalizedData);
41743 }
41744
41745 _this4.showManipulatorToolbar();
41746 });
41747 } else {
41748 this.showManipulatorToolbar();
41749 throw new Error("The function for add does not support two arguments (data,callback)");
41750 }
41751 } else {
41752 this.body.data.nodes.getDataSet().add(defaultData);
41753 this.showManipulatorToolbar();
41754 }
41755 }
41756 /**
41757 * connect two nodes with a new edge.
41758 *
41759 * @param {Node.id} sourceNodeId
41760 * @param {Node.id} targetNodeId
41761 * @private
41762 */
41763
41764 }, {
41765 key: "_performAddEdge",
41766 value: function _performAddEdge(sourceNodeId, targetNodeId) {
41767 var _this5 = this;
41768
41769 var defaultData = {
41770 from: sourceNodeId,
41771 to: targetNodeId
41772 };
41773
41774 if (typeof this.options.addEdge === "function") {
41775 if (this.options.addEdge.length === 2) {
41776 this.options.addEdge(defaultData, function (finalizedData) {
41777 if (finalizedData !== null && finalizedData !== undefined && _this5.inMode === "addEdge") {
41778 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
41779 _this5.body.data.edges.getDataSet().add(finalizedData);
41780
41781 _this5.selectionHandler.unselectAll();
41782
41783 _this5.showManipulatorToolbar();
41784 }
41785 });
41786 } else {
41787 throw new Error("The function for connect does not support two arguments (data,callback)");
41788 }
41789 } else {
41790 this.body.data.edges.getDataSet().add(defaultData);
41791 this.selectionHandler.unselectAll();
41792 this.showManipulatorToolbar();
41793 }
41794 }
41795 /**
41796 * connect two nodes with a new edge.
41797 *
41798 * @param {Node.id} sourceNodeId
41799 * @param {Node.id} targetNodeId
41800 * @private
41801 */
41802
41803 }, {
41804 key: "_performEditEdge",
41805 value: function _performEditEdge(sourceNodeId, targetNodeId) {
41806 var _this6 = this;
41807
41808 var defaultData = {
41809 id: this.edgeBeingEditedId,
41810 from: sourceNodeId,
41811 to: targetNodeId,
41812 label: this.body.data.edges.get(this.edgeBeingEditedId).label
41813 };
41814 var eeFunct = this.options.editEdge;
41815
41816 if (_typeof(eeFunct) === "object") {
41817 eeFunct = eeFunct.editWithoutDrag;
41818 }
41819
41820 if (typeof eeFunct === "function") {
41821 if (eeFunct.length === 2) {
41822 eeFunct(defaultData, function (finalizedData) {
41823 if (finalizedData === null || finalizedData === undefined || _this6.inMode !== "editEdge") {
41824 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
41825 _this6.body.edges[defaultData.id].updateEdgeType();
41826
41827 _this6.body.emitter.emit("_redraw");
41828
41829 _this6.showManipulatorToolbar();
41830 } else {
41831 _this6.body.data.edges.getDataSet().update(finalizedData);
41832
41833 _this6.selectionHandler.unselectAll();
41834
41835 _this6.showManipulatorToolbar();
41836 }
41837 });
41838 } else {
41839 throw new Error("The function for edit does not support two arguments (data, callback)");
41840 }
41841 } else {
41842 this.body.data.edges.getDataSet().update(defaultData);
41843 this.selectionHandler.unselectAll();
41844 this.showManipulatorToolbar();
41845 }
41846 }
41847 }]);
41848
41849 return ManipulationSystem;
41850}();
41851
41852/**
41853 * This object contains all possible options. It will check if the types are correct, if required if the option is one
41854 * of the allowed values.
41855 *
41856 * __any__ means that the name of the property does not matter.
41857 * __type__ is a required field for all objects and contains the allowed types of all objects
41858 */
41859var string = "string";
41860var bool = "boolean";
41861var number = "number";
41862var array = "array";
41863var object = "object"; // should only be in a __type__ property
41864
41865var dom = "dom";
41866var any = "any"; // List of endpoints
41867
41868var endPoints = ["arrow", "bar", "box", "circle", "crow", "curve", "diamond", "image", "inv_curve", "inv_triangle", "triangle", "vee"];
41869/* eslint-disable @typescript-eslint/naming-convention -- The __*__ format is used to prevent collisions with actual option names. */
41870
41871var nodeOptions = {
41872 borderWidth: {
41873 number: number
41874 },
41875 borderWidthSelected: {
41876 number: number,
41877 undefined: "undefined"
41878 },
41879 brokenImage: {
41880 string: string,
41881 undefined: "undefined"
41882 },
41883 chosen: {
41884 label: {
41885 boolean: bool,
41886 function: "function"
41887 },
41888 node: {
41889 boolean: bool,
41890 function: "function"
41891 },
41892 __type__: {
41893 object: object,
41894 boolean: bool
41895 }
41896 },
41897 color: {
41898 border: {
41899 string: string
41900 },
41901 background: {
41902 string: string
41903 },
41904 highlight: {
41905 border: {
41906 string: string
41907 },
41908 background: {
41909 string: string
41910 },
41911 __type__: {
41912 object: object,
41913 string: string
41914 }
41915 },
41916 hover: {
41917 border: {
41918 string: string
41919 },
41920 background: {
41921 string: string
41922 },
41923 __type__: {
41924 object: object,
41925 string: string
41926 }
41927 },
41928 __type__: {
41929 object: object,
41930 string: string
41931 }
41932 },
41933 opacity: {
41934 number: number,
41935 undefined: "undefined"
41936 },
41937 fixed: {
41938 x: {
41939 boolean: bool
41940 },
41941 y: {
41942 boolean: bool
41943 },
41944 __type__: {
41945 object: object,
41946 boolean: bool
41947 }
41948 },
41949 font: {
41950 align: {
41951 string: string
41952 },
41953 color: {
41954 string: string
41955 },
41956 size: {
41957 number: number
41958 },
41959 face: {
41960 string: string
41961 },
41962 background: {
41963 string: string
41964 },
41965 strokeWidth: {
41966 number: number
41967 },
41968 strokeColor: {
41969 string: string
41970 },
41971 vadjust: {
41972 number: number
41973 },
41974 multi: {
41975 boolean: bool,
41976 string: string
41977 },
41978 bold: {
41979 color: {
41980 string: string
41981 },
41982 size: {
41983 number: number
41984 },
41985 face: {
41986 string: string
41987 },
41988 mod: {
41989 string: string
41990 },
41991 vadjust: {
41992 number: number
41993 },
41994 __type__: {
41995 object: object,
41996 string: string
41997 }
41998 },
41999 boldital: {
42000 color: {
42001 string: string
42002 },
42003 size: {
42004 number: number
42005 },
42006 face: {
42007 string: string
42008 },
42009 mod: {
42010 string: string
42011 },
42012 vadjust: {
42013 number: number
42014 },
42015 __type__: {
42016 object: object,
42017 string: string
42018 }
42019 },
42020 ital: {
42021 color: {
42022 string: string
42023 },
42024 size: {
42025 number: number
42026 },
42027 face: {
42028 string: string
42029 },
42030 mod: {
42031 string: string
42032 },
42033 vadjust: {
42034 number: number
42035 },
42036 __type__: {
42037 object: object,
42038 string: string
42039 }
42040 },
42041 mono: {
42042 color: {
42043 string: string
42044 },
42045 size: {
42046 number: number
42047 },
42048 face: {
42049 string: string
42050 },
42051 mod: {
42052 string: string
42053 },
42054 vadjust: {
42055 number: number
42056 },
42057 __type__: {
42058 object: object,
42059 string: string
42060 }
42061 },
42062 __type__: {
42063 object: object,
42064 string: string
42065 }
42066 },
42067 group: {
42068 string: string,
42069 number: number,
42070 undefined: "undefined"
42071 },
42072 heightConstraint: {
42073 minimum: {
42074 number: number
42075 },
42076 valign: {
42077 string: string
42078 },
42079 __type__: {
42080 object: object,
42081 boolean: bool,
42082 number: number
42083 }
42084 },
42085 hidden: {
42086 boolean: bool
42087 },
42088 icon: {
42089 face: {
42090 string: string
42091 },
42092 code: {
42093 string: string
42094 },
42095 size: {
42096 number: number
42097 },
42098 color: {
42099 string: string
42100 },
42101 weight: {
42102 string: string,
42103 number: number
42104 },
42105 __type__: {
42106 object: object
42107 }
42108 },
42109 id: {
42110 string: string,
42111 number: number
42112 },
42113 image: {
42114 selected: {
42115 string: string,
42116 undefined: "undefined"
42117 },
42118 unselected: {
42119 string: string,
42120 undefined: "undefined"
42121 },
42122 __type__: {
42123 object: object,
42124 string: string
42125 }
42126 },
42127 imagePadding: {
42128 top: {
42129 number: number
42130 },
42131 right: {
42132 number: number
42133 },
42134 bottom: {
42135 number: number
42136 },
42137 left: {
42138 number: number
42139 },
42140 __type__: {
42141 object: object,
42142 number: number
42143 }
42144 },
42145 label: {
42146 string: string,
42147 undefined: "undefined"
42148 },
42149 labelHighlightBold: {
42150 boolean: bool
42151 },
42152 level: {
42153 number: number,
42154 undefined: "undefined"
42155 },
42156 margin: {
42157 top: {
42158 number: number
42159 },
42160 right: {
42161 number: number
42162 },
42163 bottom: {
42164 number: number
42165 },
42166 left: {
42167 number: number
42168 },
42169 __type__: {
42170 object: object,
42171 number: number
42172 }
42173 },
42174 mass: {
42175 number: number
42176 },
42177 physics: {
42178 boolean: bool
42179 },
42180 scaling: {
42181 min: {
42182 number: number
42183 },
42184 max: {
42185 number: number
42186 },
42187 label: {
42188 enabled: {
42189 boolean: bool
42190 },
42191 min: {
42192 number: number
42193 },
42194 max: {
42195 number: number
42196 },
42197 maxVisible: {
42198 number: number
42199 },
42200 drawThreshold: {
42201 number: number
42202 },
42203 __type__: {
42204 object: object,
42205 boolean: bool
42206 }
42207 },
42208 customScalingFunction: {
42209 function: "function"
42210 },
42211 __type__: {
42212 object: object
42213 }
42214 },
42215 shadow: {
42216 enabled: {
42217 boolean: bool
42218 },
42219 color: {
42220 string: string
42221 },
42222 size: {
42223 number: number
42224 },
42225 x: {
42226 number: number
42227 },
42228 y: {
42229 number: number
42230 },
42231 __type__: {
42232 object: object,
42233 boolean: bool
42234 }
42235 },
42236 shape: {
42237 string: ["custom", "ellipse", "circle", "database", "box", "text", "image", "circularImage", "diamond", "dot", "star", "triangle", "triangleDown", "square", "icon", "hexagon"]
42238 },
42239 ctxRenderer: {
42240 function: "function"
42241 },
42242 shapeProperties: {
42243 borderDashes: {
42244 boolean: bool,
42245 array: array
42246 },
42247 borderRadius: {
42248 number: number
42249 },
42250 interpolation: {
42251 boolean: bool
42252 },
42253 useImageSize: {
42254 boolean: bool
42255 },
42256 useBorderWithImage: {
42257 boolean: bool
42258 },
42259 coordinateOrigin: {
42260 string: ["center", "top-left"]
42261 },
42262 __type__: {
42263 object: object
42264 }
42265 },
42266 size: {
42267 number: number
42268 },
42269 title: {
42270 string: string,
42271 dom: dom,
42272 undefined: "undefined"
42273 },
42274 value: {
42275 number: number,
42276 undefined: "undefined"
42277 },
42278 widthConstraint: {
42279 minimum: {
42280 number: number
42281 },
42282 maximum: {
42283 number: number
42284 },
42285 __type__: {
42286 object: object,
42287 boolean: bool,
42288 number: number
42289 }
42290 },
42291 x: {
42292 number: number
42293 },
42294 y: {
42295 number: number
42296 },
42297 __type__: {
42298 object: object
42299 }
42300};
42301var allOptions = {
42302 configure: {
42303 enabled: {
42304 boolean: bool
42305 },
42306 filter: {
42307 boolean: bool,
42308 string: string,
42309 array: array,
42310 function: "function"
42311 },
42312 container: {
42313 dom: dom
42314 },
42315 showButton: {
42316 boolean: bool
42317 },
42318 __type__: {
42319 object: object,
42320 boolean: bool,
42321 string: string,
42322 array: array,
42323 function: "function"
42324 }
42325 },
42326 edges: {
42327 arrows: {
42328 to: {
42329 enabled: {
42330 boolean: bool
42331 },
42332 scaleFactor: {
42333 number: number
42334 },
42335 type: {
42336 string: endPoints
42337 },
42338 imageHeight: {
42339 number: number
42340 },
42341 imageWidth: {
42342 number: number
42343 },
42344 src: {
42345 string: string
42346 },
42347 __type__: {
42348 object: object,
42349 boolean: bool
42350 }
42351 },
42352 middle: {
42353 enabled: {
42354 boolean: bool
42355 },
42356 scaleFactor: {
42357 number: number
42358 },
42359 type: {
42360 string: endPoints
42361 },
42362 imageWidth: {
42363 number: number
42364 },
42365 imageHeight: {
42366 number: number
42367 },
42368 src: {
42369 string: string
42370 },
42371 __type__: {
42372 object: object,
42373 boolean: bool
42374 }
42375 },
42376 from: {
42377 enabled: {
42378 boolean: bool
42379 },
42380 scaleFactor: {
42381 number: number
42382 },
42383 type: {
42384 string: endPoints
42385 },
42386 imageWidth: {
42387 number: number
42388 },
42389 imageHeight: {
42390 number: number
42391 },
42392 src: {
42393 string: string
42394 },
42395 __type__: {
42396 object: object,
42397 boolean: bool
42398 }
42399 },
42400 __type__: {
42401 string: ["from", "to", "middle"],
42402 object: object
42403 }
42404 },
42405 endPointOffset: {
42406 from: {
42407 number: number
42408 },
42409 to: {
42410 number: number
42411 },
42412 __type__: {
42413 object: object,
42414 number: number
42415 }
42416 },
42417 arrowStrikethrough: {
42418 boolean: bool
42419 },
42420 background: {
42421 enabled: {
42422 boolean: bool
42423 },
42424 color: {
42425 string: string
42426 },
42427 size: {
42428 number: number
42429 },
42430 dashes: {
42431 boolean: bool,
42432 array: array
42433 },
42434 __type__: {
42435 object: object,
42436 boolean: bool
42437 }
42438 },
42439 chosen: {
42440 label: {
42441 boolean: bool,
42442 function: "function"
42443 },
42444 edge: {
42445 boolean: bool,
42446 function: "function"
42447 },
42448 __type__: {
42449 object: object,
42450 boolean: bool
42451 }
42452 },
42453 color: {
42454 color: {
42455 string: string
42456 },
42457 highlight: {
42458 string: string
42459 },
42460 hover: {
42461 string: string
42462 },
42463 inherit: {
42464 string: ["from", "to", "both"],
42465 boolean: bool
42466 },
42467 opacity: {
42468 number: number
42469 },
42470 __type__: {
42471 object: object,
42472 string: string
42473 }
42474 },
42475 dashes: {
42476 boolean: bool,
42477 array: array
42478 },
42479 font: {
42480 color: {
42481 string: string
42482 },
42483 size: {
42484 number: number
42485 },
42486 face: {
42487 string: string
42488 },
42489 background: {
42490 string: string
42491 },
42492 strokeWidth: {
42493 number: number
42494 },
42495 strokeColor: {
42496 string: string
42497 },
42498 align: {
42499 string: ["horizontal", "top", "middle", "bottom"]
42500 },
42501 vadjust: {
42502 number: number
42503 },
42504 multi: {
42505 boolean: bool,
42506 string: string
42507 },
42508 bold: {
42509 color: {
42510 string: string
42511 },
42512 size: {
42513 number: number
42514 },
42515 face: {
42516 string: string
42517 },
42518 mod: {
42519 string: string
42520 },
42521 vadjust: {
42522 number: number
42523 },
42524 __type__: {
42525 object: object,
42526 string: string
42527 }
42528 },
42529 boldital: {
42530 color: {
42531 string: string
42532 },
42533 size: {
42534 number: number
42535 },
42536 face: {
42537 string: string
42538 },
42539 mod: {
42540 string: string
42541 },
42542 vadjust: {
42543 number: number
42544 },
42545 __type__: {
42546 object: object,
42547 string: string
42548 }
42549 },
42550 ital: {
42551 color: {
42552 string: string
42553 },
42554 size: {
42555 number: number
42556 },
42557 face: {
42558 string: string
42559 },
42560 mod: {
42561 string: string
42562 },
42563 vadjust: {
42564 number: number
42565 },
42566 __type__: {
42567 object: object,
42568 string: string
42569 }
42570 },
42571 mono: {
42572 color: {
42573 string: string
42574 },
42575 size: {
42576 number: number
42577 },
42578 face: {
42579 string: string
42580 },
42581 mod: {
42582 string: string
42583 },
42584 vadjust: {
42585 number: number
42586 },
42587 __type__: {
42588 object: object,
42589 string: string
42590 }
42591 },
42592 __type__: {
42593 object: object,
42594 string: string
42595 }
42596 },
42597 hidden: {
42598 boolean: bool
42599 },
42600 hoverWidth: {
42601 function: "function",
42602 number: number
42603 },
42604 label: {
42605 string: string,
42606 undefined: "undefined"
42607 },
42608 labelHighlightBold: {
42609 boolean: bool
42610 },
42611 length: {
42612 number: number,
42613 undefined: "undefined"
42614 },
42615 physics: {
42616 boolean: bool
42617 },
42618 scaling: {
42619 min: {
42620 number: number
42621 },
42622 max: {
42623 number: number
42624 },
42625 label: {
42626 enabled: {
42627 boolean: bool
42628 },
42629 min: {
42630 number: number
42631 },
42632 max: {
42633 number: number
42634 },
42635 maxVisible: {
42636 number: number
42637 },
42638 drawThreshold: {
42639 number: number
42640 },
42641 __type__: {
42642 object: object,
42643 boolean: bool
42644 }
42645 },
42646 customScalingFunction: {
42647 function: "function"
42648 },
42649 __type__: {
42650 object: object
42651 }
42652 },
42653 selectionWidth: {
42654 function: "function",
42655 number: number
42656 },
42657 selfReferenceSize: {
42658 number: number
42659 },
42660 selfReference: {
42661 size: {
42662 number: number
42663 },
42664 angle: {
42665 number: number
42666 },
42667 renderBehindTheNode: {
42668 boolean: bool
42669 },
42670 __type__: {
42671 object: object
42672 }
42673 },
42674 shadow: {
42675 enabled: {
42676 boolean: bool
42677 },
42678 color: {
42679 string: string
42680 },
42681 size: {
42682 number: number
42683 },
42684 x: {
42685 number: number
42686 },
42687 y: {
42688 number: number
42689 },
42690 __type__: {
42691 object: object,
42692 boolean: bool
42693 }
42694 },
42695 smooth: {
42696 enabled: {
42697 boolean: bool
42698 },
42699 type: {
42700 string: ["dynamic", "continuous", "discrete", "diagonalCross", "straightCross", "horizontal", "vertical", "curvedCW", "curvedCCW", "cubicBezier"]
42701 },
42702 roundness: {
42703 number: number
42704 },
42705 forceDirection: {
42706 string: ["horizontal", "vertical", "none"],
42707 boolean: bool
42708 },
42709 __type__: {
42710 object: object,
42711 boolean: bool
42712 }
42713 },
42714 title: {
42715 string: string,
42716 undefined: "undefined"
42717 },
42718 width: {
42719 number: number
42720 },
42721 widthConstraint: {
42722 maximum: {
42723 number: number
42724 },
42725 __type__: {
42726 object: object,
42727 boolean: bool,
42728 number: number
42729 }
42730 },
42731 value: {
42732 number: number,
42733 undefined: "undefined"
42734 },
42735 __type__: {
42736 object: object
42737 }
42738 },
42739 groups: {
42740 useDefaultGroups: {
42741 boolean: bool
42742 },
42743 __any__: nodeOptions,
42744 __type__: {
42745 object: object
42746 }
42747 },
42748 interaction: {
42749 dragNodes: {
42750 boolean: bool
42751 },
42752 dragView: {
42753 boolean: bool
42754 },
42755 hideEdgesOnDrag: {
42756 boolean: bool
42757 },
42758 hideEdgesOnZoom: {
42759 boolean: bool
42760 },
42761 hideNodesOnDrag: {
42762 boolean: bool
42763 },
42764 hover: {
42765 boolean: bool
42766 },
42767 keyboard: {
42768 enabled: {
42769 boolean: bool
42770 },
42771 speed: {
42772 x: {
42773 number: number
42774 },
42775 y: {
42776 number: number
42777 },
42778 zoom: {
42779 number: number
42780 },
42781 __type__: {
42782 object: object
42783 }
42784 },
42785 bindToWindow: {
42786 boolean: bool
42787 },
42788 autoFocus: {
42789 boolean: bool
42790 },
42791 __type__: {
42792 object: object,
42793 boolean: bool
42794 }
42795 },
42796 multiselect: {
42797 boolean: bool
42798 },
42799 navigationButtons: {
42800 boolean: bool
42801 },
42802 selectable: {
42803 boolean: bool
42804 },
42805 selectConnectedEdges: {
42806 boolean: bool
42807 },
42808 hoverConnectedEdges: {
42809 boolean: bool
42810 },
42811 tooltipDelay: {
42812 number: number
42813 },
42814 zoomView: {
42815 boolean: bool
42816 },
42817 zoomSpeed: {
42818 number: number
42819 },
42820 __type__: {
42821 object: object
42822 }
42823 },
42824 layout: {
42825 randomSeed: {
42826 undefined: "undefined",
42827 number: number,
42828 string: string
42829 },
42830 improvedLayout: {
42831 boolean: bool
42832 },
42833 clusterThreshold: {
42834 number: number
42835 },
42836 hierarchical: {
42837 enabled: {
42838 boolean: bool
42839 },
42840 levelSeparation: {
42841 number: number
42842 },
42843 nodeSpacing: {
42844 number: number
42845 },
42846 treeSpacing: {
42847 number: number
42848 },
42849 blockShifting: {
42850 boolean: bool
42851 },
42852 edgeMinimization: {
42853 boolean: bool
42854 },
42855 parentCentralization: {
42856 boolean: bool
42857 },
42858 direction: {
42859 string: ["UD", "DU", "LR", "RL"]
42860 },
42861 sortMethod: {
42862 string: ["hubsize", "directed"]
42863 },
42864 shakeTowards: {
42865 string: ["leaves", "roots"]
42866 },
42867 __type__: {
42868 object: object,
42869 boolean: bool
42870 }
42871 },
42872 __type__: {
42873 object: object
42874 }
42875 },
42876 manipulation: {
42877 enabled: {
42878 boolean: bool
42879 },
42880 initiallyActive: {
42881 boolean: bool
42882 },
42883 addNode: {
42884 boolean: bool,
42885 function: "function"
42886 },
42887 addEdge: {
42888 boolean: bool,
42889 function: "function"
42890 },
42891 editNode: {
42892 function: "function"
42893 },
42894 editEdge: {
42895 editWithoutDrag: {
42896 function: "function"
42897 },
42898 __type__: {
42899 object: object,
42900 boolean: bool,
42901 function: "function"
42902 }
42903 },
42904 deleteNode: {
42905 boolean: bool,
42906 function: "function"
42907 },
42908 deleteEdge: {
42909 boolean: bool,
42910 function: "function"
42911 },
42912 controlNodeStyle: nodeOptions,
42913 __type__: {
42914 object: object,
42915 boolean: bool
42916 }
42917 },
42918 nodes: nodeOptions,
42919 physics: {
42920 enabled: {
42921 boolean: bool
42922 },
42923 barnesHut: {
42924 theta: {
42925 number: number
42926 },
42927 gravitationalConstant: {
42928 number: number
42929 },
42930 centralGravity: {
42931 number: number
42932 },
42933 springLength: {
42934 number: number
42935 },
42936 springConstant: {
42937 number: number
42938 },
42939 damping: {
42940 number: number
42941 },
42942 avoidOverlap: {
42943 number: number
42944 },
42945 __type__: {
42946 object: object
42947 }
42948 },
42949 forceAtlas2Based: {
42950 theta: {
42951 number: number
42952 },
42953 gravitationalConstant: {
42954 number: number
42955 },
42956 centralGravity: {
42957 number: number
42958 },
42959 springLength: {
42960 number: number
42961 },
42962 springConstant: {
42963 number: number
42964 },
42965 damping: {
42966 number: number
42967 },
42968 avoidOverlap: {
42969 number: number
42970 },
42971 __type__: {
42972 object: object
42973 }
42974 },
42975 repulsion: {
42976 centralGravity: {
42977 number: number
42978 },
42979 springLength: {
42980 number: number
42981 },
42982 springConstant: {
42983 number: number
42984 },
42985 nodeDistance: {
42986 number: number
42987 },
42988 damping: {
42989 number: number
42990 },
42991 __type__: {
42992 object: object
42993 }
42994 },
42995 hierarchicalRepulsion: {
42996 centralGravity: {
42997 number: number
42998 },
42999 springLength: {
43000 number: number
43001 },
43002 springConstant: {
43003 number: number
43004 },
43005 nodeDistance: {
43006 number: number
43007 },
43008 damping: {
43009 number: number
43010 },
43011 avoidOverlap: {
43012 number: number
43013 },
43014 __type__: {
43015 object: object
43016 }
43017 },
43018 maxVelocity: {
43019 number: number
43020 },
43021 minVelocity: {
43022 number: number
43023 },
43024 solver: {
43025 string: ["barnesHut", "repulsion", "hierarchicalRepulsion", "forceAtlas2Based"]
43026 },
43027 stabilization: {
43028 enabled: {
43029 boolean: bool
43030 },
43031 iterations: {
43032 number: number
43033 },
43034 updateInterval: {
43035 number: number
43036 },
43037 onlyDynamicEdges: {
43038 boolean: bool
43039 },
43040 fit: {
43041 boolean: bool
43042 },
43043 __type__: {
43044 object: object,
43045 boolean: bool
43046 }
43047 },
43048 timestep: {
43049 number: number
43050 },
43051 adaptiveTimestep: {
43052 boolean: bool
43053 },
43054 wind: {
43055 x: {
43056 number: number
43057 },
43058 y: {
43059 number: number
43060 },
43061 __type__: {
43062 object: object
43063 }
43064 },
43065 __type__: {
43066 object: object,
43067 boolean: bool
43068 }
43069 },
43070 //globals :
43071 autoResize: {
43072 boolean: bool
43073 },
43074 clickToUse: {
43075 boolean: bool
43076 },
43077 locale: {
43078 string: string
43079 },
43080 locales: {
43081 __any__: {
43082 any: any
43083 },
43084 __type__: {
43085 object: object
43086 }
43087 },
43088 height: {
43089 string: string
43090 },
43091 width: {
43092 string: string
43093 },
43094 __type__: {
43095 object: object
43096 }
43097};
43098/* eslint-enable @typescript-eslint/naming-convention */
43099
43100/**
43101 * This provides ranges, initial values, steps and dropdown menu choices for the
43102 * configuration.
43103 *
43104 * @remarks
43105 * Checkbox: `boolean`
43106 * The value supllied will be used as the initial value.
43107 *
43108 * Text field: `string`
43109 * The passed text will be used as the initial value. Any text will be
43110 * accepted afterwards.
43111 *
43112 * Number range: `[number, number, number, number]`
43113 * The meanings are `[initial value, min, max, step]`.
43114 *
43115 * Dropdown: `[Exclude<string, "color">, ...(string | number | boolean)[]]`
43116 * Translations for people with poor understanding of TypeScript: the first
43117 * value always has to be a string but never `"color"`, the rest can be any
43118 * combination of strings, numbers and booleans.
43119 *
43120 * Color picker: `["color", string]`
43121 * The first value says this will be a color picker not a dropdown menu. The
43122 * next value is the initial color.
43123 */
43124
43125var configureOptions = {
43126 nodes: {
43127 borderWidth: [1, 0, 10, 1],
43128 borderWidthSelected: [2, 0, 10, 1],
43129 color: {
43130 border: ["color", "#2B7CE9"],
43131 background: ["color", "#97C2FC"],
43132 highlight: {
43133 border: ["color", "#2B7CE9"],
43134 background: ["color", "#D2E5FF"]
43135 },
43136 hover: {
43137 border: ["color", "#2B7CE9"],
43138 background: ["color", "#D2E5FF"]
43139 }
43140 },
43141 opacity: [0, 0, 1, 0.1],
43142 fixed: {
43143 x: false,
43144 y: false
43145 },
43146 font: {
43147 color: ["color", "#343434"],
43148 size: [14, 0, 100, 1],
43149 face: ["arial", "verdana", "tahoma"],
43150 background: ["color", "none"],
43151 strokeWidth: [0, 0, 50, 1],
43152 strokeColor: ["color", "#ffffff"]
43153 },
43154 //group: 'string',
43155 hidden: false,
43156 labelHighlightBold: true,
43157 //icon: {
43158 // face: 'string', //'FontAwesome',
43159 // code: 'string', //'\uf007',
43160 // size: [50, 0, 200, 1], //50,
43161 // color: ['color','#2B7CE9'] //'#aa00ff'
43162 //},
43163 //image: 'string', // --> URL
43164 physics: true,
43165 scaling: {
43166 min: [10, 0, 200, 1],
43167 max: [30, 0, 200, 1],
43168 label: {
43169 enabled: false,
43170 min: [14, 0, 200, 1],
43171 max: [30, 0, 200, 1],
43172 maxVisible: [30, 0, 200, 1],
43173 drawThreshold: [5, 0, 20, 1]
43174 }
43175 },
43176 shadow: {
43177 enabled: false,
43178 color: "rgba(0,0,0,0.5)",
43179 size: [10, 0, 20, 1],
43180 x: [5, -30, 30, 1],
43181 y: [5, -30, 30, 1]
43182 },
43183 shape: ["ellipse", "box", "circle", "database", "diamond", "dot", "square", "star", "text", "triangle", "triangleDown", "hexagon"],
43184 shapeProperties: {
43185 borderDashes: false,
43186 borderRadius: [6, 0, 20, 1],
43187 interpolation: true,
43188 useImageSize: false
43189 },
43190 size: [25, 0, 200, 1]
43191 },
43192 edges: {
43193 arrows: {
43194 to: {
43195 enabled: false,
43196 scaleFactor: [1, 0, 3, 0.05],
43197 type: "arrow"
43198 },
43199 middle: {
43200 enabled: false,
43201 scaleFactor: [1, 0, 3, 0.05],
43202 type: "arrow"
43203 },
43204 from: {
43205 enabled: false,
43206 scaleFactor: [1, 0, 3, 0.05],
43207 type: "arrow"
43208 }
43209 },
43210 endPointOffset: {
43211 from: [0, -10, 10, 1],
43212 to: [0, -10, 10, 1]
43213 },
43214 arrowStrikethrough: true,
43215 color: {
43216 color: ["color", "#848484"],
43217 highlight: ["color", "#848484"],
43218 hover: ["color", "#848484"],
43219 inherit: ["from", "to", "both", true, false],
43220 opacity: [1, 0, 1, 0.05]
43221 },
43222 dashes: false,
43223 font: {
43224 color: ["color", "#343434"],
43225 size: [14, 0, 100, 1],
43226 face: ["arial", "verdana", "tahoma"],
43227 background: ["color", "none"],
43228 strokeWidth: [2, 0, 50, 1],
43229 strokeColor: ["color", "#ffffff"],
43230 align: ["horizontal", "top", "middle", "bottom"]
43231 },
43232 hidden: false,
43233 hoverWidth: [1.5, 0, 5, 0.1],
43234 labelHighlightBold: true,
43235 physics: true,
43236 scaling: {
43237 min: [1, 0, 100, 1],
43238 max: [15, 0, 100, 1],
43239 label: {
43240 enabled: true,
43241 min: [14, 0, 200, 1],
43242 max: [30, 0, 200, 1],
43243 maxVisible: [30, 0, 200, 1],
43244 drawThreshold: [5, 0, 20, 1]
43245 }
43246 },
43247 selectionWidth: [1.5, 0, 5, 0.1],
43248 selfReferenceSize: [20, 0, 200, 1],
43249 selfReference: {
43250 size: [20, 0, 200, 1],
43251 angle: [Math.PI / 2, -6 * Math.PI, 6 * Math.PI, Math.PI / 8],
43252 renderBehindTheNode: true
43253 },
43254 shadow: {
43255 enabled: false,
43256 color: "rgba(0,0,0,0.5)",
43257 size: [10, 0, 20, 1],
43258 x: [5, -30, 30, 1],
43259 y: [5, -30, 30, 1]
43260 },
43261 smooth: {
43262 enabled: true,
43263 type: ["dynamic", "continuous", "discrete", "diagonalCross", "straightCross", "horizontal", "vertical", "curvedCW", "curvedCCW", "cubicBezier"],
43264 forceDirection: ["horizontal", "vertical", "none"],
43265 roundness: [0.5, 0, 1, 0.05]
43266 },
43267 width: [1, 0, 30, 1]
43268 },
43269 layout: {
43270 //randomSeed: [0, 0, 500, 1],
43271 //improvedLayout: true,
43272 hierarchical: {
43273 enabled: false,
43274 levelSeparation: [150, 20, 500, 5],
43275 nodeSpacing: [100, 20, 500, 5],
43276 treeSpacing: [200, 20, 500, 5],
43277 blockShifting: true,
43278 edgeMinimization: true,
43279 parentCentralization: true,
43280 direction: ["UD", "DU", "LR", "RL"],
43281 sortMethod: ["hubsize", "directed"],
43282 shakeTowards: ["leaves", "roots"] // leaves, roots
43283
43284 }
43285 },
43286 interaction: {
43287 dragNodes: true,
43288 dragView: true,
43289 hideEdgesOnDrag: false,
43290 hideEdgesOnZoom: false,
43291 hideNodesOnDrag: false,
43292 hover: false,
43293 keyboard: {
43294 enabled: false,
43295 speed: {
43296 x: [10, 0, 40, 1],
43297 y: [10, 0, 40, 1],
43298 zoom: [0.02, 0, 0.1, 0.005]
43299 },
43300 bindToWindow: true,
43301 autoFocus: true
43302 },
43303 multiselect: false,
43304 navigationButtons: false,
43305 selectable: true,
43306 selectConnectedEdges: true,
43307 hoverConnectedEdges: true,
43308 tooltipDelay: [300, 0, 1000, 25],
43309 zoomView: true,
43310 zoomSpeed: [1, 0.1, 2, 0.1]
43311 },
43312 manipulation: {
43313 enabled: false,
43314 initiallyActive: false
43315 },
43316 physics: {
43317 enabled: true,
43318 barnesHut: {
43319 theta: [0.5, 0.1, 1, 0.05],
43320 gravitationalConstant: [-2000, -30000, 0, 50],
43321 centralGravity: [0.3, 0, 10, 0.05],
43322 springLength: [95, 0, 500, 5],
43323 springConstant: [0.04, 0, 1.2, 0.005],
43324 damping: [0.09, 0, 1, 0.01],
43325 avoidOverlap: [0, 0, 1, 0.01]
43326 },
43327 forceAtlas2Based: {
43328 theta: [0.5, 0.1, 1, 0.05],
43329 gravitationalConstant: [-50, -500, 0, 1],
43330 centralGravity: [0.01, 0, 1, 0.005],
43331 springLength: [95, 0, 500, 5],
43332 springConstant: [0.08, 0, 1.2, 0.005],
43333 damping: [0.4, 0, 1, 0.01],
43334 avoidOverlap: [0, 0, 1, 0.01]
43335 },
43336 repulsion: {
43337 centralGravity: [0.2, 0, 10, 0.05],
43338 springLength: [200, 0, 500, 5],
43339 springConstant: [0.05, 0, 1.2, 0.005],
43340 nodeDistance: [100, 0, 500, 5],
43341 damping: [0.09, 0, 1, 0.01]
43342 },
43343 hierarchicalRepulsion: {
43344 centralGravity: [0.2, 0, 10, 0.05],
43345 springLength: [100, 0, 500, 5],
43346 springConstant: [0.01, 0, 1.2, 0.005],
43347 nodeDistance: [120, 0, 500, 5],
43348 damping: [0.09, 0, 1, 0.01],
43349 avoidOverlap: [0, 0, 1, 0.01]
43350 },
43351 maxVelocity: [50, 0, 150, 1],
43352 minVelocity: [0.1, 0.01, 0.5, 0.01],
43353 solver: ["barnesHut", "forceAtlas2Based", "repulsion", "hierarchicalRepulsion"],
43354 timestep: [0.5, 0.01, 1, 0.01],
43355 wind: {
43356 x: [0, -10, 10, 0.1],
43357 y: [0, -10, 10, 0.1]
43358 } //adaptiveTimestep: true
43359
43360 }
43361};
43362var configuratorHideOption = function configuratorHideOption(parentPath, optionName, options) {
43363 var _context;
43364
43365 if (includes(parentPath).call(parentPath, "physics") && includes(_context = configureOptions.physics.solver).call(_context, optionName) && options.physics.solver !== optionName && optionName !== "wind") {
43366 return true;
43367 }
43368
43369 return false;
43370};
43371
43372var allOptions$1 = /*#__PURE__*/Object.freeze({
43373 __proto__: null,
43374 configuratorHideOption: configuratorHideOption,
43375 allOptions: allOptions,
43376 configureOptions: configureOptions
43377});
43378
43379/**
43380 * The Floyd–Warshall algorithm is an algorithm for finding shortest paths in
43381 * a weighted graph with positive or negative edge weights (but with no negative
43382 * cycles). - https://en.wikipedia.org/wiki/Floyd–Warshall_algorithm
43383 */
43384var FloydWarshall = /*#__PURE__*/function () {
43385 /**
43386 * @ignore
43387 */
43388 function FloydWarshall() {
43389 _classCallCheck(this, FloydWarshall);
43390 }
43391 /**
43392 *
43393 * @param {object} body
43394 * @param {Array.<Node>} nodesArray
43395 * @param {Array.<Edge>} edgesArray
43396 * @returns {{}}
43397 */
43398
43399
43400 _createClass(FloydWarshall, [{
43401 key: "getDistances",
43402 value: function getDistances(body, nodesArray, edgesArray) {
43403 var D_matrix = {};
43404 var edges = body.edges; // prepare matrix with large numbers
43405
43406 for (var i = 0; i < nodesArray.length; i++) {
43407 var node = nodesArray[i];
43408 var cell = {};
43409 D_matrix[node] = cell;
43410
43411 for (var j = 0; j < nodesArray.length; j++) {
43412 cell[nodesArray[j]] = i == j ? 0 : 1e9;
43413 }
43414 } // put the weights for the edges in. This assumes unidirectionality.
43415
43416
43417 for (var _i = 0; _i < edgesArray.length; _i++) {
43418 var edge = edges[edgesArray[_i]]; // edge has to be connected if it counts to the distances. If it is connected to inner clusters it will crash so we also check if it is in the D_matrix
43419
43420 if (edge.connected === true && D_matrix[edge.fromId] !== undefined && D_matrix[edge.toId] !== undefined) {
43421 D_matrix[edge.fromId][edge.toId] = 1;
43422 D_matrix[edge.toId][edge.fromId] = 1;
43423 }
43424 }
43425
43426 var nodeCount = nodesArray.length; // Adapted FloydWarshall based on unidirectionality to greatly reduce complexity.
43427
43428 for (var k = 0; k < nodeCount; k++) {
43429 var knode = nodesArray[k];
43430 var kcolm = D_matrix[knode];
43431
43432 for (var _i2 = 0; _i2 < nodeCount - 1; _i2++) {
43433 var inode = nodesArray[_i2];
43434 var icolm = D_matrix[inode];
43435
43436 for (var _j = _i2 + 1; _j < nodeCount; _j++) {
43437 var jnode = nodesArray[_j];
43438 var jcolm = D_matrix[jnode];
43439 var val = Math.min(icolm[jnode], icolm[knode] + kcolm[jnode]);
43440 icolm[jnode] = val;
43441 jcolm[inode] = val;
43442 }
43443 }
43444 }
43445
43446 return D_matrix;
43447 }
43448 }]);
43449
43450 return FloydWarshall;
43451}();
43452
43453/**
43454 * KamadaKawai positions the nodes initially based on
43455 *
43456 * "AN ALGORITHM FOR DRAWING GENERAL UNDIRECTED GRAPHS"
43457 * -- Tomihisa KAMADA and Satoru KAWAI in 1989
43458 *
43459 * Possible optimizations in the distance calculation can be implemented.
43460 */
43461
43462var KamadaKawai = /*#__PURE__*/function () {
43463 /**
43464 * @param {object} body
43465 * @param {number} edgeLength
43466 * @param {number} edgeStrength
43467 */
43468 function KamadaKawai(body, edgeLength, edgeStrength) {
43469 _classCallCheck(this, KamadaKawai);
43470
43471 this.body = body;
43472 this.springLength = edgeLength;
43473 this.springConstant = edgeStrength;
43474 this.distanceSolver = new FloydWarshall();
43475 }
43476 /**
43477 * Not sure if needed but can be used to update the spring length and spring constant
43478 *
43479 * @param {object} options
43480 */
43481
43482
43483 _createClass(KamadaKawai, [{
43484 key: "setOptions",
43485 value: function setOptions(options) {
43486 if (options) {
43487 if (options.springLength) {
43488 this.springLength = options.springLength;
43489 }
43490
43491 if (options.springConstant) {
43492 this.springConstant = options.springConstant;
43493 }
43494 }
43495 }
43496 /**
43497 * Position the system
43498 *
43499 * @param {Array.<Node>} nodesArray
43500 * @param {Array.<vis.Edge>} edgesArray
43501 * @param {boolean} [ignoreClusters=false]
43502 */
43503
43504 }, {
43505 key: "solve",
43506 value: function solve(nodesArray, edgesArray) {
43507 var ignoreClusters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
43508 // get distance matrix
43509 var D_matrix = this.distanceSolver.getDistances(this.body, nodesArray, edgesArray); // distance matrix
43510 // get the L Matrix
43511
43512 this._createL_matrix(D_matrix); // get the K Matrix
43513
43514
43515 this._createK_matrix(D_matrix); // initial E Matrix
43516
43517
43518 this._createE_matrix(); // calculate positions
43519
43520
43521 var threshold = 0.01;
43522 var innerThreshold = 1;
43523 var iterations = 0;
43524 var maxIterations = Math.max(1000, Math.min(10 * this.body.nodeIndices.length, 6000));
43525 var maxInnerIterations = 5;
43526 var maxEnergy = 1e9;
43527 var highE_nodeId = 0,
43528 dE_dx = 0,
43529 dE_dy = 0,
43530 delta_m = 0,
43531 subIterations = 0;
43532
43533 while (maxEnergy > threshold && iterations < maxIterations) {
43534 iterations += 1;
43535
43536 var _this$_getHighestEner = this._getHighestEnergyNode(ignoreClusters);
43537
43538 var _this$_getHighestEner2 = _slicedToArray(_this$_getHighestEner, 4);
43539
43540 highE_nodeId = _this$_getHighestEner2[0];
43541 maxEnergy = _this$_getHighestEner2[1];
43542 dE_dx = _this$_getHighestEner2[2];
43543 dE_dy = _this$_getHighestEner2[3];
43544 delta_m = maxEnergy;
43545 subIterations = 0;
43546
43547 while (delta_m > innerThreshold && subIterations < maxInnerIterations) {
43548 subIterations += 1;
43549
43550 this._moveNode(highE_nodeId, dE_dx, dE_dy);
43551
43552 var _this$_getEnergy = this._getEnergy(highE_nodeId);
43553
43554 var _this$_getEnergy2 = _slicedToArray(_this$_getEnergy, 3);
43555
43556 delta_m = _this$_getEnergy2[0];
43557 dE_dx = _this$_getEnergy2[1];
43558 dE_dy = _this$_getEnergy2[2];
43559 }
43560 }
43561 }
43562 /**
43563 * get the node with the highest energy
43564 *
43565 * @param {boolean} ignoreClusters
43566 * @returns {number[]}
43567 * @private
43568 */
43569
43570 }, {
43571 key: "_getHighestEnergyNode",
43572 value: function _getHighestEnergyNode(ignoreClusters) {
43573 var nodesArray = this.body.nodeIndices;
43574 var nodes = this.body.nodes;
43575 var maxEnergy = 0;
43576 var maxEnergyNodeId = nodesArray[0];
43577 var dE_dx_max = 0,
43578 dE_dy_max = 0;
43579
43580 for (var nodeIdx = 0; nodeIdx < nodesArray.length; nodeIdx++) {
43581 var m = nodesArray[nodeIdx]; // by not evaluating nodes with predefined positions we should only move nodes that have no positions.
43582
43583 if (nodes[m].predefinedPosition !== true || nodes[m].isCluster === true && ignoreClusters === true || nodes[m].options.fixed.x !== true || nodes[m].options.fixed.y !== true) {
43584 var _this$_getEnergy3 = this._getEnergy(m),
43585 _this$_getEnergy4 = _slicedToArray(_this$_getEnergy3, 3),
43586 delta_m = _this$_getEnergy4[0],
43587 dE_dx = _this$_getEnergy4[1],
43588 dE_dy = _this$_getEnergy4[2];
43589
43590 if (maxEnergy < delta_m) {
43591 maxEnergy = delta_m;
43592 maxEnergyNodeId = m;
43593 dE_dx_max = dE_dx;
43594 dE_dy_max = dE_dy;
43595 }
43596 }
43597 }
43598
43599 return [maxEnergyNodeId, maxEnergy, dE_dx_max, dE_dy_max];
43600 }
43601 /**
43602 * calculate the energy of a single node
43603 *
43604 * @param {Node.id} m
43605 * @returns {number[]}
43606 * @private
43607 */
43608
43609 }, {
43610 key: "_getEnergy",
43611 value: function _getEnergy(m) {
43612 var _this$E_sums$m = _slicedToArray(this.E_sums[m], 2),
43613 dE_dx = _this$E_sums$m[0],
43614 dE_dy = _this$E_sums$m[1];
43615
43616 var delta_m = Math.sqrt(Math.pow(dE_dx, 2) + Math.pow(dE_dy, 2));
43617 return [delta_m, dE_dx, dE_dy];
43618 }
43619 /**
43620 * move the node based on it's energy
43621 * the dx and dy are calculated from the linear system proposed by Kamada and Kawai
43622 *
43623 * @param {number} m
43624 * @param {number} dE_dx
43625 * @param {number} dE_dy
43626 * @private
43627 */
43628
43629 }, {
43630 key: "_moveNode",
43631 value: function _moveNode(m, dE_dx, dE_dy) {
43632 var nodesArray = this.body.nodeIndices;
43633 var nodes = this.body.nodes;
43634 var d2E_dx2 = 0;
43635 var d2E_dxdy = 0;
43636 var d2E_dy2 = 0;
43637 var x_m = nodes[m].x;
43638 var y_m = nodes[m].y;
43639 var km = this.K_matrix[m];
43640 var lm = this.L_matrix[m];
43641
43642 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
43643 var i = nodesArray[iIdx];
43644
43645 if (i !== m) {
43646 var x_i = nodes[i].x;
43647 var y_i = nodes[i].y;
43648 var kmat = km[i];
43649 var lmat = lm[i];
43650 var denominator = 1.0 / Math.pow(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2), 1.5);
43651 d2E_dx2 += kmat * (1 - lmat * Math.pow(y_m - y_i, 2) * denominator);
43652 d2E_dxdy += kmat * (lmat * (x_m - x_i) * (y_m - y_i) * denominator);
43653 d2E_dy2 += kmat * (1 - lmat * Math.pow(x_m - x_i, 2) * denominator);
43654 }
43655 } // make the variable names easier to make the solving of the linear system easier to read
43656
43657
43658 var A = d2E_dx2,
43659 B = d2E_dxdy,
43660 C = dE_dx,
43661 D = d2E_dy2,
43662 E = dE_dy; // solve the linear system for dx and dy
43663
43664 var dy = (C / A + E / B) / (B / A - D / B);
43665 var dx = -(B * dy + C) / A; // move the node
43666
43667 nodes[m].x += dx;
43668 nodes[m].y += dy; // Recalculate E_matrix (should be incremental)
43669
43670 this._updateE_matrix(m);
43671 }
43672 /**
43673 * Create the L matrix: edge length times shortest path
43674 *
43675 * @param {object} D_matrix
43676 * @private
43677 */
43678
43679 }, {
43680 key: "_createL_matrix",
43681 value: function _createL_matrix(D_matrix) {
43682 var nodesArray = this.body.nodeIndices;
43683 var edgeLength = this.springLength;
43684 this.L_matrix = [];
43685
43686 for (var i = 0; i < nodesArray.length; i++) {
43687 this.L_matrix[nodesArray[i]] = {};
43688
43689 for (var j = 0; j < nodesArray.length; j++) {
43690 this.L_matrix[nodesArray[i]][nodesArray[j]] = edgeLength * D_matrix[nodesArray[i]][nodesArray[j]];
43691 }
43692 }
43693 }
43694 /**
43695 * Create the K matrix: spring constants times shortest path
43696 *
43697 * @param {object} D_matrix
43698 * @private
43699 */
43700
43701 }, {
43702 key: "_createK_matrix",
43703 value: function _createK_matrix(D_matrix) {
43704 var nodesArray = this.body.nodeIndices;
43705 var edgeStrength = this.springConstant;
43706 this.K_matrix = [];
43707
43708 for (var i = 0; i < nodesArray.length; i++) {
43709 this.K_matrix[nodesArray[i]] = {};
43710
43711 for (var j = 0; j < nodesArray.length; j++) {
43712 this.K_matrix[nodesArray[i]][nodesArray[j]] = edgeStrength * Math.pow(D_matrix[nodesArray[i]][nodesArray[j]], -2);
43713 }
43714 }
43715 }
43716 /**
43717 * Create matrix with all energies between nodes
43718 *
43719 * @private
43720 */
43721
43722 }, {
43723 key: "_createE_matrix",
43724 value: function _createE_matrix() {
43725 var nodesArray = this.body.nodeIndices;
43726 var nodes = this.body.nodes;
43727 this.E_matrix = {};
43728 this.E_sums = {};
43729
43730 for (var mIdx = 0; mIdx < nodesArray.length; mIdx++) {
43731 this.E_matrix[nodesArray[mIdx]] = [];
43732 }
43733
43734 for (var _mIdx = 0; _mIdx < nodesArray.length; _mIdx++) {
43735 var m = nodesArray[_mIdx];
43736 var x_m = nodes[m].x;
43737 var y_m = nodes[m].y;
43738 var dE_dx = 0;
43739 var dE_dy = 0;
43740
43741 for (var iIdx = _mIdx; iIdx < nodesArray.length; iIdx++) {
43742 var i = nodesArray[iIdx];
43743
43744 if (i !== m) {
43745 var x_i = nodes[i].x;
43746 var y_i = nodes[i].y;
43747 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
43748 this.E_matrix[m][iIdx] = [this.K_matrix[m][i] * (x_m - x_i - this.L_matrix[m][i] * (x_m - x_i) * denominator), this.K_matrix[m][i] * (y_m - y_i - this.L_matrix[m][i] * (y_m - y_i) * denominator)];
43749 this.E_matrix[i][_mIdx] = this.E_matrix[m][iIdx];
43750 dE_dx += this.E_matrix[m][iIdx][0];
43751 dE_dy += this.E_matrix[m][iIdx][1];
43752 }
43753 } //Store sum
43754
43755
43756 this.E_sums[m] = [dE_dx, dE_dy];
43757 }
43758 }
43759 /**
43760 * Update method, just doing single column (rows are auto-updated) (update all sums)
43761 *
43762 * @param {number} m
43763 * @private
43764 */
43765
43766 }, {
43767 key: "_updateE_matrix",
43768 value: function _updateE_matrix(m) {
43769 var nodesArray = this.body.nodeIndices;
43770 var nodes = this.body.nodes;
43771 var colm = this.E_matrix[m];
43772 var kcolm = this.K_matrix[m];
43773 var lcolm = this.L_matrix[m];
43774 var x_m = nodes[m].x;
43775 var y_m = nodes[m].y;
43776 var dE_dx = 0;
43777 var dE_dy = 0;
43778
43779 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
43780 var i = nodesArray[iIdx];
43781
43782 if (i !== m) {
43783 //Keep old energy value for sum modification below
43784 var cell = colm[iIdx];
43785 var oldDx = cell[0];
43786 var oldDy = cell[1]; //Calc new energy:
43787
43788 var x_i = nodes[i].x;
43789 var y_i = nodes[i].y;
43790 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
43791 var dx = kcolm[i] * (x_m - x_i - lcolm[i] * (x_m - x_i) * denominator);
43792 var dy = kcolm[i] * (y_m - y_i - lcolm[i] * (y_m - y_i) * denominator);
43793 colm[iIdx] = [dx, dy];
43794 dE_dx += dx;
43795 dE_dy += dy; //add new energy to sum of each column
43796
43797 var sum = this.E_sums[i];
43798 sum[0] += dx - oldDx;
43799 sum[1] += dy - oldDy;
43800 }
43801 } //Store sum at -1 index
43802
43803
43804 this.E_sums[m] = [dE_dx, dE_dy];
43805 }
43806 }]);
43807
43808 return KamadaKawai;
43809}();
43810
43811/**
43812 * Create a network visualization, displaying nodes and edges.
43813 *
43814 * @param {Element} container The DOM element in which the Network will
43815 * be created. Normally a div element.
43816 * @param {object} data An object containing parameters
43817 * {Array} nodes
43818 * {Array} edges
43819 * @param {object} options Options
43820 * @class Network
43821 */
43822
43823function Network(container, data, options) {
43824 var _context,
43825 _context2,
43826 _context3,
43827 _context4,
43828 _this = this;
43829
43830 if (!(this instanceof Network)) {
43831 throw new SyntaxError("Constructor must be called with the new operator");
43832 } // set constant values
43833
43834
43835 this.options = {};
43836 this.defaultOptions = {
43837 locale: "en",
43838 locales: locales,
43839 clickToUse: false
43840 };
43841
43842 assign$2(this.options, this.defaultOptions);
43843 /**
43844 * Containers for nodes and edges.
43845 *
43846 * 'edges' and 'nodes' contain the full definitions of all the network elements.
43847 * 'nodeIndices' and 'edgeIndices' contain the id's of the active elements.
43848 *
43849 * The distinction is important, because a defined node need not be active, i.e.
43850 * visible on the canvas. This happens in particular when clusters are defined, in
43851 * that case there will be nodes and edges not displayed.
43852 * The bottom line is that all code with actions related to visibility, *must* use
43853 * 'nodeIndices' and 'edgeIndices', not 'nodes' and 'edges' directly.
43854 */
43855
43856
43857 this.body = {
43858 container: container,
43859 // See comment above for following fields
43860 nodes: {},
43861 nodeIndices: [],
43862 edges: {},
43863 edgeIndices: [],
43864 emitter: {
43865 on: bind(_context = this.on).call(_context, this),
43866 off: bind(_context2 = this.off).call(_context2, this),
43867 emit: bind(_context3 = this.emit).call(_context3, this),
43868 once: bind(_context4 = this.once).call(_context4, this)
43869 },
43870 eventListeners: {
43871 onTap: function onTap() {},
43872 onTouch: function onTouch() {},
43873 onDoubleTap: function onDoubleTap() {},
43874 onHold: function onHold() {},
43875 onDragStart: function onDragStart() {},
43876 onDrag: function onDrag() {},
43877 onDragEnd: function onDragEnd() {},
43878 onMouseWheel: function onMouseWheel() {},
43879 onPinch: function onPinch() {},
43880 onMouseMove: function onMouseMove() {},
43881 onRelease: function onRelease() {},
43882 onContext: function onContext() {}
43883 },
43884 data: {
43885 nodes: null,
43886 // A DataSet or DataView
43887 edges: null // A DataSet or DataView
43888
43889 },
43890 functions: {
43891 createNode: function createNode() {},
43892 createEdge: function createEdge() {},
43893 getPointer: function getPointer() {}
43894 },
43895 modules: {},
43896 view: {
43897 scale: 1,
43898 translation: {
43899 x: 0,
43900 y: 0
43901 }
43902 },
43903 selectionBox: {
43904 show: false,
43905 position: {
43906 start: {
43907 x: 0,
43908 y: 0
43909 },
43910 end: {
43911 x: 0,
43912 y: 0
43913 }
43914 }
43915 }
43916 }; // bind the event listeners
43917
43918 this.bindEventListeners(); // setting up all modules
43919
43920 this.images = new Images(function () {
43921 return _this.body.emitter.emit("_requestRedraw");
43922 }); // object with images
43923
43924 this.groups = new Groups(); // object with groups
43925
43926 this.canvas = new Canvas(this.body); // DOM handler
43927
43928 this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler
43929
43930 this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key
43931
43932 this.view = new View(this.body, this.canvas); // camera handler, does animations and zooms
43933
43934 this.renderer = new CanvasRenderer(this.body, this.canvas); // renderer, starts renderloop, has events that modules can hook into
43935
43936 this.physics = new PhysicsEngine(this.body); // physics engine, does all the simulations
43937
43938 this.layoutEngine = new LayoutEngine(this.body); // layout engine for inital layout and hierarchical layout
43939
43940 this.clustering = new ClusterEngine(this.body); // clustering api
43941
43942 this.manipulation = new ManipulationSystem(this.body, this.canvas, this.selectionHandler, this.interactionHandler); // data manipulation system
43943
43944 this.nodesHandler = new NodesHandler(this.body, this.images, this.groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
43945
43946 this.edgesHandler = new EdgesHandler(this.body, this.images, this.groups); // Handle adding, deleting and updating of edges as well as global options
43947
43948 this.body.modules["kamadaKawai"] = new KamadaKawai(this.body, 150, 0.05); // Layouting algorithm.
43949
43950 this.body.modules["clustering"] = this.clustering; // create the DOM elements
43951
43952 this.canvas._create(); // apply options
43953
43954
43955 this.setOptions(options); // load data (the disable start variable will be the same as the enabled clustering)
43956
43957 this.setData(data);
43958} // Extend Network with an Emitter mixin
43959
43960componentEmitter(Network.prototype);
43961/**
43962 * Set options
43963 *
43964 * @param {object} options
43965 */
43966
43967Network.prototype.setOptions = function (options) {
43968 var _this2 = this;
43969
43970 if (options === null) {
43971 options = undefined; // This ensures that options handling doesn't crash in the handling
43972 }
43973
43974 if (options !== undefined) {
43975 var errorFound = Validator$1.validate(options, allOptions);
43976
43977 if (errorFound === true) {
43978 console.error("%cErrors have been found in the supplied options object.", VALIDATOR_PRINT_STYLE$1);
43979 } // copy the global fields over
43980
43981
43982 var fields = ["locale", "locales", "clickToUse"];
43983 selectiveDeepExtend(fields, this.options, options); // normalize the locale or use English
43984
43985 if (options.locale !== undefined) {
43986 options.locale = normalizeLanguageCode(options.locales || this.options.locales, options.locale);
43987 } // the hierarchical system can adapt the edges and the physics to it's own options because not all combinations work with the hierarichical system.
43988
43989
43990 options = this.layoutEngine.setOptions(options.layout, options);
43991 this.canvas.setOptions(options); // options for canvas are in globals
43992 // pass the options to the modules
43993
43994 this.groups.setOptions(options.groups);
43995 this.nodesHandler.setOptions(options.nodes);
43996 this.edgesHandler.setOptions(options.edges);
43997 this.physics.setOptions(options.physics);
43998 this.manipulation.setOptions(options.manipulation, options, this.options); // manipulation uses the locales in the globals
43999
44000 this.interactionHandler.setOptions(options.interaction);
44001 this.renderer.setOptions(options.interaction); // options for rendering are in interaction
44002
44003 this.selectionHandler.setOptions(options.interaction); // options for selection are in interaction
44004 // reload the settings of the nodes to apply changes in groups that are not referenced by pointer.
44005
44006 if (options.groups !== undefined) {
44007 this.body.emitter.emit("refreshNodes");
44008 } // these two do not have options at the moment, here for completeness
44009 //this.view.setOptions(options.view);
44010 //this.clustering.setOptions(options.clustering);
44011
44012
44013 if ("configure" in options) {
44014 if (!this.configurator) {
44015 this.configurator = new Configurator$1(this, this.body.container, configureOptions, this.canvas.pixelRatio, configuratorHideOption);
44016 }
44017
44018 this.configurator.setOptions(options.configure);
44019 } // if the configuration system is enabled, copy all options and put them into the config system
44020
44021
44022 if (this.configurator && this.configurator.options.enabled === true) {
44023 var networkOptions = {
44024 nodes: {},
44025 edges: {},
44026 layout: {},
44027 interaction: {},
44028 manipulation: {},
44029 physics: {},
44030 global: {}
44031 };
44032 deepExtend(networkOptions.nodes, this.nodesHandler.options);
44033 deepExtend(networkOptions.edges, this.edgesHandler.options);
44034 deepExtend(networkOptions.layout, this.layoutEngine.options); // load the selectionHandler and render default options in to the interaction group
44035
44036 deepExtend(networkOptions.interaction, this.selectionHandler.options);
44037 deepExtend(networkOptions.interaction, this.renderer.options);
44038 deepExtend(networkOptions.interaction, this.interactionHandler.options);
44039 deepExtend(networkOptions.manipulation, this.manipulation.options);
44040 deepExtend(networkOptions.physics, this.physics.options); // load globals into the global object
44041
44042 deepExtend(networkOptions.global, this.canvas.options);
44043 deepExtend(networkOptions.global, this.options);
44044 this.configurator.setModuleOptions(networkOptions);
44045 } // handle network global options
44046
44047
44048 if (options.clickToUse !== undefined) {
44049 if (options.clickToUse === true) {
44050 if (this.activator === undefined) {
44051 this.activator = new Activator$1(this.canvas.frame);
44052 this.activator.on("change", function () {
44053 _this2.body.emitter.emit("activate");
44054 });
44055 }
44056 } else {
44057 if (this.activator !== undefined) {
44058 this.activator.destroy();
44059 delete this.activator;
44060 }
44061
44062 this.body.emitter.emit("activate");
44063 }
44064 } else {
44065 this.body.emitter.emit("activate");
44066 }
44067
44068 this.canvas.setSize(); // start the physics simulation. Can be safely called multiple times.
44069
44070 this.body.emitter.emit("startSimulation");
44071 }
44072};
44073/**
44074 * Update the visible nodes and edges list with the most recent node state.
44075 *
44076 * Visible nodes are stored in this.body.nodeIndices.
44077 * Visible edges are stored in this.body.edgeIndices.
44078 * A node or edges is visible if it is not hidden or clustered.
44079 *
44080 * @private
44081 */
44082
44083
44084Network.prototype._updateVisibleIndices = function () {
44085 var nodes = this.body.nodes;
44086 var edges = this.body.edges;
44087 this.body.nodeIndices = [];
44088 this.body.edgeIndices = [];
44089
44090 for (var nodeId in nodes) {
44091 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
44092 if (!this.clustering._isClusteredNode(nodeId) && nodes[nodeId].options.hidden === false) {
44093 this.body.nodeIndices.push(nodes[nodeId].id);
44094 }
44095 }
44096 }
44097
44098 for (var edgeId in edges) {
44099 if (Object.prototype.hasOwnProperty.call(edges, edgeId)) {
44100 var edge = edges[edgeId]; // It can happen that this is executed *after* a node edge has been removed,
44101 // but *before* the edge itself has been removed. Taking this into account.
44102
44103 var fromNode = nodes[edge.fromId];
44104 var toNode = nodes[edge.toId];
44105 var edgeNodesPresent = fromNode !== undefined && toNode !== undefined;
44106 var isVisible = !this.clustering._isClusteredEdge(edgeId) && edge.options.hidden === false && edgeNodesPresent && fromNode.options.hidden === false && // Also hidden if any of its connecting nodes are hidden
44107 toNode.options.hidden === false; // idem
44108
44109 if (isVisible) {
44110 this.body.edgeIndices.push(edge.id);
44111 }
44112 }
44113 }
44114};
44115/**
44116 * Bind all events
44117 */
44118
44119
44120Network.prototype.bindEventListeners = function () {
44121 var _this3 = this;
44122
44123 // This event will trigger a rebuilding of the cache everything.
44124 // Used when nodes or edges have been added or removed.
44125 this.body.emitter.on("_dataChanged", function () {
44126 _this3.edgesHandler._updateState();
44127
44128 _this3.body.emitter.emit("_dataUpdated");
44129 }); // this is called when options of EXISTING nodes or edges have changed.
44130
44131 this.body.emitter.on("_dataUpdated", function () {
44132 // Order important in following block
44133 _this3.clustering._updateState();
44134
44135 _this3._updateVisibleIndices();
44136
44137 _this3._updateValueRange(_this3.body.nodes);
44138
44139 _this3._updateValueRange(_this3.body.edges); // start simulation (can be called safely, even if already running)
44140
44141
44142 _this3.body.emitter.emit("startSimulation");
44143
44144 _this3.body.emitter.emit("_requestRedraw");
44145 });
44146};
44147/**
44148 * Set nodes and edges, and optionally options as well.
44149 *
44150 * @param {object} data Object containing parameters:
44151 * {Array | DataSet | DataView} [nodes] Array with nodes
44152 * {Array | DataSet | DataView} [edges] Array with edges
44153 * {String} [dot] String containing data in DOT format
44154 * {String} [gephi] String containing data in gephi JSON format
44155 * {Options} [options] Object with options
44156 */
44157
44158
44159Network.prototype.setData = function (data) {
44160 // reset the physics engine.
44161 this.body.emitter.emit("resetPhysics");
44162 this.body.emitter.emit("_resetData"); // unselect all to ensure no selections from old data are carried over.
44163
44164 this.selectionHandler.unselectAll();
44165
44166 if (data && data.dot && (data.nodes || data.edges)) {
44167 throw new SyntaxError('Data must contain either parameter "dot" or ' + ' parameter pair "nodes" and "edges", but not both.');
44168 } // set options
44169
44170
44171 this.setOptions(data && data.options); // set all data
44172
44173 if (data && data.dot) {
44174 console.warn("The dot property has been deprecated. Please use the static convertDot method to convert DOT into vis.network format and use the normal data format with nodes and edges. This converter is used like this: var data = vis.network.convertDot(dotString);"); // parse DOT file
44175
44176 var dotData = DOTToGraph(data.dot);
44177 this.setData(dotData);
44178 return;
44179 } else if (data && data.gephi) {
44180 // parse DOT file
44181 console.warn("The gephi property has been deprecated. Please use the static convertGephi method to convert gephi into vis.network format and use the normal data format with nodes and edges. This converter is used like this: var data = vis.network.convertGephi(gephiJson);");
44182 var gephiData = parseGephi(data.gephi);
44183 this.setData(gephiData);
44184 return;
44185 } else {
44186 this.nodesHandler.setData(data && data.nodes, true);
44187 this.edgesHandler.setData(data && data.edges, true);
44188 } // emit change in data
44189
44190
44191 this.body.emitter.emit("_dataChanged"); // emit data loaded
44192
44193 this.body.emitter.emit("_dataLoaded"); // find a stable position or start animating to a stable position
44194
44195 this.body.emitter.emit("initPhysics");
44196};
44197/**
44198 * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function.
44199 * var network = new vis.Network(..);
44200 * network.destroy();
44201 * network = null;
44202 */
44203
44204
44205Network.prototype.destroy = function () {
44206 this.body.emitter.emit("destroy"); // clear events
44207
44208 this.body.emitter.off();
44209 this.off(); // delete modules
44210
44211 delete this.groups;
44212 delete this.canvas;
44213 delete this.selectionHandler;
44214 delete this.interactionHandler;
44215 delete this.view;
44216 delete this.renderer;
44217 delete this.physics;
44218 delete this.layoutEngine;
44219 delete this.clustering;
44220 delete this.manipulation;
44221 delete this.nodesHandler;
44222 delete this.edgesHandler;
44223 delete this.configurator;
44224 delete this.images;
44225
44226 for (var nodeId in this.body.nodes) {
44227 if (!Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) continue;
44228 delete this.body.nodes[nodeId];
44229 }
44230
44231 for (var edgeId in this.body.edges) {
44232 if (!Object.prototype.hasOwnProperty.call(this.body.edges, edgeId)) continue;
44233 delete this.body.edges[edgeId];
44234 } // remove the container and everything inside it recursively
44235
44236
44237 recursiveDOMDelete(this.body.container);
44238};
44239/**
44240 * Update the values of all object in the given array according to the current
44241 * value range of the objects in the array.
44242 *
44243 * @param {object} obj An object containing a set of Edges or Nodes
44244 * The objects must have a method getValue() and
44245 * setValueRange(min, max).
44246 * @private
44247 */
44248
44249
44250Network.prototype._updateValueRange = function (obj) {
44251 var id; // determine the range of the objects
44252
44253 var valueMin = undefined;
44254 var valueMax = undefined;
44255 var valueTotal = 0;
44256
44257 for (id in obj) {
44258 if (Object.prototype.hasOwnProperty.call(obj, id)) {
44259 var value = obj[id].getValue();
44260
44261 if (value !== undefined) {
44262 valueMin = valueMin === undefined ? value : Math.min(value, valueMin);
44263 valueMax = valueMax === undefined ? value : Math.max(value, valueMax);
44264 valueTotal += value;
44265 }
44266 }
44267 } // adjust the range of all objects
44268
44269
44270 if (valueMin !== undefined && valueMax !== undefined) {
44271 for (id in obj) {
44272 if (Object.prototype.hasOwnProperty.call(obj, id)) {
44273 obj[id].setValueRange(valueMin, valueMax, valueTotal);
44274 }
44275 }
44276 }
44277};
44278/**
44279 * Returns true when the Network is active.
44280 *
44281 * @returns {boolean}
44282 */
44283
44284
44285Network.prototype.isActive = function () {
44286 return !this.activator || this.activator.active;
44287};
44288
44289Network.prototype.setSize = function () {
44290 return this.canvas.setSize.apply(this.canvas, arguments);
44291};
44292
44293Network.prototype.canvasToDOM = function () {
44294 return this.canvas.canvasToDOM.apply(this.canvas, arguments);
44295};
44296
44297Network.prototype.DOMtoCanvas = function () {
44298 return this.canvas.DOMtoCanvas.apply(this.canvas, arguments);
44299};
44300/**
44301 * Nodes can be in clusters. Clusters can also be in clusters. This function returns and array of
44302 * nodeIds showing where the node is.
44303 *
44304 * If any nodeId in the chain, especially the first passed in as a parameter, is not present in
44305 * the current nodes list, an empty array is returned.
44306 *
44307 * Example:
44308 * cluster 'A' contains cluster 'B',
44309 * cluster 'B' contains cluster 'C',
44310 * cluster 'C' contains node 'fred'.
44311 * `jsnetwork.clustering.findNode('fred')` will return `['A','B','C','fred']`.
44312 *
44313 * @param {string|number} nodeId
44314 * @returns {Array}
44315 */
44316
44317
44318Network.prototype.findNode = function () {
44319 return this.clustering.findNode.apply(this.clustering, arguments);
44320};
44321
44322Network.prototype.isCluster = function () {
44323 return this.clustering.isCluster.apply(this.clustering, arguments);
44324};
44325
44326Network.prototype.openCluster = function () {
44327 return this.clustering.openCluster.apply(this.clustering, arguments);
44328};
44329
44330Network.prototype.cluster = function () {
44331 return this.clustering.cluster.apply(this.clustering, arguments);
44332};
44333
44334Network.prototype.getNodesInCluster = function () {
44335 return this.clustering.getNodesInCluster.apply(this.clustering, arguments);
44336};
44337
44338Network.prototype.clusterByConnection = function () {
44339 return this.clustering.clusterByConnection.apply(this.clustering, arguments);
44340};
44341
44342Network.prototype.clusterByHubsize = function () {
44343 return this.clustering.clusterByHubsize.apply(this.clustering, arguments);
44344};
44345
44346Network.prototype.updateClusteredNode = function () {
44347 return this.clustering.updateClusteredNode.apply(this.clustering, arguments);
44348};
44349
44350Network.prototype.getClusteredEdges = function () {
44351 return this.clustering.getClusteredEdges.apply(this.clustering, arguments);
44352};
44353
44354Network.prototype.getBaseEdge = function () {
44355 return this.clustering.getBaseEdge.apply(this.clustering, arguments);
44356};
44357
44358Network.prototype.getBaseEdges = function () {
44359 return this.clustering.getBaseEdges.apply(this.clustering, arguments);
44360};
44361
44362Network.prototype.updateEdge = function () {
44363 return this.clustering.updateEdge.apply(this.clustering, arguments);
44364};
44365/**
44366 * This method will cluster all nodes with 1 edge with their respective connected node.
44367 * The options object is explained in full <a data-scroll="" data-options="{ &quot;easing&quot;: &quot;easeInCubic&quot; }" href="#optionsObject">below</a>.
44368 *
44369 * @param {object} [options]
44370 * @returns {undefined}
44371 */
44372
44373
44374Network.prototype.clusterOutliers = function () {
44375 return this.clustering.clusterOutliers.apply(this.clustering, arguments);
44376};
44377
44378Network.prototype.getSeed = function () {
44379 return this.layoutEngine.getSeed.apply(this.layoutEngine, arguments);
44380};
44381
44382Network.prototype.enableEditMode = function () {
44383 return this.manipulation.enableEditMode.apply(this.manipulation, arguments);
44384};
44385
44386Network.prototype.disableEditMode = function () {
44387 return this.manipulation.disableEditMode.apply(this.manipulation, arguments);
44388};
44389
44390Network.prototype.addNodeMode = function () {
44391 return this.manipulation.addNodeMode.apply(this.manipulation, arguments);
44392};
44393
44394Network.prototype.editNode = function () {
44395 return this.manipulation.editNode.apply(this.manipulation, arguments);
44396};
44397
44398Network.prototype.editNodeMode = function () {
44399 console.warn("Deprecated: Please use editNode instead of editNodeMode.");
44400 return this.manipulation.editNode.apply(this.manipulation, arguments);
44401};
44402
44403Network.prototype.addEdgeMode = function () {
44404 return this.manipulation.addEdgeMode.apply(this.manipulation, arguments);
44405};
44406
44407Network.prototype.editEdgeMode = function () {
44408 return this.manipulation.editEdgeMode.apply(this.manipulation, arguments);
44409};
44410
44411Network.prototype.deleteSelected = function () {
44412 return this.manipulation.deleteSelected.apply(this.manipulation, arguments);
44413};
44414
44415Network.prototype.getPositions = function () {
44416 return this.nodesHandler.getPositions.apply(this.nodesHandler, arguments);
44417};
44418
44419Network.prototype.getPosition = function () {
44420 return this.nodesHandler.getPosition.apply(this.nodesHandler, arguments);
44421};
44422
44423Network.prototype.storePositions = function () {
44424 return this.nodesHandler.storePositions.apply(this.nodesHandler, arguments);
44425};
44426
44427Network.prototype.moveNode = function () {
44428 return this.nodesHandler.moveNode.apply(this.nodesHandler, arguments);
44429};
44430
44431Network.prototype.getBoundingBox = function () {
44432 return this.nodesHandler.getBoundingBox.apply(this.nodesHandler, arguments);
44433};
44434
44435Network.prototype.getConnectedNodes = function (objectId) {
44436 if (this.body.nodes[objectId] !== undefined) {
44437 return this.nodesHandler.getConnectedNodes.apply(this.nodesHandler, arguments);
44438 } else {
44439 return this.edgesHandler.getConnectedNodes.apply(this.edgesHandler, arguments);
44440 }
44441};
44442
44443Network.prototype.getConnectedEdges = function () {
44444 return this.nodesHandler.getConnectedEdges.apply(this.nodesHandler, arguments);
44445};
44446
44447Network.prototype.startSimulation = function () {
44448 return this.physics.startSimulation.apply(this.physics, arguments);
44449};
44450
44451Network.prototype.stopSimulation = function () {
44452 return this.physics.stopSimulation.apply(this.physics, arguments);
44453};
44454
44455Network.prototype.stabilize = function () {
44456 return this.physics.stabilize.apply(this.physics, arguments);
44457};
44458
44459Network.prototype.getSelection = function () {
44460 return this.selectionHandler.getSelection.apply(this.selectionHandler, arguments);
44461};
44462
44463Network.prototype.setSelection = function () {
44464 return this.selectionHandler.setSelection.apply(this.selectionHandler, arguments);
44465};
44466
44467Network.prototype.getSelectedNodes = function () {
44468 return this.selectionHandler.getSelectedNodeIds.apply(this.selectionHandler, arguments);
44469};
44470
44471Network.prototype.getSelectedEdges = function () {
44472 return this.selectionHandler.getSelectedEdgeIds.apply(this.selectionHandler, arguments);
44473};
44474
44475Network.prototype.getNodeAt = function () {
44476 var node = this.selectionHandler.getNodeAt.apply(this.selectionHandler, arguments);
44477
44478 if (node !== undefined && node.id !== undefined) {
44479 return node.id;
44480 }
44481
44482 return node;
44483};
44484
44485Network.prototype.getEdgeAt = function () {
44486 var edge = this.selectionHandler.getEdgeAt.apply(this.selectionHandler, arguments);
44487
44488 if (edge !== undefined && edge.id !== undefined) {
44489 return edge.id;
44490 }
44491
44492 return edge;
44493};
44494
44495Network.prototype.selectNodes = function () {
44496 return this.selectionHandler.selectNodes.apply(this.selectionHandler, arguments);
44497};
44498
44499Network.prototype.selectEdges = function () {
44500 return this.selectionHandler.selectEdges.apply(this.selectionHandler, arguments);
44501};
44502
44503Network.prototype.unselectAll = function () {
44504 this.selectionHandler.unselectAll.apply(this.selectionHandler, arguments);
44505 this.selectionHandler.commitWithoutEmitting.apply(this.selectionHandler);
44506 this.redraw();
44507};
44508
44509Network.prototype.redraw = function () {
44510 return this.renderer.redraw.apply(this.renderer, arguments);
44511};
44512
44513Network.prototype.getScale = function () {
44514 return this.view.getScale.apply(this.view, arguments);
44515};
44516
44517Network.prototype.getViewPosition = function () {
44518 return this.view.getViewPosition.apply(this.view, arguments);
44519};
44520
44521Network.prototype.fit = function () {
44522 return this.view.fit.apply(this.view, arguments);
44523};
44524
44525Network.prototype.moveTo = function () {
44526 return this.view.moveTo.apply(this.view, arguments);
44527};
44528
44529Network.prototype.focus = function () {
44530 return this.view.focus.apply(this.view, arguments);
44531};
44532
44533Network.prototype.releaseNode = function () {
44534 return this.view.releaseNode.apply(this.view, arguments);
44535};
44536
44537Network.prototype.getOptionsFromConfigurator = function () {
44538 var options = {};
44539
44540 if (this.configurator) {
44541 options = this.configurator.getOptions.apply(this.configurator);
44542 }
44543
44544 return options;
44545};
44546
44547// DOM utility methods
44548
44549/**
44550 * this prepares the JSON container for allocating SVG elements
44551 *
44552 * @param {object} JSONcontainer
44553 * @private
44554 */
44555function prepareElements(JSONcontainer) {
44556 // cleanup the redundant svgElements;
44557 for (var elementType in JSONcontainer) {
44558 if (Object.prototype.hasOwnProperty.call(JSONcontainer, elementType)) {
44559 JSONcontainer[elementType].redundant = JSONcontainer[elementType].used;
44560 JSONcontainer[elementType].used = [];
44561 }
44562 }
44563}
44564/**
44565 * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from
44566 * which to remove the redundant elements.
44567 *
44568 * @param {object} JSONcontainer
44569 * @private
44570 */
44571
44572function cleanupElements(JSONcontainer) {
44573 // cleanup the redundant svgElements;
44574 for (var elementType in JSONcontainer) {
44575 if (Object.prototype.hasOwnProperty.call(JSONcontainer, elementType)) {
44576 if (JSONcontainer[elementType].redundant) {
44577 for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) {
44578 JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]);
44579 }
44580
44581 JSONcontainer[elementType].redundant = [];
44582 }
44583 }
44584 }
44585}
44586/**
44587 * Ensures that all elements are removed first up so they can be recreated cleanly
44588 *
44589 * @param {object} JSONcontainer
44590 */
44591
44592function resetElements(JSONcontainer) {
44593 prepareElements(JSONcontainer);
44594 cleanupElements(JSONcontainer);
44595 prepareElements(JSONcontainer);
44596}
44597/**
44598 * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
44599 * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
44600 *
44601 * @param {string} elementType
44602 * @param {object} JSONcontainer
44603 * @param {object} svgContainer
44604 * @returns {Element}
44605 * @private
44606 */
44607
44608function getSVGElement(elementType, JSONcontainer, svgContainer) {
44609 var element; // allocate SVG element, if it doesnt yet exist, create one.
44610
44611 if (Object.prototype.hasOwnProperty.call(JSONcontainer, elementType)) {
44612 // this element has been created before
44613 // check if there is an redundant element
44614 if (JSONcontainer[elementType].redundant.length > 0) {
44615 element = JSONcontainer[elementType].redundant[0];
44616 JSONcontainer[elementType].redundant.shift();
44617 } else {
44618 // create a new element and add it to the SVG
44619 element = document.createElementNS("http://www.w3.org/2000/svg", elementType);
44620 svgContainer.appendChild(element);
44621 }
44622 } else {
44623 // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
44624 element = document.createElementNS("http://www.w3.org/2000/svg", elementType);
44625 JSONcontainer[elementType] = {
44626 used: [],
44627 redundant: []
44628 };
44629 svgContainer.appendChild(element);
44630 }
44631
44632 JSONcontainer[elementType].used.push(element);
44633 return element;
44634}
44635/**
44636 * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
44637 * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
44638 *
44639 * @param {string} elementType
44640 * @param {object} JSONcontainer
44641 * @param {Element} DOMContainer
44642 * @param {Element} insertBefore
44643 * @returns {*}
44644 */
44645
44646function getDOMElement(elementType, JSONcontainer, DOMContainer, insertBefore) {
44647 var element; // allocate DOM element, if it doesnt yet exist, create one.
44648
44649 if (Object.prototype.hasOwnProperty.call(JSONcontainer, elementType)) {
44650 // this element has been created before
44651 // check if there is an redundant element
44652 if (JSONcontainer[elementType].redundant.length > 0) {
44653 element = JSONcontainer[elementType].redundant[0];
44654 JSONcontainer[elementType].redundant.shift();
44655 } else {
44656 // create a new element and add it to the SVG
44657 element = document.createElement(elementType);
44658
44659 if (insertBefore !== undefined) {
44660 DOMContainer.insertBefore(element, insertBefore);
44661 } else {
44662 DOMContainer.appendChild(element);
44663 }
44664 }
44665 } else {
44666 // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
44667 element = document.createElement(elementType);
44668 JSONcontainer[elementType] = {
44669 used: [],
44670 redundant: []
44671 };
44672
44673 if (insertBefore !== undefined) {
44674 DOMContainer.insertBefore(element, insertBefore);
44675 } else {
44676 DOMContainer.appendChild(element);
44677 }
44678 }
44679
44680 JSONcontainer[elementType].used.push(element);
44681 return element;
44682}
44683/**
44684 * Draw a point object. This is a separate function because it can also be called by the legend.
44685 * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions
44686 * as well.
44687 *
44688 * @param {number} x
44689 * @param {number} y
44690 * @param {object} groupTemplate: A template containing the necessary information to draw the datapoint e.g., {style: 'circle', size: 5, className: 'className' }
44691 * @param groupTemplate
44692 * @param {object} JSONcontainer
44693 * @param {object} svgContainer
44694 * @param {object} labelObj
44695 * @returns {vis.PointItem}
44696 */
44697
44698function drawPoint(x, y, groupTemplate, JSONcontainer, svgContainer, labelObj) {
44699 var point;
44700
44701 if (groupTemplate.style == "circle") {
44702 point = getSVGElement("circle", JSONcontainer, svgContainer);
44703 point.setAttributeNS(null, "cx", x);
44704 point.setAttributeNS(null, "cy", y);
44705 point.setAttributeNS(null, "r", 0.5 * groupTemplate.size);
44706 } else {
44707 point = getSVGElement("rect", JSONcontainer, svgContainer);
44708 point.setAttributeNS(null, "x", x - 0.5 * groupTemplate.size);
44709 point.setAttributeNS(null, "y", y - 0.5 * groupTemplate.size);
44710 point.setAttributeNS(null, "width", groupTemplate.size);
44711 point.setAttributeNS(null, "height", groupTemplate.size);
44712 }
44713
44714 if (groupTemplate.styles !== undefined) {
44715 point.setAttributeNS(null, "style", groupTemplate.styles);
44716 }
44717
44718 point.setAttributeNS(null, "class", groupTemplate.className + " vis-point"); //handle label
44719
44720 if (labelObj) {
44721 var label = getSVGElement("text", JSONcontainer, svgContainer);
44722
44723 if (labelObj.xOffset) {
44724 x = x + labelObj.xOffset;
44725 }
44726
44727 if (labelObj.yOffset) {
44728 y = y + labelObj.yOffset;
44729 }
44730
44731 if (labelObj.content) {
44732 label.textContent = labelObj.content;
44733 }
44734
44735 if (labelObj.className) {
44736 label.setAttributeNS(null, "class", labelObj.className + " vis-label");
44737 }
44738
44739 label.setAttributeNS(null, "x", x);
44740 label.setAttributeNS(null, "y", y);
44741 }
44742
44743 return point;
44744}
44745/**
44746 * draw a bar SVG element centered on the X coordinate
44747 *
44748 * @param {number} x
44749 * @param {number} y
44750 * @param {number} width
44751 * @param {number} height
44752 * @param {string} className
44753 * @param {object} JSONcontainer
44754 * @param {object} svgContainer
44755 * @param {string} style
44756 */
44757
44758function drawBar(x, y, width, height, className, JSONcontainer, svgContainer, style) {
44759 if (height != 0) {
44760 if (height < 0) {
44761 height *= -1;
44762 y -= height;
44763 }
44764
44765 var rect = getSVGElement("rect", JSONcontainer, svgContainer);
44766 rect.setAttributeNS(null, "x", x - 0.5 * width);
44767 rect.setAttributeNS(null, "y", y);
44768 rect.setAttributeNS(null, "width", width);
44769 rect.setAttributeNS(null, "height", height);
44770 rect.setAttributeNS(null, "class", className);
44771
44772 if (style) {
44773 rect.setAttributeNS(null, "style", style);
44774 }
44775 }
44776}
44777
44778var DOMutil = /*#__PURE__*/Object.freeze({
44779 __proto__: null,
44780 prepareElements: prepareElements,
44781 cleanupElements: cleanupElements,
44782 resetElements: resetElements,
44783 getSVGElement: getSVGElement,
44784 getDOMElement: getDOMElement,
44785 drawPoint: drawPoint,
44786 drawBar: drawBar
44787});
44788
44789// Network.
44790var network = {
44791 Images: Images,
44792 dotparser: dotparser,
44793 gephiParser: gephiParser,
44794 allOptions: allOptions$1,
44795 convertDot: DOTToGraph,
44796 convertGephi: parseGephi
44797}; // utils
44798
44799var indexLegacy = /*#__PURE__*/Object.freeze({
44800 __proto__: null,
44801 network: network,
44802 DOMutil: DOMutil,
44803 util: index$2,
44804 data: index,
44805 Hammer: Hammer$1,
44806 keycharm: keycharm$1,
44807 DataSet: DataSet,
44808 DataView: DataView,
44809 Queue: Queue,
44810 Network: Network
44811});
44812
44813export { DOMutil, DataSet, DataView, Hammer$1 as Hammer, Network, Queue, index as data, indexLegacy as default, keycharm$1 as keycharm, network, index$2 as util };
44814//# sourceMappingURL=vis-network.esm.js.map