UNPKG

1.23 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:43:14.666Z
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
27(function (global, factory) {
28 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vis-data/peer/umd/vis-data.js')) :
29 typeof define === 'function' && define.amd ? define(['exports', 'vis-data/peer/umd/vis-data.js'], factory) :
30 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vis = global.vis || {}, global.vis));
31}(this, (function (exports, esnext) {
32 var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
33
34 var check = function (it) {
35 return it && it.Math == Math && it;
36 }; // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
37
38
39 var global$k = // eslint-disable-next-line es/no-global-this -- safe
40 check(typeof globalThis == 'object' && globalThis) || check(typeof window == 'object' && window) || // eslint-disable-next-line no-restricted-globals -- safe
41 check(typeof self == 'object' && self) || check(typeof commonjsGlobal == 'object' && commonjsGlobal) || // eslint-disable-next-line no-new-func -- fallback
42 function () {
43 return this;
44 }() || Function('return this')();
45
46 var objectGetOwnPropertyDescriptor = {};
47
48 var fails$m = function (exec) {
49 try {
50 return !!exec();
51 } catch (error) {
52 return true;
53 }
54 };
55
56 var fails$l = fails$m; // Detect IE8's incomplete defineProperty implementation
57
58 var descriptors = !fails$l(function () {
59 // eslint-disable-next-line es/no-object-defineproperty -- required for testing
60 return Object.defineProperty({}, 1, {
61 get: function () {
62 return 7;
63 }
64 })[1] != 7;
65 });
66
67 var objectPropertyIsEnumerable = {};
68
69 var $propertyIsEnumerable$1 = {}.propertyIsEnumerable; // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
70
71 var getOwnPropertyDescriptor$7 = Object.getOwnPropertyDescriptor; // Nashorn ~ JDK8 bug
72
73 var NASHORN_BUG = getOwnPropertyDescriptor$7 && !$propertyIsEnumerable$1.call({
74 1: 2
75 }, 1); // `Object.prototype.propertyIsEnumerable` method implementation
76 // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
77
78 objectPropertyIsEnumerable.f = NASHORN_BUG ? function propertyIsEnumerable(V) {
79 var descriptor = getOwnPropertyDescriptor$7(this, V);
80 return !!descriptor && descriptor.enumerable;
81 } : $propertyIsEnumerable$1;
82
83 var createPropertyDescriptor$5 = function (bitmap, value) {
84 return {
85 enumerable: !(bitmap & 1),
86 configurable: !(bitmap & 2),
87 writable: !(bitmap & 4),
88 value: value
89 };
90 };
91
92 var toString$a = {}.toString;
93
94 var classofRaw$1 = function (it) {
95 return toString$a.call(it).slice(8, -1);
96 };
97
98 var fails$k = fails$m;
99 var classof$9 = classofRaw$1;
100 var split = ''.split; // fallback for non-array-like ES3 and non-enumerable old V8 strings
101
102 var indexedObject = fails$k(function () {
103 // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
104 // eslint-disable-next-line no-prototype-builtins -- safe
105 return !Object('z').propertyIsEnumerable(0);
106 }) ? function (it) {
107 return classof$9(it) == 'String' ? split.call(it, '') : Object(it);
108 } : Object;
109
110 // https://tc39.es/ecma262/#sec-requireobjectcoercible
111
112 var requireObjectCoercible$5 = function (it) {
113 if (it == undefined) throw TypeError("Can't call method on " + it);
114 return it;
115 };
116
117 var IndexedObject$3 = indexedObject;
118 var requireObjectCoercible$4 = requireObjectCoercible$5;
119
120 var toIndexedObject$a = function (it) {
121 return IndexedObject$3(requireObjectCoercible$4(it));
122 };
123
124 var isObject$j = function (it) {
125 return typeof it === 'object' ? it !== null : typeof it === 'function';
126 };
127
128 var path$x = {};
129
130 var path$w = path$x;
131 var global$j = global$k;
132
133 var aFunction$6 = function (variable) {
134 return typeof variable == 'function' ? variable : undefined;
135 };
136
137 var getBuiltIn$8 = function (namespace, method) {
138 return arguments.length < 2 ? aFunction$6(path$w[namespace]) || aFunction$6(global$j[namespace]) : path$w[namespace] && path$w[namespace][method] || global$j[namespace] && global$j[namespace][method];
139 };
140
141 var getBuiltIn$7 = getBuiltIn$8;
142 var engineUserAgent = getBuiltIn$7('navigator', 'userAgent') || '';
143
144 var global$i = global$k;
145 var userAgent$3 = engineUserAgent;
146 var process = global$i.process;
147 var Deno = global$i.Deno;
148 var versions = process && process.versions || Deno && Deno.version;
149 var v8 = versions && versions.v8;
150 var match, version;
151
152 if (v8) {
153 match = v8.split('.');
154 version = match[0] < 4 ? 1 : match[0] + match[1];
155 } else if (userAgent$3) {
156 match = userAgent$3.match(/Edge\/(\d+)/);
157
158 if (!match || match[1] >= 74) {
159 match = userAgent$3.match(/Chrome\/(\d+)/);
160 if (match) version = match[1];
161 }
162 }
163
164 var engineV8Version = version && +version;
165
166 /* eslint-disable es/no-symbol -- required for testing */
167 var V8_VERSION$2 = engineV8Version;
168 var fails$j = fails$m; // eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
169
170 var nativeSymbol = !!Object.getOwnPropertySymbols && !fails$j(function () {
171 var symbol = Symbol(); // Chrome 38 Symbol has incorrect toString conversion
172 // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
173
174 return !String(symbol) || !(Object(symbol) instanceof Symbol) || // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
175 !Symbol.sham && V8_VERSION$2 && V8_VERSION$2 < 41;
176 });
177
178 /* eslint-disable es/no-symbol -- required for testing */
179 var NATIVE_SYMBOL$2 = nativeSymbol;
180 var useSymbolAsUid = NATIVE_SYMBOL$2 && !Symbol.sham && typeof Symbol.iterator == 'symbol';
181
182 var getBuiltIn$6 = getBuiltIn$8;
183 var USE_SYMBOL_AS_UID$1 = useSymbolAsUid;
184 var isSymbol$4 = USE_SYMBOL_AS_UID$1 ? function (it) {
185 return typeof it == 'symbol';
186 } : function (it) {
187 var $Symbol = getBuiltIn$6('Symbol');
188 return typeof $Symbol == 'function' && Object(it) instanceof $Symbol;
189 };
190
191 var isObject$i = isObject$j; // `OrdinaryToPrimitive` abstract operation
192 // https://tc39.es/ecma262/#sec-ordinarytoprimitive
193
194 var ordinaryToPrimitive$1 = function (input, pref) {
195 var fn, val;
196 if (pref === 'string' && typeof (fn = input.toString) == 'function' && !isObject$i(val = fn.call(input))) return val;
197 if (typeof (fn = input.valueOf) == 'function' && !isObject$i(val = fn.call(input))) return val;
198 if (pref !== 'string' && typeof (fn = input.toString) == 'function' && !isObject$i(val = fn.call(input))) return val;
199 throw TypeError("Can't convert object to primitive value");
200 };
201
202 var shared$4 = {exports: {}};
203
204 var global$h = global$k;
205
206 var setGlobal$1 = function (key, value) {
207 try {
208 // eslint-disable-next-line es/no-object-defineproperty -- safe
209 Object.defineProperty(global$h, key, {
210 value: value,
211 configurable: true,
212 writable: true
213 });
214 } catch (error) {
215 global$h[key] = value;
216 }
217
218 return value;
219 };
220
221 var global$g = global$k;
222 var setGlobal = setGlobal$1;
223 var SHARED = '__core-js_shared__';
224 var store$3 = global$g[SHARED] || setGlobal(SHARED, {});
225 var sharedStore = store$3;
226
227 var store$2 = sharedStore;
228 (shared$4.exports = function (key, value) {
229 return store$2[key] || (store$2[key] = value !== undefined ? value : {});
230 })('versions', []).push({
231 version: '3.16.1',
232 mode: 'pure' ,
233 copyright: '© 2021 Denis Pushkarev (zloirock.ru)'
234 });
235
236 var requireObjectCoercible$3 = requireObjectCoercible$5; // `ToObject` abstract operation
237 // https://tc39.es/ecma262/#sec-toobject
238
239 var toObject$d = function (argument) {
240 return Object(requireObjectCoercible$3(argument));
241 };
242
243 var toObject$c = toObject$d;
244 var hasOwnProperty = {}.hasOwnProperty;
245
246 var has$c = Object.hasOwn || function hasOwn(it, key) {
247 return hasOwnProperty.call(toObject$c(it), key);
248 };
249
250 var id$2 = 0;
251 var postfix = Math.random();
252
253 var uid$4 = function (key) {
254 return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id$2 + postfix).toString(36);
255 };
256
257 var global$f = global$k;
258 var shared$3 = shared$4.exports;
259 var has$b = has$c;
260 var uid$3 = uid$4;
261 var NATIVE_SYMBOL$1 = nativeSymbol;
262 var USE_SYMBOL_AS_UID = useSymbolAsUid;
263 var WellKnownSymbolsStore$1 = shared$3('wks');
264 var Symbol$1 = global$f.Symbol;
265 var createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid$3;
266
267 var wellKnownSymbol$j = function (name) {
268 if (!has$b(WellKnownSymbolsStore$1, name) || !(NATIVE_SYMBOL$1 || typeof WellKnownSymbolsStore$1[name] == 'string')) {
269 if (NATIVE_SYMBOL$1 && has$b(Symbol$1, name)) {
270 WellKnownSymbolsStore$1[name] = Symbol$1[name];
271 } else {
272 WellKnownSymbolsStore$1[name] = createWellKnownSymbol('Symbol.' + name);
273 }
274 }
275
276 return WellKnownSymbolsStore$1[name];
277 };
278
279 var isObject$h = isObject$j;
280 var isSymbol$3 = isSymbol$4;
281 var ordinaryToPrimitive = ordinaryToPrimitive$1;
282 var wellKnownSymbol$i = wellKnownSymbol$j;
283 var TO_PRIMITIVE$1 = wellKnownSymbol$i('toPrimitive'); // `ToPrimitive` abstract operation
284 // https://tc39.es/ecma262/#sec-toprimitive
285
286 var toPrimitive$1 = function (input, pref) {
287 if (!isObject$h(input) || isSymbol$3(input)) return input;
288 var exoticToPrim = input[TO_PRIMITIVE$1];
289 var result;
290
291 if (exoticToPrim !== undefined) {
292 if (pref === undefined) pref = 'default';
293 result = exoticToPrim.call(input, pref);
294 if (!isObject$h(result) || isSymbol$3(result)) return result;
295 throw TypeError("Can't convert object to primitive value");
296 }
297
298 if (pref === undefined) pref = 'number';
299 return ordinaryToPrimitive(input, pref);
300 };
301
302 var toPrimitive = toPrimitive$1;
303 var isSymbol$2 = isSymbol$4; // `ToPropertyKey` abstract operation
304 // https://tc39.es/ecma262/#sec-topropertykey
305
306 var toPropertyKey$4 = function (argument) {
307 var key = toPrimitive(argument, 'string');
308 return isSymbol$2(key) ? key : String(key);
309 };
310
311 var global$e = global$k;
312 var isObject$g = isObject$j;
313 var document$1 = global$e.document; // typeof document.createElement is 'object' in old IE
314
315 var EXISTS = isObject$g(document$1) && isObject$g(document$1.createElement);
316
317 var documentCreateElement$1 = function (it) {
318 return EXISTS ? document$1.createElement(it) : {};
319 };
320
321 var DESCRIPTORS$f = descriptors;
322 var fails$i = fails$m;
323 var createElement = documentCreateElement$1; // Thank's IE8 for his funny defineProperty
324
325 var ie8DomDefine = !DESCRIPTORS$f && !fails$i(function () {
326 // eslint-disable-next-line es/no-object-defineproperty -- requied for testing
327 return Object.defineProperty(createElement('div'), 'a', {
328 get: function () {
329 return 7;
330 }
331 }).a != 7;
332 });
333
334 var DESCRIPTORS$e = descriptors;
335 var propertyIsEnumerableModule$2 = objectPropertyIsEnumerable;
336 var createPropertyDescriptor$4 = createPropertyDescriptor$5;
337 var toIndexedObject$9 = toIndexedObject$a;
338 var toPropertyKey$3 = toPropertyKey$4;
339 var has$a = has$c;
340 var IE8_DOM_DEFINE$1 = ie8DomDefine; // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
341
342 var $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor; // `Object.getOwnPropertyDescriptor` method
343 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
344
345 objectGetOwnPropertyDescriptor.f = DESCRIPTORS$e ? $getOwnPropertyDescriptor$1 : function getOwnPropertyDescriptor(O, P) {
346 O = toIndexedObject$9(O);
347 P = toPropertyKey$3(P);
348 if (IE8_DOM_DEFINE$1) try {
349 return $getOwnPropertyDescriptor$1(O, P);
350 } catch (error) {
351 /* empty */
352 }
353 if (has$a(O, P)) return createPropertyDescriptor$4(!propertyIsEnumerableModule$2.f.call(O, P), O[P]);
354 };
355
356 var fails$h = fails$m;
357 var replacement = /#|\.prototype\./;
358
359 var isForced$1 = function (feature, detection) {
360 var value = data[normalize(feature)];
361 return value == POLYFILL ? true : value == NATIVE ? false : typeof detection == 'function' ? fails$h(detection) : !!detection;
362 };
363
364 var normalize = isForced$1.normalize = function (string) {
365 return String(string).replace(replacement, '.').toLowerCase();
366 };
367
368 var data = isForced$1.data = {};
369 var NATIVE = isForced$1.NATIVE = 'N';
370 var POLYFILL = isForced$1.POLYFILL = 'P';
371 var isForced_1 = isForced$1;
372
373 var aFunction$5 = function (it) {
374 if (typeof it != 'function') {
375 throw TypeError(String(it) + ' is not a function');
376 }
377
378 return it;
379 };
380
381 var aFunction$4 = aFunction$5; // optional / simple context binding
382
383 var functionBindContext = function (fn, that, length) {
384 aFunction$4(fn);
385 if (that === undefined) return fn;
386
387 switch (length) {
388 case 0:
389 return function () {
390 return fn.call(that);
391 };
392
393 case 1:
394 return function (a) {
395 return fn.call(that, a);
396 };
397
398 case 2:
399 return function (a, b) {
400 return fn.call(that, a, b);
401 };
402
403 case 3:
404 return function (a, b, c) {
405 return fn.call(that, a, b, c);
406 };
407 }
408
409 return function () {
410 return fn.apply(that, arguments);
411 };
412 };
413
414 var objectDefineProperty = {};
415
416 var isObject$f = isObject$j;
417
418 var anObject$c = function (it) {
419 if (!isObject$f(it)) {
420 throw TypeError(String(it) + ' is not an object');
421 }
422
423 return it;
424 };
425
426 var DESCRIPTORS$d = descriptors;
427 var IE8_DOM_DEFINE = ie8DomDefine;
428 var anObject$b = anObject$c;
429 var toPropertyKey$2 = toPropertyKey$4; // eslint-disable-next-line es/no-object-defineproperty -- safe
430
431 var $defineProperty$1 = Object.defineProperty; // `Object.defineProperty` method
432 // https://tc39.es/ecma262/#sec-object.defineproperty
433
434 objectDefineProperty.f = DESCRIPTORS$d ? $defineProperty$1 : function defineProperty(O, P, Attributes) {
435 anObject$b(O);
436 P = toPropertyKey$2(P);
437 anObject$b(Attributes);
438 if (IE8_DOM_DEFINE) try {
439 return $defineProperty$1(O, P, Attributes);
440 } catch (error) {
441 /* empty */
442 }
443 if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
444 if ('value' in Attributes) O[P] = Attributes.value;
445 return O;
446 };
447
448 var DESCRIPTORS$c = descriptors;
449 var definePropertyModule$4 = objectDefineProperty;
450 var createPropertyDescriptor$3 = createPropertyDescriptor$5;
451 var createNonEnumerableProperty$9 = DESCRIPTORS$c ? function (object, key, value) {
452 return definePropertyModule$4.f(object, key, createPropertyDescriptor$3(1, value));
453 } : function (object, key, value) {
454 object[key] = value;
455 return object;
456 };
457
458 var global$d = global$k;
459 var getOwnPropertyDescriptor$6 = objectGetOwnPropertyDescriptor.f;
460 var isForced = isForced_1;
461 var path$v = path$x;
462 var bind$a = functionBindContext;
463 var createNonEnumerableProperty$8 = createNonEnumerableProperty$9;
464 var has$9 = has$c;
465
466 var wrapConstructor = function (NativeConstructor) {
467 var Wrapper = function (a, b, c) {
468 if (this instanceof NativeConstructor) {
469 switch (arguments.length) {
470 case 0:
471 return new NativeConstructor();
472
473 case 1:
474 return new NativeConstructor(a);
475
476 case 2:
477 return new NativeConstructor(a, b);
478 }
479
480 return new NativeConstructor(a, b, c);
481 }
482
483 return NativeConstructor.apply(this, arguments);
484 };
485
486 Wrapper.prototype = NativeConstructor.prototype;
487 return Wrapper;
488 };
489 /*
490 options.target - name of the target object
491 options.global - target is the global object
492 options.stat - export as static methods of target
493 options.proto - export as prototype methods of target
494 options.real - real prototype method for the `pure` version
495 options.forced - export even if the native feature is available
496 options.bind - bind methods to the target, required for the `pure` version
497 options.wrap - wrap constructors to preventing global pollution, required for the `pure` version
498 options.unsafe - use the simple assignment of property instead of delete + defineProperty
499 options.sham - add a flag to not completely full polyfills
500 options.enumerable - export as enumerable property
501 options.noTargetGet - prevent calling a getter on target
502 */
503
504
505 var _export = function (options, source) {
506 var TARGET = options.target;
507 var GLOBAL = options.global;
508 var STATIC = options.stat;
509 var PROTO = options.proto;
510 var nativeSource = GLOBAL ? global$d : STATIC ? global$d[TARGET] : (global$d[TARGET] || {}).prototype;
511 var target = GLOBAL ? path$v : path$v[TARGET] || (path$v[TARGET] = {});
512 var targetPrototype = target.prototype;
513 var FORCED, USE_NATIVE, VIRTUAL_PROTOTYPE;
514 var key, sourceProperty, targetProperty, nativeProperty, resultProperty, descriptor;
515
516 for (key in source) {
517 FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced); // contains in native
518
519 USE_NATIVE = !FORCED && nativeSource && has$9(nativeSource, key);
520 targetProperty = target[key];
521 if (USE_NATIVE) if (options.noTargetGet) {
522 descriptor = getOwnPropertyDescriptor$6(nativeSource, key);
523 nativeProperty = descriptor && descriptor.value;
524 } else nativeProperty = nativeSource[key]; // export native or implementation
525
526 sourceProperty = USE_NATIVE && nativeProperty ? nativeProperty : source[key];
527 if (USE_NATIVE && typeof targetProperty === typeof sourceProperty) continue; // bind timers to global for call from export context
528
529 if (options.bind && USE_NATIVE) resultProperty = bind$a(sourceProperty, global$d); // wrap global constructors for prevent changs in this version
530 else if (options.wrap && USE_NATIVE) resultProperty = wrapConstructor(sourceProperty); // make static versions for prototype methods
531 else if (PROTO && typeof sourceProperty == 'function') resultProperty = bind$a(Function.call, sourceProperty); // default case
532 else resultProperty = sourceProperty; // add a flag to not completely full polyfills
533
534 if (options.sham || sourceProperty && sourceProperty.sham || targetProperty && targetProperty.sham) {
535 createNonEnumerableProperty$8(resultProperty, 'sham', true);
536 }
537
538 target[key] = resultProperty;
539
540 if (PROTO) {
541 VIRTUAL_PROTOTYPE = TARGET + 'Prototype';
542
543 if (!has$9(path$v, VIRTUAL_PROTOTYPE)) {
544 createNonEnumerableProperty$8(path$v, VIRTUAL_PROTOTYPE, {});
545 } // export virtual prototype methods
546
547
548 path$v[VIRTUAL_PROTOTYPE][key] = sourceProperty; // export real prototype methods
549
550 if (options.real && targetPrototype && !targetPrototype[key]) {
551 createNonEnumerableProperty$8(targetPrototype, key, sourceProperty);
552 }
553 }
554 }
555 };
556
557 var ceil = Math.ceil;
558 var floor$1 = Math.floor; // `ToInteger` abstract operation
559 // https://tc39.es/ecma262/#sec-tointeger
560
561 var toInteger$4 = function (argument) {
562 return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor$1 : ceil)(argument);
563 };
564
565 var toInteger$3 = toInteger$4;
566 var min$2 = Math.min; // `ToLength` abstract operation
567 // https://tc39.es/ecma262/#sec-tolength
568
569 var toLength$a = function (argument) {
570 return argument > 0 ? min$2(toInteger$3(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
571 };
572
573 var toInteger$2 = toInteger$4;
574 var max$2 = Math.max;
575 var min$1 = Math.min; // Helper for a popular repeating case of the spec:
576 // Let integer be ? ToInteger(index).
577 // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
578
579 var toAbsoluteIndex$4 = function (index, length) {
580 var integer = toInteger$2(index);
581 return integer < 0 ? max$2(integer + length, 0) : min$1(integer, length);
582 };
583
584 var toIndexedObject$8 = toIndexedObject$a;
585 var toLength$9 = toLength$a;
586 var toAbsoluteIndex$3 = toAbsoluteIndex$4; // `Array.prototype.{ indexOf, includes }` methods implementation
587
588 var createMethod$5 = function (IS_INCLUDES) {
589 return function ($this, el, fromIndex) {
590 var O = toIndexedObject$8($this);
591 var length = toLength$9(O.length);
592 var index = toAbsoluteIndex$3(fromIndex, length);
593 var value; // Array#includes uses SameValueZero equality algorithm
594 // eslint-disable-next-line no-self-compare -- NaN check
595
596 if (IS_INCLUDES && el != el) while (length > index) {
597 value = O[index++]; // eslint-disable-next-line no-self-compare -- NaN check
598
599 if (value != value) return true; // Array#indexOf ignores holes, Array#includes - not
600 } else for (; length > index; index++) {
601 if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
602 }
603 return !IS_INCLUDES && -1;
604 };
605 };
606
607 var arrayIncludes$1 = {
608 // `Array.prototype.includes` method
609 // https://tc39.es/ecma262/#sec-array.prototype.includes
610 includes: createMethod$5(true),
611 // `Array.prototype.indexOf` method
612 // https://tc39.es/ecma262/#sec-array.prototype.indexof
613 indexOf: createMethod$5(false)
614 };
615
616 var hiddenKeys$6 = {};
617
618 var has$8 = has$c;
619 var toIndexedObject$7 = toIndexedObject$a;
620 var indexOf$4 = arrayIncludes$1.indexOf;
621 var hiddenKeys$5 = hiddenKeys$6;
622
623 var objectKeysInternal = function (object, names) {
624 var O = toIndexedObject$7(object);
625 var i = 0;
626 var result = [];
627 var key;
628
629 for (key in O) !has$8(hiddenKeys$5, key) && has$8(O, key) && result.push(key); // Don't enum bug & hidden keys
630
631
632 while (names.length > i) if (has$8(O, key = names[i++])) {
633 ~indexOf$4(result, key) || result.push(key);
634 }
635
636 return result;
637 };
638
639 var enumBugKeys$3 = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'];
640
641 var internalObjectKeys$1 = objectKeysInternal;
642 var enumBugKeys$2 = enumBugKeys$3; // `Object.keys` method
643 // https://tc39.es/ecma262/#sec-object.keys
644 // eslint-disable-next-line es/no-object-keys -- safe
645
646 var objectKeys$4 = Object.keys || function keys(O) {
647 return internalObjectKeys$1(O, enumBugKeys$2);
648 };
649
650 var objectGetOwnPropertySymbols = {};
651
652 objectGetOwnPropertySymbols.f = Object.getOwnPropertySymbols;
653
654 var DESCRIPTORS$b = descriptors;
655 var fails$g = fails$m;
656 var objectKeys$3 = objectKeys$4;
657 var getOwnPropertySymbolsModule$2 = objectGetOwnPropertySymbols;
658 var propertyIsEnumerableModule$1 = objectPropertyIsEnumerable;
659 var toObject$b = toObject$d;
660 var IndexedObject$2 = indexedObject; // eslint-disable-next-line es/no-object-assign -- safe
661
662 var $assign = Object.assign; // eslint-disable-next-line es/no-object-defineproperty -- required for testing
663
664 var defineProperty$b = Object.defineProperty; // `Object.assign` method
665 // https://tc39.es/ecma262/#sec-object.assign
666
667 var objectAssign = !$assign || fails$g(function () {
668 // should have correct order of operations (Edge bug)
669 if (DESCRIPTORS$b && $assign({
670 b: 1
671 }, $assign(defineProperty$b({}, 'a', {
672 enumerable: true,
673 get: function () {
674 defineProperty$b(this, 'b', {
675 value: 3,
676 enumerable: false
677 });
678 }
679 }), {
680 b: 2
681 })).b !== 1) return true; // should work with symbols and should have deterministic property order (V8 bug)
682
683 var A = {};
684 var B = {}; // eslint-disable-next-line es/no-symbol -- safe
685
686 var symbol = Symbol();
687 var alphabet = 'abcdefghijklmnopqrst';
688 A[symbol] = 7;
689 alphabet.split('').forEach(function (chr) {
690 B[chr] = chr;
691 });
692 return $assign({}, A)[symbol] != 7 || objectKeys$3($assign({}, B)).join('') != alphabet;
693 }) ? function assign(target, source) {
694 // eslint-disable-line no-unused-vars -- required for `.length`
695 var T = toObject$b(target);
696 var argumentsLength = arguments.length;
697 var index = 1;
698 var getOwnPropertySymbols = getOwnPropertySymbolsModule$2.f;
699 var propertyIsEnumerable = propertyIsEnumerableModule$1.f;
700
701 while (argumentsLength > index) {
702 var S = IndexedObject$2(arguments[index++]);
703 var keys = getOwnPropertySymbols ? objectKeys$3(S).concat(getOwnPropertySymbols(S)) : objectKeys$3(S);
704 var length = keys.length;
705 var j = 0;
706 var key;
707
708 while (length > j) {
709 key = keys[j++];
710 if (!DESCRIPTORS$b || propertyIsEnumerable.call(S, key)) T[key] = S[key];
711 }
712 }
713
714 return T;
715 } : $assign;
716
717 var $$I = _export;
718 var assign$5 = objectAssign; // `Object.assign` method
719 // https://tc39.es/ecma262/#sec-object.assign
720 // eslint-disable-next-line es/no-object-assign -- required for testing
721
722 $$I({
723 target: 'Object',
724 stat: true,
725 forced: Object.assign !== assign$5
726 }, {
727 assign: assign$5
728 });
729
730 var path$u = path$x;
731 var assign$4 = path$u.Object.assign;
732
733 var parent$T = assign$4;
734 var assign$3 = parent$T;
735
736 var assign$2 = assign$3;
737
738 var aFunction$3 = aFunction$5;
739 var isObject$e = isObject$j;
740 var slice$7 = [].slice;
741 var factories = {};
742
743 var construct$3 = function (C, argsLength, args) {
744 if (!(argsLength in factories)) {
745 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
746
747
748 factories[argsLength] = Function('C,a', 'return new C(' + list.join(',') + ')');
749 }
750
751 return factories[argsLength](C, args);
752 }; // `Function.prototype.bind` method implementation
753 // https://tc39.es/ecma262/#sec-function.prototype.bind
754
755
756 var functionBind = Function.bind || function bind(that
757 /* , ...args */
758 ) {
759 var fn = aFunction$3(this);
760 var partArgs = slice$7.call(arguments, 1);
761
762 var boundFunction = function bound() {
763 var args = partArgs.concat(slice$7.call(arguments));
764 return this instanceof boundFunction ? construct$3(fn, args.length, args) : fn.apply(that, args);
765 };
766
767 if (isObject$e(fn.prototype)) boundFunction.prototype = fn.prototype;
768 return boundFunction;
769 };
770
771 var $$H = _export;
772 var bind$9 = functionBind; // `Function.prototype.bind` method
773 // https://tc39.es/ecma262/#sec-function.prototype.bind
774
775 $$H({
776 target: 'Function',
777 proto: true
778 }, {
779 bind: bind$9
780 });
781
782 var path$t = path$x;
783
784 var entryVirtual$i = function (CONSTRUCTOR) {
785 return path$t[CONSTRUCTOR + 'Prototype'];
786 };
787
788 var entryVirtual$h = entryVirtual$i;
789 var bind$8 = entryVirtual$h('Function').bind;
790
791 var bind$7 = bind$8;
792 var FunctionPrototype = Function.prototype;
793
794 var bind_1 = function (it) {
795 var own = it.bind;
796 return it === FunctionPrototype || it instanceof Function && own === FunctionPrototype.bind ? bind$7 : own;
797 };
798
799 var parent$S = bind_1;
800 var bind$6 = parent$S;
801
802 var bind$5 = bind$6;
803
804 /**
805 * Draw a circle.
806 *
807 * @param ctx - The context this shape will be rendered to.
808 * @param x - The position of the center on the x axis.
809 * @param y - The position of the center on the y axis.
810 * @param r - The radius of the circle.
811 */
812 function drawCircle(ctx, x, y, r) {
813 ctx.beginPath();
814 ctx.arc(x, y, r, 0, 2 * Math.PI, false);
815 ctx.closePath();
816 }
817 /**
818 * Draw a square.
819 *
820 * @param ctx - The context this shape will be rendered to.
821 * @param x - The position of the center on the x axis.
822 * @param y - The position of the center on the y axis.
823 * @param r - Half of the width and height of the square.
824 */
825
826 function drawSquare(ctx, x, y, r) {
827 ctx.beginPath();
828 ctx.rect(x - r, y - r, r * 2, r * 2);
829 ctx.closePath();
830 }
831 /**
832 * Draw an equilateral triangle standing on a side.
833 *
834 * @param ctx - The context this shape will be rendered to.
835 * @param x - The position of the center on the x axis.
836 * @param y - The position of the center on the y axis.
837 * @param r - Half of the length of the sides.
838 *
839 * @remarks
840 * http://en.wikipedia.org/wiki/Equilateral_triangle
841 */
842
843 function drawTriangle(ctx, x, y, r) {
844 ctx.beginPath(); // the change in radius and the offset is here to center the shape
845
846 r *= 1.15;
847 y += 0.275 * r;
848 var s = r * 2;
849 var s2 = s / 2;
850 var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
851
852 var h = Math.sqrt(s * s - s2 * s2); // height
853
854 ctx.moveTo(x, y - (h - ir));
855 ctx.lineTo(x + s2, y + ir);
856 ctx.lineTo(x - s2, y + ir);
857 ctx.lineTo(x, y - (h - ir));
858 ctx.closePath();
859 }
860 /**
861 * Draw an equilateral triangle standing on a vertex.
862 *
863 * @param ctx - The context this shape will be rendered to.
864 * @param x - The position of the center on the x axis.
865 * @param y - The position of the center on the y axis.
866 * @param r - Half of the length of the sides.
867 *
868 * @remarks
869 * http://en.wikipedia.org/wiki/Equilateral_triangle
870 */
871
872 function drawTriangleDown(ctx, x, y, r) {
873 ctx.beginPath(); // the change in radius and the offset is here to center the shape
874
875 r *= 1.15;
876 y -= 0.275 * r;
877 var s = r * 2;
878 var s2 = s / 2;
879 var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
880
881 var h = Math.sqrt(s * s - s2 * s2); // height
882
883 ctx.moveTo(x, y + (h - ir));
884 ctx.lineTo(x + s2, y - ir);
885 ctx.lineTo(x - s2, y - ir);
886 ctx.lineTo(x, y + (h - ir));
887 ctx.closePath();
888 }
889 /**
890 * Draw a star.
891 *
892 * @param ctx - The context this shape will be rendered to.
893 * @param x - The position of the center on the x axis.
894 * @param y - The position of the center on the y axis.
895 * @param r - The outer radius of the star.
896 */
897
898 function drawStar(ctx, x, y, r) {
899 // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
900 ctx.beginPath(); // the change in radius and the offset is here to center the shape
901
902 r *= 0.82;
903 y += 0.1 * r;
904
905 for (var n = 0; n < 10; n++) {
906 var radius = n % 2 === 0 ? r * 1.3 : r * 0.5;
907 ctx.lineTo(x + radius * Math.sin(n * 2 * Math.PI / 10), y - radius * Math.cos(n * 2 * Math.PI / 10));
908 }
909
910 ctx.closePath();
911 }
912 /**
913 * Draw a diamond.
914 *
915 * @param ctx - The context this shape will be rendered to.
916 * @param x - The position of the center on the x axis.
917 * @param y - The position of the center on the y axis.
918 * @param r - Half of the width and height of the diamond.
919 *
920 * @remarks
921 * http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
922 */
923
924 function drawDiamond(ctx, x, y, r) {
925 ctx.beginPath();
926 ctx.lineTo(x, y + r);
927 ctx.lineTo(x + r, y);
928 ctx.lineTo(x, y - r);
929 ctx.lineTo(x - r, y);
930 ctx.closePath();
931 }
932 /**
933 * Draw a rectangle with rounded corners.
934 *
935 * @param ctx - The context this shape will be rendered to.
936 * @param x - The position of the center on the x axis.
937 * @param y - The position of the center on the y axis.
938 * @param w - The width of the rectangle.
939 * @param h - The height of the rectangle.
940 * @param r - The radius of the corners.
941 *
942 * @remarks
943 * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas
944 */
945
946 function drawRoundRect(ctx, x, y, w, h, r) {
947 var r2d = Math.PI / 180;
948
949 if (w - 2 * r < 0) {
950 r = w / 2;
951 } //ensure that the radius isn't too large for x
952
953
954 if (h - 2 * r < 0) {
955 r = h / 2;
956 } //ensure that the radius isn't too large for y
957
958
959 ctx.beginPath();
960 ctx.moveTo(x + r, y);
961 ctx.lineTo(x + w - r, y);
962 ctx.arc(x + w - r, y + r, r, r2d * 270, r2d * 360, false);
963 ctx.lineTo(x + w, y + h - r);
964 ctx.arc(x + w - r, y + h - r, r, 0, r2d * 90, false);
965 ctx.lineTo(x + r, y + h);
966 ctx.arc(x + r, y + h - r, r, r2d * 90, r2d * 180, false);
967 ctx.lineTo(x, y + r);
968 ctx.arc(x + r, y + r, r, r2d * 180, r2d * 270, false);
969 ctx.closePath();
970 }
971 /**
972 * Draw an ellipse.
973 *
974 * @param ctx - The context this shape will be rendered to.
975 * @param x - The position of the center on the x axis.
976 * @param y - The position of the center on the y axis.
977 * @param w - The width of the ellipse.
978 * @param h - The height of the ellipse.
979 *
980 * @remarks
981 * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
982 *
983 * Postfix '_vis' added to discern it from standard method ellipse().
984 */
985
986 function drawEllipse(ctx, x, y, w, h) {
987 var kappa = 0.5522848,
988 ox = w / 2 * kappa,
989 // control point offset horizontal
990 oy = h / 2 * kappa,
991 // control point offset vertical
992 xe = x + w,
993 // x-end
994 ye = y + h,
995 // y-end
996 xm = x + w / 2,
997 // x-middle
998 ym = y + h / 2; // y-middle
999
1000 ctx.beginPath();
1001 ctx.moveTo(x, ym);
1002 ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
1003 ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
1004 ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
1005 ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
1006 ctx.closePath();
1007 }
1008 /**
1009 * Draw an isometric cylinder.
1010 *
1011 * @param ctx - The context this shape will be rendered to.
1012 * @param x - The position of the center on the x axis.
1013 * @param y - The position of the center on the y axis.
1014 * @param w - The width of the database.
1015 * @param h - The height of the database.
1016 *
1017 * @remarks
1018 * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
1019 */
1020
1021 function drawDatabase(ctx, x, y, w, h) {
1022 var f = 1 / 3;
1023 var wEllipse = w;
1024 var hEllipse = h * f;
1025 var kappa = 0.5522848,
1026 ox = wEllipse / 2 * kappa,
1027 // control point offset horizontal
1028 oy = hEllipse / 2 * kappa,
1029 // control point offset vertical
1030 xe = x + wEllipse,
1031 // x-end
1032 ye = y + hEllipse,
1033 // y-end
1034 xm = x + wEllipse / 2,
1035 // x-middle
1036 ym = y + hEllipse / 2,
1037 // y-middle
1038 ymb = y + (h - hEllipse / 2),
1039 // y-midlle, bottom ellipse
1040 yeb = y + h; // y-end, bottom ellipse
1041
1042 ctx.beginPath();
1043 ctx.moveTo(xe, ym);
1044 ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
1045 ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
1046 ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
1047 ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
1048 ctx.lineTo(xe, ymb);
1049 ctx.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb);
1050 ctx.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb);
1051 ctx.lineTo(x, ym);
1052 }
1053 /**
1054 * Draw a dashed line.
1055 *
1056 * @param ctx - The context this shape will be rendered to.
1057 * @param x - The start position on the x axis.
1058 * @param y - The start position on the y axis.
1059 * @param x2 - The end position on the x axis.
1060 * @param y2 - The end position on the y axis.
1061 * @param pattern - List of lengths starting with line and then alternating between space and line.
1062 *
1063 * @author David Jordan
1064 * @remarks
1065 * date 2012-08-08
1066 * http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas
1067 */
1068
1069 function drawDashedLine(ctx, x, y, x2, y2, pattern) {
1070 ctx.beginPath();
1071 ctx.moveTo(x, y);
1072 var patternLength = pattern.length;
1073 var dx = x2 - x;
1074 var dy = y2 - y;
1075 var slope = dy / dx;
1076 var distRemaining = Math.sqrt(dx * dx + dy * dy);
1077 var patternIndex = 0;
1078 var draw = true;
1079 var xStep = 0;
1080 var dashLength = +pattern[0];
1081
1082 while (distRemaining >= 0.1) {
1083 dashLength = +pattern[patternIndex++ % patternLength];
1084
1085 if (dashLength > distRemaining) {
1086 dashLength = distRemaining;
1087 }
1088
1089 xStep = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
1090 xStep = dx < 0 ? -xStep : xStep;
1091 x += xStep;
1092 y += slope * xStep;
1093
1094 if (draw === true) {
1095 ctx.lineTo(x, y);
1096 } else {
1097 ctx.moveTo(x, y);
1098 }
1099
1100 distRemaining -= dashLength;
1101 draw = !draw;
1102 }
1103 }
1104 /**
1105 * Draw a hexagon.
1106 *
1107 * @param ctx - The context this shape will be rendered to.
1108 * @param x - The position of the center on the x axis.
1109 * @param y - The position of the center on the y axis.
1110 * @param r - The radius of the hexagon.
1111 */
1112
1113 function drawHexagon(ctx, x, y, r) {
1114 ctx.beginPath();
1115 var sides = 6;
1116 var a = Math.PI * 2 / sides;
1117 ctx.moveTo(x + r, y);
1118
1119 for (var i = 1; i < sides; i++) {
1120 ctx.lineTo(x + r * Math.cos(a * i), y + r * Math.sin(a * i));
1121 }
1122
1123 ctx.closePath();
1124 }
1125 var shapeMap = {
1126 circle: drawCircle,
1127 dashedLine: drawDashedLine,
1128 database: drawDatabase,
1129 diamond: drawDiamond,
1130 ellipse: drawEllipse,
1131 ellipse_vis: drawEllipse,
1132 hexagon: drawHexagon,
1133 roundRect: drawRoundRect,
1134 square: drawSquare,
1135 star: drawStar,
1136 triangle: drawTriangle,
1137 triangleDown: drawTriangleDown
1138 };
1139 /**
1140 * Returns either custom or native drawing function base on supplied name.
1141 *
1142 * @param name - The name of the function. Either the name of a
1143 * CanvasRenderingContext2D property or an export from shapes.ts without the
1144 * draw prefix.
1145 *
1146 * @returns The function that can be used for rendering. In case of native
1147 * CanvasRenderingContext2D function the API is normalized to
1148 * `(ctx: CanvasRenderingContext2D, ...originalArgs) => void`.
1149 */
1150
1151 function getShape(name) {
1152 if (Object.prototype.hasOwnProperty.call(shapeMap, name)) {
1153 return shapeMap[name];
1154 } else {
1155 return function (ctx) {
1156 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
1157 args[_key - 1] = arguments[_key];
1158 }
1159
1160 CanvasRenderingContext2D.prototype[name].call(ctx, args);
1161 };
1162 }
1163 }
1164
1165 var componentEmitter = {exports: {}};
1166
1167 (function (module) {
1168 /**
1169 * Expose `Emitter`.
1170 */
1171 {
1172 module.exports = Emitter;
1173 }
1174 /**
1175 * Initialize a new `Emitter`.
1176 *
1177 * @api public
1178 */
1179
1180
1181 function Emitter(obj) {
1182 if (obj) return mixin(obj);
1183 }
1184 /**
1185 * Mixin the emitter properties.
1186 *
1187 * @param {Object} obj
1188 * @return {Object}
1189 * @api private
1190 */
1191
1192 function mixin(obj) {
1193 for (var key in Emitter.prototype) {
1194 obj[key] = Emitter.prototype[key];
1195 }
1196
1197 return obj;
1198 }
1199 /**
1200 * Listen on the given `event` with `fn`.
1201 *
1202 * @param {String} event
1203 * @param {Function} fn
1204 * @return {Emitter}
1205 * @api public
1206 */
1207
1208
1209 Emitter.prototype.on = Emitter.prototype.addEventListener = function (event, fn) {
1210 this._callbacks = this._callbacks || {};
1211 (this._callbacks['$' + event] = this._callbacks['$' + event] || []).push(fn);
1212 return this;
1213 };
1214 /**
1215 * Adds an `event` listener that will be invoked a single
1216 * time then automatically removed.
1217 *
1218 * @param {String} event
1219 * @param {Function} fn
1220 * @return {Emitter}
1221 * @api public
1222 */
1223
1224
1225 Emitter.prototype.once = function (event, fn) {
1226 function on() {
1227 this.off(event, on);
1228 fn.apply(this, arguments);
1229 }
1230
1231 on.fn = fn;
1232 this.on(event, on);
1233 return this;
1234 };
1235 /**
1236 * Remove the given callback for `event` or all
1237 * registered callbacks.
1238 *
1239 * @param {String} event
1240 * @param {Function} fn
1241 * @return {Emitter}
1242 * @api public
1243 */
1244
1245
1246 Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function (event, fn) {
1247 this._callbacks = this._callbacks || {}; // all
1248
1249 if (0 == arguments.length) {
1250 this._callbacks = {};
1251 return this;
1252 } // specific event
1253
1254
1255 var callbacks = this._callbacks['$' + event];
1256 if (!callbacks) return this; // remove all handlers
1257
1258 if (1 == arguments.length) {
1259 delete this._callbacks['$' + event];
1260 return this;
1261 } // remove specific handler
1262
1263
1264 var cb;
1265
1266 for (var i = 0; i < callbacks.length; i++) {
1267 cb = callbacks[i];
1268
1269 if (cb === fn || cb.fn === fn) {
1270 callbacks.splice(i, 1);
1271 break;
1272 }
1273 } // Remove event specific arrays for event types that no
1274 // one is subscribed for to avoid memory leak.
1275
1276
1277 if (callbacks.length === 0) {
1278 delete this._callbacks['$' + event];
1279 }
1280
1281 return this;
1282 };
1283 /**
1284 * Emit `event` with the given args.
1285 *
1286 * @param {String} event
1287 * @param {Mixed} ...
1288 * @return {Emitter}
1289 */
1290
1291
1292 Emitter.prototype.emit = function (event) {
1293 this._callbacks = this._callbacks || {};
1294 var args = new Array(arguments.length - 1),
1295 callbacks = this._callbacks['$' + event];
1296
1297 for (var i = 1; i < arguments.length; i++) {
1298 args[i - 1] = arguments[i];
1299 }
1300
1301 if (callbacks) {
1302 callbacks = callbacks.slice(0);
1303
1304 for (var i = 0, len = callbacks.length; i < len; ++i) {
1305 callbacks[i].apply(this, args);
1306 }
1307 }
1308
1309 return this;
1310 };
1311 /**
1312 * Return array of callbacks for `event`.
1313 *
1314 * @param {String} event
1315 * @return {Array}
1316 * @api public
1317 */
1318
1319
1320 Emitter.prototype.listeners = function (event) {
1321 this._callbacks = this._callbacks || {};
1322 return this._callbacks['$' + event] || [];
1323 };
1324 /**
1325 * Check if this emitter has `event` handlers.
1326 *
1327 * @param {String} event
1328 * @return {Boolean}
1329 * @api public
1330 */
1331
1332
1333 Emitter.prototype.hasListeners = function (event) {
1334 return !!this.listeners(event).length;
1335 };
1336 })(componentEmitter);
1337
1338 var Emitter = componentEmitter.exports;
1339
1340 var isSymbol$1 = isSymbol$4;
1341
1342 var toString$9 = function (argument) {
1343 if (isSymbol$1(argument)) throw TypeError('Cannot convert a Symbol value to a string');
1344 return String(argument);
1345 };
1346
1347 var toInteger$1 = toInteger$4;
1348 var toString$8 = toString$9;
1349 var requireObjectCoercible$2 = requireObjectCoercible$5; // `String.prototype.codePointAt` methods implementation
1350
1351 var createMethod$4 = function (CONVERT_TO_STRING) {
1352 return function ($this, pos) {
1353 var S = toString$8(requireObjectCoercible$2($this));
1354 var position = toInteger$1(pos);
1355 var size = S.length;
1356 var first, second;
1357 if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
1358 first = S.charCodeAt(position);
1359 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;
1360 };
1361 };
1362
1363 var stringMultibyte = {
1364 // `String.prototype.codePointAt` method
1365 // https://tc39.es/ecma262/#sec-string.prototype.codepointat
1366 codeAt: createMethod$4(false),
1367 // `String.prototype.at` method
1368 // https://github.com/mathiasbynens/String.prototype.at
1369 charAt: createMethod$4(true)
1370 };
1371
1372 var store$1 = sharedStore;
1373 var functionToString = Function.toString; // this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper
1374
1375 if (typeof store$1.inspectSource != 'function') {
1376 store$1.inspectSource = function (it) {
1377 return functionToString.call(it);
1378 };
1379 }
1380
1381 var inspectSource$1 = store$1.inspectSource;
1382
1383 var global$c = global$k;
1384 var inspectSource = inspectSource$1;
1385 var WeakMap$1 = global$c.WeakMap;
1386 var nativeWeakMap = typeof WeakMap$1 === 'function' && /native code/.test(inspectSource(WeakMap$1));
1387
1388 var shared$2 = shared$4.exports;
1389 var uid$2 = uid$4;
1390 var keys$3 = shared$2('keys');
1391
1392 var sharedKey$4 = function (key) {
1393 return keys$3[key] || (keys$3[key] = uid$2(key));
1394 };
1395
1396 var NATIVE_WEAK_MAP$1 = nativeWeakMap;
1397 var global$b = global$k;
1398 var isObject$d = isObject$j;
1399 var createNonEnumerableProperty$7 = createNonEnumerableProperty$9;
1400 var objectHas = has$c;
1401 var shared$1 = sharedStore;
1402 var sharedKey$3 = sharedKey$4;
1403 var hiddenKeys$4 = hiddenKeys$6;
1404 var OBJECT_ALREADY_INITIALIZED = 'Object already initialized';
1405 var WeakMap = global$b.WeakMap;
1406 var set$3, get$5, has$7;
1407
1408 var enforce = function (it) {
1409 return has$7(it) ? get$5(it) : set$3(it, {});
1410 };
1411
1412 var getterFor = function (TYPE) {
1413 return function (it) {
1414 var state;
1415
1416 if (!isObject$d(it) || (state = get$5(it)).type !== TYPE) {
1417 throw TypeError('Incompatible receiver, ' + TYPE + ' required');
1418 }
1419
1420 return state;
1421 };
1422 };
1423
1424 if (NATIVE_WEAK_MAP$1 || shared$1.state) {
1425 var store = shared$1.state || (shared$1.state = new WeakMap());
1426 var wmget = store.get;
1427 var wmhas = store.has;
1428 var wmset = store.set;
1429
1430 set$3 = function (it, metadata) {
1431 if (wmhas.call(store, it)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
1432 metadata.facade = it;
1433 wmset.call(store, it, metadata);
1434 return metadata;
1435 };
1436
1437 get$5 = function (it) {
1438 return wmget.call(store, it) || {};
1439 };
1440
1441 has$7 = function (it) {
1442 return wmhas.call(store, it);
1443 };
1444 } else {
1445 var STATE = sharedKey$3('state');
1446 hiddenKeys$4[STATE] = true;
1447
1448 set$3 = function (it, metadata) {
1449 if (objectHas(it, STATE)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
1450 metadata.facade = it;
1451 createNonEnumerableProperty$7(it, STATE, metadata);
1452 return metadata;
1453 };
1454
1455 get$5 = function (it) {
1456 return objectHas(it, STATE) ? it[STATE] : {};
1457 };
1458
1459 has$7 = function (it) {
1460 return objectHas(it, STATE);
1461 };
1462 }
1463
1464 var internalState = {
1465 set: set$3,
1466 get: get$5,
1467 has: has$7,
1468 enforce: enforce,
1469 getterFor: getterFor
1470 };
1471
1472 var fails$f = fails$m;
1473 var correctPrototypeGetter = !fails$f(function () {
1474 function F() {
1475 /* empty */
1476 }
1477
1478 F.prototype.constructor = null; // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
1479
1480 return Object.getPrototypeOf(new F()) !== F.prototype;
1481 });
1482
1483 var has$6 = has$c;
1484 var toObject$a = toObject$d;
1485 var sharedKey$2 = sharedKey$4;
1486 var CORRECT_PROTOTYPE_GETTER$1 = correctPrototypeGetter;
1487 var IE_PROTO$1 = sharedKey$2('IE_PROTO');
1488 var ObjectPrototype$1 = Object.prototype; // `Object.getPrototypeOf` method
1489 // https://tc39.es/ecma262/#sec-object.getprototypeof
1490 // eslint-disable-next-line es/no-object-getprototypeof -- safe
1491
1492 var objectGetPrototypeOf = CORRECT_PROTOTYPE_GETTER$1 ? Object.getPrototypeOf : function (O) {
1493 O = toObject$a(O);
1494 if (has$6(O, IE_PROTO$1)) return O[IE_PROTO$1];
1495
1496 if (typeof O.constructor == 'function' && O instanceof O.constructor) {
1497 return O.constructor.prototype;
1498 }
1499
1500 return O instanceof Object ? ObjectPrototype$1 : null;
1501 };
1502
1503 var fails$e = fails$m;
1504 var getPrototypeOf$7 = objectGetPrototypeOf;
1505 var createNonEnumerableProperty$6 = createNonEnumerableProperty$9;
1506 var has$5 = has$c;
1507 var wellKnownSymbol$h = wellKnownSymbol$j;
1508 var ITERATOR$4 = wellKnownSymbol$h('iterator');
1509 var BUGGY_SAFARI_ITERATORS$1 = false;
1510
1511 var returnThis$2 = function () {
1512 return this;
1513 }; // `%IteratorPrototype%` object
1514 // https://tc39.es/ecma262/#sec-%iteratorprototype%-object
1515
1516
1517 var IteratorPrototype$2, PrototypeOfArrayIteratorPrototype, arrayIterator;
1518 /* eslint-disable es/no-array-prototype-keys -- safe */
1519
1520 if ([].keys) {
1521 arrayIterator = [].keys(); // Safari 8 has buggy iterators w/o `next`
1522
1523 if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS$1 = true;else {
1524 PrototypeOfArrayIteratorPrototype = getPrototypeOf$7(getPrototypeOf$7(arrayIterator));
1525 if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype$2 = PrototypeOfArrayIteratorPrototype;
1526 }
1527 }
1528
1529 var NEW_ITERATOR_PROTOTYPE = IteratorPrototype$2 == undefined || fails$e(function () {
1530 var test = {}; // FF44- legacy iterators case
1531
1532 return IteratorPrototype$2[ITERATOR$4].call(test) !== test;
1533 });
1534 if (NEW_ITERATOR_PROTOTYPE) IteratorPrototype$2 = {}; // `%IteratorPrototype%[@@iterator]()` method
1535 // https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator
1536
1537 if ((NEW_ITERATOR_PROTOTYPE) && !has$5(IteratorPrototype$2, ITERATOR$4)) {
1538 createNonEnumerableProperty$6(IteratorPrototype$2, ITERATOR$4, returnThis$2);
1539 }
1540
1541 var iteratorsCore = {
1542 IteratorPrototype: IteratorPrototype$2,
1543 BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS$1
1544 };
1545
1546 var DESCRIPTORS$a = descriptors;
1547 var definePropertyModule$3 = objectDefineProperty;
1548 var anObject$a = anObject$c;
1549 var objectKeys$2 = objectKeys$4; // `Object.defineProperties` method
1550 // https://tc39.es/ecma262/#sec-object.defineproperties
1551 // eslint-disable-next-line es/no-object-defineproperties -- safe
1552
1553 var objectDefineProperties = DESCRIPTORS$a ? Object.defineProperties : function defineProperties(O, Properties) {
1554 anObject$a(O);
1555 var keys = objectKeys$2(Properties);
1556 var length = keys.length;
1557 var index = 0;
1558 var key;
1559
1560 while (length > index) definePropertyModule$3.f(O, key = keys[index++], Properties[key]);
1561
1562 return O;
1563 };
1564
1565 var getBuiltIn$5 = getBuiltIn$8;
1566 var html$1 = getBuiltIn$5('document', 'documentElement');
1567
1568 /* global ActiveXObject -- old IE, WSH */
1569 var anObject$9 = anObject$c;
1570 var defineProperties$5 = objectDefineProperties;
1571 var enumBugKeys$1 = enumBugKeys$3;
1572 var hiddenKeys$3 = hiddenKeys$6;
1573 var html = html$1;
1574 var documentCreateElement = documentCreateElement$1;
1575 var sharedKey$1 = sharedKey$4;
1576 var GT = '>';
1577 var LT = '<';
1578 var PROTOTYPE$1 = 'prototype';
1579 var SCRIPT = 'script';
1580 var IE_PROTO = sharedKey$1('IE_PROTO');
1581
1582 var EmptyConstructor = function () {
1583 /* empty */
1584 };
1585
1586 var scriptTag = function (content) {
1587 return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
1588 }; // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
1589
1590
1591 var NullProtoObjectViaActiveX = function (activeXDocument) {
1592 activeXDocument.write(scriptTag(''));
1593 activeXDocument.close();
1594 var temp = activeXDocument.parentWindow.Object;
1595 activeXDocument = null; // avoid memory leak
1596
1597 return temp;
1598 }; // Create object with fake `null` prototype: use iframe Object with cleared prototype
1599
1600
1601 var NullProtoObjectViaIFrame = function () {
1602 // Thrash, waste and sodomy: IE GC bug
1603 var iframe = documentCreateElement('iframe');
1604 var JS = 'java' + SCRIPT + ':';
1605 var iframeDocument;
1606
1607 if (iframe.style) {
1608 iframe.style.display = 'none';
1609 html.appendChild(iframe); // https://github.com/zloirock/core-js/issues/475
1610
1611 iframe.src = String(JS);
1612 iframeDocument = iframe.contentWindow.document;
1613 iframeDocument.open();
1614 iframeDocument.write(scriptTag('document.F=Object'));
1615 iframeDocument.close();
1616 return iframeDocument.F;
1617 }
1618 }; // Check for document.domain and active x support
1619 // No need to use active x approach when document.domain is not set
1620 // see https://github.com/es-shims/es5-shim/issues/150
1621 // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
1622 // avoid IE GC bug
1623
1624
1625 var activeXDocument;
1626
1627 var NullProtoObject = function () {
1628 try {
1629 activeXDocument = new ActiveXObject('htmlfile');
1630 } catch (error) {
1631 /* ignore */
1632 }
1633
1634 NullProtoObject = document.domain && activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : // old IE
1635 NullProtoObjectViaIFrame() || NullProtoObjectViaActiveX(activeXDocument); // WSH
1636
1637 var length = enumBugKeys$1.length;
1638
1639 while (length--) delete NullProtoObject[PROTOTYPE$1][enumBugKeys$1[length]];
1640
1641 return NullProtoObject();
1642 };
1643
1644 hiddenKeys$3[IE_PROTO] = true; // `Object.create` method
1645 // https://tc39.es/ecma262/#sec-object.create
1646
1647 var objectCreate = Object.create || function create(O, Properties) {
1648 var result;
1649
1650 if (O !== null) {
1651 EmptyConstructor[PROTOTYPE$1] = anObject$9(O);
1652 result = new EmptyConstructor();
1653 EmptyConstructor[PROTOTYPE$1] = null; // add "__proto__" for Object.getPrototypeOf polyfill
1654
1655 result[IE_PROTO] = O;
1656 } else result = NullProtoObject();
1657
1658 return Properties === undefined ? result : defineProperties$5(result, Properties);
1659 };
1660
1661 var wellKnownSymbol$g = wellKnownSymbol$j;
1662 var TO_STRING_TAG$3 = wellKnownSymbol$g('toStringTag');
1663 var test$2 = {};
1664 test$2[TO_STRING_TAG$3] = 'z';
1665 var toStringTagSupport = String(test$2) === '[object z]';
1666
1667 var TO_STRING_TAG_SUPPORT$2 = toStringTagSupport;
1668 var classofRaw = classofRaw$1;
1669 var wellKnownSymbol$f = wellKnownSymbol$j;
1670 var TO_STRING_TAG$2 = wellKnownSymbol$f('toStringTag'); // ES3 wrong here
1671
1672 var CORRECT_ARGUMENTS = classofRaw(function () {
1673 return arguments;
1674 }()) == 'Arguments'; // fallback for IE11 Script Access Denied error
1675
1676 var tryGet = function (it, key) {
1677 try {
1678 return it[key];
1679 } catch (error) {
1680 /* empty */
1681 }
1682 }; // getting tag from ES6+ `Object.prototype.toString`
1683
1684
1685 var classof$8 = TO_STRING_TAG_SUPPORT$2 ? classofRaw : function (it) {
1686 var O, tag, result;
1687 return it === undefined ? 'Undefined' : it === null ? 'Null' // @@toStringTag case
1688 : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag // builtinTag case
1689 : CORRECT_ARGUMENTS ? classofRaw(O) // ES3 arguments fallback
1690 : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
1691 };
1692
1693 var TO_STRING_TAG_SUPPORT$1 = toStringTagSupport;
1694 var classof$7 = classof$8; // `Object.prototype.toString` method implementation
1695 // https://tc39.es/ecma262/#sec-object.prototype.tostring
1696
1697 var objectToString = TO_STRING_TAG_SUPPORT$1 ? {}.toString : function toString() {
1698 return '[object ' + classof$7(this) + ']';
1699 };
1700
1701 var TO_STRING_TAG_SUPPORT = toStringTagSupport;
1702 var defineProperty$a = objectDefineProperty.f;
1703 var createNonEnumerableProperty$5 = createNonEnumerableProperty$9;
1704 var has$4 = has$c;
1705 var toString$7 = objectToString;
1706 var wellKnownSymbol$e = wellKnownSymbol$j;
1707 var TO_STRING_TAG$1 = wellKnownSymbol$e('toStringTag');
1708
1709 var setToStringTag$5 = function (it, TAG, STATIC, SET_METHOD) {
1710 if (it) {
1711 var target = STATIC ? it : it.prototype;
1712
1713 if (!has$4(target, TO_STRING_TAG$1)) {
1714 defineProperty$a(target, TO_STRING_TAG$1, {
1715 configurable: true,
1716 value: TAG
1717 });
1718 }
1719
1720 if (SET_METHOD && !TO_STRING_TAG_SUPPORT) {
1721 createNonEnumerableProperty$5(target, 'toString', toString$7);
1722 }
1723 }
1724 };
1725
1726 var iterators = {};
1727
1728 var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;
1729 var create$8 = objectCreate;
1730 var createPropertyDescriptor$2 = createPropertyDescriptor$5;
1731 var setToStringTag$4 = setToStringTag$5;
1732 var Iterators$5 = iterators;
1733
1734 var returnThis$1 = function () {
1735 return this;
1736 };
1737
1738 var createIteratorConstructor$1 = function (IteratorConstructor, NAME, next) {
1739 var TO_STRING_TAG = NAME + ' Iterator';
1740 IteratorConstructor.prototype = create$8(IteratorPrototype$1, {
1741 next: createPropertyDescriptor$2(1, next)
1742 });
1743 setToStringTag$4(IteratorConstructor, TO_STRING_TAG, false, true);
1744 Iterators$5[TO_STRING_TAG] = returnThis$1;
1745 return IteratorConstructor;
1746 };
1747
1748 var isObject$c = isObject$j;
1749
1750 var aPossiblePrototype$1 = function (it) {
1751 if (!isObject$c(it) && it !== null) {
1752 throw TypeError("Can't set " + String(it) + ' as a prototype');
1753 }
1754
1755 return it;
1756 };
1757
1758 /* eslint-disable no-proto -- safe */
1759 var anObject$8 = anObject$c;
1760 var aPossiblePrototype = aPossiblePrototype$1; // `Object.setPrototypeOf` method
1761 // https://tc39.es/ecma262/#sec-object.setprototypeof
1762 // Works with __proto__ only. Old v8 can't work with null proto objects.
1763 // eslint-disable-next-line es/no-object-setprototypeof -- safe
1764
1765 var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
1766 var CORRECT_SETTER = false;
1767 var test = {};
1768 var setter;
1769
1770 try {
1771 // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
1772 setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
1773 setter.call(test, []);
1774 CORRECT_SETTER = test instanceof Array;
1775 } catch (error) {
1776 /* empty */
1777 }
1778
1779 return function setPrototypeOf(O, proto) {
1780 anObject$8(O);
1781 aPossiblePrototype(proto);
1782 if (CORRECT_SETTER) setter.call(O, proto);else O.__proto__ = proto;
1783 return O;
1784 };
1785 }() : undefined);
1786
1787 var createNonEnumerableProperty$4 = createNonEnumerableProperty$9;
1788
1789 var redefine$3 = function (target, key, value, options) {
1790 if (options && options.enumerable) target[key] = value;else createNonEnumerableProperty$4(target, key, value);
1791 };
1792
1793 var $$G = _export;
1794 var createIteratorConstructor = createIteratorConstructor$1;
1795 var getPrototypeOf$6 = objectGetPrototypeOf;
1796 var setToStringTag$3 = setToStringTag$5;
1797 var createNonEnumerableProperty$3 = createNonEnumerableProperty$9;
1798 var redefine$2 = redefine$3;
1799 var wellKnownSymbol$d = wellKnownSymbol$j;
1800 var Iterators$4 = iterators;
1801 var IteratorsCore = iteratorsCore;
1802 var IteratorPrototype = IteratorsCore.IteratorPrototype;
1803 var BUGGY_SAFARI_ITERATORS = IteratorsCore.BUGGY_SAFARI_ITERATORS;
1804 var ITERATOR$3 = wellKnownSymbol$d('iterator');
1805 var KEYS = 'keys';
1806 var VALUES = 'values';
1807 var ENTRIES = 'entries';
1808
1809 var returnThis = function () {
1810 return this;
1811 };
1812
1813 var defineIterator$3 = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
1814 createIteratorConstructor(IteratorConstructor, NAME, next);
1815
1816 var getIterationMethod = function (KIND) {
1817 if (KIND === DEFAULT && defaultIterator) return defaultIterator;
1818 if (!BUGGY_SAFARI_ITERATORS && KIND in IterablePrototype) return IterablePrototype[KIND];
1819
1820 switch (KIND) {
1821 case KEYS:
1822 return function keys() {
1823 return new IteratorConstructor(this, KIND);
1824 };
1825
1826 case VALUES:
1827 return function values() {
1828 return new IteratorConstructor(this, KIND);
1829 };
1830
1831 case ENTRIES:
1832 return function entries() {
1833 return new IteratorConstructor(this, KIND);
1834 };
1835 }
1836
1837 return function () {
1838 return new IteratorConstructor(this);
1839 };
1840 };
1841
1842 var TO_STRING_TAG = NAME + ' Iterator';
1843 var INCORRECT_VALUES_NAME = false;
1844 var IterablePrototype = Iterable.prototype;
1845 var nativeIterator = IterablePrototype[ITERATOR$3] || IterablePrototype['@@iterator'] || DEFAULT && IterablePrototype[DEFAULT];
1846 var defaultIterator = !BUGGY_SAFARI_ITERATORS && nativeIterator || getIterationMethod(DEFAULT);
1847 var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
1848 var CurrentIteratorPrototype, methods, KEY; // fix native
1849
1850 if (anyNativeIterator) {
1851 CurrentIteratorPrototype = getPrototypeOf$6(anyNativeIterator.call(new Iterable()));
1852
1853 if (IteratorPrototype !== Object.prototype && CurrentIteratorPrototype.next) {
1854
1855
1856 setToStringTag$3(CurrentIteratorPrototype, TO_STRING_TAG, true, true);
1857 Iterators$4[TO_STRING_TAG] = returnThis;
1858 }
1859 } // fix Array.prototype.{ values, @@iterator }.name in V8 / FF
1860
1861
1862 if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
1863 INCORRECT_VALUES_NAME = true;
1864
1865 defaultIterator = function values() {
1866 return nativeIterator.call(this);
1867 };
1868 } // define iterator
1869
1870
1871 if ((FORCED) && IterablePrototype[ITERATOR$3] !== defaultIterator) {
1872 createNonEnumerableProperty$3(IterablePrototype, ITERATOR$3, defaultIterator);
1873 }
1874
1875 Iterators$4[NAME] = defaultIterator; // export additional methods
1876
1877 if (DEFAULT) {
1878 methods = {
1879 values: getIterationMethod(VALUES),
1880 keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
1881 entries: getIterationMethod(ENTRIES)
1882 };
1883 if (FORCED) for (KEY in methods) {
1884 if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
1885 redefine$2(IterablePrototype, KEY, methods[KEY]);
1886 }
1887 } else $$G({
1888 target: NAME,
1889 proto: true,
1890 forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME
1891 }, methods);
1892 }
1893
1894 return methods;
1895 };
1896
1897 var charAt = stringMultibyte.charAt;
1898 var toString$6 = toString$9;
1899 var InternalStateModule$5 = internalState;
1900 var defineIterator$2 = defineIterator$3;
1901 var STRING_ITERATOR = 'String Iterator';
1902 var setInternalState$5 = InternalStateModule$5.set;
1903 var getInternalState$2 = InternalStateModule$5.getterFor(STRING_ITERATOR); // `String.prototype[@@iterator]` method
1904 // https://tc39.es/ecma262/#sec-string.prototype-@@iterator
1905
1906 defineIterator$2(String, 'String', function (iterated) {
1907 setInternalState$5(this, {
1908 type: STRING_ITERATOR,
1909 string: toString$6(iterated),
1910 index: 0
1911 }); // `%StringIteratorPrototype%.next` method
1912 // https://tc39.es/ecma262/#sec-%stringiteratorprototype%.next
1913 }, function next() {
1914 var state = getInternalState$2(this);
1915 var string = state.string;
1916 var index = state.index;
1917 var point;
1918 if (index >= string.length) return {
1919 value: undefined,
1920 done: true
1921 };
1922 point = charAt(string, index);
1923 state.index += point.length;
1924 return {
1925 value: point,
1926 done: false
1927 };
1928 });
1929
1930 var anObject$7 = anObject$c;
1931
1932 var iteratorClose$2 = function (iterator) {
1933 var returnMethod = iterator['return'];
1934
1935 if (returnMethod !== undefined) {
1936 return anObject$7(returnMethod.call(iterator)).value;
1937 }
1938 };
1939
1940 var anObject$6 = anObject$c;
1941 var iteratorClose$1 = iteratorClose$2; // call something on iterator step with safe closing on error
1942
1943 var callWithSafeIterationClosing$1 = function (iterator, fn, value, ENTRIES) {
1944 try {
1945 return ENTRIES ? fn(anObject$6(value)[0], value[1]) : fn(value);
1946 } catch (error) {
1947 iteratorClose$1(iterator);
1948 throw error;
1949 }
1950 };
1951
1952 var wellKnownSymbol$c = wellKnownSymbol$j;
1953 var Iterators$3 = iterators;
1954 var ITERATOR$2 = wellKnownSymbol$c('iterator');
1955 var ArrayPrototype$f = Array.prototype; // check on default Array iterator
1956
1957 var isArrayIteratorMethod$2 = function (it) {
1958 return it !== undefined && (Iterators$3.Array === it || ArrayPrototype$f[ITERATOR$2] === it);
1959 };
1960
1961 var toPropertyKey$1 = toPropertyKey$4;
1962 var definePropertyModule$2 = objectDefineProperty;
1963 var createPropertyDescriptor$1 = createPropertyDescriptor$5;
1964
1965 var createProperty$5 = function (object, key, value) {
1966 var propertyKey = toPropertyKey$1(key);
1967 if (propertyKey in object) definePropertyModule$2.f(object, propertyKey, createPropertyDescriptor$1(0, value));else object[propertyKey] = value;
1968 };
1969
1970 var classof$6 = classof$8;
1971 var Iterators$2 = iterators;
1972 var wellKnownSymbol$b = wellKnownSymbol$j;
1973 var ITERATOR$1 = wellKnownSymbol$b('iterator');
1974
1975 var getIteratorMethod$6 = function (it) {
1976 if (it != undefined) return it[ITERATOR$1] || it['@@iterator'] || Iterators$2[classof$6(it)];
1977 };
1978
1979 var bind$4 = functionBindContext;
1980 var toObject$9 = toObject$d;
1981 var callWithSafeIterationClosing = callWithSafeIterationClosing$1;
1982 var isArrayIteratorMethod$1 = isArrayIteratorMethod$2;
1983 var toLength$8 = toLength$a;
1984 var createProperty$4 = createProperty$5;
1985 var getIteratorMethod$5 = getIteratorMethod$6; // `Array.from` method implementation
1986 // https://tc39.es/ecma262/#sec-array.from
1987
1988 var arrayFrom = function from(arrayLike
1989 /* , mapfn = undefined, thisArg = undefined */
1990 ) {
1991 var O = toObject$9(arrayLike);
1992 var C = typeof this == 'function' ? this : Array;
1993 var argumentsLength = arguments.length;
1994 var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
1995 var mapping = mapfn !== undefined;
1996 var iteratorMethod = getIteratorMethod$5(O);
1997 var index = 0;
1998 var length, result, step, iterator, next, value;
1999 if (mapping) mapfn = bind$4(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
2000
2001 if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod$1(iteratorMethod))) {
2002 iterator = iteratorMethod.call(O);
2003 next = iterator.next;
2004 result = new C();
2005
2006 for (; !(step = next.call(iterator)).done; index++) {
2007 value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
2008 createProperty$4(result, index, value);
2009 }
2010 } else {
2011 length = toLength$8(O.length);
2012 result = new C(length);
2013
2014 for (; length > index; index++) {
2015 value = mapping ? mapfn(O[index], index) : O[index];
2016 createProperty$4(result, index, value);
2017 }
2018 }
2019
2020 result.length = index;
2021 return result;
2022 };
2023
2024 var wellKnownSymbol$a = wellKnownSymbol$j;
2025 var ITERATOR = wellKnownSymbol$a('iterator');
2026 var SAFE_CLOSING = false;
2027
2028 try {
2029 var called = 0;
2030 var iteratorWithReturn = {
2031 next: function () {
2032 return {
2033 done: !!called++
2034 };
2035 },
2036 'return': function () {
2037 SAFE_CLOSING = true;
2038 }
2039 };
2040
2041 iteratorWithReturn[ITERATOR] = function () {
2042 return this;
2043 }; // eslint-disable-next-line es/no-array-from, no-throw-literal -- required for testing
2044
2045
2046 Array.from(iteratorWithReturn, function () {
2047 throw 2;
2048 });
2049 } catch (error) {
2050 /* empty */
2051 }
2052
2053 var checkCorrectnessOfIteration$1 = function (exec, SKIP_CLOSING) {
2054 if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
2055 var ITERATION_SUPPORT = false;
2056
2057 try {
2058 var object = {};
2059
2060 object[ITERATOR] = function () {
2061 return {
2062 next: function () {
2063 return {
2064 done: ITERATION_SUPPORT = true
2065 };
2066 }
2067 };
2068 };
2069
2070 exec(object);
2071 } catch (error) {
2072 /* empty */
2073 }
2074
2075 return ITERATION_SUPPORT;
2076 };
2077
2078 var $$F = _export;
2079 var from$5 = arrayFrom;
2080 var checkCorrectnessOfIteration = checkCorrectnessOfIteration$1;
2081 var INCORRECT_ITERATION = !checkCorrectnessOfIteration(function (iterable) {
2082 // eslint-disable-next-line es/no-array-from -- required for testing
2083 Array.from(iterable);
2084 }); // `Array.from` method
2085 // https://tc39.es/ecma262/#sec-array.from
2086
2087 $$F({
2088 target: 'Array',
2089 stat: true,
2090 forced: INCORRECT_ITERATION
2091 }, {
2092 from: from$5
2093 });
2094
2095 var path$s = path$x;
2096 var from$4 = path$s.Array.from;
2097
2098 var parent$R = from$4;
2099 var from$3 = parent$R;
2100
2101 var from$2 = from$3;
2102
2103 var toIndexedObject$6 = toIndexedObject$a;
2104 var Iterators$1 = iterators;
2105 var InternalStateModule$4 = internalState;
2106 var defineIterator$1 = defineIterator$3;
2107 var ARRAY_ITERATOR = 'Array Iterator';
2108 var setInternalState$4 = InternalStateModule$4.set;
2109 var getInternalState$1 = InternalStateModule$4.getterFor(ARRAY_ITERATOR); // `Array.prototype.entries` method
2110 // https://tc39.es/ecma262/#sec-array.prototype.entries
2111 // `Array.prototype.keys` method
2112 // https://tc39.es/ecma262/#sec-array.prototype.keys
2113 // `Array.prototype.values` method
2114 // https://tc39.es/ecma262/#sec-array.prototype.values
2115 // `Array.prototype[@@iterator]` method
2116 // https://tc39.es/ecma262/#sec-array.prototype-@@iterator
2117 // `CreateArrayIterator` internal method
2118 // https://tc39.es/ecma262/#sec-createarrayiterator
2119
2120 defineIterator$1(Array, 'Array', function (iterated, kind) {
2121 setInternalState$4(this, {
2122 type: ARRAY_ITERATOR,
2123 target: toIndexedObject$6(iterated),
2124 // target
2125 index: 0,
2126 // next index
2127 kind: kind // kind
2128
2129 }); // `%ArrayIteratorPrototype%.next` method
2130 // https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
2131 }, function () {
2132 var state = getInternalState$1(this);
2133 var target = state.target;
2134 var kind = state.kind;
2135 var index = state.index++;
2136
2137 if (!target || index >= target.length) {
2138 state.target = undefined;
2139 return {
2140 value: undefined,
2141 done: true
2142 };
2143 }
2144
2145 if (kind == 'keys') return {
2146 value: index,
2147 done: false
2148 };
2149 if (kind == 'values') return {
2150 value: target[index],
2151 done: false
2152 };
2153 return {
2154 value: [index, target[index]],
2155 done: false
2156 };
2157 }, 'values'); // argumentsList[@@iterator] is %ArrayProto_values%
2158 // https://tc39.es/ecma262/#sec-createunmappedargumentsobject
2159 // https://tc39.es/ecma262/#sec-createmappedargumentsobject
2160
2161 Iterators$1.Arguments = Iterators$1.Array; // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
2162
2163 var getIteratorMethod$4 = getIteratorMethod$6;
2164 var getIteratorMethod_1 = getIteratorMethod$4;
2165
2166 // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
2167
2168 var domIterables = {
2169 CSSRuleList: 0,
2170 CSSStyleDeclaration: 0,
2171 CSSValueList: 0,
2172 ClientRectList: 0,
2173 DOMRectList: 0,
2174 DOMStringList: 0,
2175 DOMTokenList: 1,
2176 DataTransferItemList: 0,
2177 FileList: 0,
2178 HTMLAllCollection: 0,
2179 HTMLCollection: 0,
2180 HTMLFormElement: 0,
2181 HTMLSelectElement: 0,
2182 MediaList: 0,
2183 MimeTypeArray: 0,
2184 NamedNodeMap: 0,
2185 NodeList: 1,
2186 PaintRequestList: 0,
2187 Plugin: 0,
2188 PluginArray: 0,
2189 SVGLengthList: 0,
2190 SVGNumberList: 0,
2191 SVGPathSegList: 0,
2192 SVGPointList: 0,
2193 SVGStringList: 0,
2194 SVGTransformList: 0,
2195 SourceBufferList: 0,
2196 StyleSheetList: 0,
2197 TextTrackCueList: 0,
2198 TextTrackList: 0,
2199 TouchList: 0
2200 };
2201
2202 var DOMIterables$2 = domIterables;
2203 var global$a = global$k;
2204 var classof$5 = classof$8;
2205 var createNonEnumerableProperty$2 = createNonEnumerableProperty$9;
2206 var Iterators = iterators;
2207 var wellKnownSymbol$9 = wellKnownSymbol$j;
2208 var TO_STRING_TAG = wellKnownSymbol$9('toStringTag');
2209
2210 for (var COLLECTION_NAME in DOMIterables$2) {
2211 var Collection = global$a[COLLECTION_NAME];
2212 var CollectionPrototype = Collection && Collection.prototype;
2213
2214 if (CollectionPrototype && classof$5(CollectionPrototype) !== TO_STRING_TAG) {
2215 createNonEnumerableProperty$2(CollectionPrototype, TO_STRING_TAG, COLLECTION_NAME);
2216 }
2217
2218 Iterators[COLLECTION_NAME] = Iterators.Array;
2219 }
2220
2221 var parent$Q = getIteratorMethod_1;
2222 var getIteratorMethod$3 = parent$Q;
2223
2224 var parent$P = getIteratorMethod$3;
2225 var getIteratorMethod$2 = parent$P;
2226
2227 var getIteratorMethod$1 = getIteratorMethod$2;
2228
2229 var classof$4 = classofRaw$1; // `IsArray` abstract operation
2230 // https://tc39.es/ecma262/#sec-isarray
2231 // eslint-disable-next-line es/no-array-isarray -- safe
2232
2233 var isArray$b = Array.isArray || function isArray(arg) {
2234 return classof$4(arg) == 'Array';
2235 };
2236
2237 var objectGetOwnPropertyNames = {};
2238
2239 var internalObjectKeys = objectKeysInternal;
2240 var enumBugKeys = enumBugKeys$3;
2241 var hiddenKeys$2 = enumBugKeys.concat('length', 'prototype'); // `Object.getOwnPropertyNames` method
2242 // https://tc39.es/ecma262/#sec-object.getownpropertynames
2243 // eslint-disable-next-line es/no-object-getownpropertynames -- safe
2244
2245 objectGetOwnPropertyNames.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
2246 return internalObjectKeys(O, hiddenKeys$2);
2247 };
2248
2249 var objectGetOwnPropertyNamesExternal = {};
2250
2251 /* eslint-disable es/no-object-getownpropertynames -- safe */
2252 var toIndexedObject$5 = toIndexedObject$a;
2253 var $getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
2254 var toString$5 = {}.toString;
2255 var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : [];
2256
2257 var getWindowNames = function (it) {
2258 try {
2259 return $getOwnPropertyNames$1(it);
2260 } catch (error) {
2261 return windowNames.slice();
2262 }
2263 }; // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
2264
2265
2266 objectGetOwnPropertyNamesExternal.f = function getOwnPropertyNames(it) {
2267 return windowNames && toString$5.call(it) == '[object Window]' ? getWindowNames(it) : $getOwnPropertyNames$1(toIndexedObject$5(it));
2268 };
2269
2270 var wellKnownSymbolWrapped = {};
2271
2272 var wellKnownSymbol$8 = wellKnownSymbol$j;
2273 wellKnownSymbolWrapped.f = wellKnownSymbol$8;
2274
2275 var path$r = path$x;
2276 var has$3 = has$c;
2277 var wrappedWellKnownSymbolModule$1 = wellKnownSymbolWrapped;
2278 var defineProperty$9 = objectDefineProperty.f;
2279
2280 var defineWellKnownSymbol$l = function (NAME) {
2281 var Symbol = path$r.Symbol || (path$r.Symbol = {});
2282 if (!has$3(Symbol, NAME)) defineProperty$9(Symbol, NAME, {
2283 value: wrappedWellKnownSymbolModule$1.f(NAME)
2284 });
2285 };
2286
2287 var isObject$b = isObject$j;
2288 var isArray$a = isArray$b;
2289 var wellKnownSymbol$7 = wellKnownSymbol$j;
2290 var SPECIES$3 = wellKnownSymbol$7('species'); // a part of `ArraySpeciesCreate` abstract operation
2291 // https://tc39.es/ecma262/#sec-arrayspeciescreate
2292
2293 var arraySpeciesConstructor$1 = function (originalArray) {
2294 var C;
2295
2296 if (isArray$a(originalArray)) {
2297 C = originalArray.constructor; // cross-realm fallback
2298
2299 if (typeof C == 'function' && (C === Array || isArray$a(C.prototype))) C = undefined;else if (isObject$b(C)) {
2300 C = C[SPECIES$3];
2301 if (C === null) C = undefined;
2302 }
2303 }
2304
2305 return C === undefined ? Array : C;
2306 };
2307
2308 var arraySpeciesConstructor = arraySpeciesConstructor$1; // `ArraySpeciesCreate` abstract operation
2309 // https://tc39.es/ecma262/#sec-arrayspeciescreate
2310
2311 var arraySpeciesCreate$3 = function (originalArray, length) {
2312 return new (arraySpeciesConstructor(originalArray))(length === 0 ? 0 : length);
2313 };
2314
2315 var bind$3 = functionBindContext;
2316 var IndexedObject$1 = indexedObject;
2317 var toObject$8 = toObject$d;
2318 var toLength$7 = toLength$a;
2319 var arraySpeciesCreate$2 = arraySpeciesCreate$3;
2320 var push = [].push; // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterReject }` methods implementation
2321
2322 var createMethod$3 = function (TYPE) {
2323 var IS_MAP = TYPE == 1;
2324 var IS_FILTER = TYPE == 2;
2325 var IS_SOME = TYPE == 3;
2326 var IS_EVERY = TYPE == 4;
2327 var IS_FIND_INDEX = TYPE == 6;
2328 var IS_FILTER_REJECT = TYPE == 7;
2329 var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
2330 return function ($this, callbackfn, that, specificCreate) {
2331 var O = toObject$8($this);
2332 var self = IndexedObject$1(O);
2333 var boundFunction = bind$3(callbackfn, that, 3);
2334 var length = toLength$7(self.length);
2335 var index = 0;
2336 var create = specificCreate || arraySpeciesCreate$2;
2337 var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_REJECT ? create($this, 0) : undefined;
2338 var value, result;
2339
2340 for (; length > index; index++) if (NO_HOLES || index in self) {
2341 value = self[index];
2342 result = boundFunction(value, index, O);
2343
2344 if (TYPE) {
2345 if (IS_MAP) target[index] = result; // map
2346 else if (result) switch (TYPE) {
2347 case 3:
2348 return true;
2349 // some
2350
2351 case 5:
2352 return value;
2353 // find
2354
2355 case 6:
2356 return index;
2357 // findIndex
2358
2359 case 2:
2360 push.call(target, value);
2361 // filter
2362 } else switch (TYPE) {
2363 case 4:
2364 return false;
2365 // every
2366
2367 case 7:
2368 push.call(target, value);
2369 // filterReject
2370 }
2371 }
2372 }
2373
2374 return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
2375 };
2376 };
2377
2378 var arrayIteration = {
2379 // `Array.prototype.forEach` method
2380 // https://tc39.es/ecma262/#sec-array.prototype.foreach
2381 forEach: createMethod$3(0),
2382 // `Array.prototype.map` method
2383 // https://tc39.es/ecma262/#sec-array.prototype.map
2384 map: createMethod$3(1),
2385 // `Array.prototype.filter` method
2386 // https://tc39.es/ecma262/#sec-array.prototype.filter
2387 filter: createMethod$3(2),
2388 // `Array.prototype.some` method
2389 // https://tc39.es/ecma262/#sec-array.prototype.some
2390 some: createMethod$3(3),
2391 // `Array.prototype.every` method
2392 // https://tc39.es/ecma262/#sec-array.prototype.every
2393 every: createMethod$3(4),
2394 // `Array.prototype.find` method
2395 // https://tc39.es/ecma262/#sec-array.prototype.find
2396 find: createMethod$3(5),
2397 // `Array.prototype.findIndex` method
2398 // https://tc39.es/ecma262/#sec-array.prototype.findIndex
2399 findIndex: createMethod$3(6),
2400 // `Array.prototype.filterReject` method
2401 // https://github.com/tc39/proposal-array-filtering
2402 filterReject: createMethod$3(7)
2403 };
2404
2405 var $$E = _export;
2406 var global$9 = global$k;
2407 var getBuiltIn$4 = getBuiltIn$8;
2408 var DESCRIPTORS$9 = descriptors;
2409 var NATIVE_SYMBOL = nativeSymbol;
2410 var fails$d = fails$m;
2411 var has$2 = has$c;
2412 var isArray$9 = isArray$b;
2413 var isObject$a = isObject$j;
2414 var isSymbol = isSymbol$4;
2415 var anObject$5 = anObject$c;
2416 var toObject$7 = toObject$d;
2417 var toIndexedObject$4 = toIndexedObject$a;
2418 var toPropertyKey = toPropertyKey$4;
2419 var $toString = toString$9;
2420 var createPropertyDescriptor = createPropertyDescriptor$5;
2421 var nativeObjectCreate = objectCreate;
2422 var objectKeys$1 = objectKeys$4;
2423 var getOwnPropertyNamesModule$2 = objectGetOwnPropertyNames;
2424 var getOwnPropertyNamesExternal = objectGetOwnPropertyNamesExternal;
2425 var getOwnPropertySymbolsModule$1 = objectGetOwnPropertySymbols;
2426 var getOwnPropertyDescriptorModule$2 = objectGetOwnPropertyDescriptor;
2427 var definePropertyModule$1 = objectDefineProperty;
2428 var propertyIsEnumerableModule = objectPropertyIsEnumerable;
2429 var createNonEnumerableProperty$1 = createNonEnumerableProperty$9;
2430 var redefine$1 = redefine$3;
2431 var shared = shared$4.exports;
2432 var sharedKey = sharedKey$4;
2433 var hiddenKeys$1 = hiddenKeys$6;
2434 var uid$1 = uid$4;
2435 var wellKnownSymbol$6 = wellKnownSymbol$j;
2436 var wrappedWellKnownSymbolModule = wellKnownSymbolWrapped;
2437 var defineWellKnownSymbol$k = defineWellKnownSymbol$l;
2438 var setToStringTag$2 = setToStringTag$5;
2439 var InternalStateModule$3 = internalState;
2440 var $forEach$1 = arrayIteration.forEach;
2441 var HIDDEN = sharedKey('hidden');
2442 var SYMBOL = 'Symbol';
2443 var PROTOTYPE = 'prototype';
2444 var TO_PRIMITIVE = wellKnownSymbol$6('toPrimitive');
2445 var setInternalState$3 = InternalStateModule$3.set;
2446 var getInternalState = InternalStateModule$3.getterFor(SYMBOL);
2447 var ObjectPrototype = Object[PROTOTYPE];
2448 var $Symbol = global$9.Symbol;
2449 var $stringify$1 = getBuiltIn$4('JSON', 'stringify');
2450 var nativeGetOwnPropertyDescriptor$1 = getOwnPropertyDescriptorModule$2.f;
2451 var nativeDefineProperty = definePropertyModule$1.f;
2452 var nativeGetOwnPropertyNames = getOwnPropertyNamesExternal.f;
2453 var nativePropertyIsEnumerable = propertyIsEnumerableModule.f;
2454 var AllSymbols = shared('symbols');
2455 var ObjectPrototypeSymbols = shared('op-symbols');
2456 var StringToSymbolRegistry = shared('string-to-symbol-registry');
2457 var SymbolToStringRegistry = shared('symbol-to-string-registry');
2458 var WellKnownSymbolsStore = shared('wks');
2459 var QObject = global$9.QObject; // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
2460
2461 var USE_SETTER = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild; // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
2462
2463 var setSymbolDescriptor = DESCRIPTORS$9 && fails$d(function () {
2464 return nativeObjectCreate(nativeDefineProperty({}, 'a', {
2465 get: function () {
2466 return nativeDefineProperty(this, 'a', {
2467 value: 7
2468 }).a;
2469 }
2470 })).a != 7;
2471 }) ? function (O, P, Attributes) {
2472 var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype, P);
2473 if (ObjectPrototypeDescriptor) delete ObjectPrototype[P];
2474 nativeDefineProperty(O, P, Attributes);
2475
2476 if (ObjectPrototypeDescriptor && O !== ObjectPrototype) {
2477 nativeDefineProperty(ObjectPrototype, P, ObjectPrototypeDescriptor);
2478 }
2479 } : nativeDefineProperty;
2480
2481 var wrap$1 = function (tag, description) {
2482 var symbol = AllSymbols[tag] = nativeObjectCreate($Symbol[PROTOTYPE]);
2483 setInternalState$3(symbol, {
2484 type: SYMBOL,
2485 tag: tag,
2486 description: description
2487 });
2488 if (!DESCRIPTORS$9) symbol.description = description;
2489 return symbol;
2490 };
2491
2492 var $defineProperty = function defineProperty(O, P, Attributes) {
2493 if (O === ObjectPrototype) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
2494 anObject$5(O);
2495 var key = toPropertyKey(P);
2496 anObject$5(Attributes);
2497
2498 if (has$2(AllSymbols, key)) {
2499 if (!Attributes.enumerable) {
2500 if (!has$2(O, HIDDEN)) nativeDefineProperty(O, HIDDEN, createPropertyDescriptor(1, {}));
2501 O[HIDDEN][key] = true;
2502 } else {
2503 if (has$2(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
2504 Attributes = nativeObjectCreate(Attributes, {
2505 enumerable: createPropertyDescriptor(0, false)
2506 });
2507 }
2508
2509 return setSymbolDescriptor(O, key, Attributes);
2510 }
2511
2512 return nativeDefineProperty(O, key, Attributes);
2513 };
2514
2515 var $defineProperties = function defineProperties(O, Properties) {
2516 anObject$5(O);
2517 var properties = toIndexedObject$4(Properties);
2518 var keys = objectKeys$1(properties).concat($getOwnPropertySymbols(properties));
2519 $forEach$1(keys, function (key) {
2520 if (!DESCRIPTORS$9 || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
2521 });
2522 return O;
2523 };
2524
2525 var $create = function create(O, Properties) {
2526 return Properties === undefined ? nativeObjectCreate(O) : $defineProperties(nativeObjectCreate(O), Properties);
2527 };
2528
2529 var $propertyIsEnumerable = function propertyIsEnumerable(V) {
2530 var P = toPropertyKey(V);
2531 var enumerable = nativePropertyIsEnumerable.call(this, P);
2532 if (this === ObjectPrototype && has$2(AllSymbols, P) && !has$2(ObjectPrototypeSymbols, P)) return false;
2533 return enumerable || !has$2(this, P) || !has$2(AllSymbols, P) || has$2(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
2534 };
2535
2536 var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
2537 var it = toIndexedObject$4(O);
2538 var key = toPropertyKey(P);
2539 if (it === ObjectPrototype && has$2(AllSymbols, key) && !has$2(ObjectPrototypeSymbols, key)) return;
2540 var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);
2541
2542 if (descriptor && has$2(AllSymbols, key) && !(has$2(it, HIDDEN) && it[HIDDEN][key])) {
2543 descriptor.enumerable = true;
2544 }
2545
2546 return descriptor;
2547 };
2548
2549 var $getOwnPropertyNames = function getOwnPropertyNames(O) {
2550 var names = nativeGetOwnPropertyNames(toIndexedObject$4(O));
2551 var result = [];
2552 $forEach$1(names, function (key) {
2553 if (!has$2(AllSymbols, key) && !has$2(hiddenKeys$1, key)) result.push(key);
2554 });
2555 return result;
2556 };
2557
2558 var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
2559 var IS_OBJECT_PROTOTYPE = O === ObjectPrototype;
2560 var names = nativeGetOwnPropertyNames(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject$4(O));
2561 var result = [];
2562 $forEach$1(names, function (key) {
2563 if (has$2(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has$2(ObjectPrototype, key))) {
2564 result.push(AllSymbols[key]);
2565 }
2566 });
2567 return result;
2568 }; // `Symbol` constructor
2569 // https://tc39.es/ecma262/#sec-symbol-constructor
2570
2571
2572 if (!NATIVE_SYMBOL) {
2573 $Symbol = function Symbol() {
2574 if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
2575 var description = !arguments.length || arguments[0] === undefined ? undefined : $toString(arguments[0]);
2576 var tag = uid$1(description);
2577
2578 var setter = function (value) {
2579 if (this === ObjectPrototype) setter.call(ObjectPrototypeSymbols, value);
2580 if (has$2(this, HIDDEN) && has$2(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
2581 setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
2582 };
2583
2584 if (DESCRIPTORS$9 && USE_SETTER) setSymbolDescriptor(ObjectPrototype, tag, {
2585 configurable: true,
2586 set: setter
2587 });
2588 return wrap$1(tag, description);
2589 };
2590
2591 redefine$1($Symbol[PROTOTYPE], 'toString', function toString() {
2592 return getInternalState(this).tag;
2593 });
2594 redefine$1($Symbol, 'withoutSetter', function (description) {
2595 return wrap$1(uid$1(description), description);
2596 });
2597 propertyIsEnumerableModule.f = $propertyIsEnumerable;
2598 definePropertyModule$1.f = $defineProperty;
2599 getOwnPropertyDescriptorModule$2.f = $getOwnPropertyDescriptor;
2600 getOwnPropertyNamesModule$2.f = getOwnPropertyNamesExternal.f = $getOwnPropertyNames;
2601 getOwnPropertySymbolsModule$1.f = $getOwnPropertySymbols;
2602
2603 wrappedWellKnownSymbolModule.f = function (name) {
2604 return wrap$1(wellKnownSymbol$6(name), name);
2605 };
2606
2607 if (DESCRIPTORS$9) {
2608 // https://github.com/tc39/proposal-Symbol-description
2609 nativeDefineProperty($Symbol[PROTOTYPE], 'description', {
2610 configurable: true,
2611 get: function description() {
2612 return getInternalState(this).description;
2613 }
2614 });
2615 }
2616 }
2617
2618 $$E({
2619 global: true,
2620 wrap: true,
2621 forced: !NATIVE_SYMBOL,
2622 sham: !NATIVE_SYMBOL
2623 }, {
2624 Symbol: $Symbol
2625 });
2626 $forEach$1(objectKeys$1(WellKnownSymbolsStore), function (name) {
2627 defineWellKnownSymbol$k(name);
2628 });
2629 $$E({
2630 target: SYMBOL,
2631 stat: true,
2632 forced: !NATIVE_SYMBOL
2633 }, {
2634 // `Symbol.for` method
2635 // https://tc39.es/ecma262/#sec-symbol.for
2636 'for': function (key) {
2637 var string = $toString(key);
2638 if (has$2(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
2639 var symbol = $Symbol(string);
2640 StringToSymbolRegistry[string] = symbol;
2641 SymbolToStringRegistry[symbol] = string;
2642 return symbol;
2643 },
2644 // `Symbol.keyFor` method
2645 // https://tc39.es/ecma262/#sec-symbol.keyfor
2646 keyFor: function keyFor(sym) {
2647 if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol');
2648 if (has$2(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
2649 },
2650 useSetter: function () {
2651 USE_SETTER = true;
2652 },
2653 useSimple: function () {
2654 USE_SETTER = false;
2655 }
2656 });
2657 $$E({
2658 target: 'Object',
2659 stat: true,
2660 forced: !NATIVE_SYMBOL,
2661 sham: !DESCRIPTORS$9
2662 }, {
2663 // `Object.create` method
2664 // https://tc39.es/ecma262/#sec-object.create
2665 create: $create,
2666 // `Object.defineProperty` method
2667 // https://tc39.es/ecma262/#sec-object.defineproperty
2668 defineProperty: $defineProperty,
2669 // `Object.defineProperties` method
2670 // https://tc39.es/ecma262/#sec-object.defineproperties
2671 defineProperties: $defineProperties,
2672 // `Object.getOwnPropertyDescriptor` method
2673 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
2674 getOwnPropertyDescriptor: $getOwnPropertyDescriptor
2675 });
2676 $$E({
2677 target: 'Object',
2678 stat: true,
2679 forced: !NATIVE_SYMBOL
2680 }, {
2681 // `Object.getOwnPropertyNames` method
2682 // https://tc39.es/ecma262/#sec-object.getownpropertynames
2683 getOwnPropertyNames: $getOwnPropertyNames,
2684 // `Object.getOwnPropertySymbols` method
2685 // https://tc39.es/ecma262/#sec-object.getownpropertysymbols
2686 getOwnPropertySymbols: $getOwnPropertySymbols
2687 }); // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
2688 // https://bugs.chromium.org/p/v8/issues/detail?id=3443
2689
2690 $$E({
2691 target: 'Object',
2692 stat: true,
2693 forced: fails$d(function () {
2694 getOwnPropertySymbolsModule$1.f(1);
2695 })
2696 }, {
2697 getOwnPropertySymbols: function getOwnPropertySymbols(it) {
2698 return getOwnPropertySymbolsModule$1.f(toObject$7(it));
2699 }
2700 }); // `JSON.stringify` method behavior with symbols
2701 // https://tc39.es/ecma262/#sec-json.stringify
2702
2703 if ($stringify$1) {
2704 var FORCED_JSON_STRINGIFY = !NATIVE_SYMBOL || fails$d(function () {
2705 var symbol = $Symbol(); // MS Edge converts symbol values to JSON as {}
2706
2707 return $stringify$1([symbol]) != '[null]' // WebKit converts symbol values to JSON as null
2708 || $stringify$1({
2709 a: symbol
2710 }) != '{}' // V8 throws on boxed symbols
2711 || $stringify$1(Object(symbol)) != '{}';
2712 });
2713 $$E({
2714 target: 'JSON',
2715 stat: true,
2716 forced: FORCED_JSON_STRINGIFY
2717 }, {
2718 // eslint-disable-next-line no-unused-vars -- required for `.length`
2719 stringify: function stringify(it, replacer, space) {
2720 var args = [it];
2721 var index = 1;
2722 var $replacer;
2723
2724 while (arguments.length > index) args.push(arguments[index++]);
2725
2726 $replacer = replacer;
2727 if (!isObject$a(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined
2728
2729 if (!isArray$9(replacer)) replacer = function (key, value) {
2730 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
2731 if (!isSymbol(value)) return value;
2732 };
2733 args[1] = replacer;
2734 return $stringify$1.apply(null, args);
2735 }
2736 });
2737 } // `Symbol.prototype[@@toPrimitive]` method
2738 // https://tc39.es/ecma262/#sec-symbol.prototype-@@toprimitive
2739
2740
2741 if (!$Symbol[PROTOTYPE][TO_PRIMITIVE]) {
2742 createNonEnumerableProperty$1($Symbol[PROTOTYPE], TO_PRIMITIVE, $Symbol[PROTOTYPE].valueOf);
2743 } // `Symbol.prototype[@@toStringTag]` property
2744 // https://tc39.es/ecma262/#sec-symbol.prototype-@@tostringtag
2745
2746
2747 setToStringTag$2($Symbol, SYMBOL);
2748 hiddenKeys$1[HIDDEN] = true;
2749
2750 var path$q = path$x;
2751 var getOwnPropertySymbols$2 = path$q.Object.getOwnPropertySymbols;
2752
2753 var parent$O = getOwnPropertySymbols$2;
2754 var getOwnPropertySymbols$1 = parent$O;
2755
2756 var getOwnPropertySymbols = getOwnPropertySymbols$1;
2757
2758 var getOwnPropertyDescriptor$5 = {exports: {}};
2759
2760 var $$D = _export;
2761 var fails$c = fails$m;
2762 var toIndexedObject$3 = toIndexedObject$a;
2763 var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
2764 var DESCRIPTORS$8 = descriptors;
2765 var FAILS_ON_PRIMITIVES$3 = fails$c(function () {
2766 nativeGetOwnPropertyDescriptor(1);
2767 });
2768 var FORCED$6 = !DESCRIPTORS$8 || FAILS_ON_PRIMITIVES$3; // `Object.getOwnPropertyDescriptor` method
2769 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
2770
2771 $$D({
2772 target: 'Object',
2773 stat: true,
2774 forced: FORCED$6,
2775 sham: !DESCRIPTORS$8
2776 }, {
2777 getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
2778 return nativeGetOwnPropertyDescriptor(toIndexedObject$3(it), key);
2779 }
2780 });
2781
2782 var path$p = path$x;
2783 var Object$5 = path$p.Object;
2784
2785 var getOwnPropertyDescriptor$4 = getOwnPropertyDescriptor$5.exports = function getOwnPropertyDescriptor(it, key) {
2786 return Object$5.getOwnPropertyDescriptor(it, key);
2787 };
2788
2789 if (Object$5.getOwnPropertyDescriptor.sham) getOwnPropertyDescriptor$4.sham = true;
2790
2791 var parent$N = getOwnPropertyDescriptor$5.exports;
2792 var getOwnPropertyDescriptor$3 = parent$N;
2793
2794 var getOwnPropertyDescriptor$2 = getOwnPropertyDescriptor$3;
2795
2796 var getBuiltIn$3 = getBuiltIn$8;
2797 var getOwnPropertyNamesModule$1 = objectGetOwnPropertyNames;
2798 var getOwnPropertySymbolsModule = objectGetOwnPropertySymbols;
2799 var anObject$4 = anObject$c; // all object keys, includes non-enumerable and symbols
2800
2801 var ownKeys$6 = getBuiltIn$3('Reflect', 'ownKeys') || function ownKeys(it) {
2802 var keys = getOwnPropertyNamesModule$1.f(anObject$4(it));
2803 var getOwnPropertySymbols = getOwnPropertySymbolsModule.f;
2804 return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
2805 };
2806
2807 var $$C = _export;
2808 var DESCRIPTORS$7 = descriptors;
2809 var ownKeys$5 = ownKeys$6;
2810 var toIndexedObject$2 = toIndexedObject$a;
2811 var getOwnPropertyDescriptorModule$1 = objectGetOwnPropertyDescriptor;
2812 var createProperty$3 = createProperty$5; // `Object.getOwnPropertyDescriptors` method
2813 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
2814
2815 $$C({
2816 target: 'Object',
2817 stat: true,
2818 sham: !DESCRIPTORS$7
2819 }, {
2820 getOwnPropertyDescriptors: function getOwnPropertyDescriptors(object) {
2821 var O = toIndexedObject$2(object);
2822 var getOwnPropertyDescriptor = getOwnPropertyDescriptorModule$1.f;
2823 var keys = ownKeys$5(O);
2824 var result = {};
2825 var index = 0;
2826 var key, descriptor;
2827
2828 while (keys.length > index) {
2829 descriptor = getOwnPropertyDescriptor(O, key = keys[index++]);
2830 if (descriptor !== undefined) createProperty$3(result, key, descriptor);
2831 }
2832
2833 return result;
2834 }
2835 });
2836
2837 var path$o = path$x;
2838 var getOwnPropertyDescriptors$2 = path$o.Object.getOwnPropertyDescriptors;
2839
2840 var parent$M = getOwnPropertyDescriptors$2;
2841 var getOwnPropertyDescriptors$1 = parent$M;
2842
2843 var getOwnPropertyDescriptors = getOwnPropertyDescriptors$1;
2844
2845 var defineProperties$4 = {exports: {}};
2846
2847 var $$B = _export;
2848 var DESCRIPTORS$6 = descriptors;
2849 var defineProperties$3 = objectDefineProperties; // `Object.defineProperties` method
2850 // https://tc39.es/ecma262/#sec-object.defineproperties
2851
2852 $$B({
2853 target: 'Object',
2854 stat: true,
2855 forced: !DESCRIPTORS$6,
2856 sham: !DESCRIPTORS$6
2857 }, {
2858 defineProperties: defineProperties$3
2859 });
2860
2861 var path$n = path$x;
2862 var Object$4 = path$n.Object;
2863
2864 var defineProperties$2 = defineProperties$4.exports = function defineProperties(T, D) {
2865 return Object$4.defineProperties(T, D);
2866 };
2867
2868 if (Object$4.defineProperties.sham) defineProperties$2.sham = true;
2869
2870 var parent$L = defineProperties$4.exports;
2871 var defineProperties$1 = parent$L;
2872
2873 var defineProperties = defineProperties$1;
2874
2875 var defineProperty$8 = {exports: {}};
2876
2877 var $$A = _export;
2878 var DESCRIPTORS$5 = descriptors;
2879 var objectDefinePropertyModile = objectDefineProperty; // `Object.defineProperty` method
2880 // https://tc39.es/ecma262/#sec-object.defineproperty
2881
2882 $$A({
2883 target: 'Object',
2884 stat: true,
2885 forced: !DESCRIPTORS$5,
2886 sham: !DESCRIPTORS$5
2887 }, {
2888 defineProperty: objectDefinePropertyModile.f
2889 });
2890
2891 var path$m = path$x;
2892 var Object$3 = path$m.Object;
2893
2894 var defineProperty$7 = defineProperty$8.exports = function defineProperty(it, key, desc) {
2895 return Object$3.defineProperty(it, key, desc);
2896 };
2897
2898 if (Object$3.defineProperty.sham) defineProperty$7.sham = true;
2899
2900 var parent$K = defineProperty$8.exports;
2901 var defineProperty$6 = parent$K;
2902
2903 var defineProperty$5 = defineProperty$6;
2904
2905 function _classCallCheck(instance, Constructor) {
2906 if (!(instance instanceof Constructor)) {
2907 throw new TypeError("Cannot call a class as a function");
2908 }
2909 }
2910
2911 var parent$J = defineProperty$6;
2912 var defineProperty$4 = parent$J;
2913
2914 var defineProperty$3 = defineProperty$4;
2915
2916 function _defineProperties(target, props) {
2917 for (var i = 0; i < props.length; i++) {
2918 var descriptor = props[i];
2919 descriptor.enumerable = descriptor.enumerable || false;
2920 descriptor.configurable = true;
2921 if ("value" in descriptor) descriptor.writable = true;
2922
2923 defineProperty$3(target, descriptor.key, descriptor);
2924 }
2925 }
2926
2927 function _createClass(Constructor, protoProps, staticProps) {
2928 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
2929 if (staticProps) _defineProperties(Constructor, staticProps);
2930 return Constructor;
2931 }
2932
2933 function _defineProperty(obj, key, value) {
2934 if (key in obj) {
2935 defineProperty$3(obj, key, {
2936 value: value,
2937 enumerable: true,
2938 configurable: true,
2939 writable: true
2940 });
2941 } else {
2942 obj[key] = value;
2943 }
2944
2945 return obj;
2946 }
2947
2948 var $$z = _export;
2949 var isArray$8 = isArray$b; // `Array.isArray` method
2950 // https://tc39.es/ecma262/#sec-array.isarray
2951
2952 $$z({
2953 target: 'Array',
2954 stat: true
2955 }, {
2956 isArray: isArray$8
2957 });
2958
2959 var path$l = path$x;
2960 var isArray$7 = path$l.Array.isArray;
2961
2962 var parent$I = isArray$7;
2963 var isArray$6 = parent$I;
2964
2965 var parent$H = isArray$6;
2966 var isArray$5 = parent$H;
2967
2968 var isArray$4 = isArray$5;
2969
2970 function _arrayWithHoles(arr) {
2971 if (isArray$4(arr)) return arr;
2972 }
2973
2974 var fails$b = fails$m;
2975 var wellKnownSymbol$5 = wellKnownSymbol$j;
2976 var V8_VERSION$1 = engineV8Version;
2977 var SPECIES$2 = wellKnownSymbol$5('species');
2978
2979 var arrayMethodHasSpeciesSupport$5 = function (METHOD_NAME) {
2980 // We can't use this feature detection in V8 since it causes
2981 // deoptimization and serious performance degradation
2982 // https://github.com/zloirock/core-js/issues/677
2983 return V8_VERSION$1 >= 51 || !fails$b(function () {
2984 var array = [];
2985 var constructor = array.constructor = {};
2986
2987 constructor[SPECIES$2] = function () {
2988 return {
2989 foo: 1
2990 };
2991 };
2992
2993 return array[METHOD_NAME](Boolean).foo !== 1;
2994 });
2995 };
2996
2997 var $$y = _export;
2998 var fails$a = fails$m;
2999 var isArray$3 = isArray$b;
3000 var isObject$9 = isObject$j;
3001 var toObject$6 = toObject$d;
3002 var toLength$6 = toLength$a;
3003 var createProperty$2 = createProperty$5;
3004 var arraySpeciesCreate$1 = arraySpeciesCreate$3;
3005 var arrayMethodHasSpeciesSupport$4 = arrayMethodHasSpeciesSupport$5;
3006 var wellKnownSymbol$4 = wellKnownSymbol$j;
3007 var V8_VERSION = engineV8Version;
3008 var IS_CONCAT_SPREADABLE = wellKnownSymbol$4('isConcatSpreadable');
3009 var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
3010 var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded'; // We can't use this feature detection in V8 since it causes
3011 // deoptimization and serious performance degradation
3012 // https://github.com/zloirock/core-js/issues/679
3013
3014 var IS_CONCAT_SPREADABLE_SUPPORT = V8_VERSION >= 51 || !fails$a(function () {
3015 var array = [];
3016 array[IS_CONCAT_SPREADABLE] = false;
3017 return array.concat()[0] !== array;
3018 });
3019 var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport$4('concat');
3020
3021 var isConcatSpreadable = function (O) {
3022 if (!isObject$9(O)) return false;
3023 var spreadable = O[IS_CONCAT_SPREADABLE];
3024 return spreadable !== undefined ? !!spreadable : isArray$3(O);
3025 };
3026
3027 var FORCED$5 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT; // `Array.prototype.concat` method
3028 // https://tc39.es/ecma262/#sec-array.prototype.concat
3029 // with adding support of @@isConcatSpreadable and @@species
3030
3031 $$y({
3032 target: 'Array',
3033 proto: true,
3034 forced: FORCED$5
3035 }, {
3036 // eslint-disable-next-line no-unused-vars -- required for `.length`
3037 concat: function concat(arg) {
3038 var O = toObject$6(this);
3039 var A = arraySpeciesCreate$1(O, 0);
3040 var n = 0;
3041 var i, k, length, len, E;
3042
3043 for (i = -1, length = arguments.length; i < length; i++) {
3044 E = i === -1 ? O : arguments[i];
3045
3046 if (isConcatSpreadable(E)) {
3047 len = toLength$6(E.length);
3048 if (n + len > MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
3049
3050 for (k = 0; k < len; k++, n++) if (k in E) createProperty$2(A, n, E[k]);
3051 } else {
3052 if (n >= MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
3053 createProperty$2(A, n++, E);
3054 }
3055 }
3056
3057 A.length = n;
3058 return A;
3059 }
3060 });
3061
3062 var defineWellKnownSymbol$j = defineWellKnownSymbol$l; // `Symbol.asyncIterator` well-known symbol
3063 // https://tc39.es/ecma262/#sec-symbol.asynciterator
3064
3065 defineWellKnownSymbol$j('asyncIterator');
3066
3067 var defineWellKnownSymbol$i = defineWellKnownSymbol$l; // `Symbol.hasInstance` well-known symbol
3068 // https://tc39.es/ecma262/#sec-symbol.hasinstance
3069
3070 defineWellKnownSymbol$i('hasInstance');
3071
3072 var defineWellKnownSymbol$h = defineWellKnownSymbol$l; // `Symbol.isConcatSpreadable` well-known symbol
3073 // https://tc39.es/ecma262/#sec-symbol.isconcatspreadable
3074
3075 defineWellKnownSymbol$h('isConcatSpreadable');
3076
3077 var defineWellKnownSymbol$g = defineWellKnownSymbol$l; // `Symbol.iterator` well-known symbol
3078 // https://tc39.es/ecma262/#sec-symbol.iterator
3079
3080 defineWellKnownSymbol$g('iterator');
3081
3082 var defineWellKnownSymbol$f = defineWellKnownSymbol$l; // `Symbol.match` well-known symbol
3083 // https://tc39.es/ecma262/#sec-symbol.match
3084
3085 defineWellKnownSymbol$f('match');
3086
3087 var defineWellKnownSymbol$e = defineWellKnownSymbol$l; // `Symbol.matchAll` well-known symbol
3088 // https://tc39.es/ecma262/#sec-symbol.matchall
3089
3090 defineWellKnownSymbol$e('matchAll');
3091
3092 var defineWellKnownSymbol$d = defineWellKnownSymbol$l; // `Symbol.replace` well-known symbol
3093 // https://tc39.es/ecma262/#sec-symbol.replace
3094
3095 defineWellKnownSymbol$d('replace');
3096
3097 var defineWellKnownSymbol$c = defineWellKnownSymbol$l; // `Symbol.search` well-known symbol
3098 // https://tc39.es/ecma262/#sec-symbol.search
3099
3100 defineWellKnownSymbol$c('search');
3101
3102 var defineWellKnownSymbol$b = defineWellKnownSymbol$l; // `Symbol.species` well-known symbol
3103 // https://tc39.es/ecma262/#sec-symbol.species
3104
3105 defineWellKnownSymbol$b('species');
3106
3107 var defineWellKnownSymbol$a = defineWellKnownSymbol$l; // `Symbol.split` well-known symbol
3108 // https://tc39.es/ecma262/#sec-symbol.split
3109
3110 defineWellKnownSymbol$a('split');
3111
3112 var defineWellKnownSymbol$9 = defineWellKnownSymbol$l; // `Symbol.toPrimitive` well-known symbol
3113 // https://tc39.es/ecma262/#sec-symbol.toprimitive
3114
3115 defineWellKnownSymbol$9('toPrimitive');
3116
3117 var defineWellKnownSymbol$8 = defineWellKnownSymbol$l; // `Symbol.toStringTag` well-known symbol
3118 // https://tc39.es/ecma262/#sec-symbol.tostringtag
3119
3120 defineWellKnownSymbol$8('toStringTag');
3121
3122 var defineWellKnownSymbol$7 = defineWellKnownSymbol$l; // `Symbol.unscopables` well-known symbol
3123 // https://tc39.es/ecma262/#sec-symbol.unscopables
3124
3125 defineWellKnownSymbol$7('unscopables');
3126
3127 var global$8 = global$k;
3128 var setToStringTag$1 = setToStringTag$5; // JSON[@@toStringTag] property
3129 // https://tc39.es/ecma262/#sec-json-@@tostringtag
3130
3131 setToStringTag$1(global$8.JSON, 'JSON', true);
3132
3133 var path$k = path$x;
3134 var symbol$4 = path$k.Symbol;
3135
3136 var parent$G = symbol$4;
3137 var symbol$3 = parent$G;
3138
3139 var defineWellKnownSymbol$6 = defineWellKnownSymbol$l; // `Symbol.asyncDispose` well-known symbol
3140 // https://github.com/tc39/proposal-using-statement
3141
3142 defineWellKnownSymbol$6('asyncDispose');
3143
3144 var defineWellKnownSymbol$5 = defineWellKnownSymbol$l; // `Symbol.dispose` well-known symbol
3145 // https://github.com/tc39/proposal-using-statement
3146
3147 defineWellKnownSymbol$5('dispose');
3148
3149 var defineWellKnownSymbol$4 = defineWellKnownSymbol$l; // `Symbol.matcher` well-known symbol
3150 // https://github.com/tc39/proposal-pattern-matching
3151
3152 defineWellKnownSymbol$4('matcher');
3153
3154 var defineWellKnownSymbol$3 = defineWellKnownSymbol$l; // `Symbol.metadata` well-known symbol
3155 // https://github.com/tc39/proposal-decorators
3156
3157 defineWellKnownSymbol$3('metadata');
3158
3159 var defineWellKnownSymbol$2 = defineWellKnownSymbol$l; // `Symbol.observable` well-known symbol
3160 // https://github.com/tc39/proposal-observable
3161
3162 defineWellKnownSymbol$2('observable');
3163
3164 var defineWellKnownSymbol$1 = defineWellKnownSymbol$l; // `Symbol.patternMatch` well-known symbol
3165 // https://github.com/tc39/proposal-pattern-matching
3166
3167 defineWellKnownSymbol$1('patternMatch');
3168
3169 var defineWellKnownSymbol = defineWellKnownSymbol$l;
3170 defineWellKnownSymbol('replaceAll');
3171
3172 var parent$F = symbol$3; // TODO: Remove from `core-js@4`
3173 // TODO: Remove from `core-js@4`
3174
3175 var symbol$2 = parent$F;
3176
3177 var symbol$1 = symbol$2;
3178
3179 function _iterableToArrayLimit(arr, i) {
3180 var _i = arr == null ? null : typeof symbol$1 !== "undefined" && getIteratorMethod$1(arr) || arr["@@iterator"];
3181
3182 if (_i == null) return;
3183 var _arr = [];
3184 var _n = true;
3185 var _d = false;
3186
3187 var _s, _e;
3188
3189 try {
3190 for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
3191 _arr.push(_s.value);
3192
3193 if (i && _arr.length === i) break;
3194 }
3195 } catch (err) {
3196 _d = true;
3197 _e = err;
3198 } finally {
3199 try {
3200 if (!_n && _i["return"] != null) _i["return"]();
3201 } finally {
3202 if (_d) throw _e;
3203 }
3204 }
3205
3206 return _arr;
3207 }
3208
3209 var $$x = _export;
3210 var isObject$8 = isObject$j;
3211 var isArray$2 = isArray$b;
3212 var toAbsoluteIndex$2 = toAbsoluteIndex$4;
3213 var toLength$5 = toLength$a;
3214 var toIndexedObject$1 = toIndexedObject$a;
3215 var createProperty$1 = createProperty$5;
3216 var wellKnownSymbol$3 = wellKnownSymbol$j;
3217 var arrayMethodHasSpeciesSupport$3 = arrayMethodHasSpeciesSupport$5;
3218 var HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport$3('slice');
3219 var SPECIES$1 = wellKnownSymbol$3('species');
3220 var nativeSlice = [].slice;
3221 var max$1 = Math.max; // `Array.prototype.slice` method
3222 // https://tc39.es/ecma262/#sec-array.prototype.slice
3223 // fallback for not array-like ES3 strings and DOM objects
3224
3225 $$x({
3226 target: 'Array',
3227 proto: true,
3228 forced: !HAS_SPECIES_SUPPORT$3
3229 }, {
3230 slice: function slice(start, end) {
3231 var O = toIndexedObject$1(this);
3232 var length = toLength$5(O.length);
3233 var k = toAbsoluteIndex$2(start, length);
3234 var fin = toAbsoluteIndex$2(end === undefined ? length : end, length); // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
3235
3236 var Constructor, result, n;
3237
3238 if (isArray$2(O)) {
3239 Constructor = O.constructor; // cross-realm fallback
3240
3241 if (typeof Constructor == 'function' && (Constructor === Array || isArray$2(Constructor.prototype))) {
3242 Constructor = undefined;
3243 } else if (isObject$8(Constructor)) {
3244 Constructor = Constructor[SPECIES$1];
3245 if (Constructor === null) Constructor = undefined;
3246 }
3247
3248 if (Constructor === Array || Constructor === undefined) {
3249 return nativeSlice.call(O, k, fin);
3250 }
3251 }
3252
3253 result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0));
3254
3255 for (n = 0; k < fin; k++, n++) if (k in O) createProperty$1(result, n, O[k]);
3256
3257 result.length = n;
3258 return result;
3259 }
3260 });
3261
3262 var entryVirtual$g = entryVirtual$i;
3263 var slice$6 = entryVirtual$g('Array').slice;
3264
3265 var slice$5 = slice$6;
3266 var ArrayPrototype$e = Array.prototype;
3267
3268 var slice_1 = function (it) {
3269 var own = it.slice;
3270 return it === ArrayPrototype$e || it instanceof Array && own === ArrayPrototype$e.slice ? slice$5 : own;
3271 };
3272
3273 var parent$E = slice_1;
3274 var slice$4 = parent$E;
3275
3276 var parent$D = slice$4;
3277 var slice$3 = parent$D;
3278
3279 var slice$2 = slice$3;
3280
3281 var parent$C = from$3;
3282 var from$1 = parent$C;
3283
3284 var from = from$1;
3285
3286 function _arrayLikeToArray$8(arr, len) {
3287 if (len == null || len > arr.length) len = arr.length;
3288
3289 for (var i = 0, arr2 = new Array(len); i < len; i++) {
3290 arr2[i] = arr[i];
3291 }
3292
3293 return arr2;
3294 }
3295
3296 function _unsupportedIterableToArray$8(o, minLen) {
3297 var _context;
3298
3299 if (!o) return;
3300 if (typeof o === "string") return _arrayLikeToArray$8(o, minLen);
3301
3302 var n = slice$2(_context = Object.prototype.toString.call(o)).call(_context, 8, -1);
3303
3304 if (n === "Object" && o.constructor) n = o.constructor.name;
3305 if (n === "Map" || n === "Set") return from(o);
3306 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$8(o, minLen);
3307 }
3308
3309 function _nonIterableRest() {
3310 throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
3311 }
3312
3313 function _slicedToArray(arr, i) {
3314 return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray$8(arr, i) || _nonIterableRest();
3315 }
3316
3317 var WrappedWellKnownSymbolModule = wellKnownSymbolWrapped;
3318 var iterator$3 = WrappedWellKnownSymbolModule.f('iterator');
3319
3320 var parent$B = iterator$3;
3321 var iterator$2 = parent$B;
3322
3323 var parent$A = iterator$2;
3324 var iterator$1 = parent$A;
3325
3326 var iterator = iterator$1;
3327
3328 function _typeof(obj) {
3329 "@babel/helpers - typeof";
3330
3331 if (typeof symbol$1 === "function" && typeof iterator === "symbol") {
3332 _typeof = function _typeof(obj) {
3333 return typeof obj;
3334 };
3335 } else {
3336 _typeof = function _typeof(obj) {
3337 return obj && typeof symbol$1 === "function" && obj.constructor === symbol$1 && obj !== symbol$1.prototype ? "symbol" : typeof obj;
3338 };
3339 }
3340
3341 return _typeof(obj);
3342 }
3343
3344 function _arrayWithoutHoles(arr) {
3345 if (isArray$4(arr)) return _arrayLikeToArray$8(arr);
3346 }
3347
3348 function _iterableToArray(iter) {
3349 if (typeof symbol$1 !== "undefined" && getIteratorMethod$1(iter) != null || iter["@@iterator"] != null) return from(iter);
3350 }
3351
3352 function _nonIterableSpread() {
3353 throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
3354 }
3355
3356 function _toConsumableArray(arr) {
3357 return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray$8(arr) || _nonIterableSpread();
3358 }
3359
3360 var symbol = symbol$3;
3361
3362 var entryVirtual$f = entryVirtual$i;
3363 var concat$3 = entryVirtual$f('Array').concat;
3364
3365 var concat$2 = concat$3;
3366 var ArrayPrototype$d = Array.prototype;
3367
3368 var concat_1 = function (it) {
3369 var own = it.concat;
3370 return it === ArrayPrototype$d || it instanceof Array && own === ArrayPrototype$d.concat ? concat$2 : own;
3371 };
3372
3373 var parent$z = concat_1;
3374 var concat$1 = parent$z;
3375
3376 var concat = concat$1;
3377
3378 var slice$1 = slice$4;
3379
3380 var $$w = _export;
3381 var ownKeys$4 = ownKeys$6; // `Reflect.ownKeys` method
3382 // https://tc39.es/ecma262/#sec-reflect.ownkeys
3383
3384 $$w({
3385 target: 'Reflect',
3386 stat: true
3387 }, {
3388 ownKeys: ownKeys$4
3389 });
3390
3391 var path$j = path$x;
3392 path$j.Reflect.ownKeys;
3393
3394 var isArray$1 = isArray$6;
3395
3396 var $$v = _export;
3397 var $map = arrayIteration.map;
3398 var arrayMethodHasSpeciesSupport$2 = arrayMethodHasSpeciesSupport$5;
3399 var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport$2('map'); // `Array.prototype.map` method
3400 // https://tc39.es/ecma262/#sec-array.prototype.map
3401 // with adding support of @@species
3402
3403 $$v({
3404 target: 'Array',
3405 proto: true,
3406 forced: !HAS_SPECIES_SUPPORT$2
3407 }, {
3408 map: function map(callbackfn
3409 /* , thisArg */
3410 ) {
3411 return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3412 }
3413 });
3414
3415 var entryVirtual$e = entryVirtual$i;
3416 var map$6 = entryVirtual$e('Array').map;
3417
3418 var map$5 = map$6;
3419 var ArrayPrototype$c = Array.prototype;
3420
3421 var map_1 = function (it) {
3422 var own = it.map;
3423 return it === ArrayPrototype$c || it instanceof Array && own === ArrayPrototype$c.map ? map$5 : own;
3424 };
3425
3426 var parent$y = map_1;
3427 var map$4 = parent$y;
3428
3429 var map$3 = map$4;
3430
3431 var $$u = _export;
3432 var toObject$5 = toObject$d;
3433 var nativeKeys = objectKeys$4;
3434 var fails$9 = fails$m;
3435 var FAILS_ON_PRIMITIVES$2 = fails$9(function () {
3436 nativeKeys(1);
3437 }); // `Object.keys` method
3438 // https://tc39.es/ecma262/#sec-object.keys
3439
3440 $$u({
3441 target: 'Object',
3442 stat: true,
3443 forced: FAILS_ON_PRIMITIVES$2
3444 }, {
3445 keys: function keys(it) {
3446 return nativeKeys(toObject$5(it));
3447 }
3448 });
3449
3450 var path$i = path$x;
3451 var keys$2 = path$i.Object.keys;
3452
3453 var parent$x = keys$2;
3454 var keys$1 = parent$x;
3455
3456 var keys = keys$1;
3457
3458 var $$t = _export; // `Date.now` method
3459 // https://tc39.es/ecma262/#sec-date.now
3460
3461 $$t({
3462 target: 'Date',
3463 stat: true
3464 }, {
3465 now: function now() {
3466 return new Date().getTime();
3467 }
3468 });
3469
3470 var path$h = path$x;
3471 var now$3 = path$h.Date.now;
3472
3473 var parent$w = now$3;
3474 var now$2 = parent$w;
3475
3476 var now$1 = now$2;
3477
3478 var fails$8 = fails$m;
3479
3480 var arrayMethodIsStrict$6 = function (METHOD_NAME, argument) {
3481 var method = [][METHOD_NAME];
3482 return !!method && fails$8(function () {
3483 // eslint-disable-next-line no-useless-call,no-throw-literal -- required for testing
3484 method.call(null, argument || function () {
3485 throw 1;
3486 }, 1);
3487 });
3488 };
3489
3490 var $forEach = arrayIteration.forEach;
3491 var arrayMethodIsStrict$5 = arrayMethodIsStrict$6;
3492 var STRICT_METHOD$5 = arrayMethodIsStrict$5('forEach'); // `Array.prototype.forEach` method implementation
3493 // https://tc39.es/ecma262/#sec-array.prototype.foreach
3494
3495 var arrayForEach = !STRICT_METHOD$5 ? function forEach(callbackfn
3496 /* , thisArg */
3497 ) {
3498 return $forEach(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); // eslint-disable-next-line es/no-array-prototype-foreach -- safe
3499 } : [].forEach;
3500
3501 var $$s = _export;
3502 var forEach$6 = arrayForEach; // `Array.prototype.forEach` method
3503 // https://tc39.es/ecma262/#sec-array.prototype.foreach
3504 // eslint-disable-next-line es/no-array-prototype-foreach -- safe
3505
3506 $$s({
3507 target: 'Array',
3508 proto: true,
3509 forced: [].forEach != forEach$6
3510 }, {
3511 forEach: forEach$6
3512 });
3513
3514 var entryVirtual$d = entryVirtual$i;
3515 var forEach$5 = entryVirtual$d('Array').forEach;
3516
3517 var parent$v = forEach$5;
3518 var forEach$4 = parent$v;
3519
3520 var forEach$3 = forEach$4;
3521 var classof$3 = classof$8;
3522 var ArrayPrototype$b = Array.prototype;
3523 var DOMIterables$1 = {
3524 DOMTokenList: true,
3525 NodeList: true
3526 };
3527
3528 var forEach_1 = function (it) {
3529 var own = it.forEach;
3530 return it === ArrayPrototype$b || it instanceof Array && own === ArrayPrototype$b.forEach // eslint-disable-next-line no-prototype-builtins -- safe
3531 || DOMIterables$1.hasOwnProperty(classof$3(it)) ? forEach$3 : own;
3532 };
3533
3534 var forEach$2 = forEach_1;
3535
3536 var $$r = _export;
3537 var isArray = isArray$b;
3538 var nativeReverse = [].reverse;
3539 var test$1 = [1, 2]; // `Array.prototype.reverse` method
3540 // https://tc39.es/ecma262/#sec-array.prototype.reverse
3541 // fix for Safari 12.0 bug
3542 // https://bugs.webkit.org/show_bug.cgi?id=188794
3543
3544 $$r({
3545 target: 'Array',
3546 proto: true,
3547 forced: String(test$1) === String(test$1.reverse())
3548 }, {
3549 reverse: function reverse() {
3550 // eslint-disable-next-line no-self-assign -- dirty hack
3551 if (isArray(this)) this.length = this.length;
3552 return nativeReverse.call(this);
3553 }
3554 });
3555
3556 var entryVirtual$c = entryVirtual$i;
3557 var reverse$3 = entryVirtual$c('Array').reverse;
3558
3559 var reverse$2 = reverse$3;
3560 var ArrayPrototype$a = Array.prototype;
3561
3562 var reverse_1 = function (it) {
3563 var own = it.reverse;
3564 return it === ArrayPrototype$a || it instanceof Array && own === ArrayPrototype$a.reverse ? reverse$2 : own;
3565 };
3566
3567 var parent$u = reverse_1;
3568 var reverse$1 = parent$u;
3569
3570 var reverse = reverse$1;
3571
3572 var $$q = _export;
3573 var toAbsoluteIndex$1 = toAbsoluteIndex$4;
3574 var toInteger = toInteger$4;
3575 var toLength$4 = toLength$a;
3576 var toObject$4 = toObject$d;
3577 var arraySpeciesCreate = arraySpeciesCreate$3;
3578 var createProperty = createProperty$5;
3579 var arrayMethodHasSpeciesSupport$1 = arrayMethodHasSpeciesSupport$5;
3580 var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport$1('splice');
3581 var max = Math.max;
3582 var min = Math.min;
3583 var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
3584 var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded'; // `Array.prototype.splice` method
3585 // https://tc39.es/ecma262/#sec-array.prototype.splice
3586 // with adding support of @@species
3587
3588 $$q({
3589 target: 'Array',
3590 proto: true,
3591 forced: !HAS_SPECIES_SUPPORT$1
3592 }, {
3593 splice: function splice(start, deleteCount
3594 /* , ...items */
3595 ) {
3596 var O = toObject$4(this);
3597 var len = toLength$4(O.length);
3598 var actualStart = toAbsoluteIndex$1(start, len);
3599 var argumentsLength = arguments.length;
3600 var insertCount, actualDeleteCount, A, k, from, to;
3601
3602 if (argumentsLength === 0) {
3603 insertCount = actualDeleteCount = 0;
3604 } else if (argumentsLength === 1) {
3605 insertCount = 0;
3606 actualDeleteCount = len - actualStart;
3607 } else {
3608 insertCount = argumentsLength - 2;
3609 actualDeleteCount = min(max(toInteger(deleteCount), 0), len - actualStart);
3610 }
3611
3612 if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER) {
3613 throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
3614 }
3615
3616 A = arraySpeciesCreate(O, actualDeleteCount);
3617
3618 for (k = 0; k < actualDeleteCount; k++) {
3619 from = actualStart + k;
3620 if (from in O) createProperty(A, k, O[from]);
3621 }
3622
3623 A.length = actualDeleteCount;
3624
3625 if (insertCount < actualDeleteCount) {
3626 for (k = actualStart; k < len - actualDeleteCount; k++) {
3627 from = k + actualDeleteCount;
3628 to = k + insertCount;
3629 if (from in O) O[to] = O[from];else delete O[to];
3630 }
3631
3632 for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
3633 } else if (insertCount > actualDeleteCount) {
3634 for (k = len - actualDeleteCount; k > actualStart; k--) {
3635 from = k + actualDeleteCount - 1;
3636 to = k + insertCount - 1;
3637 if (from in O) O[to] = O[from];else delete O[to];
3638 }
3639 }
3640
3641 for (k = 0; k < insertCount; k++) {
3642 O[k + actualStart] = arguments[k + 2];
3643 }
3644
3645 O.length = len - actualDeleteCount + insertCount;
3646 return A;
3647 }
3648 });
3649
3650 var entryVirtual$b = entryVirtual$i;
3651 var splice$3 = entryVirtual$b('Array').splice;
3652
3653 var splice$2 = splice$3;
3654 var ArrayPrototype$9 = Array.prototype;
3655
3656 var splice_1 = function (it) {
3657 var own = it.splice;
3658 return it === ArrayPrototype$9 || it instanceof Array && own === ArrayPrototype$9.splice ? splice$2 : own;
3659 };
3660
3661 var parent$t = splice_1;
3662 var splice$1 = parent$t;
3663
3664 var splice = splice$1;
3665
3666 var $$p = _export;
3667 var $includes = arrayIncludes$1.includes;
3668 // https://tc39.es/ecma262/#sec-array.prototype.includes
3669
3670 $$p({
3671 target: 'Array',
3672 proto: true
3673 }, {
3674 includes: function includes(el
3675 /* , fromIndex = 0 */
3676 ) {
3677 return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
3678 }
3679 }); // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
3680
3681 var entryVirtual$a = entryVirtual$i;
3682 var includes$4 = entryVirtual$a('Array').includes;
3683
3684 var isObject$7 = isObject$j;
3685 var classof$2 = classofRaw$1;
3686 var wellKnownSymbol$2 = wellKnownSymbol$j;
3687 var MATCH$1 = wellKnownSymbol$2('match'); // `IsRegExp` abstract operation
3688 // https://tc39.es/ecma262/#sec-isregexp
3689
3690 var isRegexp = function (it) {
3691 var isRegExp;
3692 return isObject$7(it) && ((isRegExp = it[MATCH$1]) !== undefined ? !!isRegExp : classof$2(it) == 'RegExp');
3693 };
3694
3695 var isRegExp = isRegexp;
3696
3697 var notARegexp = function (it) {
3698 if (isRegExp(it)) {
3699 throw TypeError("The method doesn't accept regular expressions");
3700 }
3701
3702 return it;
3703 };
3704
3705 var wellKnownSymbol$1 = wellKnownSymbol$j;
3706 var MATCH = wellKnownSymbol$1('match');
3707
3708 var correctIsRegexpLogic = function (METHOD_NAME) {
3709 var regexp = /./;
3710
3711 try {
3712 '/./'[METHOD_NAME](regexp);
3713 } catch (error1) {
3714 try {
3715 regexp[MATCH] = false;
3716 return '/./'[METHOD_NAME](regexp);
3717 } catch (error2) {
3718 /* empty */
3719 }
3720 }
3721
3722 return false;
3723 };
3724
3725 var $$o = _export;
3726 var notARegExp = notARegexp;
3727 var requireObjectCoercible$1 = requireObjectCoercible$5;
3728 var toString$4 = toString$9;
3729 var correctIsRegExpLogic = correctIsRegexpLogic; // `String.prototype.includes` method
3730 // https://tc39.es/ecma262/#sec-string.prototype.includes
3731
3732 $$o({
3733 target: 'String',
3734 proto: true,
3735 forced: !correctIsRegExpLogic('includes')
3736 }, {
3737 includes: function includes(searchString
3738 /* , position = 0 */
3739 ) {
3740 return !!~toString$4(requireObjectCoercible$1(this)).indexOf(toString$4(notARegExp(searchString)), arguments.length > 1 ? arguments[1] : undefined);
3741 }
3742 });
3743
3744 var entryVirtual$9 = entryVirtual$i;
3745 var includes$3 = entryVirtual$9('String').includes;
3746
3747 var arrayIncludes = includes$4;
3748 var stringIncludes = includes$3;
3749 var ArrayPrototype$8 = Array.prototype;
3750 var StringPrototype = String.prototype;
3751
3752 var includes$2 = function (it) {
3753 var own = it.includes;
3754 if (it === ArrayPrototype$8 || it instanceof Array && own === ArrayPrototype$8.includes) return arrayIncludes;
3755
3756 if (typeof it === 'string' || it === StringPrototype || it instanceof String && own === StringPrototype.includes) {
3757 return stringIncludes;
3758 }
3759
3760 return own;
3761 };
3762
3763 var parent$s = includes$2;
3764 var includes$1 = parent$s;
3765
3766 var includes = includes$1;
3767
3768 var $$n = _export;
3769 var fails$7 = fails$m;
3770 var toObject$3 = toObject$d;
3771 var nativeGetPrototypeOf = objectGetPrototypeOf;
3772 var CORRECT_PROTOTYPE_GETTER = correctPrototypeGetter;
3773 var FAILS_ON_PRIMITIVES$1 = fails$7(function () {
3774 nativeGetPrototypeOf(1);
3775 }); // `Object.getPrototypeOf` method
3776 // https://tc39.es/ecma262/#sec-object.getprototypeof
3777
3778 $$n({
3779 target: 'Object',
3780 stat: true,
3781 forced: FAILS_ON_PRIMITIVES$1,
3782 sham: !CORRECT_PROTOTYPE_GETTER
3783 }, {
3784 getPrototypeOf: function getPrototypeOf(it) {
3785 return nativeGetPrototypeOf(toObject$3(it));
3786 }
3787 });
3788
3789 var path$g = path$x;
3790 var getPrototypeOf$5 = path$g.Object.getPrototypeOf;
3791
3792 var parent$r = getPrototypeOf$5;
3793 var getPrototypeOf$4 = parent$r;
3794
3795 var getPrototypeOf$3 = getPrototypeOf$4;
3796
3797 var $$m = _export;
3798 var $filter = arrayIteration.filter;
3799 var arrayMethodHasSpeciesSupport = arrayMethodHasSpeciesSupport$5;
3800 var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('filter'); // `Array.prototype.filter` method
3801 // https://tc39.es/ecma262/#sec-array.prototype.filter
3802 // with adding support of @@species
3803
3804 $$m({
3805 target: 'Array',
3806 proto: true,
3807 forced: !HAS_SPECIES_SUPPORT
3808 }, {
3809 filter: function filter(callbackfn
3810 /* , thisArg */
3811 ) {
3812 return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3813 }
3814 });
3815
3816 var entryVirtual$8 = entryVirtual$i;
3817 var filter$3 = entryVirtual$8('Array').filter;
3818
3819 var filter$2 = filter$3;
3820 var ArrayPrototype$7 = Array.prototype;
3821
3822 var filter_1 = function (it) {
3823 var own = it.filter;
3824 return it === ArrayPrototype$7 || it instanceof Array && own === ArrayPrototype$7.filter ? filter$2 : own;
3825 };
3826
3827 var parent$q = filter_1;
3828 var filter$1 = parent$q;
3829
3830 var filter = filter$1;
3831
3832 var DESCRIPTORS$4 = descriptors;
3833 var objectKeys = objectKeys$4;
3834 var toIndexedObject = toIndexedObject$a;
3835 var propertyIsEnumerable = objectPropertyIsEnumerable.f; // `Object.{ entries, values }` methods implementation
3836
3837 var createMethod$2 = function (TO_ENTRIES) {
3838 return function (it) {
3839 var O = toIndexedObject(it);
3840 var keys = objectKeys(O);
3841 var length = keys.length;
3842 var i = 0;
3843 var result = [];
3844 var key;
3845
3846 while (length > i) {
3847 key = keys[i++];
3848
3849 if (!DESCRIPTORS$4 || propertyIsEnumerable.call(O, key)) {
3850 result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
3851 }
3852 }
3853
3854 return result;
3855 };
3856 };
3857
3858 var objectToArray = {
3859 // `Object.entries` method
3860 // https://tc39.es/ecma262/#sec-object.entries
3861 entries: createMethod$2(true),
3862 // `Object.values` method
3863 // https://tc39.es/ecma262/#sec-object.values
3864 values: createMethod$2(false)
3865 };
3866
3867 var $$l = _export;
3868 var $values = objectToArray.values; // `Object.values` method
3869 // https://tc39.es/ecma262/#sec-object.values
3870
3871 $$l({
3872 target: 'Object',
3873 stat: true
3874 }, {
3875 values: function values(O) {
3876 return $values(O);
3877 }
3878 });
3879
3880 var path$f = path$x;
3881 path$f.Object.values;
3882
3883 var whitespaces$4 = '\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';
3884
3885 var requireObjectCoercible = requireObjectCoercible$5;
3886 var toString$3 = toString$9;
3887 var whitespaces$3 = whitespaces$4;
3888 var whitespace = '[' + whitespaces$3 + ']';
3889 var ltrim = RegExp('^' + whitespace + whitespace + '*');
3890 var rtrim = RegExp(whitespace + whitespace + '*$'); // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
3891
3892 var createMethod$1 = function (TYPE) {
3893 return function ($this) {
3894 var string = toString$3(requireObjectCoercible($this));
3895 if (TYPE & 1) string = string.replace(ltrim, '');
3896 if (TYPE & 2) string = string.replace(rtrim, '');
3897 return string;
3898 };
3899 };
3900
3901 var stringTrim = {
3902 // `String.prototype.{ trimLeft, trimStart }` methods
3903 // https://tc39.es/ecma262/#sec-string.prototype.trimstart
3904 start: createMethod$1(1),
3905 // `String.prototype.{ trimRight, trimEnd }` methods
3906 // https://tc39.es/ecma262/#sec-string.prototype.trimend
3907 end: createMethod$1(2),
3908 // `String.prototype.trim` method
3909 // https://tc39.es/ecma262/#sec-string.prototype.trim
3910 trim: createMethod$1(3)
3911 };
3912
3913 var global$7 = global$k;
3914 var toString$2 = toString$9;
3915 var trim$1 = stringTrim.trim;
3916 var whitespaces$2 = whitespaces$4;
3917 var $parseInt = global$7.parseInt;
3918 var hex = /^[+-]?0[Xx]/;
3919 var FORCED$4 = $parseInt(whitespaces$2 + '08') !== 8 || $parseInt(whitespaces$2 + '0x16') !== 22; // `parseInt` method
3920 // https://tc39.es/ecma262/#sec-parseint-string-radix
3921
3922 var numberParseInt = FORCED$4 ? function parseInt(string, radix) {
3923 var S = trim$1(toString$2(string));
3924 return $parseInt(S, radix >>> 0 || (hex.test(S) ? 16 : 10));
3925 } : $parseInt;
3926
3927 var $$k = _export;
3928 var parseIntImplementation = numberParseInt; // `parseInt` method
3929 // https://tc39.es/ecma262/#sec-parseint-string-radix
3930
3931 $$k({
3932 global: true,
3933 forced: parseInt != parseIntImplementation
3934 }, {
3935 parseInt: parseIntImplementation
3936 });
3937
3938 var path$e = path$x;
3939 var _parseInt$2 = path$e.parseInt;
3940
3941 var parent$p = _parseInt$2;
3942 var _parseInt$1 = parent$p;
3943
3944 var _parseInt = _parseInt$1;
3945
3946 /* eslint-disable es/no-array-prototype-indexof -- required for testing */
3947
3948
3949 var $$j = _export;
3950 var $indexOf = arrayIncludes$1.indexOf;
3951 var arrayMethodIsStrict$4 = arrayMethodIsStrict$6;
3952 var nativeIndexOf = [].indexOf;
3953 var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
3954 var STRICT_METHOD$4 = arrayMethodIsStrict$4('indexOf'); // `Array.prototype.indexOf` method
3955 // https://tc39.es/ecma262/#sec-array.prototype.indexof
3956
3957 $$j({
3958 target: 'Array',
3959 proto: true,
3960 forced: NEGATIVE_ZERO || !STRICT_METHOD$4
3961 }, {
3962 indexOf: function indexOf(searchElement
3963 /* , fromIndex = 0 */
3964 ) {
3965 return NEGATIVE_ZERO // convert -0 to +0
3966 ? nativeIndexOf.apply(this, arguments) || 0 : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
3967 }
3968 });
3969
3970 var entryVirtual$7 = entryVirtual$i;
3971 var indexOf$3 = entryVirtual$7('Array').indexOf;
3972
3973 var indexOf$2 = indexOf$3;
3974 var ArrayPrototype$6 = Array.prototype;
3975
3976 var indexOf_1 = function (it) {
3977 var own = it.indexOf;
3978 return it === ArrayPrototype$6 || it instanceof Array && own === ArrayPrototype$6.indexOf ? indexOf$2 : own;
3979 };
3980
3981 var parent$o = indexOf_1;
3982 var indexOf$1 = parent$o;
3983
3984 var indexOf = indexOf$1;
3985
3986 var fails$6 = fails$m;
3987 var whitespaces$1 = whitespaces$4;
3988 var non = '\u200B\u0085\u180E'; // check that a method works with the correct list
3989 // of whitespaces and has a correct name
3990
3991 var stringTrimForced = function (METHOD_NAME) {
3992 return fails$6(function () {
3993 return !!whitespaces$1[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces$1[METHOD_NAME].name !== METHOD_NAME;
3994 });
3995 };
3996
3997 var $$i = _export;
3998 var $trim = stringTrim.trim;
3999 var forcedStringTrimMethod = stringTrimForced; // `String.prototype.trim` method
4000 // https://tc39.es/ecma262/#sec-string.prototype.trim
4001
4002 $$i({
4003 target: 'String',
4004 proto: true,
4005 forced: forcedStringTrimMethod('trim')
4006 }, {
4007 trim: function trim() {
4008 return $trim(this);
4009 }
4010 });
4011
4012 var entryVirtual$6 = entryVirtual$i;
4013 entryVirtual$6('String').trim;
4014
4015 var $$h = _export;
4016 var DESCRIPTORS$3 = descriptors;
4017 var create$7 = objectCreate; // `Object.create` method
4018 // https://tc39.es/ecma262/#sec-object.create
4019
4020 $$h({
4021 target: 'Object',
4022 stat: true,
4023 sham: !DESCRIPTORS$3
4024 }, {
4025 create: create$7
4026 });
4027
4028 var path$d = path$x;
4029 var Object$2 = path$d.Object;
4030
4031 var create$6 = function create(P, D) {
4032 return Object$2.create(P, D);
4033 };
4034
4035 var parent$n = create$6;
4036 var create$5 = parent$n;
4037
4038 var create$4 = create$5;
4039
4040 var $$g = _export;
4041 var getBuiltIn$2 = getBuiltIn$8;
4042 var fails$5 = fails$m;
4043 var $stringify = getBuiltIn$2('JSON', 'stringify');
4044 var re = /[\uD800-\uDFFF]/g;
4045 var low = /^[\uD800-\uDBFF]$/;
4046 var hi = /^[\uDC00-\uDFFF]$/;
4047
4048 var fix = function (match, offset, string) {
4049 var prev = string.charAt(offset - 1);
4050 var next = string.charAt(offset + 1);
4051
4052 if (low.test(match) && !hi.test(next) || hi.test(match) && !low.test(prev)) {
4053 return '\\u' + match.charCodeAt(0).toString(16);
4054 }
4055
4056 return match;
4057 };
4058
4059 var FORCED$3 = fails$5(function () {
4060 return $stringify('\uDF06\uD834') !== '"\\udf06\\ud834"' || $stringify('\uDEAD') !== '"\\udead"';
4061 });
4062
4063 if ($stringify) {
4064 // `JSON.stringify` method
4065 // https://tc39.es/ecma262/#sec-json.stringify
4066 // https://github.com/tc39/proposal-well-formed-stringify
4067 $$g({
4068 target: 'JSON',
4069 stat: true,
4070 forced: FORCED$3
4071 }, {
4072 // eslint-disable-next-line no-unused-vars -- required for `.length`
4073 stringify: function stringify(it, replacer, space) {
4074 var result = $stringify.apply(null, arguments);
4075 return typeof result == 'string' ? result.replace(re, fix) : result;
4076 }
4077 });
4078 }
4079
4080 var core = path$x; // eslint-disable-next-line es/no-json -- safe
4081
4082 if (!core.JSON) core.JSON = {
4083 stringify: JSON.stringify
4084 }; // eslint-disable-next-line no-unused-vars -- required for `.length`
4085
4086 var stringify$3 = function stringify(it, replacer, space) {
4087 return core.JSON.stringify.apply(null, arguments);
4088 };
4089
4090 var parent$m = stringify$3;
4091 var stringify$2 = parent$m;
4092
4093 var stringify$1 = stringify$2;
4094
4095 var $$f = _export;
4096 var global$6 = global$k;
4097 var userAgent$2 = engineUserAgent;
4098 var slice = [].slice;
4099 var MSIE = /MSIE .\./.test(userAgent$2); // <- dirty ie9- check
4100
4101 var wrap = function (scheduler) {
4102 return function (handler, timeout
4103 /* , ...arguments */
4104 ) {
4105 var boundArgs = arguments.length > 2;
4106 var args = boundArgs ? slice.call(arguments, 2) : undefined;
4107 return scheduler(boundArgs ? function () {
4108 // eslint-disable-next-line no-new-func -- spec requirement
4109 (typeof handler == 'function' ? handler : Function(handler)).apply(this, args);
4110 } : handler, timeout);
4111 };
4112 }; // ie9- setTimeout & setInterval additional parameters fix
4113 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
4114
4115
4116 $$f({
4117 global: true,
4118 bind: true,
4119 forced: MSIE
4120 }, {
4121 // `setTimeout` method
4122 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout
4123 setTimeout: wrap(global$6.setTimeout),
4124 // `setInterval` method
4125 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
4126 setInterval: wrap(global$6.setInterval)
4127 });
4128
4129 var path$c = path$x;
4130 var setTimeout$2 = path$c.setTimeout;
4131
4132 var setTimeout$1 = setTimeout$2;
4133
4134 var toObject$2 = toObject$d;
4135 var toAbsoluteIndex = toAbsoluteIndex$4;
4136 var toLength$3 = toLength$a; // `Array.prototype.fill` method implementation
4137 // https://tc39.es/ecma262/#sec-array.prototype.fill
4138
4139 var arrayFill = function fill(value
4140 /* , start = 0, end = @length */
4141 ) {
4142 var O = toObject$2(this);
4143 var length = toLength$3(O.length);
4144 var argumentsLength = arguments.length;
4145 var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);
4146 var end = argumentsLength > 2 ? arguments[2] : undefined;
4147 var endPos = end === undefined ? length : toAbsoluteIndex(end, length);
4148
4149 while (endPos > index) O[index++] = value;
4150
4151 return O;
4152 };
4153
4154 var $$e = _export;
4155 var fill$4 = arrayFill;
4156 // https://tc39.es/ecma262/#sec-array.prototype.fill
4157
4158 $$e({
4159 target: 'Array',
4160 proto: true
4161 }, {
4162 fill: fill$4
4163 }); // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
4164
4165 var entryVirtual$5 = entryVirtual$i;
4166 var fill$3 = entryVirtual$5('Array').fill;
4167
4168 var fill$2 = fill$3;
4169 var ArrayPrototype$5 = Array.prototype;
4170
4171 var fill_1 = function (it) {
4172 var own = it.fill;
4173 return it === ArrayPrototype$5 || it instanceof Array && own === ArrayPrototype$5.fill ? fill$2 : own;
4174 };
4175
4176 var parent$l = fill_1;
4177 var fill$1 = parent$l;
4178
4179 var fill = fill$1;
4180
4181 /*! Hammer.JS - v2.0.17-rc - 2019-12-16
4182 * http://naver.github.io/egjs
4183 *
4184 * Forked By Naver egjs
4185 * Copyright (c) hammerjs
4186 * Licensed under the MIT license */
4187 function _extends() {
4188 _extends = Object.assign || function (target) {
4189 for (var i = 1; i < arguments.length; i++) {
4190 var source = arguments[i];
4191
4192 for (var key in source) {
4193 if (Object.prototype.hasOwnProperty.call(source, key)) {
4194 target[key] = source[key];
4195 }
4196 }
4197 }
4198
4199 return target;
4200 };
4201
4202 return _extends.apply(this, arguments);
4203 }
4204
4205 function _inheritsLoose(subClass, superClass) {
4206 subClass.prototype = Object.create(superClass.prototype);
4207 subClass.prototype.constructor = subClass;
4208 subClass.__proto__ = superClass;
4209 }
4210
4211 function _assertThisInitialized$1(self) {
4212 if (self === void 0) {
4213 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
4214 }
4215
4216 return self;
4217 }
4218 /**
4219 * @private
4220 * extend object.
4221 * means that properties in dest will be overwritten by the ones in src.
4222 * @param {Object} target
4223 * @param {...Object} objects_to_assign
4224 * @returns {Object} target
4225 */
4226
4227
4228 var assign;
4229
4230 if (typeof Object.assign !== 'function') {
4231 assign = function assign(target) {
4232 if (target === undefined || target === null) {
4233 throw new TypeError('Cannot convert undefined or null to object');
4234 }
4235
4236 var output = Object(target);
4237
4238 for (var index = 1; index < arguments.length; index++) {
4239 var source = arguments[index];
4240
4241 if (source !== undefined && source !== null) {
4242 for (var nextKey in source) {
4243 if (source.hasOwnProperty(nextKey)) {
4244 output[nextKey] = source[nextKey];
4245 }
4246 }
4247 }
4248 }
4249
4250 return output;
4251 };
4252 } else {
4253 assign = Object.assign;
4254 }
4255
4256 var assign$1 = assign;
4257 var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
4258 var TEST_ELEMENT = typeof document === "undefined" ? {
4259 style: {}
4260 } : document.createElement('div');
4261 var TYPE_FUNCTION = 'function';
4262 var round = Math.round,
4263 abs$1 = Math.abs;
4264 var now = Date.now;
4265 /**
4266 * @private
4267 * get the prefixed property
4268 * @param {Object} obj
4269 * @param {String} property
4270 * @returns {String|Undefined} prefixed
4271 */
4272
4273 function prefixed(obj, property) {
4274 var prefix;
4275 var prop;
4276 var camelProp = property[0].toUpperCase() + property.slice(1);
4277 var i = 0;
4278
4279 while (i < VENDOR_PREFIXES.length) {
4280 prefix = VENDOR_PREFIXES[i];
4281 prop = prefix ? prefix + camelProp : property;
4282
4283 if (prop in obj) {
4284 return prop;
4285 }
4286
4287 i++;
4288 }
4289
4290 return undefined;
4291 }
4292 /* eslint-disable no-new-func, no-nested-ternary */
4293
4294
4295 var win;
4296
4297 if (typeof window === "undefined") {
4298 // window is undefined in node.js
4299 win = {};
4300 } else {
4301 win = window;
4302 }
4303
4304 var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
4305 var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
4306
4307 function getTouchActionProps() {
4308 if (!NATIVE_TOUCH_ACTION) {
4309 return false;
4310 }
4311
4312 var touchMap = {};
4313 var cssSupports = win.CSS && win.CSS.supports;
4314 ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function (val) {
4315 // If css.supports is not supported but there is native touch-action assume it supports
4316 // all values. This is the case for IE 10 and 11.
4317 return touchMap[val] = cssSupports ? win.CSS.supports('touch-action', val) : true;
4318 });
4319 return touchMap;
4320 }
4321
4322 var TOUCH_ACTION_COMPUTE = 'compute';
4323 var TOUCH_ACTION_AUTO = 'auto';
4324 var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
4325
4326 var TOUCH_ACTION_NONE = 'none';
4327 var TOUCH_ACTION_PAN_X = 'pan-x';
4328 var TOUCH_ACTION_PAN_Y = 'pan-y';
4329 var TOUCH_ACTION_MAP = getTouchActionProps();
4330 var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
4331 var SUPPORT_TOUCH = ('ontouchstart' in win);
4332 var SUPPORT_POINTER_EVENTS = prefixed(win, 'PointerEvent') !== undefined;
4333 var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
4334 var INPUT_TYPE_TOUCH = 'touch';
4335 var INPUT_TYPE_PEN = 'pen';
4336 var INPUT_TYPE_MOUSE = 'mouse';
4337 var INPUT_TYPE_KINECT = 'kinect';
4338 var COMPUTE_INTERVAL = 25;
4339 var INPUT_START = 1;
4340 var INPUT_MOVE = 2;
4341 var INPUT_END = 4;
4342 var INPUT_CANCEL = 8;
4343 var DIRECTION_NONE = 1;
4344 var DIRECTION_LEFT = 2;
4345 var DIRECTION_RIGHT = 4;
4346 var DIRECTION_UP = 8;
4347 var DIRECTION_DOWN = 16;
4348 var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
4349 var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
4350 var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
4351 var PROPS_XY = ['x', 'y'];
4352 var PROPS_CLIENT_XY = ['clientX', 'clientY'];
4353 /**
4354 * @private
4355 * walk objects and arrays
4356 * @param {Object} obj
4357 * @param {Function} iterator
4358 * @param {Object} context
4359 */
4360
4361 function each(obj, iterator, context) {
4362 var i;
4363
4364 if (!obj) {
4365 return;
4366 }
4367
4368 if (obj.forEach) {
4369 obj.forEach(iterator, context);
4370 } else if (obj.length !== undefined) {
4371 i = 0;
4372
4373 while (i < obj.length) {
4374 iterator.call(context, obj[i], i, obj);
4375 i++;
4376 }
4377 } else {
4378 for (i in obj) {
4379 obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
4380 }
4381 }
4382 }
4383 /**
4384 * @private
4385 * let a boolean value also be a function that must return a boolean
4386 * this first item in args will be used as the context
4387 * @param {Boolean|Function} val
4388 * @param {Array} [args]
4389 * @returns {Boolean}
4390 */
4391
4392
4393 function boolOrFn(val, args) {
4394 if (typeof val === TYPE_FUNCTION) {
4395 return val.apply(args ? args[0] || undefined : undefined, args);
4396 }
4397
4398 return val;
4399 }
4400 /**
4401 * @private
4402 * small indexOf wrapper
4403 * @param {String} str
4404 * @param {String} find
4405 * @returns {Boolean} found
4406 */
4407
4408
4409 function inStr(str, find) {
4410 return str.indexOf(find) > -1;
4411 }
4412 /**
4413 * @private
4414 * when the touchActions are collected they are not a valid value, so we need to clean things up. *
4415 * @param {String} actions
4416 * @returns {*}
4417 */
4418
4419
4420 function cleanTouchActions(actions) {
4421 // none
4422 if (inStr(actions, TOUCH_ACTION_NONE)) {
4423 return TOUCH_ACTION_NONE;
4424 }
4425
4426 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
4427 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); // if both pan-x and pan-y are set (different recognizers
4428 // for different directions, e.g. horizontal pan but vertical swipe?)
4429 // we need none (as otherwise with pan-x pan-y combined none of these
4430 // recognizers will work, since the browser would handle all panning
4431
4432 if (hasPanX && hasPanY) {
4433 return TOUCH_ACTION_NONE;
4434 } // pan-x OR pan-y
4435
4436
4437 if (hasPanX || hasPanY) {
4438 return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
4439 } // manipulation
4440
4441
4442 if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
4443 return TOUCH_ACTION_MANIPULATION;
4444 }
4445
4446 return TOUCH_ACTION_AUTO;
4447 }
4448 /**
4449 * @private
4450 * Touch Action
4451 * sets the touchAction property or uses the js alternative
4452 * @param {Manager} manager
4453 * @param {String} value
4454 * @constructor
4455 */
4456
4457
4458 var TouchAction = /*#__PURE__*/function () {
4459 function TouchAction(manager, value) {
4460 this.manager = manager;
4461 this.set(value);
4462 }
4463 /**
4464 * @private
4465 * set the touchAction value on the element or enable the polyfill
4466 * @param {String} value
4467 */
4468
4469
4470 var _proto = TouchAction.prototype;
4471
4472 _proto.set = function set(value) {
4473 // find out the touch-action by the event handlers
4474 if (value === TOUCH_ACTION_COMPUTE) {
4475 value = this.compute();
4476 }
4477
4478 if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
4479 this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
4480 }
4481
4482 this.actions = value.toLowerCase().trim();
4483 };
4484 /**
4485 * @private
4486 * just re-set the touchAction value
4487 */
4488
4489
4490 _proto.update = function update() {
4491 this.set(this.manager.options.touchAction);
4492 };
4493 /**
4494 * @private
4495 * compute the value for the touchAction property based on the recognizer's settings
4496 * @returns {String} value
4497 */
4498
4499
4500 _proto.compute = function compute() {
4501 var actions = [];
4502 each(this.manager.recognizers, function (recognizer) {
4503 if (boolOrFn(recognizer.options.enable, [recognizer])) {
4504 actions = actions.concat(recognizer.getTouchAction());
4505 }
4506 });
4507 return cleanTouchActions(actions.join(' '));
4508 };
4509 /**
4510 * @private
4511 * this method is called on each input cycle and provides the preventing of the browser behavior
4512 * @param {Object} input
4513 */
4514
4515
4516 _proto.preventDefaults = function preventDefaults(input) {
4517 var srcEvent = input.srcEvent;
4518 var direction = input.offsetDirection; // if the touch action did prevented once this session
4519
4520 if (this.manager.session.prevented) {
4521 srcEvent.preventDefault();
4522 return;
4523 }
4524
4525 var actions = this.actions;
4526 var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
4527 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
4528 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
4529
4530 if (hasNone) {
4531 // do not prevent defaults if this is a tap gesture
4532 var isTapPointer = input.pointers.length === 1;
4533 var isTapMovement = input.distance < 2;
4534 var isTapTouchTime = input.deltaTime < 250;
4535
4536 if (isTapPointer && isTapMovement && isTapTouchTime) {
4537 return;
4538 }
4539 }
4540
4541 if (hasPanX && hasPanY) {
4542 // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
4543 return;
4544 }
4545
4546 if (hasNone || hasPanY && direction & DIRECTION_HORIZONTAL || hasPanX && direction & DIRECTION_VERTICAL) {
4547 return this.preventSrc(srcEvent);
4548 }
4549 };
4550 /**
4551 * @private
4552 * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
4553 * @param {Object} srcEvent
4554 */
4555
4556
4557 _proto.preventSrc = function preventSrc(srcEvent) {
4558 this.manager.session.prevented = true;
4559 srcEvent.preventDefault();
4560 };
4561
4562 return TouchAction;
4563 }();
4564 /**
4565 * @private
4566 * find if a node is in the given parent
4567 * @method hasParent
4568 * @param {HTMLElement} node
4569 * @param {HTMLElement} parent
4570 * @return {Boolean} found
4571 */
4572
4573
4574 function hasParent(node, parent) {
4575 while (node) {
4576 if (node === parent) {
4577 return true;
4578 }
4579
4580 node = node.parentNode;
4581 }
4582
4583 return false;
4584 }
4585 /**
4586 * @private
4587 * get the center of all the pointers
4588 * @param {Array} pointers
4589 * @return {Object} center contains `x` and `y` properties
4590 */
4591
4592
4593 function getCenter(pointers) {
4594 var pointersLength = pointers.length; // no need to loop when only one touch
4595
4596 if (pointersLength === 1) {
4597 return {
4598 x: round(pointers[0].clientX),
4599 y: round(pointers[0].clientY)
4600 };
4601 }
4602
4603 var x = 0;
4604 var y = 0;
4605 var i = 0;
4606
4607 while (i < pointersLength) {
4608 x += pointers[i].clientX;
4609 y += pointers[i].clientY;
4610 i++;
4611 }
4612
4613 return {
4614 x: round(x / pointersLength),
4615 y: round(y / pointersLength)
4616 };
4617 }
4618 /**
4619 * @private
4620 * create a simple clone from the input used for storage of firstInput and firstMultiple
4621 * @param {Object} input
4622 * @returns {Object} clonedInputData
4623 */
4624
4625
4626 function simpleCloneInputData(input) {
4627 // make a simple copy of the pointers because we will get a reference if we don't
4628 // we only need clientXY for the calculations
4629 var pointers = [];
4630 var i = 0;
4631
4632 while (i < input.pointers.length) {
4633 pointers[i] = {
4634 clientX: round(input.pointers[i].clientX),
4635 clientY: round(input.pointers[i].clientY)
4636 };
4637 i++;
4638 }
4639
4640 return {
4641 timeStamp: now(),
4642 pointers: pointers,
4643 center: getCenter(pointers),
4644 deltaX: input.deltaX,
4645 deltaY: input.deltaY
4646 };
4647 }
4648 /**
4649 * @private
4650 * calculate the absolute distance between two points
4651 * @param {Object} p1 {x, y}
4652 * @param {Object} p2 {x, y}
4653 * @param {Array} [props] containing x and y keys
4654 * @return {Number} distance
4655 */
4656
4657
4658 function getDistance(p1, p2, props) {
4659 if (!props) {
4660 props = PROPS_XY;
4661 }
4662
4663 var x = p2[props[0]] - p1[props[0]];
4664 var y = p2[props[1]] - p1[props[1]];
4665 return Math.sqrt(x * x + y * y);
4666 }
4667 /**
4668 * @private
4669 * calculate the angle between two coordinates
4670 * @param {Object} p1
4671 * @param {Object} p2
4672 * @param {Array} [props] containing x and y keys
4673 * @return {Number} angle
4674 */
4675
4676
4677 function getAngle(p1, p2, props) {
4678 if (!props) {
4679 props = PROPS_XY;
4680 }
4681
4682 var x = p2[props[0]] - p1[props[0]];
4683 var y = p2[props[1]] - p1[props[1]];
4684 return Math.atan2(y, x) * 180 / Math.PI;
4685 }
4686 /**
4687 * @private
4688 * get the direction between two points
4689 * @param {Number} x
4690 * @param {Number} y
4691 * @return {Number} direction
4692 */
4693
4694
4695 function getDirection(x, y) {
4696 if (x === y) {
4697 return DIRECTION_NONE;
4698 }
4699
4700 if (abs$1(x) >= abs$1(y)) {
4701 return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
4702 }
4703
4704 return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
4705 }
4706
4707 function computeDeltaXY(session, input) {
4708 var center = input.center; // let { offsetDelta:offset = {}, prevDelta = {}, prevInput = {} } = session;
4709 // jscs throwing error on defalut destructured values and without defaults tests fail
4710
4711 var offset = session.offsetDelta || {};
4712 var prevDelta = session.prevDelta || {};
4713 var prevInput = session.prevInput || {};
4714
4715 if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
4716 prevDelta = session.prevDelta = {
4717 x: prevInput.deltaX || 0,
4718 y: prevInput.deltaY || 0
4719 };
4720 offset = session.offsetDelta = {
4721 x: center.x,
4722 y: center.y
4723 };
4724 }
4725
4726 input.deltaX = prevDelta.x + (center.x - offset.x);
4727 input.deltaY = prevDelta.y + (center.y - offset.y);
4728 }
4729 /**
4730 * @private
4731 * calculate the velocity between two points. unit is in px per ms.
4732 * @param {Number} deltaTime
4733 * @param {Number} x
4734 * @param {Number} y
4735 * @return {Object} velocity `x` and `y`
4736 */
4737
4738
4739 function getVelocity(deltaTime, x, y) {
4740 return {
4741 x: x / deltaTime || 0,
4742 y: y / deltaTime || 0
4743 };
4744 }
4745 /**
4746 * @private
4747 * calculate the scale factor between two pointersets
4748 * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
4749 * @param {Array} start array of pointers
4750 * @param {Array} end array of pointers
4751 * @return {Number} scale
4752 */
4753
4754
4755 function getScale(start, end) {
4756 return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
4757 }
4758 /**
4759 * @private
4760 * calculate the rotation degrees between two pointersets
4761 * @param {Array} start array of pointers
4762 * @param {Array} end array of pointers
4763 * @return {Number} rotation
4764 */
4765
4766
4767 function getRotation(start, end) {
4768 return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
4769 }
4770 /**
4771 * @private
4772 * velocity is calculated every x ms
4773 * @param {Object} session
4774 * @param {Object} input
4775 */
4776
4777
4778 function computeIntervalInputData(session, input) {
4779 var last = session.lastInterval || input;
4780 var deltaTime = input.timeStamp - last.timeStamp;
4781 var velocity;
4782 var velocityX;
4783 var velocityY;
4784 var direction;
4785
4786 if (input.eventType !== INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
4787 var deltaX = input.deltaX - last.deltaX;
4788 var deltaY = input.deltaY - last.deltaY;
4789 var v = getVelocity(deltaTime, deltaX, deltaY);
4790 velocityX = v.x;
4791 velocityY = v.y;
4792 velocity = abs$1(v.x) > abs$1(v.y) ? v.x : v.y;
4793 direction = getDirection(deltaX, deltaY);
4794 session.lastInterval = input;
4795 } else {
4796 // use latest velocity info if it doesn't overtake a minimum period
4797 velocity = last.velocity;
4798 velocityX = last.velocityX;
4799 velocityY = last.velocityY;
4800 direction = last.direction;
4801 }
4802
4803 input.velocity = velocity;
4804 input.velocityX = velocityX;
4805 input.velocityY = velocityY;
4806 input.direction = direction;
4807 }
4808 /**
4809 * @private
4810 * extend the data with some usable properties like scale, rotate, velocity etc
4811 * @param {Object} manager
4812 * @param {Object} input
4813 */
4814
4815
4816 function computeInputData(manager, input) {
4817 var session = manager.session;
4818 var pointers = input.pointers;
4819 var pointersLength = pointers.length; // store the first input to calculate the distance and direction
4820
4821 if (!session.firstInput) {
4822 session.firstInput = simpleCloneInputData(input);
4823 } // to compute scale and rotation we need to store the multiple touches
4824
4825
4826 if (pointersLength > 1 && !session.firstMultiple) {
4827 session.firstMultiple = simpleCloneInputData(input);
4828 } else if (pointersLength === 1) {
4829 session.firstMultiple = false;
4830 }
4831
4832 var firstInput = session.firstInput,
4833 firstMultiple = session.firstMultiple;
4834 var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
4835 var center = input.center = getCenter(pointers);
4836 input.timeStamp = now();
4837 input.deltaTime = input.timeStamp - firstInput.timeStamp;
4838 input.angle = getAngle(offsetCenter, center);
4839 input.distance = getDistance(offsetCenter, center);
4840 computeDeltaXY(session, input);
4841 input.offsetDirection = getDirection(input.deltaX, input.deltaY);
4842 var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
4843 input.overallVelocityX = overallVelocity.x;
4844 input.overallVelocityY = overallVelocity.y;
4845 input.overallVelocity = abs$1(overallVelocity.x) > abs$1(overallVelocity.y) ? overallVelocity.x : overallVelocity.y;
4846 input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
4847 input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
4848 input.maxPointers = !session.prevInput ? input.pointers.length : input.pointers.length > session.prevInput.maxPointers ? input.pointers.length : session.prevInput.maxPointers;
4849 computeIntervalInputData(session, input); // find the correct target
4850
4851 var target = manager.element;
4852 var srcEvent = input.srcEvent;
4853 var srcEventTarget;
4854
4855 if (srcEvent.composedPath) {
4856 srcEventTarget = srcEvent.composedPath()[0];
4857 } else if (srcEvent.path) {
4858 srcEventTarget = srcEvent.path[0];
4859 } else {
4860 srcEventTarget = srcEvent.target;
4861 }
4862
4863 if (hasParent(srcEventTarget, target)) {
4864 target = srcEventTarget;
4865 }
4866
4867 input.target = target;
4868 }
4869 /**
4870 * @private
4871 * handle input events
4872 * @param {Manager} manager
4873 * @param {String} eventType
4874 * @param {Object} input
4875 */
4876
4877
4878 function inputHandler(manager, eventType, input) {
4879 var pointersLen = input.pointers.length;
4880 var changedPointersLen = input.changedPointers.length;
4881 var isFirst = eventType & INPUT_START && pointersLen - changedPointersLen === 0;
4882 var isFinal = eventType & (INPUT_END | INPUT_CANCEL) && pointersLen - changedPointersLen === 0;
4883 input.isFirst = !!isFirst;
4884 input.isFinal = !!isFinal;
4885
4886 if (isFirst) {
4887 manager.session = {};
4888 } // source event is the normalized value of the domEvents
4889 // like 'touchstart, mouseup, pointerdown'
4890
4891
4892 input.eventType = eventType; // compute scale, rotation etc
4893
4894 computeInputData(manager, input); // emit secret event
4895
4896 manager.emit('hammer.input', input);
4897 manager.recognize(input);
4898 manager.session.prevInput = input;
4899 }
4900 /**
4901 * @private
4902 * split string on whitespace
4903 * @param {String} str
4904 * @returns {Array} words
4905 */
4906
4907
4908 function splitStr(str) {
4909 return str.trim().split(/\s+/g);
4910 }
4911 /**
4912 * @private
4913 * addEventListener with multiple events at once
4914 * @param {EventTarget} target
4915 * @param {String} types
4916 * @param {Function} handler
4917 */
4918
4919
4920 function addEventListeners(target, types, handler) {
4921 each(splitStr(types), function (type) {
4922 target.addEventListener(type, handler, false);
4923 });
4924 }
4925 /**
4926 * @private
4927 * removeEventListener with multiple events at once
4928 * @param {EventTarget} target
4929 * @param {String} types
4930 * @param {Function} handler
4931 */
4932
4933
4934 function removeEventListeners(target, types, handler) {
4935 each(splitStr(types), function (type) {
4936 target.removeEventListener(type, handler, false);
4937 });
4938 }
4939 /**
4940 * @private
4941 * get the window object of an element
4942 * @param {HTMLElement} element
4943 * @returns {DocumentView|Window}
4944 */
4945
4946
4947 function getWindowForElement(element) {
4948 var doc = element.ownerDocument || element;
4949 return doc.defaultView || doc.parentWindow || window;
4950 }
4951 /**
4952 * @private
4953 * create new input type manager
4954 * @param {Manager} manager
4955 * @param {Function} callback
4956 * @returns {Input}
4957 * @constructor
4958 */
4959
4960
4961 var Input = /*#__PURE__*/function () {
4962 function Input(manager, callback) {
4963 var self = this;
4964 this.manager = manager;
4965 this.callback = callback;
4966 this.element = manager.element;
4967 this.target = manager.options.inputTarget; // smaller wrapper around the handler, for the scope and the enabled state of the manager,
4968 // so when disabled the input events are completely bypassed.
4969
4970 this.domHandler = function (ev) {
4971 if (boolOrFn(manager.options.enable, [manager])) {
4972 self.handler(ev);
4973 }
4974 };
4975
4976 this.init();
4977 }
4978 /**
4979 * @private
4980 * should handle the inputEvent data and trigger the callback
4981 * @virtual
4982 */
4983
4984
4985 var _proto = Input.prototype;
4986
4987 _proto.handler = function handler() {};
4988 /**
4989 * @private
4990 * bind the events
4991 */
4992
4993
4994 _proto.init = function init() {
4995 this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
4996 this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
4997 this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
4998 };
4999 /**
5000 * @private
5001 * unbind the events
5002 */
5003
5004
5005 _proto.destroy = function destroy() {
5006 this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
5007 this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
5008 this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
5009 };
5010
5011 return Input;
5012 }();
5013 /**
5014 * @private
5015 * find if a array contains the object using indexOf or a simple polyFill
5016 * @param {Array} src
5017 * @param {String} find
5018 * @param {String} [findByKey]
5019 * @return {Boolean|Number} false when not found, or the index
5020 */
5021
5022
5023 function inArray(src, find, findByKey) {
5024 if (src.indexOf && !findByKey) {
5025 return src.indexOf(find);
5026 } else {
5027 var i = 0;
5028
5029 while (i < src.length) {
5030 if (findByKey && src[i][findByKey] == find || !findByKey && src[i] === find) {
5031 // do not use === here, test fails
5032 return i;
5033 }
5034
5035 i++;
5036 }
5037
5038 return -1;
5039 }
5040 }
5041
5042 var POINTER_INPUT_MAP = {
5043 pointerdown: INPUT_START,
5044 pointermove: INPUT_MOVE,
5045 pointerup: INPUT_END,
5046 pointercancel: INPUT_CANCEL,
5047 pointerout: INPUT_CANCEL
5048 }; // in IE10 the pointer types is defined as an enum
5049
5050 var IE10_POINTER_TYPE_ENUM = {
5051 2: INPUT_TYPE_TOUCH,
5052 3: INPUT_TYPE_PEN,
5053 4: INPUT_TYPE_MOUSE,
5054 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
5055
5056 };
5057 var POINTER_ELEMENT_EVENTS = 'pointerdown';
5058 var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; // IE10 has prefixed support, and case-sensitive
5059
5060 if (win.MSPointerEvent && !win.PointerEvent) {
5061 POINTER_ELEMENT_EVENTS = 'MSPointerDown';
5062 POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
5063 }
5064 /**
5065 * @private
5066 * Pointer events input
5067 * @constructor
5068 * @extends Input
5069 */
5070
5071
5072 var PointerEventInput = /*#__PURE__*/function (_Input) {
5073 _inheritsLoose(PointerEventInput, _Input);
5074
5075 function PointerEventInput() {
5076 var _this;
5077
5078 var proto = PointerEventInput.prototype;
5079 proto.evEl = POINTER_ELEMENT_EVENTS;
5080 proto.evWin = POINTER_WINDOW_EVENTS;
5081 _this = _Input.apply(this, arguments) || this;
5082 _this.store = _this.manager.session.pointerEvents = [];
5083 return _this;
5084 }
5085 /**
5086 * @private
5087 * handle mouse events
5088 * @param {Object} ev
5089 */
5090
5091
5092 var _proto = PointerEventInput.prototype;
5093
5094 _proto.handler = function handler(ev) {
5095 var store = this.store;
5096 var removePointer = false;
5097 var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
5098 var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
5099 var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
5100 var isTouch = pointerType === INPUT_TYPE_TOUCH; // get index of the event in the store
5101
5102 var storeIndex = inArray(store, ev.pointerId, 'pointerId'); // start and mouse must be down
5103
5104 if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
5105 if (storeIndex < 0) {
5106 store.push(ev);
5107 storeIndex = store.length - 1;
5108 }
5109 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
5110 removePointer = true;
5111 } // it not found, so the pointer hasn't been down (so it's probably a hover)
5112
5113
5114 if (storeIndex < 0) {
5115 return;
5116 } // update the event in the store
5117
5118
5119 store[storeIndex] = ev;
5120 this.callback(this.manager, eventType, {
5121 pointers: store,
5122 changedPointers: [ev],
5123 pointerType: pointerType,
5124 srcEvent: ev
5125 });
5126
5127 if (removePointer) {
5128 // remove from the store
5129 store.splice(storeIndex, 1);
5130 }
5131 };
5132
5133 return PointerEventInput;
5134 }(Input);
5135 /**
5136 * @private
5137 * convert array-like objects to real arrays
5138 * @param {Object} obj
5139 * @returns {Array}
5140 */
5141
5142
5143 function toArray(obj) {
5144 return Array.prototype.slice.call(obj, 0);
5145 }
5146 /**
5147 * @private
5148 * unique array with objects based on a key (like 'id') or just by the array's value
5149 * @param {Array} src [{id:1},{id:2},{id:1}]
5150 * @param {String} [key]
5151 * @param {Boolean} [sort=False]
5152 * @returns {Array} [{id:1},{id:2}]
5153 */
5154
5155
5156 function uniqueArray(src, key, sort) {
5157 var results = [];
5158 var values = [];
5159 var i = 0;
5160
5161 while (i < src.length) {
5162 var val = key ? src[i][key] : src[i];
5163
5164 if (inArray(values, val) < 0) {
5165 results.push(src[i]);
5166 }
5167
5168 values[i] = val;
5169 i++;
5170 }
5171
5172 if (sort) {
5173 if (!key) {
5174 results = results.sort();
5175 } else {
5176 results = results.sort(function (a, b) {
5177 return a[key] > b[key];
5178 });
5179 }
5180 }
5181
5182 return results;
5183 }
5184
5185 var TOUCH_INPUT_MAP = {
5186 touchstart: INPUT_START,
5187 touchmove: INPUT_MOVE,
5188 touchend: INPUT_END,
5189 touchcancel: INPUT_CANCEL
5190 };
5191 var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
5192 /**
5193 * @private
5194 * Multi-user touch events input
5195 * @constructor
5196 * @extends Input
5197 */
5198
5199 var TouchInput = /*#__PURE__*/function (_Input) {
5200 _inheritsLoose(TouchInput, _Input);
5201
5202 function TouchInput() {
5203 var _this;
5204
5205 TouchInput.prototype.evTarget = TOUCH_TARGET_EVENTS;
5206 _this = _Input.apply(this, arguments) || this;
5207 _this.targetIds = {}; // this.evTarget = TOUCH_TARGET_EVENTS;
5208
5209 return _this;
5210 }
5211
5212 var _proto = TouchInput.prototype;
5213
5214 _proto.handler = function handler(ev) {
5215 var type = TOUCH_INPUT_MAP[ev.type];
5216 var touches = getTouches.call(this, ev, type);
5217
5218 if (!touches) {
5219 return;
5220 }
5221
5222 this.callback(this.manager, type, {
5223 pointers: touches[0],
5224 changedPointers: touches[1],
5225 pointerType: INPUT_TYPE_TOUCH,
5226 srcEvent: ev
5227 });
5228 };
5229
5230 return TouchInput;
5231 }(Input);
5232
5233 function getTouches(ev, type) {
5234 var allTouches = toArray(ev.touches);
5235 var targetIds = this.targetIds; // when there is only one touch, the process can be simplified
5236
5237 if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
5238 targetIds[allTouches[0].identifier] = true;
5239 return [allTouches, allTouches];
5240 }
5241
5242 var i;
5243 var targetTouches;
5244 var changedTouches = toArray(ev.changedTouches);
5245 var changedTargetTouches = [];
5246 var target = this.target; // get target touches from touches
5247
5248 targetTouches = allTouches.filter(function (touch) {
5249 return hasParent(touch.target, target);
5250 }); // collect touches
5251
5252 if (type === INPUT_START) {
5253 i = 0;
5254
5255 while (i < targetTouches.length) {
5256 targetIds[targetTouches[i].identifier] = true;
5257 i++;
5258 }
5259 } // filter changed touches to only contain touches that exist in the collected target ids
5260
5261
5262 i = 0;
5263
5264 while (i < changedTouches.length) {
5265 if (targetIds[changedTouches[i].identifier]) {
5266 changedTargetTouches.push(changedTouches[i]);
5267 } // cleanup removed touches
5268
5269
5270 if (type & (INPUT_END | INPUT_CANCEL)) {
5271 delete targetIds[changedTouches[i].identifier];
5272 }
5273
5274 i++;
5275 }
5276
5277 if (!changedTargetTouches.length) {
5278 return;
5279 }
5280
5281 return [// merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
5282 uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), changedTargetTouches];
5283 }
5284
5285 var MOUSE_INPUT_MAP = {
5286 mousedown: INPUT_START,
5287 mousemove: INPUT_MOVE,
5288 mouseup: INPUT_END
5289 };
5290 var MOUSE_ELEMENT_EVENTS = 'mousedown';
5291 var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
5292 /**
5293 * @private
5294 * Mouse events input
5295 * @constructor
5296 * @extends Input
5297 */
5298
5299 var MouseInput = /*#__PURE__*/function (_Input) {
5300 _inheritsLoose(MouseInput, _Input);
5301
5302 function MouseInput() {
5303 var _this;
5304
5305 var proto = MouseInput.prototype;
5306 proto.evEl = MOUSE_ELEMENT_EVENTS;
5307 proto.evWin = MOUSE_WINDOW_EVENTS;
5308 _this = _Input.apply(this, arguments) || this;
5309 _this.pressed = false; // mousedown state
5310
5311 return _this;
5312 }
5313 /**
5314 * @private
5315 * handle mouse events
5316 * @param {Object} ev
5317 */
5318
5319
5320 var _proto = MouseInput.prototype;
5321
5322 _proto.handler = function handler(ev) {
5323 var eventType = MOUSE_INPUT_MAP[ev.type]; // on start we want to have the left mouse button down
5324
5325 if (eventType & INPUT_START && ev.button === 0) {
5326 this.pressed = true;
5327 }
5328
5329 if (eventType & INPUT_MOVE && ev.which !== 1) {
5330 eventType = INPUT_END;
5331 } // mouse must be down
5332
5333
5334 if (!this.pressed) {
5335 return;
5336 }
5337
5338 if (eventType & INPUT_END) {
5339 this.pressed = false;
5340 }
5341
5342 this.callback(this.manager, eventType, {
5343 pointers: [ev],
5344 changedPointers: [ev],
5345 pointerType: INPUT_TYPE_MOUSE,
5346 srcEvent: ev
5347 });
5348 };
5349
5350 return MouseInput;
5351 }(Input);
5352 /**
5353 * @private
5354 * Combined touch and mouse input
5355 *
5356 * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
5357 * This because touch devices also emit mouse events while doing a touch.
5358 *
5359 * @constructor
5360 * @extends Input
5361 */
5362
5363
5364 var DEDUP_TIMEOUT = 2500;
5365 var DEDUP_DISTANCE = 25;
5366
5367 function setLastTouch(eventData) {
5368 var _eventData$changedPoi = eventData.changedPointers,
5369 touch = _eventData$changedPoi[0];
5370
5371 if (touch.identifier === this.primaryTouch) {
5372 var lastTouch = {
5373 x: touch.clientX,
5374 y: touch.clientY
5375 };
5376 var lts = this.lastTouches;
5377 this.lastTouches.push(lastTouch);
5378
5379 var removeLastTouch = function removeLastTouch() {
5380 var i = lts.indexOf(lastTouch);
5381
5382 if (i > -1) {
5383 lts.splice(i, 1);
5384 }
5385 };
5386
5387 setTimeout(removeLastTouch, DEDUP_TIMEOUT);
5388 }
5389 }
5390
5391 function recordTouches(eventType, eventData) {
5392 if (eventType & INPUT_START) {
5393 this.primaryTouch = eventData.changedPointers[0].identifier;
5394 setLastTouch.call(this, eventData);
5395 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
5396 setLastTouch.call(this, eventData);
5397 }
5398 }
5399
5400 function isSyntheticEvent(eventData) {
5401 var x = eventData.srcEvent.clientX;
5402 var y = eventData.srcEvent.clientY;
5403
5404 for (var i = 0; i < this.lastTouches.length; i++) {
5405 var t = this.lastTouches[i];
5406 var dx = Math.abs(x - t.x);
5407 var dy = Math.abs(y - t.y);
5408
5409 if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
5410 return true;
5411 }
5412 }
5413
5414 return false;
5415 }
5416
5417 var TouchMouseInput = /*#__PURE__*/function () {
5418 var TouchMouseInput = /*#__PURE__*/function (_Input) {
5419 _inheritsLoose(TouchMouseInput, _Input);
5420
5421 function TouchMouseInput(_manager, callback) {
5422 var _this;
5423
5424 _this = _Input.call(this, _manager, callback) || this;
5425
5426 _this.handler = function (manager, inputEvent, inputData) {
5427 var isTouch = inputData.pointerType === INPUT_TYPE_TOUCH;
5428 var isMouse = inputData.pointerType === INPUT_TYPE_MOUSE;
5429
5430 if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
5431 return;
5432 } // when we're in a touch event, record touches to de-dupe synthetic mouse event
5433
5434
5435 if (isTouch) {
5436 recordTouches.call(_assertThisInitialized$1(_assertThisInitialized$1(_this)), inputEvent, inputData);
5437 } else if (isMouse && isSyntheticEvent.call(_assertThisInitialized$1(_assertThisInitialized$1(_this)), inputData)) {
5438 return;
5439 }
5440
5441 _this.callback(manager, inputEvent, inputData);
5442 };
5443
5444 _this.touch = new TouchInput(_this.manager, _this.handler);
5445 _this.mouse = new MouseInput(_this.manager, _this.handler);
5446 _this.primaryTouch = null;
5447 _this.lastTouches = [];
5448 return _this;
5449 }
5450 /**
5451 * @private
5452 * handle mouse and touch events
5453 * @param {Hammer} manager
5454 * @param {String} inputEvent
5455 * @param {Object} inputData
5456 */
5457
5458
5459 var _proto = TouchMouseInput.prototype;
5460 /**
5461 * @private
5462 * remove the event listeners
5463 */
5464
5465 _proto.destroy = function destroy() {
5466 this.touch.destroy();
5467 this.mouse.destroy();
5468 };
5469
5470 return TouchMouseInput;
5471 }(Input);
5472
5473 return TouchMouseInput;
5474 }();
5475 /**
5476 * @private
5477 * create new input type manager
5478 * called by the Manager constructor
5479 * @param {Hammer} manager
5480 * @returns {Input}
5481 */
5482
5483
5484 function createInputInstance(manager) {
5485 var Type; // let inputClass = manager.options.inputClass;
5486
5487 var inputClass = manager.options.inputClass;
5488
5489 if (inputClass) {
5490 Type = inputClass;
5491 } else if (SUPPORT_POINTER_EVENTS) {
5492 Type = PointerEventInput;
5493 } else if (SUPPORT_ONLY_TOUCH) {
5494 Type = TouchInput;
5495 } else if (!SUPPORT_TOUCH) {
5496 Type = MouseInput;
5497 } else {
5498 Type = TouchMouseInput;
5499 }
5500
5501 return new Type(manager, inputHandler);
5502 }
5503 /**
5504 * @private
5505 * if the argument is an array, we want to execute the fn on each entry
5506 * if it aint an array we don't want to do a thing.
5507 * this is used by all the methods that accept a single and array argument.
5508 * @param {*|Array} arg
5509 * @param {String} fn
5510 * @param {Object} [context]
5511 * @returns {Boolean}
5512 */
5513
5514
5515 function invokeArrayArg(arg, fn, context) {
5516 if (Array.isArray(arg)) {
5517 each(arg, context[fn], context);
5518 return true;
5519 }
5520
5521 return false;
5522 }
5523
5524 var STATE_POSSIBLE = 1;
5525 var STATE_BEGAN = 2;
5526 var STATE_CHANGED = 4;
5527 var STATE_ENDED = 8;
5528 var STATE_RECOGNIZED = STATE_ENDED;
5529 var STATE_CANCELLED = 16;
5530 var STATE_FAILED = 32;
5531 /**
5532 * @private
5533 * get a unique id
5534 * @returns {number} uniqueId
5535 */
5536
5537 var _uniqueId = 1;
5538
5539 function uniqueId() {
5540 return _uniqueId++;
5541 }
5542 /**
5543 * @private
5544 * get a recognizer by name if it is bound to a manager
5545 * @param {Recognizer|String} otherRecognizer
5546 * @param {Recognizer} recognizer
5547 * @returns {Recognizer}
5548 */
5549
5550
5551 function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
5552 var manager = recognizer.manager;
5553
5554 if (manager) {
5555 return manager.get(otherRecognizer);
5556 }
5557
5558 return otherRecognizer;
5559 }
5560 /**
5561 * @private
5562 * get a usable string, used as event postfix
5563 * @param {constant} state
5564 * @returns {String} state
5565 */
5566
5567
5568 function stateStr(state) {
5569 if (state & STATE_CANCELLED) {
5570 return 'cancel';
5571 } else if (state & STATE_ENDED) {
5572 return 'end';
5573 } else if (state & STATE_CHANGED) {
5574 return 'move';
5575 } else if (state & STATE_BEGAN) {
5576 return 'start';
5577 }
5578
5579 return '';
5580 }
5581 /**
5582 * @private
5583 * Recognizer flow explained; *
5584 * All recognizers have the initial state of POSSIBLE when a input session starts.
5585 * The definition of a input session is from the first input until the last input, with all it's movement in it. *
5586 * Example session for mouse-input: mousedown -> mousemove -> mouseup
5587 *
5588 * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
5589 * which determines with state it should be.
5590 *
5591 * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
5592 * POSSIBLE to give it another change on the next cycle.
5593 *
5594 * Possible
5595 * |
5596 * +-----+---------------+
5597 * | |
5598 * +-----+-----+ |
5599 * | | |
5600 * Failed Cancelled |
5601 * +-------+------+
5602 * | |
5603 * Recognized Began
5604 * |
5605 * Changed
5606 * |
5607 * Ended/Recognized
5608 */
5609
5610 /**
5611 * @private
5612 * Recognizer
5613 * Every recognizer needs to extend from this class.
5614 * @constructor
5615 * @param {Object} options
5616 */
5617
5618
5619 var Recognizer = /*#__PURE__*/function () {
5620 function Recognizer(options) {
5621 if (options === void 0) {
5622 options = {};
5623 }
5624
5625 this.options = _extends({
5626 enable: true
5627 }, options);
5628 this.id = uniqueId();
5629 this.manager = null; // default is enable true
5630
5631 this.state = STATE_POSSIBLE;
5632 this.simultaneous = {};
5633 this.requireFail = [];
5634 }
5635 /**
5636 * @private
5637 * set options
5638 * @param {Object} options
5639 * @return {Recognizer}
5640 */
5641
5642
5643 var _proto = Recognizer.prototype;
5644
5645 _proto.set = function set(options) {
5646 assign$1(this.options, options); // also update the touchAction, in case something changed about the directions/enabled state
5647
5648 this.manager && this.manager.touchAction.update();
5649 return this;
5650 };
5651 /**
5652 * @private
5653 * recognize simultaneous with an other recognizer.
5654 * @param {Recognizer} otherRecognizer
5655 * @returns {Recognizer} this
5656 */
5657
5658
5659 _proto.recognizeWith = function recognizeWith(otherRecognizer) {
5660 if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
5661 return this;
5662 }
5663
5664 var simultaneous = this.simultaneous;
5665 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
5666
5667 if (!simultaneous[otherRecognizer.id]) {
5668 simultaneous[otherRecognizer.id] = otherRecognizer;
5669 otherRecognizer.recognizeWith(this);
5670 }
5671
5672 return this;
5673 };
5674 /**
5675 * @private
5676 * drop the simultaneous link. it doesnt remove the link on the other recognizer.
5677 * @param {Recognizer} otherRecognizer
5678 * @returns {Recognizer} this
5679 */
5680
5681
5682 _proto.dropRecognizeWith = function dropRecognizeWith(otherRecognizer) {
5683 if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
5684 return this;
5685 }
5686
5687 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
5688 delete this.simultaneous[otherRecognizer.id];
5689 return this;
5690 };
5691 /**
5692 * @private
5693 * recognizer can only run when an other is failing
5694 * @param {Recognizer} otherRecognizer
5695 * @returns {Recognizer} this
5696 */
5697
5698
5699 _proto.requireFailure = function requireFailure(otherRecognizer) {
5700 if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
5701 return this;
5702 }
5703
5704 var requireFail = this.requireFail;
5705 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
5706
5707 if (inArray(requireFail, otherRecognizer) === -1) {
5708 requireFail.push(otherRecognizer);
5709 otherRecognizer.requireFailure(this);
5710 }
5711
5712 return this;
5713 };
5714 /**
5715 * @private
5716 * drop the requireFailure link. it does not remove the link on the other recognizer.
5717 * @param {Recognizer} otherRecognizer
5718 * @returns {Recognizer} this
5719 */
5720
5721
5722 _proto.dropRequireFailure = function dropRequireFailure(otherRecognizer) {
5723 if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
5724 return this;
5725 }
5726
5727 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
5728 var index = inArray(this.requireFail, otherRecognizer);
5729
5730 if (index > -1) {
5731 this.requireFail.splice(index, 1);
5732 }
5733
5734 return this;
5735 };
5736 /**
5737 * @private
5738 * has require failures boolean
5739 * @returns {boolean}
5740 */
5741
5742
5743 _proto.hasRequireFailures = function hasRequireFailures() {
5744 return this.requireFail.length > 0;
5745 };
5746 /**
5747 * @private
5748 * if the recognizer can recognize simultaneous with an other recognizer
5749 * @param {Recognizer} otherRecognizer
5750 * @returns {Boolean}
5751 */
5752
5753
5754 _proto.canRecognizeWith = function canRecognizeWith(otherRecognizer) {
5755 return !!this.simultaneous[otherRecognizer.id];
5756 };
5757 /**
5758 * @private
5759 * You should use `tryEmit` instead of `emit` directly to check
5760 * that all the needed recognizers has failed before emitting.
5761 * @param {Object} input
5762 */
5763
5764
5765 _proto.emit = function emit(input) {
5766 var self = this;
5767 var state = this.state;
5768
5769 function emit(event) {
5770 self.manager.emit(event, input);
5771 } // 'panstart' and 'panmove'
5772
5773
5774 if (state < STATE_ENDED) {
5775 emit(self.options.event + stateStr(state));
5776 }
5777
5778 emit(self.options.event); // simple 'eventName' events
5779
5780 if (input.additionalEvent) {
5781 // additional event(panleft, panright, pinchin, pinchout...)
5782 emit(input.additionalEvent);
5783 } // panend and pancancel
5784
5785
5786 if (state >= STATE_ENDED) {
5787 emit(self.options.event + stateStr(state));
5788 }
5789 };
5790 /**
5791 * @private
5792 * Check that all the require failure recognizers has failed,
5793 * if true, it emits a gesture event,
5794 * otherwise, setup the state to FAILED.
5795 * @param {Object} input
5796 */
5797
5798
5799 _proto.tryEmit = function tryEmit(input) {
5800 if (this.canEmit()) {
5801 return this.emit(input);
5802 } // it's failing anyway
5803
5804
5805 this.state = STATE_FAILED;
5806 };
5807 /**
5808 * @private
5809 * can we emit?
5810 * @returns {boolean}
5811 */
5812
5813
5814 _proto.canEmit = function canEmit() {
5815 var i = 0;
5816
5817 while (i < this.requireFail.length) {
5818 if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
5819 return false;
5820 }
5821
5822 i++;
5823 }
5824
5825 return true;
5826 };
5827 /**
5828 * @private
5829 * update the recognizer
5830 * @param {Object} inputData
5831 */
5832
5833
5834 _proto.recognize = function recognize(inputData) {
5835 // make a new copy of the inputData
5836 // so we can change the inputData without messing up the other recognizers
5837 var inputDataClone = assign$1({}, inputData); // is is enabled and allow recognizing?
5838
5839 if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
5840 this.reset();
5841 this.state = STATE_FAILED;
5842 return;
5843 } // reset when we've reached the end
5844
5845
5846 if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
5847 this.state = STATE_POSSIBLE;
5848 }
5849
5850 this.state = this.process(inputDataClone); // the recognizer has recognized a gesture
5851 // so trigger an event
5852
5853 if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
5854 this.tryEmit(inputDataClone);
5855 }
5856 };
5857 /**
5858 * @private
5859 * return the state of the recognizer
5860 * the actual recognizing happens in this method
5861 * @virtual
5862 * @param {Object} inputData
5863 * @returns {constant} STATE
5864 */
5865
5866 /* jshint ignore:start */
5867
5868
5869 _proto.process = function process(inputData) {};
5870 /* jshint ignore:end */
5871
5872 /**
5873 * @private
5874 * return the preferred touch-action
5875 * @virtual
5876 * @returns {Array}
5877 */
5878
5879
5880 _proto.getTouchAction = function getTouchAction() {};
5881 /**
5882 * @private
5883 * called when the gesture isn't allowed to recognize
5884 * like when another is being recognized or it is disabled
5885 * @virtual
5886 */
5887
5888
5889 _proto.reset = function reset() {};
5890
5891 return Recognizer;
5892 }();
5893 /**
5894 * @private
5895 * A tap is recognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
5896 * between the given interval and position. The delay option can be used to recognize multi-taps without firing
5897 * a single tap.
5898 *
5899 * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
5900 * multi-taps being recognized.
5901 * @constructor
5902 * @extends Recognizer
5903 */
5904
5905
5906 var TapRecognizer = /*#__PURE__*/function (_Recognizer) {
5907 _inheritsLoose(TapRecognizer, _Recognizer);
5908
5909 function TapRecognizer(options) {
5910 var _this;
5911
5912 if (options === void 0) {
5913 options = {};
5914 }
5915
5916 _this = _Recognizer.call(this, _extends({
5917 event: 'tap',
5918 pointers: 1,
5919 taps: 1,
5920 interval: 300,
5921 // max time between the multi-tap taps
5922 time: 250,
5923 // max time of the pointer to be down (like finger on the screen)
5924 threshold: 9,
5925 // a minimal movement is ok, but keep it low
5926 posThreshold: 10
5927 }, options)) || this; // previous time and center,
5928 // used for tap counting
5929
5930 _this.pTime = false;
5931 _this.pCenter = false;
5932 _this._timer = null;
5933 _this._input = null;
5934 _this.count = 0;
5935 return _this;
5936 }
5937
5938 var _proto = TapRecognizer.prototype;
5939
5940 _proto.getTouchAction = function getTouchAction() {
5941 return [TOUCH_ACTION_MANIPULATION];
5942 };
5943
5944 _proto.process = function process(input) {
5945 var _this2 = this;
5946
5947 var options = this.options;
5948 var validPointers = input.pointers.length === options.pointers;
5949 var validMovement = input.distance < options.threshold;
5950 var validTouchTime = input.deltaTime < options.time;
5951 this.reset();
5952
5953 if (input.eventType & INPUT_START && this.count === 0) {
5954 return this.failTimeout();
5955 } // we only allow little movement
5956 // and we've reached an end event, so a tap is possible
5957
5958
5959 if (validMovement && validTouchTime && validPointers) {
5960 if (input.eventType !== INPUT_END) {
5961 return this.failTimeout();
5962 }
5963
5964 var validInterval = this.pTime ? input.timeStamp - this.pTime < options.interval : true;
5965 var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
5966 this.pTime = input.timeStamp;
5967 this.pCenter = input.center;
5968
5969 if (!validMultiTap || !validInterval) {
5970 this.count = 1;
5971 } else {
5972 this.count += 1;
5973 }
5974
5975 this._input = input; // if tap count matches we have recognized it,
5976 // else it has began recognizing...
5977
5978 var tapCount = this.count % options.taps;
5979
5980 if (tapCount === 0) {
5981 // no failing requirements, immediately trigger the tap event
5982 // or wait as long as the multitap interval to trigger
5983 if (!this.hasRequireFailures()) {
5984 return STATE_RECOGNIZED;
5985 } else {
5986 this._timer = setTimeout(function () {
5987 _this2.state = STATE_RECOGNIZED;
5988
5989 _this2.tryEmit();
5990 }, options.interval);
5991 return STATE_BEGAN;
5992 }
5993 }
5994 }
5995
5996 return STATE_FAILED;
5997 };
5998
5999 _proto.failTimeout = function failTimeout() {
6000 var _this3 = this;
6001
6002 this._timer = setTimeout(function () {
6003 _this3.state = STATE_FAILED;
6004 }, this.options.interval);
6005 return STATE_FAILED;
6006 };
6007
6008 _proto.reset = function reset() {
6009 clearTimeout(this._timer);
6010 };
6011
6012 _proto.emit = function emit() {
6013 if (this.state === STATE_RECOGNIZED) {
6014 this._input.tapCount = this.count;
6015 this.manager.emit(this.options.event, this._input);
6016 }
6017 };
6018
6019 return TapRecognizer;
6020 }(Recognizer);
6021 /**
6022 * @private
6023 * This recognizer is just used as a base for the simple attribute recognizers.
6024 * @constructor
6025 * @extends Recognizer
6026 */
6027
6028
6029 var AttrRecognizer = /*#__PURE__*/function (_Recognizer) {
6030 _inheritsLoose(AttrRecognizer, _Recognizer);
6031
6032 function AttrRecognizer(options) {
6033 if (options === void 0) {
6034 options = {};
6035 }
6036
6037 return _Recognizer.call(this, _extends({
6038 pointers: 1
6039 }, options)) || this;
6040 }
6041 /**
6042 * @private
6043 * Used to check if it the recognizer receives valid input, like input.distance > 10.
6044 * @memberof AttrRecognizer
6045 * @param {Object} input
6046 * @returns {Boolean} recognized
6047 */
6048
6049
6050 var _proto = AttrRecognizer.prototype;
6051
6052 _proto.attrTest = function attrTest(input) {
6053 var optionPointers = this.options.pointers;
6054 return optionPointers === 0 || input.pointers.length === optionPointers;
6055 };
6056 /**
6057 * @private
6058 * Process the input and return the state for the recognizer
6059 * @memberof AttrRecognizer
6060 * @param {Object} input
6061 * @returns {*} State
6062 */
6063
6064
6065 _proto.process = function process(input) {
6066 var state = this.state;
6067 var eventType = input.eventType;
6068 var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
6069 var isValid = this.attrTest(input); // on cancel input and we've recognized before, return STATE_CANCELLED
6070
6071 if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
6072 return state | STATE_CANCELLED;
6073 } else if (isRecognized || isValid) {
6074 if (eventType & INPUT_END) {
6075 return state | STATE_ENDED;
6076 } else if (!(state & STATE_BEGAN)) {
6077 return STATE_BEGAN;
6078 }
6079
6080 return state | STATE_CHANGED;
6081 }
6082
6083 return STATE_FAILED;
6084 };
6085
6086 return AttrRecognizer;
6087 }(Recognizer);
6088 /**
6089 * @private
6090 * direction cons to string
6091 * @param {constant} direction
6092 * @returns {String}
6093 */
6094
6095
6096 function directionStr(direction) {
6097 if (direction === DIRECTION_DOWN) {
6098 return 'down';
6099 } else if (direction === DIRECTION_UP) {
6100 return 'up';
6101 } else if (direction === DIRECTION_LEFT) {
6102 return 'left';
6103 } else if (direction === DIRECTION_RIGHT) {
6104 return 'right';
6105 }
6106
6107 return '';
6108 }
6109 /**
6110 * @private
6111 * Pan
6112 * Recognized when the pointer is down and moved in the allowed direction.
6113 * @constructor
6114 * @extends AttrRecognizer
6115 */
6116
6117
6118 var PanRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
6119 _inheritsLoose(PanRecognizer, _AttrRecognizer);
6120
6121 function PanRecognizer(options) {
6122 var _this;
6123
6124 if (options === void 0) {
6125 options = {};
6126 }
6127
6128 _this = _AttrRecognizer.call(this, _extends({
6129 event: 'pan',
6130 threshold: 10,
6131 pointers: 1,
6132 direction: DIRECTION_ALL
6133 }, options)) || this;
6134 _this.pX = null;
6135 _this.pY = null;
6136 return _this;
6137 }
6138
6139 var _proto = PanRecognizer.prototype;
6140
6141 _proto.getTouchAction = function getTouchAction() {
6142 var direction = this.options.direction;
6143 var actions = [];
6144
6145 if (direction & DIRECTION_HORIZONTAL) {
6146 actions.push(TOUCH_ACTION_PAN_Y);
6147 }
6148
6149 if (direction & DIRECTION_VERTICAL) {
6150 actions.push(TOUCH_ACTION_PAN_X);
6151 }
6152
6153 return actions;
6154 };
6155
6156 _proto.directionTest = function directionTest(input) {
6157 var options = this.options;
6158 var hasMoved = true;
6159 var distance = input.distance;
6160 var direction = input.direction;
6161 var x = input.deltaX;
6162 var y = input.deltaY; // lock to axis?
6163
6164 if (!(direction & options.direction)) {
6165 if (options.direction & DIRECTION_HORIZONTAL) {
6166 direction = x === 0 ? DIRECTION_NONE : x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
6167 hasMoved = x !== this.pX;
6168 distance = Math.abs(input.deltaX);
6169 } else {
6170 direction = y === 0 ? DIRECTION_NONE : y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
6171 hasMoved = y !== this.pY;
6172 distance = Math.abs(input.deltaY);
6173 }
6174 }
6175
6176 input.direction = direction;
6177 return hasMoved && distance > options.threshold && direction & options.direction;
6178 };
6179
6180 _proto.attrTest = function attrTest(input) {
6181 return AttrRecognizer.prototype.attrTest.call(this, input) && ( // replace with a super call
6182 this.state & STATE_BEGAN || !(this.state & STATE_BEGAN) && this.directionTest(input));
6183 };
6184
6185 _proto.emit = function emit(input) {
6186 this.pX = input.deltaX;
6187 this.pY = input.deltaY;
6188 var direction = directionStr(input.direction);
6189
6190 if (direction) {
6191 input.additionalEvent = this.options.event + direction;
6192 }
6193
6194 _AttrRecognizer.prototype.emit.call(this, input);
6195 };
6196
6197 return PanRecognizer;
6198 }(AttrRecognizer);
6199 /**
6200 * @private
6201 * Swipe
6202 * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
6203 * @constructor
6204 * @extends AttrRecognizer
6205 */
6206
6207
6208 var SwipeRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
6209 _inheritsLoose(SwipeRecognizer, _AttrRecognizer);
6210
6211 function SwipeRecognizer(options) {
6212 if (options === void 0) {
6213 options = {};
6214 }
6215
6216 return _AttrRecognizer.call(this, _extends({
6217 event: 'swipe',
6218 threshold: 10,
6219 velocity: 0.3,
6220 direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
6221 pointers: 1
6222 }, options)) || this;
6223 }
6224
6225 var _proto = SwipeRecognizer.prototype;
6226
6227 _proto.getTouchAction = function getTouchAction() {
6228 return PanRecognizer.prototype.getTouchAction.call(this);
6229 };
6230
6231 _proto.attrTest = function attrTest(input) {
6232 var direction = this.options.direction;
6233 var velocity;
6234
6235 if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
6236 velocity = input.overallVelocity;
6237 } else if (direction & DIRECTION_HORIZONTAL) {
6238 velocity = input.overallVelocityX;
6239 } else if (direction & DIRECTION_VERTICAL) {
6240 velocity = input.overallVelocityY;
6241 }
6242
6243 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;
6244 };
6245
6246 _proto.emit = function emit(input) {
6247 var direction = directionStr(input.offsetDirection);
6248
6249 if (direction) {
6250 this.manager.emit(this.options.event + direction, input);
6251 }
6252
6253 this.manager.emit(this.options.event, input);
6254 };
6255
6256 return SwipeRecognizer;
6257 }(AttrRecognizer);
6258 /**
6259 * @private
6260 * Pinch
6261 * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
6262 * @constructor
6263 * @extends AttrRecognizer
6264 */
6265
6266
6267 var PinchRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
6268 _inheritsLoose(PinchRecognizer, _AttrRecognizer);
6269
6270 function PinchRecognizer(options) {
6271 if (options === void 0) {
6272 options = {};
6273 }
6274
6275 return _AttrRecognizer.call(this, _extends({
6276 event: 'pinch',
6277 threshold: 0,
6278 pointers: 2
6279 }, options)) || this;
6280 }
6281
6282 var _proto = PinchRecognizer.prototype;
6283
6284 _proto.getTouchAction = function getTouchAction() {
6285 return [TOUCH_ACTION_NONE];
6286 };
6287
6288 _proto.attrTest = function attrTest(input) {
6289 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
6290 };
6291
6292 _proto.emit = function emit(input) {
6293 if (input.scale !== 1) {
6294 var inOut = input.scale < 1 ? 'in' : 'out';
6295 input.additionalEvent = this.options.event + inOut;
6296 }
6297
6298 _AttrRecognizer.prototype.emit.call(this, input);
6299 };
6300
6301 return PinchRecognizer;
6302 }(AttrRecognizer);
6303 /**
6304 * @private
6305 * Rotate
6306 * Recognized when two or more pointer are moving in a circular motion.
6307 * @constructor
6308 * @extends AttrRecognizer
6309 */
6310
6311
6312 var RotateRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
6313 _inheritsLoose(RotateRecognizer, _AttrRecognizer);
6314
6315 function RotateRecognizer(options) {
6316 if (options === void 0) {
6317 options = {};
6318 }
6319
6320 return _AttrRecognizer.call(this, _extends({
6321 event: 'rotate',
6322 threshold: 0,
6323 pointers: 2
6324 }, options)) || this;
6325 }
6326
6327 var _proto = RotateRecognizer.prototype;
6328
6329 _proto.getTouchAction = function getTouchAction() {
6330 return [TOUCH_ACTION_NONE];
6331 };
6332
6333 _proto.attrTest = function attrTest(input) {
6334 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
6335 };
6336
6337 return RotateRecognizer;
6338 }(AttrRecognizer);
6339 /**
6340 * @private
6341 * Press
6342 * Recognized when the pointer is down for x ms without any movement.
6343 * @constructor
6344 * @extends Recognizer
6345 */
6346
6347
6348 var PressRecognizer = /*#__PURE__*/function (_Recognizer) {
6349 _inheritsLoose(PressRecognizer, _Recognizer);
6350
6351 function PressRecognizer(options) {
6352 var _this;
6353
6354 if (options === void 0) {
6355 options = {};
6356 }
6357
6358 _this = _Recognizer.call(this, _extends({
6359 event: 'press',
6360 pointers: 1,
6361 time: 251,
6362 // minimal time of the pointer to be pressed
6363 threshold: 9
6364 }, options)) || this;
6365 _this._timer = null;
6366 _this._input = null;
6367 return _this;
6368 }
6369
6370 var _proto = PressRecognizer.prototype;
6371
6372 _proto.getTouchAction = function getTouchAction() {
6373 return [TOUCH_ACTION_AUTO];
6374 };
6375
6376 _proto.process = function process(input) {
6377 var _this2 = this;
6378
6379 var options = this.options;
6380 var validPointers = input.pointers.length === options.pointers;
6381 var validMovement = input.distance < options.threshold;
6382 var validTime = input.deltaTime > options.time;
6383 this._input = input; // we only allow little movement
6384 // and we've reached an end event, so a tap is possible
6385
6386 if (!validMovement || !validPointers || input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime) {
6387 this.reset();
6388 } else if (input.eventType & INPUT_START) {
6389 this.reset();
6390 this._timer = setTimeout(function () {
6391 _this2.state = STATE_RECOGNIZED;
6392
6393 _this2.tryEmit();
6394 }, options.time);
6395 } else if (input.eventType & INPUT_END) {
6396 return STATE_RECOGNIZED;
6397 }
6398
6399 return STATE_FAILED;
6400 };
6401
6402 _proto.reset = function reset() {
6403 clearTimeout(this._timer);
6404 };
6405
6406 _proto.emit = function emit(input) {
6407 if (this.state !== STATE_RECOGNIZED) {
6408 return;
6409 }
6410
6411 if (input && input.eventType & INPUT_END) {
6412 this.manager.emit(this.options.event + "up", input);
6413 } else {
6414 this._input.timeStamp = now();
6415 this.manager.emit(this.options.event, this._input);
6416 }
6417 };
6418
6419 return PressRecognizer;
6420 }(Recognizer);
6421
6422 var defaults = {
6423 /**
6424 * @private
6425 * set if DOM events are being triggered.
6426 * But this is slower and unused by simple implementations, so disabled by default.
6427 * @type {Boolean}
6428 * @default false
6429 */
6430 domEvents: false,
6431
6432 /**
6433 * @private
6434 * The value for the touchAction property/fallback.
6435 * When set to `compute` it will magically set the correct value based on the added recognizers.
6436 * @type {String}
6437 * @default compute
6438 */
6439 touchAction: TOUCH_ACTION_COMPUTE,
6440
6441 /**
6442 * @private
6443 * @type {Boolean}
6444 * @default true
6445 */
6446 enable: true,
6447
6448 /**
6449 * @private
6450 * EXPERIMENTAL FEATURE -- can be removed/changed
6451 * Change the parent input target element.
6452 * If Null, then it is being set the to main element.
6453 * @type {Null|EventTarget}
6454 * @default null
6455 */
6456 inputTarget: null,
6457
6458 /**
6459 * @private
6460 * force an input class
6461 * @type {Null|Function}
6462 * @default null
6463 */
6464 inputClass: null,
6465
6466 /**
6467 * @private
6468 * Some CSS properties can be used to improve the working of Hammer.
6469 * Add them to this method and they will be set when creating a new Manager.
6470 * @namespace
6471 */
6472 cssProps: {
6473 /**
6474 * @private
6475 * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
6476 * @type {String}
6477 * @default 'none'
6478 */
6479 userSelect: "none",
6480
6481 /**
6482 * @private
6483 * Disable the Windows Phone grippers when pressing an element.
6484 * @type {String}
6485 * @default 'none'
6486 */
6487 touchSelect: "none",
6488
6489 /**
6490 * @private
6491 * Disables the default callout shown when you touch and hold a touch target.
6492 * On iOS, when you touch and hold a touch target such as a link, Safari displays
6493 * a callout containing information about the link. This property allows you to disable that callout.
6494 * @type {String}
6495 * @default 'none'
6496 */
6497 touchCallout: "none",
6498
6499 /**
6500 * @private
6501 * Specifies whether zooming is enabled. Used by IE10>
6502 * @type {String}
6503 * @default 'none'
6504 */
6505 contentZooming: "none",
6506
6507 /**
6508 * @private
6509 * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
6510 * @type {String}
6511 * @default 'none'
6512 */
6513 userDrag: "none",
6514
6515 /**
6516 * @private
6517 * Overrides the highlight color shown when the user taps a link or a JavaScript
6518 * clickable element in iOS. This property obeys the alpha value, if specified.
6519 * @type {String}
6520 * @default 'rgba(0,0,0,0)'
6521 */
6522 tapHighlightColor: "rgba(0,0,0,0)"
6523 }
6524 };
6525 /**
6526 * @private
6527 * Default recognizer setup when calling `Hammer()`
6528 * When creating a new Manager these will be skipped.
6529 * This is separated with other defaults because of tree-shaking.
6530 * @type {Array}
6531 */
6532
6533 var preset = [[RotateRecognizer, {
6534 enable: false
6535 }], [PinchRecognizer, {
6536 enable: false
6537 }, ['rotate']], [SwipeRecognizer, {
6538 direction: DIRECTION_HORIZONTAL
6539 }], [PanRecognizer, {
6540 direction: DIRECTION_HORIZONTAL
6541 }, ['swipe']], [TapRecognizer], [TapRecognizer, {
6542 event: 'doubletap',
6543 taps: 2
6544 }, ['tap']], [PressRecognizer]];
6545 var STOP = 1;
6546 var FORCED_STOP = 2;
6547 /**
6548 * @private
6549 * add/remove the css properties as defined in manager.options.cssProps
6550 * @param {Manager} manager
6551 * @param {Boolean} add
6552 */
6553
6554 function toggleCssProps(manager, add) {
6555 var element = manager.element;
6556
6557 if (!element.style) {
6558 return;
6559 }
6560
6561 var prop;
6562 each(manager.options.cssProps, function (value, name) {
6563 prop = prefixed(element.style, name);
6564
6565 if (add) {
6566 manager.oldCssProps[prop] = element.style[prop];
6567 element.style[prop] = value;
6568 } else {
6569 element.style[prop] = manager.oldCssProps[prop] || "";
6570 }
6571 });
6572
6573 if (!add) {
6574 manager.oldCssProps = {};
6575 }
6576 }
6577 /**
6578 * @private
6579 * trigger dom event
6580 * @param {String} event
6581 * @param {Object} data
6582 */
6583
6584
6585 function triggerDomEvent(event, data) {
6586 var gestureEvent = document.createEvent("Event");
6587 gestureEvent.initEvent(event, true, true);
6588 gestureEvent.gesture = data;
6589 data.target.dispatchEvent(gestureEvent);
6590 }
6591 /**
6592 * @private
6593 * Manager
6594 * @param {HTMLElement} element
6595 * @param {Object} [options]
6596 * @constructor
6597 */
6598
6599
6600 var Manager = /*#__PURE__*/function () {
6601 function Manager(element, options) {
6602 var _this = this;
6603
6604 this.options = assign$1({}, defaults, options || {});
6605 this.options.inputTarget = this.options.inputTarget || element;
6606 this.handlers = {};
6607 this.session = {};
6608 this.recognizers = [];
6609 this.oldCssProps = {};
6610 this.element = element;
6611 this.input = createInputInstance(this);
6612 this.touchAction = new TouchAction(this, this.options.touchAction);
6613 toggleCssProps(this, true);
6614 each(this.options.recognizers, function (item) {
6615 var recognizer = _this.add(new item[0](item[1]));
6616
6617 item[2] && recognizer.recognizeWith(item[2]);
6618 item[3] && recognizer.requireFailure(item[3]);
6619 }, this);
6620 }
6621 /**
6622 * @private
6623 * set options
6624 * @param {Object} options
6625 * @returns {Manager}
6626 */
6627
6628
6629 var _proto = Manager.prototype;
6630
6631 _proto.set = function set(options) {
6632 assign$1(this.options, options); // Options that need a little more setup
6633
6634 if (options.touchAction) {
6635 this.touchAction.update();
6636 }
6637
6638 if (options.inputTarget) {
6639 // Clean up existing event listeners and reinitialize
6640 this.input.destroy();
6641 this.input.target = options.inputTarget;
6642 this.input.init();
6643 }
6644
6645 return this;
6646 };
6647 /**
6648 * @private
6649 * stop recognizing for this session.
6650 * This session will be discarded, when a new [input]start event is fired.
6651 * When forced, the recognizer cycle is stopped immediately.
6652 * @param {Boolean} [force]
6653 */
6654
6655
6656 _proto.stop = function stop(force) {
6657 this.session.stopped = force ? FORCED_STOP : STOP;
6658 };
6659 /**
6660 * @private
6661 * run the recognizers!
6662 * called by the inputHandler function on every movement of the pointers (touches)
6663 * it walks through all the recognizers and tries to detect the gesture that is being made
6664 * @param {Object} inputData
6665 */
6666
6667
6668 _proto.recognize = function recognize(inputData) {
6669 var session = this.session;
6670
6671 if (session.stopped) {
6672 return;
6673 } // run the touch-action polyfill
6674
6675
6676 this.touchAction.preventDefaults(inputData);
6677 var recognizer;
6678 var recognizers = this.recognizers; // this holds the recognizer that is being recognized.
6679 // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
6680 // if no recognizer is detecting a thing, it is set to `null`
6681
6682 var curRecognizer = session.curRecognizer; // reset when the last recognizer is recognized
6683 // or when we're in a new session
6684
6685 if (!curRecognizer || curRecognizer && curRecognizer.state & STATE_RECOGNIZED) {
6686 session.curRecognizer = null;
6687 curRecognizer = null;
6688 }
6689
6690 var i = 0;
6691
6692 while (i < recognizers.length) {
6693 recognizer = recognizers[i]; // find out if we are allowed try to recognize the input for this one.
6694 // 1. allow if the session is NOT forced stopped (see the .stop() method)
6695 // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
6696 // that is being recognized.
6697 // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
6698 // this can be setup with the `recognizeWith()` method on the recognizer.
6699
6700 if (session.stopped !== FORCED_STOP && ( // 1
6701 !curRecognizer || recognizer === curRecognizer || // 2
6702 recognizer.canRecognizeWith(curRecognizer))) {
6703 // 3
6704 recognizer.recognize(inputData);
6705 } else {
6706 recognizer.reset();
6707 } // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
6708 // current active recognizer. but only if we don't already have an active recognizer
6709
6710
6711 if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
6712 session.curRecognizer = recognizer;
6713 curRecognizer = recognizer;
6714 }
6715
6716 i++;
6717 }
6718 };
6719 /**
6720 * @private
6721 * get a recognizer by its event name.
6722 * @param {Recognizer|String} recognizer
6723 * @returns {Recognizer|Null}
6724 */
6725
6726
6727 _proto.get = function get(recognizer) {
6728 if (recognizer instanceof Recognizer) {
6729 return recognizer;
6730 }
6731
6732 var recognizers = this.recognizers;
6733
6734 for (var i = 0; i < recognizers.length; i++) {
6735 if (recognizers[i].options.event === recognizer) {
6736 return recognizers[i];
6737 }
6738 }
6739
6740 return null;
6741 };
6742 /**
6743 * @private add a recognizer to the manager
6744 * existing recognizers with the same event name will be removed
6745 * @param {Recognizer} recognizer
6746 * @returns {Recognizer|Manager}
6747 */
6748
6749
6750 _proto.add = function add(recognizer) {
6751 if (invokeArrayArg(recognizer, "add", this)) {
6752 return this;
6753 } // remove existing
6754
6755
6756 var existing = this.get(recognizer.options.event);
6757
6758 if (existing) {
6759 this.remove(existing);
6760 }
6761
6762 this.recognizers.push(recognizer);
6763 recognizer.manager = this;
6764 this.touchAction.update();
6765 return recognizer;
6766 };
6767 /**
6768 * @private
6769 * remove a recognizer by name or instance
6770 * @param {Recognizer|String} recognizer
6771 * @returns {Manager}
6772 */
6773
6774
6775 _proto.remove = function remove(recognizer) {
6776 if (invokeArrayArg(recognizer, "remove", this)) {
6777 return this;
6778 }
6779
6780 var targetRecognizer = this.get(recognizer); // let's make sure this recognizer exists
6781
6782 if (recognizer) {
6783 var recognizers = this.recognizers;
6784 var index = inArray(recognizers, targetRecognizer);
6785
6786 if (index !== -1) {
6787 recognizers.splice(index, 1);
6788 this.touchAction.update();
6789 }
6790 }
6791
6792 return this;
6793 };
6794 /**
6795 * @private
6796 * bind event
6797 * @param {String} events
6798 * @param {Function} handler
6799 * @returns {EventEmitter} this
6800 */
6801
6802
6803 _proto.on = function on(events, handler) {
6804 if (events === undefined || handler === undefined) {
6805 return this;
6806 }
6807
6808 var handlers = this.handlers;
6809 each(splitStr(events), function (event) {
6810 handlers[event] = handlers[event] || [];
6811 handlers[event].push(handler);
6812 });
6813 return this;
6814 };
6815 /**
6816 * @private unbind event, leave emit blank to remove all handlers
6817 * @param {String} events
6818 * @param {Function} [handler]
6819 * @returns {EventEmitter} this
6820 */
6821
6822
6823 _proto.off = function off(events, handler) {
6824 if (events === undefined) {
6825 return this;
6826 }
6827
6828 var handlers = this.handlers;
6829 each(splitStr(events), function (event) {
6830 if (!handler) {
6831 delete handlers[event];
6832 } else {
6833 handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
6834 }
6835 });
6836 return this;
6837 };
6838 /**
6839 * @private emit event to the listeners
6840 * @param {String} event
6841 * @param {Object} data
6842 */
6843
6844
6845 _proto.emit = function emit(event, data) {
6846 // we also want to trigger dom events
6847 if (this.options.domEvents) {
6848 triggerDomEvent(event, data);
6849 } // no handlers, so skip it all
6850
6851
6852 var handlers = this.handlers[event] && this.handlers[event].slice();
6853
6854 if (!handlers || !handlers.length) {
6855 return;
6856 }
6857
6858 data.type = event;
6859
6860 data.preventDefault = function () {
6861 data.srcEvent.preventDefault();
6862 };
6863
6864 var i = 0;
6865
6866 while (i < handlers.length) {
6867 handlers[i](data);
6868 i++;
6869 }
6870 };
6871 /**
6872 * @private
6873 * destroy the manager and unbinds all events
6874 * it doesn't unbind dom events, that is the user own responsibility
6875 */
6876
6877
6878 _proto.destroy = function destroy() {
6879 this.element && toggleCssProps(this, false);
6880 this.handlers = {};
6881 this.session = {};
6882 this.input.destroy();
6883 this.element = null;
6884 };
6885
6886 return Manager;
6887 }();
6888
6889 var SINGLE_TOUCH_INPUT_MAP = {
6890 touchstart: INPUT_START,
6891 touchmove: INPUT_MOVE,
6892 touchend: INPUT_END,
6893 touchcancel: INPUT_CANCEL
6894 };
6895 var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
6896 var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
6897 /**
6898 * @private
6899 * Touch events input
6900 * @constructor
6901 * @extends Input
6902 */
6903
6904 var SingleTouchInput = /*#__PURE__*/function (_Input) {
6905 _inheritsLoose(SingleTouchInput, _Input);
6906
6907 function SingleTouchInput() {
6908 var _this;
6909
6910 var proto = SingleTouchInput.prototype;
6911 proto.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
6912 proto.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
6913 _this = _Input.apply(this, arguments) || this;
6914 _this.started = false;
6915 return _this;
6916 }
6917
6918 var _proto = SingleTouchInput.prototype;
6919
6920 _proto.handler = function handler(ev) {
6921 var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; // should we handle the touch events?
6922
6923 if (type === INPUT_START) {
6924 this.started = true;
6925 }
6926
6927 if (!this.started) {
6928 return;
6929 }
6930
6931 var touches = normalizeSingleTouches.call(this, ev, type); // when done, reset the started state
6932
6933 if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
6934 this.started = false;
6935 }
6936
6937 this.callback(this.manager, type, {
6938 pointers: touches[0],
6939 changedPointers: touches[1],
6940 pointerType: INPUT_TYPE_TOUCH,
6941 srcEvent: ev
6942 });
6943 };
6944
6945 return SingleTouchInput;
6946 }(Input);
6947
6948 function normalizeSingleTouches(ev, type) {
6949 var all = toArray(ev.touches);
6950 var changed = toArray(ev.changedTouches);
6951
6952 if (type & (INPUT_END | INPUT_CANCEL)) {
6953 all = uniqueArray(all.concat(changed), 'identifier', true);
6954 }
6955
6956 return [all, changed];
6957 }
6958 /**
6959 * @private
6960 * wrap a method with a deprecation warning and stack trace
6961 * @param {Function} method
6962 * @param {String} name
6963 * @param {String} message
6964 * @returns {Function} A new function wrapping the supplied method.
6965 */
6966
6967
6968 function deprecate(method, name, message) {
6969 var deprecationMessage = "DEPRECATED METHOD: " + name + "\n" + message + " AT \n";
6970 return function () {
6971 var e = new Error('get-stack-trace');
6972 var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '').replace(/^\s+at\s+/gm, '').replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
6973 var log = window.console && (window.console.warn || window.console.log);
6974
6975 if (log) {
6976 log.call(window.console, deprecationMessage, stack);
6977 }
6978
6979 return method.apply(this, arguments);
6980 };
6981 }
6982 /**
6983 * @private
6984 * extend object.
6985 * means that properties in dest will be overwritten by the ones in src.
6986 * @param {Object} dest
6987 * @param {Object} src
6988 * @param {Boolean} [merge=false]
6989 * @returns {Object} dest
6990 */
6991
6992
6993 var extend = deprecate(function (dest, src, merge) {
6994 var keys = Object.keys(src);
6995 var i = 0;
6996
6997 while (i < keys.length) {
6998 if (!merge || merge && dest[keys[i]] === undefined) {
6999 dest[keys[i]] = src[keys[i]];
7000 }
7001
7002 i++;
7003 }
7004
7005 return dest;
7006 }, 'extend', 'Use `assign`.');
7007 /**
7008 * @private
7009 * merge the values from src in the dest.
7010 * means that properties that exist in dest will not be overwritten by src
7011 * @param {Object} dest
7012 * @param {Object} src
7013 * @returns {Object} dest
7014 */
7015
7016 var merge$2 = deprecate(function (dest, src) {
7017 return extend(dest, src, true);
7018 }, 'merge', 'Use `assign`.');
7019 /**
7020 * @private
7021 * simple class inheritance
7022 * @param {Function} child
7023 * @param {Function} base
7024 * @param {Object} [properties]
7025 */
7026
7027 function inherit(child, base, properties) {
7028 var baseP = base.prototype;
7029 var childP;
7030 childP = child.prototype = Object.create(baseP);
7031 childP.constructor = child;
7032 childP._super = baseP;
7033
7034 if (properties) {
7035 assign$1(childP, properties);
7036 }
7037 }
7038 /**
7039 * @private
7040 * simple function bind
7041 * @param {Function} fn
7042 * @param {Object} context
7043 * @returns {Function}
7044 */
7045
7046
7047 function bindFn(fn, context) {
7048 return function boundFn() {
7049 return fn.apply(context, arguments);
7050 };
7051 }
7052 /**
7053 * @private
7054 * Simple way to create a manager with a default set of recognizers.
7055 * @param {HTMLElement} element
7056 * @param {Object} [options]
7057 * @constructor
7058 */
7059
7060
7061 var Hammer$2 = /*#__PURE__*/function () {
7062 var Hammer =
7063 /**
7064 * @private
7065 * @const {string}
7066 */
7067 function Hammer(element, options) {
7068 if (options === void 0) {
7069 options = {};
7070 }
7071
7072 return new Manager(element, _extends({
7073 recognizers: preset.concat()
7074 }, options));
7075 };
7076
7077 Hammer.VERSION = "2.0.17-rc";
7078 Hammer.DIRECTION_ALL = DIRECTION_ALL;
7079 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
7080 Hammer.DIRECTION_LEFT = DIRECTION_LEFT;
7081 Hammer.DIRECTION_RIGHT = DIRECTION_RIGHT;
7082 Hammer.DIRECTION_UP = DIRECTION_UP;
7083 Hammer.DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL;
7084 Hammer.DIRECTION_VERTICAL = DIRECTION_VERTICAL;
7085 Hammer.DIRECTION_NONE = DIRECTION_NONE;
7086 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
7087 Hammer.INPUT_START = INPUT_START;
7088 Hammer.INPUT_MOVE = INPUT_MOVE;
7089 Hammer.INPUT_END = INPUT_END;
7090 Hammer.INPUT_CANCEL = INPUT_CANCEL;
7091 Hammer.STATE_POSSIBLE = STATE_POSSIBLE;
7092 Hammer.STATE_BEGAN = STATE_BEGAN;
7093 Hammer.STATE_CHANGED = STATE_CHANGED;
7094 Hammer.STATE_ENDED = STATE_ENDED;
7095 Hammer.STATE_RECOGNIZED = STATE_RECOGNIZED;
7096 Hammer.STATE_CANCELLED = STATE_CANCELLED;
7097 Hammer.STATE_FAILED = STATE_FAILED;
7098 Hammer.Manager = Manager;
7099 Hammer.Input = Input;
7100 Hammer.TouchAction = TouchAction;
7101 Hammer.TouchInput = TouchInput;
7102 Hammer.MouseInput = MouseInput;
7103 Hammer.PointerEventInput = PointerEventInput;
7104 Hammer.TouchMouseInput = TouchMouseInput;
7105 Hammer.SingleTouchInput = SingleTouchInput;
7106 Hammer.Recognizer = Recognizer;
7107 Hammer.AttrRecognizer = AttrRecognizer;
7108 Hammer.Tap = TapRecognizer;
7109 Hammer.Pan = PanRecognizer;
7110 Hammer.Swipe = SwipeRecognizer;
7111 Hammer.Pinch = PinchRecognizer;
7112 Hammer.Rotate = RotateRecognizer;
7113 Hammer.Press = PressRecognizer;
7114 Hammer.on = addEventListeners;
7115 Hammer.off = removeEventListeners;
7116 Hammer.each = each;
7117 Hammer.merge = merge$2;
7118 Hammer.extend = extend;
7119 Hammer.bindFn = bindFn;
7120 Hammer.assign = assign$1;
7121 Hammer.inherit = inherit;
7122 Hammer.bindFn = bindFn;
7123 Hammer.prefixed = prefixed;
7124 Hammer.toArray = toArray;
7125 Hammer.inArray = inArray;
7126 Hammer.uniqueArray = uniqueArray;
7127 Hammer.splitStr = splitStr;
7128 Hammer.boolOrFn = boolOrFn;
7129 Hammer.hasParent = hasParent;
7130 Hammer.addEventListeners = addEventListeners;
7131 Hammer.removeEventListeners = removeEventListeners;
7132 Hammer.defaults = assign$1({}, defaults, {
7133 preset: preset
7134 });
7135 return Hammer;
7136 }(); // style loader but by script tag, not by the loader.
7137 var RealHammer = Hammer$2;
7138
7139 function _createForOfIteratorHelper$7(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$1(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; } } }; }
7140
7141 function _unsupportedIterableToArray$7(o, minLen) { var _context21; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$7(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$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$7(o, minLen); }
7142
7143 function _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; }
7144 /**
7145 * Use this symbol to delete properies in deepObjectAssign.
7146 */
7147
7148 symbol("DELETE");
7149 /**
7150 * Seedable, fast and reasonably good (not crypto but more than okay for our
7151 * needs) random number generator.
7152 *
7153 * @remarks
7154 * Adapted from {@link https://web.archive.org/web/20110429100736/http://baagoe.com:80/en/RandomMusings/javascript}.
7155 * Original algorithm created by Johannes Baagøe \<baagoe\@baagoe.com\> in 2010.
7156 */
7157
7158 /**
7159 * Create a seeded pseudo random generator based on Alea by Johannes Baagøe.
7160 *
7161 * @param seed - All supplied arguments will be used as a seed. In case nothing
7162 * is supplied the current time will be used to seed the generator.
7163 *
7164 * @returns A ready to use seeded generator.
7165 */
7166
7167
7168 function Alea() {
7169 for (var _len3 = arguments.length, seed = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
7170 seed[_key3] = arguments[_key3];
7171 }
7172
7173 return AleaImplementation(seed.length ? seed : [now$1()]);
7174 }
7175 /**
7176 * An implementation of [[Alea]] without user input validation.
7177 *
7178 * @param seed - The data that will be used to seed the generator.
7179 *
7180 * @returns A ready to use seeded generator.
7181 */
7182
7183
7184 function AleaImplementation(seed) {
7185 var _mashSeed = mashSeed(seed),
7186 _mashSeed2 = _slicedToArray(_mashSeed, 3),
7187 s0 = _mashSeed2[0],
7188 s1 = _mashSeed2[1],
7189 s2 = _mashSeed2[2];
7190
7191 var c = 1;
7192
7193 var random = function random() {
7194 var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
7195
7196 s0 = s1;
7197 s1 = s2;
7198 return s2 = t - (c = t | 0);
7199 };
7200
7201 random.uint32 = function () {
7202 return random() * 0x100000000;
7203 }; // 2^32
7204
7205
7206 random.fract53 = function () {
7207 return random() + (random() * 0x200000 | 0) * 1.1102230246251565e-16;
7208 }; // 2^-53
7209
7210
7211 random.algorithm = "Alea";
7212 random.seed = seed;
7213 random.version = "0.9";
7214 return random;
7215 }
7216 /**
7217 * Turn arbitrary data into values [[AleaImplementation]] can use to generate
7218 * random numbers.
7219 *
7220 * @param seed - Arbitrary data that will be used as the seed.
7221 *
7222 * @returns Three numbers to use as initial values for [[AleaImplementation]].
7223 */
7224
7225
7226 function mashSeed() {
7227 var mash = Mash();
7228 var s0 = mash(" ");
7229 var s1 = mash(" ");
7230 var s2 = mash(" ");
7231
7232 for (var i = 0; i < arguments.length; i++) {
7233 s0 -= mash(i < 0 || arguments.length <= i ? undefined : arguments[i]);
7234
7235 if (s0 < 0) {
7236 s0 += 1;
7237 }
7238
7239 s1 -= mash(i < 0 || arguments.length <= i ? undefined : arguments[i]);
7240
7241 if (s1 < 0) {
7242 s1 += 1;
7243 }
7244
7245 s2 -= mash(i < 0 || arguments.length <= i ? undefined : arguments[i]);
7246
7247 if (s2 < 0) {
7248 s2 += 1;
7249 }
7250 }
7251
7252 return [s0, s1, s2];
7253 }
7254 /**
7255 * Create a new mash function.
7256 *
7257 * @returns A nonpure function that takes arbitrary [[Mashable]] data and turns
7258 * them into numbers.
7259 */
7260
7261
7262 function Mash() {
7263 var n = 0xefc8249d;
7264 return function (data) {
7265 var string = data.toString();
7266
7267 for (var i = 0; i < string.length; i++) {
7268 n += string.charCodeAt(i);
7269 var h = 0.02519603282416938 * n;
7270 n = h >>> 0;
7271 h -= n;
7272 h *= n;
7273 n = h >>> 0;
7274 h -= n;
7275 n += h * 0x100000000; // 2^32
7276 }
7277
7278 return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
7279 };
7280 }
7281 /**
7282 * Setup a mock hammer.js object, for unit testing.
7283 *
7284 * Inspiration: https://github.com/uber/deck.gl/pull/658
7285 *
7286 * @returns {{on: noop, off: noop, destroy: noop, emit: noop, get: get}}
7287 */
7288
7289
7290 function hammerMock() {
7291 var noop = function noop() {};
7292
7293 return {
7294 on: noop,
7295 off: noop,
7296 destroy: noop,
7297 emit: noop,
7298 get: function get() {
7299 return {
7300 set: noop
7301 };
7302 }
7303 };
7304 }
7305
7306 var Hammer = typeof window !== "undefined" ? window.Hammer || RealHammer : function () {
7307 // hammer.js is only available in a browser, not in node.js. Replacing it with a mock object.
7308 return hammerMock();
7309 };
7310 /**
7311 * Turn an element into an clickToUse element.
7312 * When not active, the element has a transparent overlay. When the overlay is
7313 * clicked, the mode is changed to active.
7314 * When active, the element is displayed with a blue border around it, and
7315 * the interactive contents of the element can be used. When clicked outside
7316 * the element, the elements mode is changed to inactive.
7317 *
7318 * @param {Element} container
7319 * @class Activator
7320 */
7321
7322 function Activator(container) {
7323 var _this = this,
7324 _context3;
7325
7326 this._cleanupQueue = [];
7327 this.active = false;
7328 this._dom = {
7329 container: container,
7330 overlay: document.createElement("div")
7331 };
7332
7333 this._dom.overlay.classList.add("vis-overlay");
7334
7335 this._dom.container.appendChild(this._dom.overlay);
7336
7337 this._cleanupQueue.push(function () {
7338 _this._dom.overlay.parentNode.removeChild(_this._dom.overlay);
7339 });
7340
7341 var hammer = Hammer(this._dom.overlay);
7342 hammer.on("tap", bind$5(_context3 = this._onTapOverlay).call(_context3, this));
7343
7344 this._cleanupQueue.push(function () {
7345 hammer.destroy(); // FIXME: cleaning up hammer instances doesn't work (Timeline not removed
7346 // from memory)
7347 }); // block all touch events (except tap)
7348
7349
7350 var events = ["tap", "doubletap", "press", "pinch", "pan", "panstart", "panmove", "panend"];
7351
7352 forEach$2(events).call(events, function (event) {
7353 hammer.on(event, function (event) {
7354 event.srcEvent.stopPropagation();
7355 });
7356 }); // attach a click event to the window, in order to deactivate when clicking outside the timeline
7357
7358
7359 if (document && document.body) {
7360 this._onClick = function (event) {
7361 if (!_hasParent(event.target, container)) {
7362 _this.deactivate();
7363 }
7364 };
7365
7366 document.body.addEventListener("click", this._onClick);
7367
7368 this._cleanupQueue.push(function () {
7369 document.body.removeEventListener("click", _this._onClick);
7370 });
7371 } // prepare escape key listener for deactivating when active
7372
7373
7374 this._escListener = function (event) {
7375 if ("key" in event ? event.key === "Escape" : event.keyCode === 27
7376 /* the keyCode is for IE11 */
7377 ) {
7378 _this.deactivate();
7379 }
7380 };
7381 } // turn into an event emitter
7382
7383
7384 Emitter(Activator.prototype); // The currently active activator
7385
7386 Activator.current = null;
7387 /**
7388 * Destroy the activator. Cleans up all created DOM and event listeners
7389 */
7390
7391 Activator.prototype.destroy = function () {
7392 var _context4, _context5;
7393
7394 this.deactivate();
7395
7396 var _iterator2 = _createForOfIteratorHelper$7(reverse(_context4 = splice(_context5 = this._cleanupQueue).call(_context5, 0)).call(_context4)),
7397 _step2;
7398
7399 try {
7400 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
7401 var callback = _step2.value;
7402 callback();
7403 }
7404 } catch (err) {
7405 _iterator2.e(err);
7406 } finally {
7407 _iterator2.f();
7408 }
7409 };
7410 /**
7411 * Activate the element
7412 * Overlay is hidden, element is decorated with a blue shadow border
7413 */
7414
7415
7416 Activator.prototype.activate = function () {
7417 // we allow only one active activator at a time
7418 if (Activator.current) {
7419 Activator.current.deactivate();
7420 }
7421
7422 Activator.current = this;
7423 this.active = true;
7424 this._dom.overlay.style.display = "none";
7425
7426 this._dom.container.classList.add("vis-active");
7427
7428 this.emit("change");
7429 this.emit("activate"); // ugly hack: bind ESC after emitting the events, as the Network rebinds all
7430 // keyboard events on a 'change' event
7431
7432 document.body.addEventListener("keydown", this._escListener);
7433 };
7434 /**
7435 * Deactivate the element
7436 * Overlay is displayed on top of the element
7437 */
7438
7439
7440 Activator.prototype.deactivate = function () {
7441 this.active = false;
7442 this._dom.overlay.style.display = "block";
7443
7444 this._dom.container.classList.remove("vis-active");
7445
7446 document.body.removeEventListener("keydown", this._escListener);
7447 this.emit("change");
7448 this.emit("deactivate");
7449 };
7450 /**
7451 * Handle a tap event: activate the container
7452 *
7453 * @param {Event} event The event
7454 * @private
7455 */
7456
7457
7458 Activator.prototype._onTapOverlay = function (event) {
7459 // activate the container
7460 this.activate();
7461 event.srcEvent.stopPropagation();
7462 };
7463 /**
7464 * Test whether the element has the requested parent element somewhere in
7465 * its chain of parent nodes.
7466 *
7467 * @param {HTMLElement} element
7468 * @param {HTMLElement} parent
7469 * @returns {boolean} Returns true when the parent is found somewhere in the
7470 * chain of parent nodes.
7471 * @private
7472 */
7473
7474
7475 function _hasParent(element, parent) {
7476 while (element) {
7477 if (element === parent) {
7478 return true;
7479 }
7480
7481 element = element.parentNode;
7482 }
7483
7484 return false;
7485 } // utility functions
7486
7487 var fullHexRE = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
7488 var shortHexRE = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
7489 var 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;
7490 var 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;
7491 /**
7492 * Remove everything in the DOM object.
7493 *
7494 * @param DOMobject - Node whose child nodes will be recursively deleted.
7495 */
7496
7497
7498 function recursiveDOMDelete(DOMobject) {
7499 if (DOMobject) {
7500 while (DOMobject.hasChildNodes() === true) {
7501 var child = DOMobject.firstChild;
7502
7503 if (child) {
7504 recursiveDOMDelete(child);
7505 DOMobject.removeChild(child);
7506 }
7507 }
7508 }
7509 }
7510 /**
7511 * Test whether given object is a string.
7512 *
7513 * @param value - Input value of unknown type.
7514 *
7515 * @returns True if string, false otherwise.
7516 */
7517
7518
7519 function isString(value) {
7520 return value instanceof String || typeof value === "string";
7521 }
7522 /**
7523 * Test whether given object is a object (not primitive or null).
7524 *
7525 * @param value - Input value of unknown type.
7526 *
7527 * @returns True if not null object, false otherwise.
7528 */
7529
7530
7531 function isObject$6(value) {
7532 return _typeof(value) === "object" && value !== null;
7533 }
7534 /**
7535 * Copy property from b to a if property present in a.
7536 * If property in b explicitly set to null, delete it if `allowDeletion` set.
7537 *
7538 * Internal helper routine, should not be exported. Not added to `exports` for that reason.
7539 *
7540 * @param a - Target object.
7541 * @param b - Source object.
7542 * @param prop - Name of property to copy from b to a.
7543 * @param allowDeletion - If true, delete property in a if explicitly set to null in b.
7544 */
7545
7546
7547 function copyOrDelete(a, b, prop, allowDeletion) {
7548 var doDeletion = false;
7549
7550 if (allowDeletion === true) {
7551 doDeletion = b[prop] === null && a[prop] !== undefined;
7552 }
7553
7554 if (doDeletion) {
7555 delete a[prop];
7556 } else {
7557 a[prop] = b[prop]; // Remember, this is a reference copy!
7558 }
7559 }
7560 /**
7561 * Fill an object with a possibly partially defined other object.
7562 *
7563 * Only copies values for the properties already present in a.
7564 * That means an object is not created on a property if only the b object has it.
7565 *
7566 * @param a - The object that will have it's properties updated.
7567 * @param b - The object with property updates.
7568 * @param allowDeletion - If true, delete properties in a that are explicitly set to null in b.
7569 */
7570
7571
7572 function fillIfDefined(a, b) {
7573 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
7574
7575 // NOTE: iteration of properties of a
7576 // NOTE: prototype properties iterated over as well
7577 for (var prop in a) {
7578 if (b[prop] !== undefined) {
7579 if (b[prop] === null || _typeof(b[prop]) !== "object") {
7580 // Note: typeof null === 'object'
7581 copyOrDelete(a, b, prop, allowDeletion);
7582 } else {
7583 var aProp = a[prop];
7584 var bProp = b[prop];
7585
7586 if (isObject$6(aProp) && isObject$6(bProp)) {
7587 fillIfDefined(aProp, bProp, allowDeletion);
7588 }
7589 }
7590 }
7591 }
7592 }
7593 /**
7594 * Extend object a with selected properties of object b.
7595 * Only properties with defined values are copied.
7596 *
7597 * @remarks
7598 * Previous version of this routine implied that multiple source objects could
7599 * be used; however, the implementation was **wrong**. Since multiple (\>1)
7600 * sources weren't used anywhere in the `vis.js` code, this has been removed
7601 *
7602 * @param props - Names of first-level properties to copy over.
7603 * @param a - Target object.
7604 * @param b - Source object.
7605 * @param allowDeletion - If true, delete property in a if explicitly set to null in b.
7606 *
7607 * @returns Argument a.
7608 */
7609
7610
7611 function selectiveDeepExtend(props, a, b) {
7612 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
7613
7614 // TODO: add support for Arrays to deepExtend
7615 if (isArray$1(b)) {
7616 throw new TypeError("Arrays are not supported by deepExtend");
7617 }
7618
7619 for (var p = 0; p < props.length; p++) {
7620 var prop = props[p];
7621
7622 if (Object.prototype.hasOwnProperty.call(b, prop)) {
7623 if (b[prop] && b[prop].constructor === Object) {
7624 if (a[prop] === undefined) {
7625 a[prop] = {};
7626 }
7627
7628 if (a[prop].constructor === Object) {
7629 deepExtend(a[prop], b[prop], false, allowDeletion);
7630 } else {
7631 copyOrDelete(a, b, prop, allowDeletion);
7632 }
7633 } else if (isArray$1(b[prop])) {
7634 throw new TypeError("Arrays are not supported by deepExtend");
7635 } else {
7636 copyOrDelete(a, b, prop, allowDeletion);
7637 }
7638 }
7639 }
7640
7641 return a;
7642 }
7643 /**
7644 * Extend object `a` with properties of object `b`, ignoring properties which
7645 * are explicitly specified to be excluded.
7646 *
7647 * @remarks
7648 * The properties of `b` are considered for copying. Properties which are
7649 * themselves objects are are also extended. Only properties with defined
7650 * values are copied.
7651 *
7652 * @param propsToExclude - Names of properties which should *not* be copied.
7653 * @param a - Object to extend.
7654 * @param b - Object to take properties from for extension.
7655 * @param allowDeletion - If true, delete properties in a that are explicitly
7656 * set to null in b.
7657 *
7658 * @returns Argument a.
7659 */
7660
7661
7662 function selectiveNotDeepExtend(propsToExclude, a, b) {
7663 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
7664
7665 // TODO: add support for Arrays to deepExtend
7666 // NOTE: array properties have an else-below; apparently, there is a problem here.
7667 if (isArray$1(b)) {
7668 throw new TypeError("Arrays are not supported by deepExtend");
7669 }
7670
7671 for (var prop in b) {
7672 if (!Object.prototype.hasOwnProperty.call(b, prop)) {
7673 continue;
7674 } // Handle local properties only
7675
7676
7677 if (includes(propsToExclude).call(propsToExclude, prop)) {
7678 continue;
7679 } // In exclusion list, skip
7680
7681
7682 if (b[prop] && b[prop].constructor === Object) {
7683 if (a[prop] === undefined) {
7684 a[prop] = {};
7685 }
7686
7687 if (a[prop].constructor === Object) {
7688 deepExtend(a[prop], b[prop]); // NOTE: allowDeletion not propagated!
7689 } else {
7690 copyOrDelete(a, b, prop, allowDeletion);
7691 }
7692 } else if (isArray$1(b[prop])) {
7693 a[prop] = [];
7694
7695 for (var i = 0; i < b[prop].length; i++) {
7696 a[prop].push(b[prop][i]);
7697 }
7698 } else {
7699 copyOrDelete(a, b, prop, allowDeletion);
7700 }
7701 }
7702
7703 return a;
7704 }
7705 /**
7706 * Deep extend an object a with the properties of object b.
7707 *
7708 * @param a - Target object.
7709 * @param b - Source object.
7710 * @param protoExtend - If true, the prototype values will also be extended.
7711 * (That is the options objects that inherit from others will also get the
7712 * inherited options).
7713 * @param allowDeletion - If true, the values of fields that are null will be deleted.
7714 *
7715 * @returns Argument a.
7716 */
7717
7718
7719 function deepExtend(a, b) {
7720 var protoExtend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
7721 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
7722
7723 for (var prop in b) {
7724 if (Object.prototype.hasOwnProperty.call(b, prop) || protoExtend === true) {
7725 if (_typeof(b[prop]) === "object" && b[prop] !== null && getPrototypeOf$3(b[prop]) === Object.prototype) {
7726 if (a[prop] === undefined) {
7727 a[prop] = deepExtend({}, b[prop], protoExtend); // NOTE: allowDeletion not propagated!
7728 } else if (_typeof(a[prop]) === "object" && a[prop] !== null && getPrototypeOf$3(a[prop]) === Object.prototype) {
7729 deepExtend(a[prop], b[prop], protoExtend); // NOTE: allowDeletion not propagated!
7730 } else {
7731 copyOrDelete(a, b, prop, allowDeletion);
7732 }
7733 } else if (isArray$1(b[prop])) {
7734 var _context6;
7735
7736 a[prop] = slice$1(_context6 = b[prop]).call(_context6);
7737 } else {
7738 copyOrDelete(a, b, prop, allowDeletion);
7739 }
7740 }
7741 }
7742
7743 return a;
7744 }
7745 /**
7746 * Used to extend an array and copy it. This is used to propagate paths recursively.
7747 *
7748 * @param arr - First part.
7749 * @param newValue - The value to be aadded into the array.
7750 *
7751 * @returns A new array with all items from arr and newValue (which is last).
7752 */
7753
7754
7755 function copyAndExtendArray(arr, newValue) {
7756 var _context7;
7757
7758 return concat(_context7 = []).call(_context7, _toConsumableArray(arr), [newValue]);
7759 }
7760 /**
7761 * Used to extend an array and copy it. This is used to propagate paths recursively.
7762 *
7763 * @param arr - The array to be copied.
7764 *
7765 * @returns Shallow copy of arr.
7766 */
7767
7768
7769 function copyArray(arr) {
7770 return slice$1(arr).call(arr);
7771 }
7772 /**
7773 * Retrieve the absolute left value of a DOM element.
7774 *
7775 * @param elem - A dom element, for example a div.
7776 *
7777 * @returns The absolute left position of this element in the browser page.
7778 */
7779
7780
7781 function getAbsoluteLeft(elem) {
7782 return elem.getBoundingClientRect().left;
7783 }
7784 /**
7785 * Retrieve the absolute top value of a DOM element.
7786 *
7787 * @param elem - A dom element, for example a div.
7788 *
7789 * @returns The absolute top position of this element in the browser page.
7790 */
7791
7792
7793 function getAbsoluteTop(elem) {
7794 return elem.getBoundingClientRect().top;
7795 }
7796 /**
7797 * For each method for both arrays and objects.
7798 * In case of an array, the built-in Array.forEach() is applied (**No, it's not!**).
7799 * In case of an Object, the method loops over all properties of the object.
7800 *
7801 * @param object - An Object or Array to be iterated over.
7802 * @param callback - Array.forEach-like callback.
7803 */
7804
7805
7806 function forEach$1(object, callback) {
7807 if (isArray$1(object)) {
7808 // array
7809 var len = object.length;
7810
7811 for (var i = 0; i < len; i++) {
7812 callback(object[i], i, object);
7813 }
7814 } else {
7815 // object
7816 for (var key in object) {
7817 if (Object.prototype.hasOwnProperty.call(object, key)) {
7818 callback(object[key], key, object);
7819 }
7820 }
7821 }
7822 }
7823 /**
7824 * Add and event listener. Works for all browsers.
7825 *
7826 * @param element - The element to bind the event listener to.
7827 * @param action - Same as Element.addEventListener(action, —, —).
7828 * @param listener - Same as Element.addEventListener(—, listener, —).
7829 * @param useCapture - Same as Element.addEventListener(—, —, useCapture).
7830 */
7831
7832
7833 function addEventListener(element, action, listener, useCapture) {
7834 if (element.addEventListener) {
7835 var _context8;
7836
7837 if (useCapture === undefined) {
7838 useCapture = false;
7839 }
7840
7841 if (action === "mousewheel" && includes(_context8 = navigator.userAgent).call(_context8, "Firefox")) {
7842 action = "DOMMouseScroll"; // For Firefox
7843 }
7844
7845 element.addEventListener(action, listener, useCapture);
7846 } else {
7847 // @TODO: IE types? Does anyone care?
7848 element.attachEvent("on" + action, listener); // IE browsers
7849 }
7850 }
7851 /**
7852 * Remove an event listener from an element.
7853 *
7854 * @param element - The element to bind the event listener to.
7855 * @param action - Same as Element.removeEventListener(action, —, —).
7856 * @param listener - Same as Element.removeEventListener(—, listener, —).
7857 * @param useCapture - Same as Element.removeEventListener(—, —, useCapture).
7858 */
7859
7860
7861 function removeEventListener(element, action, listener, useCapture) {
7862 if (element.removeEventListener) {
7863 var _context9;
7864
7865 // non-IE browsers
7866 if (useCapture === undefined) {
7867 useCapture = false;
7868 }
7869
7870 if (action === "mousewheel" && includes(_context9 = navigator.userAgent).call(_context9, "Firefox")) {
7871 action = "DOMMouseScroll"; // For Firefox
7872 }
7873
7874 element.removeEventListener(action, listener, useCapture);
7875 } else {
7876 // @TODO: IE types? Does anyone care?
7877 element.detachEvent("on" + action, listener); // IE browsers
7878 }
7879 }
7880 /**
7881 * Convert hex color string into RGB color object.
7882 *
7883 * @remarks
7884 * {@link http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb}
7885 *
7886 * @param hex - Hex color string (3 or 6 digits, with or without #).
7887 *
7888 * @returns RGB color object.
7889 */
7890
7891 function hexToRGB(hex) {
7892 var result;
7893
7894 switch (hex.length) {
7895 case 3:
7896 case 4:
7897 result = shortHexRE.exec(hex);
7898 return result ? {
7899 r: _parseInt(result[1] + result[1], 16),
7900 g: _parseInt(result[2] + result[2], 16),
7901 b: _parseInt(result[3] + result[3], 16)
7902 } : null;
7903
7904 case 6:
7905 case 7:
7906 result = fullHexRE.exec(hex);
7907 return result ? {
7908 r: _parseInt(result[1], 16),
7909 g: _parseInt(result[2], 16),
7910 b: _parseInt(result[3], 16)
7911 } : null;
7912
7913 default:
7914 return null;
7915 }
7916 }
7917 /**
7918 * This function takes string color in hex or RGB format and adds the opacity, RGBA is passed through unchanged.
7919 *
7920 * @param color - The color string (hex, RGB, RGBA).
7921 * @param opacity - The new opacity.
7922 *
7923 * @returns RGBA string, for example 'rgba(255, 0, 127, 0.3)'.
7924 */
7925
7926
7927 function overrideOpacity(color, opacity) {
7928 if (includes(color).call(color, "rgba")) {
7929 return color;
7930 } else if (includes(color).call(color, "rgb")) {
7931 var rgb = color.substr(indexOf(color).call(color, "(") + 1).replace(")", "").split(",");
7932 return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + opacity + ")";
7933 } else {
7934 var _rgb = hexToRGB(color);
7935
7936 if (_rgb == null) {
7937 return color;
7938 } else {
7939 return "rgba(" + _rgb.r + "," + _rgb.g + "," + _rgb.b + "," + opacity + ")";
7940 }
7941 }
7942 }
7943 /**
7944 * Convert RGB \<0, 255\> into hex color string.
7945 *
7946 * @param red - Red channel.
7947 * @param green - Green channel.
7948 * @param blue - Blue channel.
7949 *
7950 * @returns Hex color string (for example: '#0acdc0').
7951 */
7952
7953
7954 function RGBToHex(red, green, blue) {
7955 var _context10;
7956
7957 return "#" + slice$1(_context10 = ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16)).call(_context10, 1);
7958 }
7959 /**
7960 * Parse a color property into an object with border, background, and highlight colors.
7961 *
7962 * @param inputColor - Shorthand color string or input color object.
7963 * @param defaultColor - Full color object to fill in missing values in inputColor.
7964 *
7965 * @returns Color object.
7966 */
7967
7968
7969 function parseColor(inputColor, defaultColor) {
7970 if (isString(inputColor)) {
7971 var colorStr = inputColor;
7972
7973 if (isValidRGB(colorStr)) {
7974 var _context11;
7975
7976 var rgb = map$3(_context11 = colorStr.substr(4).substr(0, colorStr.length - 5).split(",")).call(_context11, function (value) {
7977 return _parseInt(value);
7978 });
7979
7980 colorStr = RGBToHex(rgb[0], rgb[1], rgb[2]);
7981 }
7982
7983 if (isValidHex(colorStr) === true) {
7984 var hsv = hexToHSV(colorStr);
7985 var lighterColorHSV = {
7986 h: hsv.h,
7987 s: hsv.s * 0.8,
7988 v: Math.min(1, hsv.v * 1.02)
7989 };
7990 var darkerColorHSV = {
7991 h: hsv.h,
7992 s: Math.min(1, hsv.s * 1.25),
7993 v: hsv.v * 0.8
7994 };
7995 var darkerColorHex = HSVToHex(darkerColorHSV.h, darkerColorHSV.s, darkerColorHSV.v);
7996 var lighterColorHex = HSVToHex(lighterColorHSV.h, lighterColorHSV.s, lighterColorHSV.v);
7997 return {
7998 background: colorStr,
7999 border: darkerColorHex,
8000 highlight: {
8001 background: lighterColorHex,
8002 border: darkerColorHex
8003 },
8004 hover: {
8005 background: lighterColorHex,
8006 border: darkerColorHex
8007 }
8008 };
8009 } else {
8010 return {
8011 background: colorStr,
8012 border: colorStr,
8013 highlight: {
8014 background: colorStr,
8015 border: colorStr
8016 },
8017 hover: {
8018 background: colorStr,
8019 border: colorStr
8020 }
8021 };
8022 }
8023 } else {
8024 if (defaultColor) {
8025 var color = {
8026 background: inputColor.background || defaultColor.background,
8027 border: inputColor.border || defaultColor.border,
8028 highlight: isString(inputColor.highlight) ? {
8029 border: inputColor.highlight,
8030 background: inputColor.highlight
8031 } : {
8032 background: inputColor.highlight && inputColor.highlight.background || defaultColor.highlight.background,
8033 border: inputColor.highlight && inputColor.highlight.border || defaultColor.highlight.border
8034 },
8035 hover: isString(inputColor.hover) ? {
8036 border: inputColor.hover,
8037 background: inputColor.hover
8038 } : {
8039 border: inputColor.hover && inputColor.hover.border || defaultColor.hover.border,
8040 background: inputColor.hover && inputColor.hover.background || defaultColor.hover.background
8041 }
8042 };
8043 return color;
8044 } else {
8045 var _color = {
8046 background: inputColor.background || undefined,
8047 border: inputColor.border || undefined,
8048 highlight: isString(inputColor.highlight) ? {
8049 border: inputColor.highlight,
8050 background: inputColor.highlight
8051 } : {
8052 background: inputColor.highlight && inputColor.highlight.background || undefined,
8053 border: inputColor.highlight && inputColor.highlight.border || undefined
8054 },
8055 hover: isString(inputColor.hover) ? {
8056 border: inputColor.hover,
8057 background: inputColor.hover
8058 } : {
8059 border: inputColor.hover && inputColor.hover.border || undefined,
8060 background: inputColor.hover && inputColor.hover.background || undefined
8061 }
8062 };
8063 return _color;
8064 }
8065 }
8066 }
8067 /**
8068 * Convert RGB \<0, 255\> into HSV object.
8069 *
8070 * @remarks
8071 * {@link http://www.javascripter.net/faq/rgb2hsv.htm}
8072 *
8073 * @param red - Red channel.
8074 * @param green - Green channel.
8075 * @param blue - Blue channel.
8076 *
8077 * @returns HSV color object.
8078 */
8079
8080
8081 function RGBToHSV(red, green, blue) {
8082 red = red / 255;
8083 green = green / 255;
8084 blue = blue / 255;
8085 var minRGB = Math.min(red, Math.min(green, blue));
8086 var maxRGB = Math.max(red, Math.max(green, blue)); // Black-gray-white
8087
8088 if (minRGB === maxRGB) {
8089 return {
8090 h: 0,
8091 s: 0,
8092 v: minRGB
8093 };
8094 } // Colors other than black-gray-white:
8095
8096
8097 var d = red === minRGB ? green - blue : blue === minRGB ? red - green : blue - red;
8098 var h = red === minRGB ? 3 : blue === minRGB ? 1 : 5;
8099 var hue = 60 * (h - d / (maxRGB - minRGB)) / 360;
8100 var saturation = (maxRGB - minRGB) / maxRGB;
8101 var value = maxRGB;
8102 return {
8103 h: hue,
8104 s: saturation,
8105 v: value
8106 };
8107 }
8108 /**
8109 * Convert HSV \<0, 1\> into RGB color object.
8110 *
8111 * @remarks
8112 * {@link https://gist.github.com/mjijackson/5311256}
8113 *
8114 * @param h - Hue.
8115 * @param s - Saturation.
8116 * @param v - Value.
8117 *
8118 * @returns RGB color object.
8119 */
8120
8121
8122 function HSVToRGB(h, s, v) {
8123 var r;
8124 var g;
8125 var b;
8126 var i = Math.floor(h * 6);
8127 var f = h * 6 - i;
8128 var p = v * (1 - s);
8129 var q = v * (1 - f * s);
8130 var t = v * (1 - (1 - f) * s);
8131
8132 switch (i % 6) {
8133 case 0:
8134 r = v, g = t, b = p;
8135 break;
8136
8137 case 1:
8138 r = q, g = v, b = p;
8139 break;
8140
8141 case 2:
8142 r = p, g = v, b = t;
8143 break;
8144
8145 case 3:
8146 r = p, g = q, b = v;
8147 break;
8148
8149 case 4:
8150 r = t, g = p, b = v;
8151 break;
8152
8153 case 5:
8154 r = v, g = p, b = q;
8155 break;
8156 }
8157
8158 return {
8159 r: Math.floor(r * 255),
8160 g: Math.floor(g * 255),
8161 b: Math.floor(b * 255)
8162 };
8163 }
8164 /**
8165 * Convert HSV \<0, 1\> into hex color string.
8166 *
8167 * @param h - Hue.
8168 * @param s - Saturation.
8169 * @param v - Value.
8170 *
8171 * @returns Hex color string.
8172 */
8173
8174
8175 function HSVToHex(h, s, v) {
8176 var rgb = HSVToRGB(h, s, v);
8177 return RGBToHex(rgb.r, rgb.g, rgb.b);
8178 }
8179 /**
8180 * Convert hex color string into HSV \<0, 1\>.
8181 *
8182 * @param hex - Hex color string.
8183 *
8184 * @returns HSV color object.
8185 */
8186
8187
8188 function hexToHSV(hex) {
8189 var rgb = hexToRGB(hex);
8190
8191 if (!rgb) {
8192 throw new TypeError("'".concat(hex, "' is not a valid color."));
8193 }
8194
8195 return RGBToHSV(rgb.r, rgb.g, rgb.b);
8196 }
8197 /**
8198 * Validate hex color string.
8199 *
8200 * @param hex - Unknown string that may contain a color.
8201 *
8202 * @returns True if the string is valid, false otherwise.
8203 */
8204
8205
8206 function isValidHex(hex) {
8207 var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex);
8208 return isOk;
8209 }
8210 /**
8211 * Validate RGB color string.
8212 *
8213 * @param rgb - Unknown string that may contain a color.
8214 *
8215 * @returns True if the string is valid, false otherwise.
8216 */
8217
8218
8219 function isValidRGB(rgb) {
8220 return rgbRE.test(rgb);
8221 }
8222 /**
8223 * Validate RGBA color string.
8224 *
8225 * @param rgba - Unknown string that may contain a color.
8226 *
8227 * @returns True if the string is valid, false otherwise.
8228 */
8229
8230
8231 function isValidRGBA(rgba) {
8232 return rgbaRE.test(rgba);
8233 }
8234 /**
8235 * This recursively redirects the prototype of JSON objects to the referenceObject.
8236 * This is used for default options.
8237 *
8238 * @param referenceObject - The original object.
8239 *
8240 * @returns The Element if the referenceObject is an Element, or a new object inheriting from the referenceObject.
8241 */
8242
8243
8244 function bridgeObject(referenceObject) {
8245 if (referenceObject === null || _typeof(referenceObject) !== "object") {
8246 return null;
8247 }
8248
8249 if (referenceObject instanceof Element) {
8250 // Avoid bridging DOM objects
8251 return referenceObject;
8252 }
8253
8254 var objectTo = create$4(referenceObject);
8255
8256 for (var i in referenceObject) {
8257 if (Object.prototype.hasOwnProperty.call(referenceObject, i)) {
8258 if (_typeof(referenceObject[i]) == "object") {
8259 objectTo[i] = bridgeObject(referenceObject[i]);
8260 }
8261 }
8262 }
8263
8264 return objectTo;
8265 }
8266 /**
8267 * This is used to set the options of subobjects in the options object.
8268 *
8269 * A requirement of these subobjects is that they have an 'enabled' element
8270 * which is optional for the user but mandatory for the program.
8271 *
8272 * The added value here of the merge is that option 'enabled' is set as required.
8273 *
8274 * @param mergeTarget - Either this.options or the options used for the groups.
8275 * @param options - Options.
8276 * @param option - Option key in the options argument.
8277 * @param globalOptions - Global options, passed in to determine value of option 'enabled'.
8278 */
8279
8280
8281 function mergeOptions(mergeTarget, options, option) {
8282 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
8283
8284 // Local helpers
8285 var isPresent = function isPresent(obj) {
8286 return obj !== null && obj !== undefined;
8287 };
8288
8289 var isObject = function isObject(obj) {
8290 return obj !== null && _typeof(obj) === "object";
8291 }; // https://stackoverflow.com/a/34491287/1223531
8292
8293
8294 var isEmpty = function isEmpty(obj) {
8295 for (var x in obj) {
8296 if (Object.prototype.hasOwnProperty.call(obj, x)) {
8297 return false;
8298 }
8299 }
8300
8301 return true;
8302 }; // Guards
8303
8304
8305 if (!isObject(mergeTarget)) {
8306 throw new Error("Parameter mergeTarget must be an object");
8307 }
8308
8309 if (!isObject(options)) {
8310 throw new Error("Parameter options must be an object");
8311 }
8312
8313 if (!isPresent(option)) {
8314 throw new Error("Parameter option must have a value");
8315 }
8316
8317 if (!isObject(globalOptions)) {
8318 throw new Error("Parameter globalOptions must be an object");
8319 } //
8320 // Actual merge routine, separated from main logic
8321 // Only a single level of options is merged. Deeper levels are ref'd. This may actually be an issue.
8322 //
8323
8324
8325 var doMerge = function doMerge(target, options, option) {
8326 if (!isObject(target[option])) {
8327 target[option] = {};
8328 }
8329
8330 var src = options[option];
8331 var dst = target[option];
8332
8333 for (var prop in src) {
8334 if (Object.prototype.hasOwnProperty.call(src, prop)) {
8335 dst[prop] = src[prop];
8336 }
8337 }
8338 }; // Local initialization
8339
8340
8341 var srcOption = options[option];
8342 var globalPassed = isObject(globalOptions) && !isEmpty(globalOptions);
8343 var globalOption = globalPassed ? globalOptions[option] : undefined;
8344 var globalEnabled = globalOption ? globalOption.enabled : undefined; /////////////////////////////////////////
8345 // Main routine
8346 /////////////////////////////////////////
8347
8348 if (srcOption === undefined) {
8349 return; // Nothing to do
8350 }
8351
8352 if (typeof srcOption === "boolean") {
8353 if (!isObject(mergeTarget[option])) {
8354 mergeTarget[option] = {};
8355 }
8356
8357 mergeTarget[option].enabled = srcOption;
8358 return;
8359 }
8360
8361 if (srcOption === null && !isObject(mergeTarget[option])) {
8362 // If possible, explicit copy from globals
8363 if (isPresent(globalOption)) {
8364 mergeTarget[option] = create$4(globalOption);
8365 } else {
8366 return; // Nothing to do
8367 }
8368 }
8369
8370 if (!isObject(srcOption)) {
8371 return;
8372 } //
8373 // Ensure that 'enabled' is properly set. It is required internally
8374 // Note that the value from options will always overwrite the existing value
8375 //
8376
8377
8378 var enabled = true; // default value
8379
8380 if (srcOption.enabled !== undefined) {
8381 enabled = srcOption.enabled;
8382 } else {
8383 // Take from globals, if present
8384 if (globalEnabled !== undefined) {
8385 enabled = globalOption.enabled;
8386 }
8387 }
8388
8389 doMerge(mergeTarget, options, option);
8390 mergeTarget[option].enabled = enabled;
8391 }
8392 /*
8393 * Easing Functions.
8394 * Only considering the t value for the range [0, 1] => [0, 1].
8395 *
8396 * Inspiration: from http://gizma.com/easing/
8397 * https://gist.github.com/gre/1650294
8398 */
8399
8400
8401 var easingFunctions = {
8402 /**
8403 * Provides no easing and no acceleration.
8404 *
8405 * @param t - Time.
8406 *
8407 * @returns Value at time t.
8408 */
8409 linear: function linear(t) {
8410 return t;
8411 },
8412
8413 /**
8414 * Accelerate from zero velocity.
8415 *
8416 * @param t - Time.
8417 *
8418 * @returns Value at time t.
8419 */
8420 easeInQuad: function easeInQuad(t) {
8421 return t * t;
8422 },
8423
8424 /**
8425 * Decelerate to zero velocity.
8426 *
8427 * @param t - Time.
8428 *
8429 * @returns Value at time t.
8430 */
8431 easeOutQuad: function easeOutQuad(t) {
8432 return t * (2 - t);
8433 },
8434
8435 /**
8436 * Accelerate until halfway, then decelerate.
8437 *
8438 * @param t - Time.
8439 *
8440 * @returns Value at time t.
8441 */
8442 easeInOutQuad: function easeInOutQuad(t) {
8443 return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
8444 },
8445
8446 /**
8447 * Accelerate from zero velocity.
8448 *
8449 * @param t - Time.
8450 *
8451 * @returns Value at time t.
8452 */
8453 easeInCubic: function easeInCubic(t) {
8454 return t * t * t;
8455 },
8456
8457 /**
8458 * Decelerate to zero velocity.
8459 *
8460 * @param t - Time.
8461 *
8462 * @returns Value at time t.
8463 */
8464 easeOutCubic: function easeOutCubic(t) {
8465 return --t * t * t + 1;
8466 },
8467
8468 /**
8469 * Accelerate until halfway, then decelerate.
8470 *
8471 * @param t - Time.
8472 *
8473 * @returns Value at time t.
8474 */
8475 easeInOutCubic: function easeInOutCubic(t) {
8476 return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
8477 },
8478
8479 /**
8480 * Accelerate from zero velocity.
8481 *
8482 * @param t - Time.
8483 *
8484 * @returns Value at time t.
8485 */
8486 easeInQuart: function easeInQuart(t) {
8487 return t * t * t * t;
8488 },
8489
8490 /**
8491 * Decelerate to zero velocity.
8492 *
8493 * @param t - Time.
8494 *
8495 * @returns Value at time t.
8496 */
8497 easeOutQuart: function easeOutQuart(t) {
8498 return 1 - --t * t * t * t;
8499 },
8500
8501 /**
8502 * Accelerate until halfway, then decelerate.
8503 *
8504 * @param t - Time.
8505 *
8506 * @returns Value at time t.
8507 */
8508 easeInOutQuart: function easeInOutQuart(t) {
8509 return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
8510 },
8511
8512 /**
8513 * Accelerate from zero velocity.
8514 *
8515 * @param t - Time.
8516 *
8517 * @returns Value at time t.
8518 */
8519 easeInQuint: function easeInQuint(t) {
8520 return t * t * t * t * t;
8521 },
8522
8523 /**
8524 * Decelerate to zero velocity.
8525 *
8526 * @param t - Time.
8527 *
8528 * @returns Value at time t.
8529 */
8530 easeOutQuint: function easeOutQuint(t) {
8531 return 1 + --t * t * t * t * t;
8532 },
8533
8534 /**
8535 * Accelerate until halfway, then decelerate.
8536 *
8537 * @param t - Time.
8538 *
8539 * @returns Value at time t.
8540 */
8541 easeInOutQuint: function easeInOutQuint(t) {
8542 return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
8543 }
8544 };
8545 // It works only for single property objects,
8546 // otherwise it combines all of the types in a union.
8547 // export function topMost<K1 extends string, V1> (
8548 // pile: Record<K1, undefined | V1>[],
8549 // accessors: K1 | [K1]
8550 // ): undefined | V1
8551 // export function topMost<K1 extends string, K2 extends string, V1, V2> (
8552 // pile: Record<K1, undefined | V1 | Record<K2, undefined | V2>>[],
8553 // accessors: [K1, K2]
8554 // ): undefined | V1 | V2
8555 // export function topMost<K1 extends string, K2 extends string, K3 extends string, V1, V2, V3> (
8556 // pile: Record<K1, undefined | V1 | Record<K2, undefined | V2 | Record<K3, undefined | V3>>>[],
8557 // accessors: [K1, K2, K3]
8558 // ): undefined | V1 | V2 | V3
8559
8560 /**
8561 * Get the top most property value from a pile of objects.
8562 *
8563 * @param pile - Array of objects, no required format.
8564 * @param accessors - Array of property names.
8565 * For example `object['foo']['bar']` → `['foo', 'bar']`.
8566 *
8567 * @returns Value of the property with given accessors path from the first pile item where it's not undefined.
8568 */
8569
8570
8571 function topMost(pile, accessors) {
8572 var candidate;
8573
8574 if (!isArray$1(accessors)) {
8575 accessors = [accessors];
8576 }
8577
8578 var _iterator3 = _createForOfIteratorHelper$7(pile),
8579 _step3;
8580
8581 try {
8582 for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
8583 var member = _step3.value;
8584
8585 if (member) {
8586 candidate = member[accessors[0]];
8587
8588 for (var i = 1; i < accessors.length; i++) {
8589 if (candidate) {
8590 candidate = candidate[accessors[i]];
8591 }
8592 }
8593
8594 if (typeof candidate !== "undefined") {
8595 break;
8596 }
8597 }
8598 }
8599 } catch (err) {
8600 _iterator3.e(err);
8601 } finally {
8602 _iterator3.f();
8603 }
8604
8605 return candidate;
8606 }
8607
8608 var htmlColors = {
8609 black: "#000000",
8610 navy: "#000080",
8611 darkblue: "#00008B",
8612 mediumblue: "#0000CD",
8613 blue: "#0000FF",
8614 darkgreen: "#006400",
8615 green: "#008000",
8616 teal: "#008080",
8617 darkcyan: "#008B8B",
8618 deepskyblue: "#00BFFF",
8619 darkturquoise: "#00CED1",
8620 mediumspringgreen: "#00FA9A",
8621 lime: "#00FF00",
8622 springgreen: "#00FF7F",
8623 aqua: "#00FFFF",
8624 cyan: "#00FFFF",
8625 midnightblue: "#191970",
8626 dodgerblue: "#1E90FF",
8627 lightseagreen: "#20B2AA",
8628 forestgreen: "#228B22",
8629 seagreen: "#2E8B57",
8630 darkslategray: "#2F4F4F",
8631 limegreen: "#32CD32",
8632 mediumseagreen: "#3CB371",
8633 turquoise: "#40E0D0",
8634 royalblue: "#4169E1",
8635 steelblue: "#4682B4",
8636 darkslateblue: "#483D8B",
8637 mediumturquoise: "#48D1CC",
8638 indigo: "#4B0082",
8639 darkolivegreen: "#556B2F",
8640 cadetblue: "#5F9EA0",
8641 cornflowerblue: "#6495ED",
8642 mediumaquamarine: "#66CDAA",
8643 dimgray: "#696969",
8644 slateblue: "#6A5ACD",
8645 olivedrab: "#6B8E23",
8646 slategray: "#708090",
8647 lightslategray: "#778899",
8648 mediumslateblue: "#7B68EE",
8649 lawngreen: "#7CFC00",
8650 chartreuse: "#7FFF00",
8651 aquamarine: "#7FFFD4",
8652 maroon: "#800000",
8653 purple: "#800080",
8654 olive: "#808000",
8655 gray: "#808080",
8656 skyblue: "#87CEEB",
8657 lightskyblue: "#87CEFA",
8658 blueviolet: "#8A2BE2",
8659 darkred: "#8B0000",
8660 darkmagenta: "#8B008B",
8661 saddlebrown: "#8B4513",
8662 darkseagreen: "#8FBC8F",
8663 lightgreen: "#90EE90",
8664 mediumpurple: "#9370D8",
8665 darkviolet: "#9400D3",
8666 palegreen: "#98FB98",
8667 darkorchid: "#9932CC",
8668 yellowgreen: "#9ACD32",
8669 sienna: "#A0522D",
8670 brown: "#A52A2A",
8671 darkgray: "#A9A9A9",
8672 lightblue: "#ADD8E6",
8673 greenyellow: "#ADFF2F",
8674 paleturquoise: "#AFEEEE",
8675 lightsteelblue: "#B0C4DE",
8676 powderblue: "#B0E0E6",
8677 firebrick: "#B22222",
8678 darkgoldenrod: "#B8860B",
8679 mediumorchid: "#BA55D3",
8680 rosybrown: "#BC8F8F",
8681 darkkhaki: "#BDB76B",
8682 silver: "#C0C0C0",
8683 mediumvioletred: "#C71585",
8684 indianred: "#CD5C5C",
8685 peru: "#CD853F",
8686 chocolate: "#D2691E",
8687 tan: "#D2B48C",
8688 lightgrey: "#D3D3D3",
8689 palevioletred: "#D87093",
8690 thistle: "#D8BFD8",
8691 orchid: "#DA70D6",
8692 goldenrod: "#DAA520",
8693 crimson: "#DC143C",
8694 gainsboro: "#DCDCDC",
8695 plum: "#DDA0DD",
8696 burlywood: "#DEB887",
8697 lightcyan: "#E0FFFF",
8698 lavender: "#E6E6FA",
8699 darksalmon: "#E9967A",
8700 violet: "#EE82EE",
8701 palegoldenrod: "#EEE8AA",
8702 lightcoral: "#F08080",
8703 khaki: "#F0E68C",
8704 aliceblue: "#F0F8FF",
8705 honeydew: "#F0FFF0",
8706 azure: "#F0FFFF",
8707 sandybrown: "#F4A460",
8708 wheat: "#F5DEB3",
8709 beige: "#F5F5DC",
8710 whitesmoke: "#F5F5F5",
8711 mintcream: "#F5FFFA",
8712 ghostwhite: "#F8F8FF",
8713 salmon: "#FA8072",
8714 antiquewhite: "#FAEBD7",
8715 linen: "#FAF0E6",
8716 lightgoldenrodyellow: "#FAFAD2",
8717 oldlace: "#FDF5E6",
8718 red: "#FF0000",
8719 fuchsia: "#FF00FF",
8720 magenta: "#FF00FF",
8721 deeppink: "#FF1493",
8722 orangered: "#FF4500",
8723 tomato: "#FF6347",
8724 hotpink: "#FF69B4",
8725 coral: "#FF7F50",
8726 darkorange: "#FF8C00",
8727 lightsalmon: "#FFA07A",
8728 orange: "#FFA500",
8729 lightpink: "#FFB6C1",
8730 pink: "#FFC0CB",
8731 gold: "#FFD700",
8732 peachpuff: "#FFDAB9",
8733 navajowhite: "#FFDEAD",
8734 moccasin: "#FFE4B5",
8735 bisque: "#FFE4C4",
8736 mistyrose: "#FFE4E1",
8737 blanchedalmond: "#FFEBCD",
8738 papayawhip: "#FFEFD5",
8739 lavenderblush: "#FFF0F5",
8740 seashell: "#FFF5EE",
8741 cornsilk: "#FFF8DC",
8742 lemonchiffon: "#FFFACD",
8743 floralwhite: "#FFFAF0",
8744 snow: "#FFFAFA",
8745 yellow: "#FFFF00",
8746 lightyellow: "#FFFFE0",
8747 ivory: "#FFFFF0",
8748 white: "#FFFFFF"
8749 };
8750 /**
8751 * @param {number} [pixelRatio=1]
8752 */
8753
8754 var ColorPicker = /*#__PURE__*/function () {
8755 /**
8756 * @param {number} [pixelRatio=1]
8757 */
8758 function ColorPicker() {
8759 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
8760
8761 _classCallCheck(this, ColorPicker);
8762
8763 this.pixelRatio = pixelRatio;
8764 this.generated = false;
8765 this.centerCoordinates = {
8766 x: 289 / 2,
8767 y: 289 / 2
8768 };
8769 this.r = 289 * 0.49;
8770 this.color = {
8771 r: 255,
8772 g: 255,
8773 b: 255,
8774 a: 1.0
8775 };
8776 this.hueCircle = undefined;
8777 this.initialColor = {
8778 r: 255,
8779 g: 255,
8780 b: 255,
8781 a: 1.0
8782 };
8783 this.previousColor = undefined;
8784 this.applied = false; // bound by
8785
8786 this.updateCallback = function () {};
8787
8788 this.closeCallback = function () {}; // create all DOM elements
8789
8790
8791 this._create();
8792 }
8793 /**
8794 * this inserts the colorPicker into a div from the DOM
8795 *
8796 * @param {Element} container
8797 */
8798
8799
8800 _createClass(ColorPicker, [{
8801 key: "insertTo",
8802 value: function insertTo(container) {
8803 if (this.hammer !== undefined) {
8804 this.hammer.destroy();
8805 this.hammer = undefined;
8806 }
8807
8808 this.container = container;
8809 this.container.appendChild(this.frame);
8810
8811 this._bindHammer();
8812
8813 this._setSize();
8814 }
8815 /**
8816 * the callback is executed on apply and save. Bind it to the application
8817 *
8818 * @param {Function} callback
8819 */
8820
8821 }, {
8822 key: "setUpdateCallback",
8823 value: function setUpdateCallback(callback) {
8824 if (typeof callback === "function") {
8825 this.updateCallback = callback;
8826 } else {
8827 throw new Error("Function attempted to set as colorPicker update callback is not a function.");
8828 }
8829 }
8830 /**
8831 * the callback is executed on apply and save. Bind it to the application
8832 *
8833 * @param {Function} callback
8834 */
8835
8836 }, {
8837 key: "setCloseCallback",
8838 value: function setCloseCallback(callback) {
8839 if (typeof callback === "function") {
8840 this.closeCallback = callback;
8841 } else {
8842 throw new Error("Function attempted to set as colorPicker closing callback is not a function.");
8843 }
8844 }
8845 /**
8846 *
8847 * @param {string} color
8848 * @returns {string}
8849 * @private
8850 */
8851
8852 }, {
8853 key: "_isColorString",
8854 value: function _isColorString(color) {
8855 if (typeof color === "string") {
8856 return htmlColors[color];
8857 }
8858 }
8859 /**
8860 * Set the color of the colorPicker
8861 * Supported formats:
8862 * 'red' --> HTML color string
8863 * '#ffffff' --> hex string
8864 * 'rgb(255,255,255)' --> rgb string
8865 * 'rgba(255,255,255,1.0)' --> rgba string
8866 * {r:255,g:255,b:255} --> rgb object
8867 * {r:255,g:255,b:255,a:1.0} --> rgba object
8868 *
8869 * @param {string | object} color
8870 * @param {boolean} [setInitial=true]
8871 */
8872
8873 }, {
8874 key: "setColor",
8875 value: function setColor(color) {
8876 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
8877
8878 if (color === "none") {
8879 return;
8880 }
8881
8882 var rgba; // if a html color shorthand is used, convert to hex
8883
8884 var htmlColor = this._isColorString(color);
8885
8886 if (htmlColor !== undefined) {
8887 color = htmlColor;
8888 } // check format
8889
8890
8891 if (isString(color) === true) {
8892 if (isValidRGB(color) === true) {
8893 var rgbaArray = color.substr(4).substr(0, color.length - 5).split(",");
8894 rgba = {
8895 r: rgbaArray[0],
8896 g: rgbaArray[1],
8897 b: rgbaArray[2],
8898 a: 1.0
8899 };
8900 } else if (isValidRGBA(color) === true) {
8901 var _rgbaArray = color.substr(5).substr(0, color.length - 6).split(",");
8902
8903 rgba = {
8904 r: _rgbaArray[0],
8905 g: _rgbaArray[1],
8906 b: _rgbaArray[2],
8907 a: _rgbaArray[3]
8908 };
8909 } else if (isValidHex(color) === true) {
8910 var rgbObj = hexToRGB(color);
8911 rgba = {
8912 r: rgbObj.r,
8913 g: rgbObj.g,
8914 b: rgbObj.b,
8915 a: 1.0
8916 };
8917 }
8918 } else {
8919 if (color instanceof Object) {
8920 if (color.r !== undefined && color.g !== undefined && color.b !== undefined) {
8921 var alpha = color.a !== undefined ? color.a : "1.0";
8922 rgba = {
8923 r: color.r,
8924 g: color.g,
8925 b: color.b,
8926 a: alpha
8927 };
8928 }
8929 }
8930 } // set color
8931
8932
8933 if (rgba === undefined) {
8934 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));
8935 } else {
8936 this._setColor(rgba, setInitial);
8937 }
8938 }
8939 /**
8940 * this shows the color picker.
8941 * The hue circle is constructed once and stored.
8942 */
8943
8944 }, {
8945 key: "show",
8946 value: function show() {
8947 if (this.closeCallback !== undefined) {
8948 this.closeCallback();
8949 this.closeCallback = undefined;
8950 }
8951
8952 this.applied = false;
8953 this.frame.style.display = "block";
8954
8955 this._generateHueCircle();
8956 } // ------------------------------------------ PRIVATE ----------------------------- //
8957
8958 /**
8959 * Hide the picker. Is called by the cancel button.
8960 * Optional boolean to store the previous color for easy access later on.
8961 *
8962 * @param {boolean} [storePrevious=true]
8963 * @private
8964 */
8965
8966 }, {
8967 key: "_hide",
8968 value: function _hide() {
8969 var _this2 = this;
8970
8971 var storePrevious = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
8972
8973 // store the previous color for next time;
8974 if (storePrevious === true) {
8975 this.previousColor = assign$2({}, this.color);
8976 }
8977
8978 if (this.applied === true) {
8979 this.updateCallback(this.initialColor);
8980 }
8981
8982 this.frame.style.display = "none"; // call the closing callback, restoring the onclick method.
8983 // this is in a setTimeout because it will trigger the show again before the click is done.
8984
8985 setTimeout$1(function () {
8986 if (_this2.closeCallback !== undefined) {
8987 _this2.closeCallback();
8988
8989 _this2.closeCallback = undefined;
8990 }
8991 }, 0);
8992 }
8993 /**
8994 * bound to the save button. Saves and hides.
8995 *
8996 * @private
8997 */
8998
8999 }, {
9000 key: "_save",
9001 value: function _save() {
9002 this.updateCallback(this.color);
9003 this.applied = false;
9004
9005 this._hide();
9006 }
9007 /**
9008 * Bound to apply button. Saves but does not close. Is undone by the cancel button.
9009 *
9010 * @private
9011 */
9012
9013 }, {
9014 key: "_apply",
9015 value: function _apply() {
9016 this.applied = true;
9017 this.updateCallback(this.color);
9018
9019 this._updatePicker(this.color);
9020 }
9021 /**
9022 * load the color from the previous session.
9023 *
9024 * @private
9025 */
9026
9027 }, {
9028 key: "_loadLast",
9029 value: function _loadLast() {
9030 if (this.previousColor !== undefined) {
9031 this.setColor(this.previousColor, false);
9032 } else {
9033 alert("There is no last color to load...");
9034 }
9035 }
9036 /**
9037 * set the color, place the picker
9038 *
9039 * @param {object} rgba
9040 * @param {boolean} [setInitial=true]
9041 * @private
9042 */
9043
9044 }, {
9045 key: "_setColor",
9046 value: function _setColor(rgba) {
9047 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
9048
9049 // store the initial color
9050 if (setInitial === true) {
9051 this.initialColor = assign$2({}, rgba);
9052 }
9053
9054 this.color = rgba;
9055 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
9056 var angleConvert = 2 * Math.PI;
9057 var radius = this.r * hsv.s;
9058 var x = this.centerCoordinates.x + radius * Math.sin(angleConvert * hsv.h);
9059 var y = this.centerCoordinates.y + radius * Math.cos(angleConvert * hsv.h);
9060 this.colorPickerSelector.style.left = x - 0.5 * this.colorPickerSelector.clientWidth + "px";
9061 this.colorPickerSelector.style.top = y - 0.5 * this.colorPickerSelector.clientHeight + "px";
9062
9063 this._updatePicker(rgba);
9064 }
9065 /**
9066 * bound to opacity control
9067 *
9068 * @param {number} value
9069 * @private
9070 */
9071
9072 }, {
9073 key: "_setOpacity",
9074 value: function _setOpacity(value) {
9075 this.color.a = value / 100;
9076
9077 this._updatePicker(this.color);
9078 }
9079 /**
9080 * bound to brightness control
9081 *
9082 * @param {number} value
9083 * @private
9084 */
9085
9086 }, {
9087 key: "_setBrightness",
9088 value: function _setBrightness(value) {
9089 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
9090 hsv.v = value / 100;
9091 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
9092 rgba["a"] = this.color.a;
9093 this.color = rgba;
9094
9095 this._updatePicker();
9096 }
9097 /**
9098 * update the color picker. A black circle overlays the hue circle to mimic the brightness decreasing.
9099 *
9100 * @param {object} rgba
9101 * @private
9102 */
9103
9104 }, {
9105 key: "_updatePicker",
9106 value: function _updatePicker() {
9107 var rgba = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.color;
9108 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
9109 var ctx = this.colorPickerCanvas.getContext("2d");
9110
9111 if (this.pixelRation === undefined) {
9112 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
9113 }
9114
9115 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
9116
9117 var w = this.colorPickerCanvas.clientWidth;
9118 var h = this.colorPickerCanvas.clientHeight;
9119 ctx.clearRect(0, 0, w, h);
9120 ctx.putImageData(this.hueCircle, 0, 0);
9121 ctx.fillStyle = "rgba(0,0,0," + (1 - hsv.v) + ")";
9122 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
9123
9124 fill(ctx).call(ctx);
9125
9126 this.brightnessRange.value = 100 * hsv.v;
9127 this.opacityRange.value = 100 * rgba.a;
9128 this.initialColorDiv.style.backgroundColor = "rgba(" + this.initialColor.r + "," + this.initialColor.g + "," + this.initialColor.b + "," + this.initialColor.a + ")";
9129 this.newColorDiv.style.backgroundColor = "rgba(" + this.color.r + "," + this.color.g + "," + this.color.b + "," + this.color.a + ")";
9130 }
9131 /**
9132 * used by create to set the size of the canvas.
9133 *
9134 * @private
9135 */
9136
9137 }, {
9138 key: "_setSize",
9139 value: function _setSize() {
9140 this.colorPickerCanvas.style.width = "100%";
9141 this.colorPickerCanvas.style.height = "100%";
9142 this.colorPickerCanvas.width = 289 * this.pixelRatio;
9143 this.colorPickerCanvas.height = 289 * this.pixelRatio;
9144 }
9145 /**
9146 * create all dom elements
9147 * TODO: cleanup, lots of similar dom elements
9148 *
9149 * @private
9150 */
9151
9152 }, {
9153 key: "_create",
9154 value: function _create() {
9155 var _context16, _context17, _context18, _context19;
9156
9157 this.frame = document.createElement("div");
9158 this.frame.className = "vis-color-picker";
9159 this.colorPickerDiv = document.createElement("div");
9160 this.colorPickerSelector = document.createElement("div");
9161 this.colorPickerSelector.className = "vis-selector";
9162 this.colorPickerDiv.appendChild(this.colorPickerSelector);
9163 this.colorPickerCanvas = document.createElement("canvas");
9164 this.colorPickerDiv.appendChild(this.colorPickerCanvas);
9165
9166 if (!this.colorPickerCanvas.getContext) {
9167 var noCanvas = document.createElement("DIV");
9168 noCanvas.style.color = "red";
9169 noCanvas.style.fontWeight = "bold";
9170 noCanvas.style.padding = "10px";
9171 noCanvas.innerText = "Error: your browser does not support HTML canvas";
9172 this.colorPickerCanvas.appendChild(noCanvas);
9173 } else {
9174 var ctx = this.colorPickerCanvas.getContext("2d");
9175 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
9176 this.colorPickerCanvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
9177 }
9178
9179 this.colorPickerDiv.className = "vis-color";
9180 this.opacityDiv = document.createElement("div");
9181 this.opacityDiv.className = "vis-opacity";
9182 this.brightnessDiv = document.createElement("div");
9183 this.brightnessDiv.className = "vis-brightness";
9184 this.arrowDiv = document.createElement("div");
9185 this.arrowDiv.className = "vis-arrow";
9186 this.opacityRange = document.createElement("input");
9187
9188 try {
9189 this.opacityRange.type = "range"; // Not supported on IE9
9190
9191 this.opacityRange.min = "0";
9192 this.opacityRange.max = "100";
9193 } catch (err) {// TODO: Add some error handling.
9194 }
9195
9196 this.opacityRange.value = "100";
9197 this.opacityRange.className = "vis-range";
9198 this.brightnessRange = document.createElement("input");
9199
9200 try {
9201 this.brightnessRange.type = "range"; // Not supported on IE9
9202
9203 this.brightnessRange.min = "0";
9204 this.brightnessRange.max = "100";
9205 } catch (err) {// TODO: Add some error handling.
9206 }
9207
9208 this.brightnessRange.value = "100";
9209 this.brightnessRange.className = "vis-range";
9210 this.opacityDiv.appendChild(this.opacityRange);
9211 this.brightnessDiv.appendChild(this.brightnessRange);
9212 var me = this;
9213
9214 this.opacityRange.onchange = function () {
9215 me._setOpacity(this.value);
9216 };
9217
9218 this.opacityRange.oninput = function () {
9219 me._setOpacity(this.value);
9220 };
9221
9222 this.brightnessRange.onchange = function () {
9223 me._setBrightness(this.value);
9224 };
9225
9226 this.brightnessRange.oninput = function () {
9227 me._setBrightness(this.value);
9228 };
9229
9230 this.brightnessLabel = document.createElement("div");
9231 this.brightnessLabel.className = "vis-label vis-brightness";
9232 this.brightnessLabel.innerText = "brightness:";
9233 this.opacityLabel = document.createElement("div");
9234 this.opacityLabel.className = "vis-label vis-opacity";
9235 this.opacityLabel.innerText = "opacity:";
9236 this.newColorDiv = document.createElement("div");
9237 this.newColorDiv.className = "vis-new-color";
9238 this.newColorDiv.innerText = "new";
9239 this.initialColorDiv = document.createElement("div");
9240 this.initialColorDiv.className = "vis-initial-color";
9241 this.initialColorDiv.innerText = "initial";
9242 this.cancelButton = document.createElement("div");
9243 this.cancelButton.className = "vis-button vis-cancel";
9244 this.cancelButton.innerText = "cancel";
9245 this.cancelButton.onclick = bind$5(_context16 = this._hide).call(_context16, this, false);
9246 this.applyButton = document.createElement("div");
9247 this.applyButton.className = "vis-button vis-apply";
9248 this.applyButton.innerText = "apply";
9249 this.applyButton.onclick = bind$5(_context17 = this._apply).call(_context17, this);
9250 this.saveButton = document.createElement("div");
9251 this.saveButton.className = "vis-button vis-save";
9252 this.saveButton.innerText = "save";
9253 this.saveButton.onclick = bind$5(_context18 = this._save).call(_context18, this);
9254 this.loadButton = document.createElement("div");
9255 this.loadButton.className = "vis-button vis-load";
9256 this.loadButton.innerText = "load last";
9257 this.loadButton.onclick = bind$5(_context19 = this._loadLast).call(_context19, this);
9258 this.frame.appendChild(this.colorPickerDiv);
9259 this.frame.appendChild(this.arrowDiv);
9260 this.frame.appendChild(this.brightnessLabel);
9261 this.frame.appendChild(this.brightnessDiv);
9262 this.frame.appendChild(this.opacityLabel);
9263 this.frame.appendChild(this.opacityDiv);
9264 this.frame.appendChild(this.newColorDiv);
9265 this.frame.appendChild(this.initialColorDiv);
9266 this.frame.appendChild(this.cancelButton);
9267 this.frame.appendChild(this.applyButton);
9268 this.frame.appendChild(this.saveButton);
9269 this.frame.appendChild(this.loadButton);
9270 }
9271 /**
9272 * bind hammer to the color picker
9273 *
9274 * @private
9275 */
9276
9277 }, {
9278 key: "_bindHammer",
9279 value: function _bindHammer() {
9280 var _this3 = this;
9281
9282 this.drag = {};
9283 this.pinch = {};
9284 this.hammer = new Hammer(this.colorPickerCanvas);
9285 this.hammer.get("pinch").set({
9286 enable: true
9287 });
9288 this.hammer.on("hammer.input", function (event) {
9289 if (event.isFirst) {
9290 _this3._moveSelector(event);
9291 }
9292 });
9293 this.hammer.on("tap", function (event) {
9294 _this3._moveSelector(event);
9295 });
9296 this.hammer.on("panstart", function (event) {
9297 _this3._moveSelector(event);
9298 });
9299 this.hammer.on("panmove", function (event) {
9300 _this3._moveSelector(event);
9301 });
9302 this.hammer.on("panend", function (event) {
9303 _this3._moveSelector(event);
9304 });
9305 }
9306 /**
9307 * generate the hue circle. This is relatively heavy (200ms) and is done only once on the first time it is shown.
9308 *
9309 * @private
9310 */
9311
9312 }, {
9313 key: "_generateHueCircle",
9314 value: function _generateHueCircle() {
9315 if (this.generated === false) {
9316 var ctx = this.colorPickerCanvas.getContext("2d");
9317
9318 if (this.pixelRation === undefined) {
9319 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
9320 }
9321
9322 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
9323
9324 var w = this.colorPickerCanvas.clientWidth;
9325 var h = this.colorPickerCanvas.clientHeight;
9326 ctx.clearRect(0, 0, w, h); // draw hue circle
9327
9328 var x, y, hue, sat;
9329 this.centerCoordinates = {
9330 x: w * 0.5,
9331 y: h * 0.5
9332 };
9333 this.r = 0.49 * w;
9334 var angleConvert = 2 * Math.PI / 360;
9335 var hfac = 1 / 360;
9336 var sfac = 1 / this.r;
9337 var rgb;
9338
9339 for (hue = 0; hue < 360; hue++) {
9340 for (sat = 0; sat < this.r; sat++) {
9341 x = this.centerCoordinates.x + sat * Math.sin(angleConvert * hue);
9342 y = this.centerCoordinates.y + sat * Math.cos(angleConvert * hue);
9343 rgb = HSVToRGB(hue * hfac, sat * sfac, 1);
9344 ctx.fillStyle = "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")";
9345 ctx.fillRect(x - 0.5, y - 0.5, 2, 2);
9346 }
9347 }
9348
9349 ctx.strokeStyle = "rgba(0,0,0,1)";
9350 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
9351 ctx.stroke();
9352 this.hueCircle = ctx.getImageData(0, 0, w, h);
9353 }
9354
9355 this.generated = true;
9356 }
9357 /**
9358 * move the selector. This is called by hammer functions.
9359 *
9360 * @param {Event} event The event
9361 * @private
9362 */
9363
9364 }, {
9365 key: "_moveSelector",
9366 value: function _moveSelector(event) {
9367 var rect = this.colorPickerDiv.getBoundingClientRect();
9368 var left = event.center.x - rect.left;
9369 var top = event.center.y - rect.top;
9370 var centerY = 0.5 * this.colorPickerDiv.clientHeight;
9371 var centerX = 0.5 * this.colorPickerDiv.clientWidth;
9372 var x = left - centerX;
9373 var y = top - centerY;
9374 var angle = Math.atan2(x, y);
9375 var radius = 0.98 * Math.min(Math.sqrt(x * x + y * y), centerX);
9376 var newTop = Math.cos(angle) * radius + centerY;
9377 var newLeft = Math.sin(angle) * radius + centerX;
9378 this.colorPickerSelector.style.top = newTop - 0.5 * this.colorPickerSelector.clientHeight + "px";
9379 this.colorPickerSelector.style.left = newLeft - 0.5 * this.colorPickerSelector.clientWidth + "px"; // set color
9380
9381 var h = angle / (2 * Math.PI);
9382 h = h < 0 ? h + 1 : h;
9383 var s = radius / this.r;
9384 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
9385 hsv.h = h;
9386 hsv.s = s;
9387 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
9388 rgba["a"] = this.color.a;
9389 this.color = rgba; // update previews
9390
9391 this.initialColorDiv.style.backgroundColor = "rgba(" + this.initialColor.r + "," + this.initialColor.g + "," + this.initialColor.b + "," + this.initialColor.a + ")";
9392 this.newColorDiv.style.backgroundColor = "rgba(" + this.color.r + "," + this.color.g + "," + this.color.b + "," + this.color.a + ")";
9393 }
9394 }]);
9395
9396 return ColorPicker;
9397 }();
9398 /**
9399 * Wrap given text (last argument) in HTML elements (all preceding arguments).
9400 *
9401 * @param {...any} rest - List of tag names followed by inner text.
9402 *
9403 * @returns An element or a text node.
9404 */
9405
9406
9407 function wrapInTag() {
9408 for (var _len5 = arguments.length, rest = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
9409 rest[_key5] = arguments[_key5];
9410 }
9411
9412 if (rest.length < 1) {
9413 throw new TypeError("Invalid arguments.");
9414 } else if (rest.length === 1) {
9415 return document.createTextNode(rest[0]);
9416 } else {
9417 var element = document.createElement(rest[0]);
9418 element.appendChild(wrapInTag.apply(void 0, _toConsumableArray(slice$1(rest).call(rest, 1))));
9419 return element;
9420 }
9421 }
9422 /**
9423 * 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.
9424 * Boolean options are recognised as Boolean
9425 * Number options should be written as array: [default value, min value, max value, stepsize]
9426 * Colors should be written as array: ['color', '#ffffff']
9427 * Strings with should be written as array: [option1, option2, option3, ..]
9428 *
9429 * The options are matched with their counterparts in each of the modules and the values used in the configuration are
9430 */
9431
9432
9433 var Configurator = /*#__PURE__*/function () {
9434 /**
9435 * @param {object} parentModule | the location where parentModule.setOptions() can be called
9436 * @param {object} defaultContainer | the default container of the module
9437 * @param {object} configureOptions | the fully configured and predefined options set found in allOptions.js
9438 * @param {number} pixelRatio | canvas pixel ratio
9439 * @param {Function} hideOption | custom logic to dynamically hide options
9440 */
9441 function Configurator(parentModule, defaultContainer, configureOptions) {
9442 var pixelRatio = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
9443 var hideOption = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : function () {
9444 return false;
9445 };
9446
9447 _classCallCheck(this, Configurator);
9448
9449 this.parent = parentModule;
9450 this.changedOptions = [];
9451 this.container = defaultContainer;
9452 this.allowCreation = false;
9453 this.hideOption = hideOption;
9454 this.options = {};
9455 this.initialized = false;
9456 this.popupCounter = 0;
9457 this.defaultOptions = {
9458 enabled: false,
9459 filter: true,
9460 container: undefined,
9461 showButton: true
9462 };
9463
9464 assign$2(this.options, this.defaultOptions);
9465
9466 this.configureOptions = configureOptions;
9467 this.moduleOptions = {};
9468 this.domElements = [];
9469 this.popupDiv = {};
9470 this.popupLimit = 5;
9471 this.popupHistory = {};
9472 this.colorPicker = new ColorPicker(pixelRatio);
9473 this.wrapper = undefined;
9474 }
9475 /**
9476 * refresh all options.
9477 * Because all modules parse their options by themselves, we just use their options. We copy them here.
9478 *
9479 * @param {object} options
9480 */
9481
9482
9483 _createClass(Configurator, [{
9484 key: "setOptions",
9485 value: function setOptions(options) {
9486 if (options !== undefined) {
9487 // reset the popup history because the indices may have been changed.
9488 this.popupHistory = {};
9489
9490 this._removePopup();
9491
9492 var enabled = true;
9493
9494 if (typeof options === "string") {
9495 this.options.filter = options;
9496 } else if (isArray$1(options)) {
9497 this.options.filter = options.join();
9498 } else if (_typeof(options) === "object") {
9499 if (options == null) {
9500 throw new TypeError("options cannot be null");
9501 }
9502
9503 if (options.container !== undefined) {
9504 this.options.container = options.container;
9505 }
9506
9507 if (filter(options) !== undefined) {
9508 this.options.filter = filter(options);
9509 }
9510
9511 if (options.showButton !== undefined) {
9512 this.options.showButton = options.showButton;
9513 }
9514
9515 if (options.enabled !== undefined) {
9516 enabled = options.enabled;
9517 }
9518 } else if (typeof options === "boolean") {
9519 this.options.filter = true;
9520 enabled = options;
9521 } else if (typeof options === "function") {
9522 this.options.filter = options;
9523 enabled = true;
9524 }
9525
9526 if (filter(this.options) === false) {
9527 enabled = false;
9528 }
9529
9530 this.options.enabled = enabled;
9531 }
9532
9533 this._clean();
9534 }
9535 /**
9536 *
9537 * @param {object} moduleOptions
9538 */
9539
9540 }, {
9541 key: "setModuleOptions",
9542 value: function setModuleOptions(moduleOptions) {
9543 this.moduleOptions = moduleOptions;
9544
9545 if (this.options.enabled === true) {
9546 this._clean();
9547
9548 if (this.options.container !== undefined) {
9549 this.container = this.options.container;
9550 }
9551
9552 this._create();
9553 }
9554 }
9555 /**
9556 * Create all DOM elements
9557 *
9558 * @private
9559 */
9560
9561 }, {
9562 key: "_create",
9563 value: function _create() {
9564 this._clean();
9565
9566 this.changedOptions = [];
9567
9568 var filter$1 = filter(this.options);
9569
9570 var counter = 0;
9571 var show = false;
9572
9573 for (var _option in this.configureOptions) {
9574 if (Object.prototype.hasOwnProperty.call(this.configureOptions, _option)) {
9575 this.allowCreation = false;
9576 show = false;
9577
9578 if (typeof filter$1 === "function") {
9579 show = filter$1(_option, []);
9580 show = show || this._handleObject(this.configureOptions[_option], [_option], true);
9581 } else if (filter$1 === true || indexOf(filter$1).call(filter$1, _option) !== -1) {
9582 show = true;
9583 }
9584
9585 if (show !== false) {
9586 this.allowCreation = true; // linebreak between categories
9587
9588 if (counter > 0) {
9589 this._makeItem([]);
9590 } // a header for the category
9591
9592
9593 this._makeHeader(_option); // get the sub options
9594
9595
9596 this._handleObject(this.configureOptions[_option], [_option]);
9597 }
9598
9599 counter++;
9600 }
9601 }
9602
9603 this._makeButton();
9604
9605 this._push(); //~ this.colorPicker.insertTo(this.container);
9606
9607 }
9608 /**
9609 * draw all DOM elements on the screen
9610 *
9611 * @private
9612 */
9613
9614 }, {
9615 key: "_push",
9616 value: function _push() {
9617 this.wrapper = document.createElement("div");
9618 this.wrapper.className = "vis-configuration-wrapper";
9619 this.container.appendChild(this.wrapper);
9620
9621 for (var i = 0; i < this.domElements.length; i++) {
9622 this.wrapper.appendChild(this.domElements[i]);
9623 }
9624
9625 this._showPopupIfNeeded();
9626 }
9627 /**
9628 * delete all DOM elements
9629 *
9630 * @private
9631 */
9632
9633 }, {
9634 key: "_clean",
9635 value: function _clean() {
9636 for (var i = 0; i < this.domElements.length; i++) {
9637 this.wrapper.removeChild(this.domElements[i]);
9638 }
9639
9640 if (this.wrapper !== undefined) {
9641 this.container.removeChild(this.wrapper);
9642 this.wrapper = undefined;
9643 }
9644
9645 this.domElements = [];
9646
9647 this._removePopup();
9648 }
9649 /**
9650 * get the value from the actualOptions if it exists
9651 *
9652 * @param {Array} path | where to look for the actual option
9653 * @returns {*}
9654 * @private
9655 */
9656
9657 }, {
9658 key: "_getValue",
9659 value: function _getValue(path) {
9660 var base = this.moduleOptions;
9661
9662 for (var i = 0; i < path.length; i++) {
9663 if (base[path[i]] !== undefined) {
9664 base = base[path[i]];
9665 } else {
9666 base = undefined;
9667 break;
9668 }
9669 }
9670
9671 return base;
9672 }
9673 /**
9674 * all option elements are wrapped in an item
9675 *
9676 * @param {Array} path | where to look for the actual option
9677 * @param {Array.<Element>} domElements
9678 * @returns {number}
9679 * @private
9680 */
9681
9682 }, {
9683 key: "_makeItem",
9684 value: function _makeItem(path) {
9685 if (this.allowCreation === true) {
9686 var item = document.createElement("div");
9687 item.className = "vis-configuration vis-config-item vis-config-s" + path.length;
9688
9689 for (var _len6 = arguments.length, domElements = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
9690 domElements[_key6 - 1] = arguments[_key6];
9691 }
9692
9693 forEach$2(domElements).call(domElements, function (element) {
9694 item.appendChild(element);
9695 });
9696
9697 this.domElements.push(item);
9698 return this.domElements.length;
9699 }
9700
9701 return 0;
9702 }
9703 /**
9704 * header for major subjects
9705 *
9706 * @param {string} name
9707 * @private
9708 */
9709
9710 }, {
9711 key: "_makeHeader",
9712 value: function _makeHeader(name) {
9713 var div = document.createElement("div");
9714 div.className = "vis-configuration vis-config-header";
9715 div.innerText = name;
9716
9717 this._makeItem([], div);
9718 }
9719 /**
9720 * make a label, if it is an object label, it gets different styling.
9721 *
9722 * @param {string} name
9723 * @param {Array} path | where to look for the actual option
9724 * @param {string} objectLabel
9725 * @returns {HTMLElement}
9726 * @private
9727 */
9728
9729 }, {
9730 key: "_makeLabel",
9731 value: function _makeLabel(name, path) {
9732 var objectLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
9733 var div = document.createElement("div");
9734 div.className = "vis-configuration vis-config-label vis-config-s" + path.length;
9735
9736 if (objectLabel === true) {
9737 while (div.firstChild) {
9738 div.removeChild(div.firstChild);
9739 }
9740
9741 div.appendChild(wrapInTag("i", "b", name));
9742 } else {
9743 div.innerText = name + ":";
9744 }
9745
9746 return div;
9747 }
9748 /**
9749 * make a dropdown list for multiple possible string optoins
9750 *
9751 * @param {Array.<number>} arr
9752 * @param {number} value
9753 * @param {Array} path | where to look for the actual option
9754 * @private
9755 */
9756
9757 }, {
9758 key: "_makeDropdown",
9759 value: function _makeDropdown(arr, value, path) {
9760 var select = document.createElement("select");
9761 select.className = "vis-configuration vis-config-select";
9762 var selectedValue = 0;
9763
9764 if (value !== undefined) {
9765 if (indexOf(arr).call(arr, value) !== -1) {
9766 selectedValue = indexOf(arr).call(arr, value);
9767 }
9768 }
9769
9770 for (var i = 0; i < arr.length; i++) {
9771 var _option2 = document.createElement("option");
9772
9773 _option2.value = arr[i];
9774
9775 if (i === selectedValue) {
9776 _option2.selected = "selected";
9777 }
9778
9779 _option2.innerText = arr[i];
9780 select.appendChild(_option2);
9781 }
9782
9783 var me = this;
9784
9785 select.onchange = function () {
9786 me._update(this.value, path);
9787 };
9788
9789 var label = this._makeLabel(path[path.length - 1], path);
9790
9791 this._makeItem(path, label, select);
9792 }
9793 /**
9794 * make a range object for numeric options
9795 *
9796 * @param {Array.<number>} arr
9797 * @param {number} value
9798 * @param {Array} path | where to look for the actual option
9799 * @private
9800 */
9801
9802 }, {
9803 key: "_makeRange",
9804 value: function _makeRange(arr, value, path) {
9805 var defaultValue = arr[0];
9806 var min = arr[1];
9807 var max = arr[2];
9808 var step = arr[3];
9809 var range = document.createElement("input");
9810 range.className = "vis-configuration vis-config-range";
9811
9812 try {
9813 range.type = "range"; // not supported on IE9
9814
9815 range.min = min;
9816 range.max = max;
9817 } catch (err) {// TODO: Add some error handling.
9818 }
9819
9820 range.step = step; // set up the popup settings in case they are needed.
9821
9822 var popupString = "";
9823 var popupValue = 0;
9824
9825 if (value !== undefined) {
9826 var factor = 1.2;
9827
9828 if (value < 0 && value * factor < min) {
9829 range.min = Math.ceil(value * factor);
9830 popupValue = range.min;
9831 popupString = "range increased";
9832 } else if (value / factor < min) {
9833 range.min = Math.ceil(value / factor);
9834 popupValue = range.min;
9835 popupString = "range increased";
9836 }
9837
9838 if (value * factor > max && max !== 1) {
9839 range.max = Math.ceil(value * factor);
9840 popupValue = range.max;
9841 popupString = "range increased";
9842 }
9843
9844 range.value = value;
9845 } else {
9846 range.value = defaultValue;
9847 }
9848
9849 var input = document.createElement("input");
9850 input.className = "vis-configuration vis-config-rangeinput";
9851 input.value = range.value;
9852 var me = this;
9853
9854 range.onchange = function () {
9855 input.value = this.value;
9856
9857 me._update(Number(this.value), path);
9858 };
9859
9860 range.oninput = function () {
9861 input.value = this.value;
9862 };
9863
9864 var label = this._makeLabel(path[path.length - 1], path);
9865
9866 var itemIndex = this._makeItem(path, label, range, input); // if a popup is needed AND it has not been shown for this value, show it.
9867
9868
9869 if (popupString !== "" && this.popupHistory[itemIndex] !== popupValue) {
9870 this.popupHistory[itemIndex] = popupValue;
9871
9872 this._setupPopup(popupString, itemIndex);
9873 }
9874 }
9875 /**
9876 * make a button object
9877 *
9878 * @private
9879 */
9880
9881 }, {
9882 key: "_makeButton",
9883 value: function _makeButton() {
9884 var _this4 = this;
9885
9886 if (this.options.showButton === true) {
9887 var generateButton = document.createElement("div");
9888 generateButton.className = "vis-configuration vis-config-button";
9889 generateButton.innerText = "generate options";
9890
9891 generateButton.onclick = function () {
9892 _this4._printOptions();
9893 };
9894
9895 generateButton.onmouseover = function () {
9896 generateButton.className = "vis-configuration vis-config-button hover";
9897 };
9898
9899 generateButton.onmouseout = function () {
9900 generateButton.className = "vis-configuration vis-config-button";
9901 };
9902
9903 this.optionsContainer = document.createElement("div");
9904 this.optionsContainer.className = "vis-configuration vis-config-option-container";
9905 this.domElements.push(this.optionsContainer);
9906 this.domElements.push(generateButton);
9907 }
9908 }
9909 /**
9910 * prepare the popup
9911 *
9912 * @param {string} string
9913 * @param {number} index
9914 * @private
9915 */
9916
9917 }, {
9918 key: "_setupPopup",
9919 value: function _setupPopup(string, index) {
9920 var _this5 = this;
9921
9922 if (this.initialized === true && this.allowCreation === true && this.popupCounter < this.popupLimit) {
9923 var div = document.createElement("div");
9924 div.id = "vis-configuration-popup";
9925 div.className = "vis-configuration-popup";
9926 div.innerText = string;
9927
9928 div.onclick = function () {
9929 _this5._removePopup();
9930 };
9931
9932 this.popupCounter += 1;
9933 this.popupDiv = {
9934 html: div,
9935 index: index
9936 };
9937 }
9938 }
9939 /**
9940 * remove the popup from the dom
9941 *
9942 * @private
9943 */
9944
9945 }, {
9946 key: "_removePopup",
9947 value: function _removePopup() {
9948 if (this.popupDiv.html !== undefined) {
9949 this.popupDiv.html.parentNode.removeChild(this.popupDiv.html);
9950 clearTimeout(this.popupDiv.hideTimeout);
9951 clearTimeout(this.popupDiv.deleteTimeout);
9952 this.popupDiv = {};
9953 }
9954 }
9955 /**
9956 * Show the popup if it is needed.
9957 *
9958 * @private
9959 */
9960
9961 }, {
9962 key: "_showPopupIfNeeded",
9963 value: function _showPopupIfNeeded() {
9964 var _this6 = this;
9965
9966 if (this.popupDiv.html !== undefined) {
9967 var correspondingElement = this.domElements[this.popupDiv.index];
9968 var rect = correspondingElement.getBoundingClientRect();
9969 this.popupDiv.html.style.left = rect.left + "px";
9970 this.popupDiv.html.style.top = rect.top - 30 + "px"; // 30 is the height;
9971
9972 document.body.appendChild(this.popupDiv.html);
9973 this.popupDiv.hideTimeout = setTimeout$1(function () {
9974 _this6.popupDiv.html.style.opacity = 0;
9975 }, 1500);
9976 this.popupDiv.deleteTimeout = setTimeout$1(function () {
9977 _this6._removePopup();
9978 }, 1800);
9979 }
9980 }
9981 /**
9982 * make a checkbox for boolean options.
9983 *
9984 * @param {number} defaultValue
9985 * @param {number} value
9986 * @param {Array} path | where to look for the actual option
9987 * @private
9988 */
9989
9990 }, {
9991 key: "_makeCheckbox",
9992 value: function _makeCheckbox(defaultValue, value, path) {
9993 var checkbox = document.createElement("input");
9994 checkbox.type = "checkbox";
9995 checkbox.className = "vis-configuration vis-config-checkbox";
9996 checkbox.checked = defaultValue;
9997
9998 if (value !== undefined) {
9999 checkbox.checked = value;
10000
10001 if (value !== defaultValue) {
10002 if (_typeof(defaultValue) === "object") {
10003 if (value !== defaultValue.enabled) {
10004 this.changedOptions.push({
10005 path: path,
10006 value: value
10007 });
10008 }
10009 } else {
10010 this.changedOptions.push({
10011 path: path,
10012 value: value
10013 });
10014 }
10015 }
10016 }
10017
10018 var me = this;
10019
10020 checkbox.onchange = function () {
10021 me._update(this.checked, path);
10022 };
10023
10024 var label = this._makeLabel(path[path.length - 1], path);
10025
10026 this._makeItem(path, label, checkbox);
10027 }
10028 /**
10029 * make a text input field for string options.
10030 *
10031 * @param {number} defaultValue
10032 * @param {number} value
10033 * @param {Array} path | where to look for the actual option
10034 * @private
10035 */
10036
10037 }, {
10038 key: "_makeTextInput",
10039 value: function _makeTextInput(defaultValue, value, path) {
10040 var checkbox = document.createElement("input");
10041 checkbox.type = "text";
10042 checkbox.className = "vis-configuration vis-config-text";
10043 checkbox.value = value;
10044
10045 if (value !== defaultValue) {
10046 this.changedOptions.push({
10047 path: path,
10048 value: value
10049 });
10050 }
10051
10052 var me = this;
10053
10054 checkbox.onchange = function () {
10055 me._update(this.value, path);
10056 };
10057
10058 var label = this._makeLabel(path[path.length - 1], path);
10059
10060 this._makeItem(path, label, checkbox);
10061 }
10062 /**
10063 * make a color field with a color picker for color fields
10064 *
10065 * @param {Array.<number>} arr
10066 * @param {number} value
10067 * @param {Array} path | where to look for the actual option
10068 * @private
10069 */
10070
10071 }, {
10072 key: "_makeColorField",
10073 value: function _makeColorField(arr, value, path) {
10074 var _this7 = this;
10075
10076 var defaultColor = arr[1];
10077 var div = document.createElement("div");
10078 value = value === undefined ? defaultColor : value;
10079
10080 if (value !== "none") {
10081 div.className = "vis-configuration vis-config-colorBlock";
10082 div.style.backgroundColor = value;
10083 } else {
10084 div.className = "vis-configuration vis-config-colorBlock none";
10085 }
10086
10087 value = value === undefined ? defaultColor : value;
10088
10089 div.onclick = function () {
10090 _this7._showColorPicker(value, div, path);
10091 };
10092
10093 var label = this._makeLabel(path[path.length - 1], path);
10094
10095 this._makeItem(path, label, div);
10096 }
10097 /**
10098 * used by the color buttons to call the color picker.
10099 *
10100 * @param {number} value
10101 * @param {HTMLElement} div
10102 * @param {Array} path | where to look for the actual option
10103 * @private
10104 */
10105
10106 }, {
10107 key: "_showColorPicker",
10108 value: function _showColorPicker(value, div, path) {
10109 var _this8 = this;
10110
10111 // clear the callback from this div
10112 div.onclick = function () {};
10113
10114 this.colorPicker.insertTo(div);
10115 this.colorPicker.show();
10116 this.colorPicker.setColor(value);
10117 this.colorPicker.setUpdateCallback(function (color) {
10118 var colorString = "rgba(" + color.r + "," + color.g + "," + color.b + "," + color.a + ")";
10119 div.style.backgroundColor = colorString;
10120
10121 _this8._update(colorString, path);
10122 }); // on close of the colorpicker, restore the callback.
10123
10124 this.colorPicker.setCloseCallback(function () {
10125 div.onclick = function () {
10126 _this8._showColorPicker(value, div, path);
10127 };
10128 });
10129 }
10130 /**
10131 * parse an object and draw the correct items
10132 *
10133 * @param {object} obj
10134 * @param {Array} [path=[]] | where to look for the actual option
10135 * @param {boolean} [checkOnly=false]
10136 * @returns {boolean}
10137 * @private
10138 */
10139
10140 }, {
10141 key: "_handleObject",
10142 value: function _handleObject(obj) {
10143 var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
10144 var checkOnly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
10145 var show = false;
10146
10147 var filter$1 = filter(this.options);
10148
10149 var visibleInSet = false;
10150
10151 for (var subObj in obj) {
10152 if (Object.prototype.hasOwnProperty.call(obj, subObj)) {
10153 show = true;
10154 var item = obj[subObj];
10155 var newPath = copyAndExtendArray(path, subObj);
10156
10157 if (typeof filter$1 === "function") {
10158 show = filter$1(subObj, path); // if needed we must go deeper into the object.
10159
10160 if (show === false) {
10161 if (!isArray$1(item) && typeof item !== "string" && typeof item !== "boolean" && item instanceof Object) {
10162 this.allowCreation = false;
10163 show = this._handleObject(item, newPath, true);
10164 this.allowCreation = checkOnly === false;
10165 }
10166 }
10167 }
10168
10169 if (show !== false) {
10170 visibleInSet = true;
10171
10172 var value = this._getValue(newPath);
10173
10174 if (isArray$1(item)) {
10175 this._handleArray(item, value, newPath);
10176 } else if (typeof item === "string") {
10177 this._makeTextInput(item, value, newPath);
10178 } else if (typeof item === "boolean") {
10179 this._makeCheckbox(item, value, newPath);
10180 } else if (item instanceof Object) {
10181 // skip the options that are not enabled
10182 if (!this.hideOption(path, subObj, this.moduleOptions)) {
10183 // initially collapse options with an disabled enabled option.
10184 if (item.enabled !== undefined) {
10185 var enabledPath = copyAndExtendArray(newPath, "enabled");
10186
10187 var enabledValue = this._getValue(enabledPath);
10188
10189 if (enabledValue === true) {
10190 var label = this._makeLabel(subObj, newPath, true);
10191
10192 this._makeItem(newPath, label);
10193
10194 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
10195 } else {
10196 this._makeCheckbox(item, enabledValue, newPath);
10197 }
10198 } else {
10199 var _label = this._makeLabel(subObj, newPath, true);
10200
10201 this._makeItem(newPath, _label);
10202
10203 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
10204 }
10205 }
10206 } else {
10207 console.error("dont know how to handle", item, subObj, newPath);
10208 }
10209 }
10210 }
10211 }
10212
10213 return visibleInSet;
10214 }
10215 /**
10216 * handle the array type of option
10217 *
10218 * @param {Array.<number>} arr
10219 * @param {number} value
10220 * @param {Array} path | where to look for the actual option
10221 * @private
10222 */
10223
10224 }, {
10225 key: "_handleArray",
10226 value: function _handleArray(arr, value, path) {
10227 if (typeof arr[0] === "string" && arr[0] === "color") {
10228 this._makeColorField(arr, value, path);
10229
10230 if (arr[1] !== value) {
10231 this.changedOptions.push({
10232 path: path,
10233 value: value
10234 });
10235 }
10236 } else if (typeof arr[0] === "string") {
10237 this._makeDropdown(arr, value, path);
10238
10239 if (arr[0] !== value) {
10240 this.changedOptions.push({
10241 path: path,
10242 value: value
10243 });
10244 }
10245 } else if (typeof arr[0] === "number") {
10246 this._makeRange(arr, value, path);
10247
10248 if (arr[0] !== value) {
10249 this.changedOptions.push({
10250 path: path,
10251 value: Number(value)
10252 });
10253 }
10254 }
10255 }
10256 /**
10257 * called to update the network with the new settings.
10258 *
10259 * @param {number} value
10260 * @param {Array} path | where to look for the actual option
10261 * @private
10262 */
10263
10264 }, {
10265 key: "_update",
10266 value: function _update(value, path) {
10267 var options = this._constructOptions(value, path);
10268
10269 if (this.parent.body && this.parent.body.emitter && this.parent.body.emitter.emit) {
10270 this.parent.body.emitter.emit("configChange", options);
10271 }
10272
10273 this.initialized = true;
10274 this.parent.setOptions(options);
10275 }
10276 /**
10277 *
10278 * @param {string | boolean} value
10279 * @param {Array.<string>} path
10280 * @param {{}} optionsObj
10281 * @returns {{}}
10282 * @private
10283 */
10284
10285 }, {
10286 key: "_constructOptions",
10287 value: function _constructOptions(value, path) {
10288 var optionsObj = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
10289 var pointer = optionsObj; // when dropdown boxes can be string or boolean, we typecast it into correct types
10290
10291 value = value === "true" ? true : value;
10292 value = value === "false" ? false : value;
10293
10294 for (var i = 0; i < path.length; i++) {
10295 if (path[i] !== "global") {
10296 if (pointer[path[i]] === undefined) {
10297 pointer[path[i]] = {};
10298 }
10299
10300 if (i !== path.length - 1) {
10301 pointer = pointer[path[i]];
10302 } else {
10303 pointer[path[i]] = value;
10304 }
10305 }
10306 }
10307
10308 return optionsObj;
10309 }
10310 /**
10311 * @private
10312 */
10313
10314 }, {
10315 key: "_printOptions",
10316 value: function _printOptions() {
10317 var options = this.getOptions();
10318
10319 while (this.optionsContainer.firstChild) {
10320 this.optionsContainer.removeChild(this.optionsContainer.firstChild);
10321 }
10322
10323 this.optionsContainer.appendChild(wrapInTag("pre", "const options = " + stringify$1(options, null, 2)));
10324 }
10325 /**
10326 *
10327 * @returns {{}} options
10328 */
10329
10330 }, {
10331 key: "getOptions",
10332 value: function getOptions() {
10333 var options = {};
10334
10335 for (var i = 0; i < this.changedOptions.length; i++) {
10336 this._constructOptions(this.changedOptions[i].value, this.changedOptions[i].path, options);
10337 }
10338
10339 return options;
10340 }
10341 }]);
10342
10343 return Configurator;
10344 }();
10345 /**
10346 * Popup is a class to create a popup window with some text
10347 */
10348
10349
10350 var Popup = /*#__PURE__*/function () {
10351 /**
10352 * @param {Element} container The container object.
10353 * @param {string} overflowMethod How the popup should act to overflowing ('flip' or 'cap')
10354 */
10355 function Popup(container, overflowMethod) {
10356 _classCallCheck(this, Popup);
10357
10358 this.container = container;
10359 this.overflowMethod = overflowMethod || "cap";
10360 this.x = 0;
10361 this.y = 0;
10362 this.padding = 5;
10363 this.hidden = false; // create the frame
10364
10365 this.frame = document.createElement("div");
10366 this.frame.className = "vis-tooltip";
10367 this.container.appendChild(this.frame);
10368 }
10369 /**
10370 * @param {number} x Horizontal position of the popup window
10371 * @param {number} y Vertical position of the popup window
10372 */
10373
10374
10375 _createClass(Popup, [{
10376 key: "setPosition",
10377 value: function setPosition(x, y) {
10378 this.x = _parseInt(x);
10379 this.y = _parseInt(y);
10380 }
10381 /**
10382 * Set the content for the popup window. This can be HTML code or text.
10383 *
10384 * @param {string | Element} content
10385 */
10386
10387 }, {
10388 key: "setText",
10389 value: function setText(content) {
10390 if (content instanceof Element) {
10391 while (this.frame.firstChild) {
10392 this.frame.removeChild(this.frame.firstChild);
10393 }
10394
10395 this.frame.appendChild(content);
10396 } else {
10397 // String containing literal text, element has to be used for HTML due to
10398 // XSS risks associated with innerHTML (i.e. prevent XSS by accident).
10399 this.frame.innerText = content;
10400 }
10401 }
10402 /**
10403 * Show the popup window
10404 *
10405 * @param {boolean} [doShow] Show or hide the window
10406 */
10407
10408 }, {
10409 key: "show",
10410 value: function show(doShow) {
10411 if (doShow === undefined) {
10412 doShow = true;
10413 }
10414
10415 if (doShow === true) {
10416 var height = this.frame.clientHeight;
10417 var width = this.frame.clientWidth;
10418 var maxHeight = this.frame.parentNode.clientHeight;
10419 var maxWidth = this.frame.parentNode.clientWidth;
10420 var left = 0,
10421 top = 0;
10422
10423 if (this.overflowMethod == "flip") {
10424 var isLeft = false,
10425 isTop = true; // Where around the position it's located
10426
10427 if (this.y - height < this.padding) {
10428 isTop = false;
10429 }
10430
10431 if (this.x + width > maxWidth - this.padding) {
10432 isLeft = true;
10433 }
10434
10435 if (isLeft) {
10436 left = this.x - width;
10437 } else {
10438 left = this.x;
10439 }
10440
10441 if (isTop) {
10442 top = this.y - height;
10443 } else {
10444 top = this.y;
10445 }
10446 } else {
10447 top = this.y - height;
10448
10449 if (top + height + this.padding > maxHeight) {
10450 top = maxHeight - height - this.padding;
10451 }
10452
10453 if (top < this.padding) {
10454 top = this.padding;
10455 }
10456
10457 left = this.x;
10458
10459 if (left + width + this.padding > maxWidth) {
10460 left = maxWidth - width - this.padding;
10461 }
10462
10463 if (left < this.padding) {
10464 left = this.padding;
10465 }
10466 }
10467
10468 this.frame.style.left = left + "px";
10469 this.frame.style.top = top + "px";
10470 this.frame.style.visibility = "visible";
10471 this.hidden = false;
10472 } else {
10473 this.hide();
10474 }
10475 }
10476 /**
10477 * Hide the popup window
10478 */
10479
10480 }, {
10481 key: "hide",
10482 value: function hide() {
10483 this.hidden = true;
10484 this.frame.style.left = "0";
10485 this.frame.style.top = "0";
10486 this.frame.style.visibility = "hidden";
10487 }
10488 /**
10489 * Remove the popup window
10490 */
10491
10492 }, {
10493 key: "destroy",
10494 value: function destroy() {
10495 this.frame.parentNode.removeChild(this.frame); // Remove element from DOM
10496 }
10497 }]);
10498
10499 return Popup;
10500 }();
10501
10502 var errorFound = false;
10503 var allOptions$1;
10504 var VALIDATOR_PRINT_STYLE = "background: #FFeeee; color: #dd0000";
10505 /**
10506 * Used to validate options.
10507 */
10508
10509 var Validator = /*#__PURE__*/function () {
10510 function Validator() {
10511 _classCallCheck(this, Validator);
10512 }
10513
10514 _createClass(Validator, null, [{
10515 key: "validate",
10516 value:
10517 /**
10518 * Main function to be called
10519 *
10520 * @param {object} options
10521 * @param {object} referenceOptions
10522 * @param {object} subObject
10523 * @returns {boolean}
10524 * @static
10525 */
10526 function validate(options, referenceOptions, subObject) {
10527 errorFound = false;
10528 allOptions$1 = referenceOptions;
10529 var usedOptions = referenceOptions;
10530
10531 if (subObject !== undefined) {
10532 usedOptions = referenceOptions[subObject];
10533 }
10534
10535 Validator.parse(options, usedOptions, []);
10536 return errorFound;
10537 }
10538 /**
10539 * Will traverse an object recursively and check every value
10540 *
10541 * @param {object} options
10542 * @param {object} referenceOptions
10543 * @param {Array} path | where to look for the actual option
10544 * @static
10545 */
10546
10547 }, {
10548 key: "parse",
10549 value: function parse(options, referenceOptions, path) {
10550 for (var _option3 in options) {
10551 if (Object.prototype.hasOwnProperty.call(options, _option3)) {
10552 Validator.check(_option3, options, referenceOptions, path);
10553 }
10554 }
10555 }
10556 /**
10557 * Check every value. If the value is an object, call the parse function on that object.
10558 *
10559 * @param {string} option
10560 * @param {object} options
10561 * @param {object} referenceOptions
10562 * @param {Array} path | where to look for the actual option
10563 * @static
10564 */
10565
10566 }, {
10567 key: "check",
10568 value: function check(option, options, referenceOptions, path) {
10569 if (referenceOptions[option] === undefined && referenceOptions.__any__ === undefined) {
10570 Validator.getSuggestion(option, referenceOptions, path);
10571 return;
10572 }
10573
10574 var referenceOption = option;
10575 var is_object = true;
10576
10577 if (referenceOptions[option] === undefined && referenceOptions.__any__ !== undefined) {
10578 // NOTE: This only triggers if the __any__ is in the top level of the options object.
10579 // THAT'S A REALLY BAD PLACE TO ALLOW IT!!!!
10580 // TODO: Examine if needed, remove if possible
10581 // __any__ is a wildcard. Any value is accepted and will be further analysed by reference.
10582 referenceOption = "__any__"; // if the any-subgroup is not a predefined object in the configurator,
10583 // we do not look deeper into the object.
10584
10585 is_object = Validator.getType(options[option]) === "object";
10586 }
10587
10588 var refOptionObj = referenceOptions[referenceOption];
10589
10590 if (is_object && refOptionObj.__type__ !== undefined) {
10591 refOptionObj = refOptionObj.__type__;
10592 }
10593
10594 Validator.checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path);
10595 }
10596 /**
10597 *
10598 * @param {string} option | the option property
10599 * @param {object} options | The supplied options object
10600 * @param {object} referenceOptions | The reference options containing all options and their allowed formats
10601 * @param {string} referenceOption | Usually this is the same as option, except when handling an __any__ tag.
10602 * @param {string} refOptionObj | This is the type object from the reference options
10603 * @param {Array} path | where in the object is the option
10604 * @static
10605 */
10606
10607 }, {
10608 key: "checkFields",
10609 value: function checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path) {
10610 var log = function log(message) {
10611 console.error("%c" + message + Validator.printLocation(path, option), VALIDATOR_PRINT_STYLE);
10612 };
10613
10614 var optionType = Validator.getType(options[option]);
10615 var refOptionType = refOptionObj[optionType];
10616
10617 if (refOptionType !== undefined) {
10618 // if the type is correct, we check if it is supposed to be one of a few select values
10619 if (Validator.getType(refOptionType) === "array" && indexOf(refOptionType).call(refOptionType, options[option]) === -1) {
10620 log('Invalid option detected in "' + option + '".' + " Allowed values are:" + Validator.print(refOptionType) + ' not "' + options[option] + '". ');
10621 errorFound = true;
10622 } else if (optionType === "object" && referenceOption !== "__any__") {
10623 path = copyAndExtendArray(path, option);
10624 Validator.parse(options[option], referenceOptions[referenceOption], path);
10625 }
10626 } else if (refOptionObj["any"] === undefined) {
10627 // type of the field is incorrect and the field cannot be any
10628 log('Invalid type received for "' + option + '". Expected: ' + Validator.print(keys(refOptionObj)) + ". Received [" + optionType + '] "' + options[option] + '"');
10629 errorFound = true;
10630 }
10631 }
10632 /**
10633 *
10634 * @param {object | boolean | number | string | Array.<number> | Date | Node | Moment | undefined | null} object
10635 * @returns {string}
10636 * @static
10637 */
10638
10639 }, {
10640 key: "getType",
10641 value: function getType(object) {
10642 var type = _typeof(object);
10643
10644 if (type === "object") {
10645 if (object === null) {
10646 return "null";
10647 }
10648
10649 if (object instanceof Boolean) {
10650 return "boolean";
10651 }
10652
10653 if (object instanceof Number) {
10654 return "number";
10655 }
10656
10657 if (object instanceof String) {
10658 return "string";
10659 }
10660
10661 if (isArray$1(object)) {
10662 return "array";
10663 }
10664
10665 if (object instanceof Date) {
10666 return "date";
10667 }
10668
10669 if (object.nodeType !== undefined) {
10670 return "dom";
10671 }
10672
10673 if (object._isAMomentObject === true) {
10674 return "moment";
10675 }
10676
10677 return "object";
10678 } else if (type === "number") {
10679 return "number";
10680 } else if (type === "boolean") {
10681 return "boolean";
10682 } else if (type === "string") {
10683 return "string";
10684 } else if (type === undefined) {
10685 return "undefined";
10686 }
10687
10688 return type;
10689 }
10690 /**
10691 * @param {string} option
10692 * @param {object} options
10693 * @param {Array.<string>} path
10694 * @static
10695 */
10696
10697 }, {
10698 key: "getSuggestion",
10699 value: function getSuggestion(option, options, path) {
10700 var localSearch = Validator.findInOptions(option, options, path, false);
10701 var globalSearch = Validator.findInOptions(option, allOptions$1, [], true);
10702 var localSearchThreshold = 8;
10703 var globalSearchThreshold = 4;
10704 var msg;
10705
10706 if (localSearch.indexMatch !== undefined) {
10707 msg = " in " + Validator.printLocation(localSearch.path, option, "") + 'Perhaps it was incomplete? Did you mean: "' + localSearch.indexMatch + '"?\n\n';
10708 } else if (globalSearch.distance <= globalSearchThreshold && localSearch.distance > globalSearch.distance) {
10709 msg = " in " + Validator.printLocation(localSearch.path, option, "") + "Perhaps it was misplaced? Matching option found at: " + Validator.printLocation(globalSearch.path, globalSearch.closestMatch, "");
10710 } else if (localSearch.distance <= localSearchThreshold) {
10711 msg = '. Did you mean "' + localSearch.closestMatch + '"?' + Validator.printLocation(localSearch.path, option);
10712 } else {
10713 msg = ". Did you mean one of these: " + Validator.print(keys(options)) + Validator.printLocation(path, option);
10714 }
10715
10716 console.error('%cUnknown option detected: "' + option + '"' + msg, VALIDATOR_PRINT_STYLE);
10717 errorFound = true;
10718 }
10719 /**
10720 * traverse the options in search for a match.
10721 *
10722 * @param {string} option
10723 * @param {object} options
10724 * @param {Array} path | where to look for the actual option
10725 * @param {boolean} [recursive=false]
10726 * @returns {{closestMatch: string, path: Array, distance: number}}
10727 * @static
10728 */
10729
10730 }, {
10731 key: "findInOptions",
10732 value: function findInOptions(option, options, path) {
10733 var recursive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
10734 var min = 1e9;
10735 var closestMatch = "";
10736 var closestMatchPath = [];
10737 var lowerCaseOption = option.toLowerCase();
10738 var indexMatch = undefined;
10739
10740 for (var op in options) {
10741 var distance = void 0;
10742
10743 if (options[op].__type__ !== undefined && recursive === true) {
10744 var result = Validator.findInOptions(option, options[op], copyAndExtendArray(path, op));
10745
10746 if (min > result.distance) {
10747 closestMatch = result.closestMatch;
10748 closestMatchPath = result.path;
10749 min = result.distance;
10750 indexMatch = result.indexMatch;
10751 }
10752 } else {
10753 var _context20;
10754
10755 if (indexOf(_context20 = op.toLowerCase()).call(_context20, lowerCaseOption) !== -1) {
10756 indexMatch = op;
10757 }
10758
10759 distance = Validator.levenshteinDistance(option, op);
10760
10761 if (min > distance) {
10762 closestMatch = op;
10763 closestMatchPath = copyArray(path);
10764 min = distance;
10765 }
10766 }
10767 }
10768
10769 return {
10770 closestMatch: closestMatch,
10771 path: closestMatchPath,
10772 distance: min,
10773 indexMatch: indexMatch
10774 };
10775 }
10776 /**
10777 * @param {Array.<string>} path
10778 * @param {object} option
10779 * @param {string} prefix
10780 * @returns {string}
10781 * @static
10782 */
10783
10784 }, {
10785 key: "printLocation",
10786 value: function printLocation(path, option) {
10787 var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "Problem value found at: \n";
10788 var str = "\n\n" + prefix + "options = {\n";
10789
10790 for (var i = 0; i < path.length; i++) {
10791 for (var j = 0; j < i + 1; j++) {
10792 str += " ";
10793 }
10794
10795 str += path[i] + ": {\n";
10796 }
10797
10798 for (var _j = 0; _j < path.length + 1; _j++) {
10799 str += " ";
10800 }
10801
10802 str += option + "\n";
10803
10804 for (var _i3 = 0; _i3 < path.length + 1; _i3++) {
10805 for (var _j2 = 0; _j2 < path.length - _i3; _j2++) {
10806 str += " ";
10807 }
10808
10809 str += "}\n";
10810 }
10811
10812 return str + "\n\n";
10813 }
10814 /**
10815 * @param {object} options
10816 * @returns {string}
10817 * @static
10818 */
10819
10820 }, {
10821 key: "print",
10822 value: function print(options) {
10823 return stringify$1(options).replace(/(")|(\[)|(\])|(,"__type__")/g, "").replace(/(,)/g, ", ");
10824 }
10825 /**
10826 * Compute the edit distance between the two given strings
10827 * http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
10828 *
10829 * Copyright (c) 2011 Andrei Mackenzie
10830 *
10831 * 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:
10832 *
10833 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10834 *
10835 * 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.
10836 *
10837 * @param {string} a
10838 * @param {string} b
10839 * @returns {Array.<Array.<number>>}}
10840 * @static
10841 */
10842
10843 }, {
10844 key: "levenshteinDistance",
10845 value: function levenshteinDistance(a, b) {
10846 if (a.length === 0) return b.length;
10847 if (b.length === 0) return a.length;
10848 var matrix = []; // increment along the first column of each row
10849
10850 var i;
10851
10852 for (i = 0; i <= b.length; i++) {
10853 matrix[i] = [i];
10854 } // increment each column in the first row
10855
10856
10857 var j;
10858
10859 for (j = 0; j <= a.length; j++) {
10860 matrix[0][j] = j;
10861 } // Fill in the rest of the matrix
10862
10863
10864 for (i = 1; i <= b.length; i++) {
10865 for (j = 1; j <= a.length; j++) {
10866 if (b.charAt(i - 1) == a.charAt(j - 1)) {
10867 matrix[i][j] = matrix[i - 1][j - 1];
10868 } else {
10869 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
10870 Math.min(matrix[i][j - 1] + 1, // insertion
10871 matrix[i - 1][j] + 1)); // deletion
10872 }
10873 }
10874 }
10875
10876 return matrix[b.length][a.length];
10877 }
10878 }]);
10879
10880 return Validator;
10881 }();
10882
10883 var Activator$1 = Activator;
10884 var Configurator$1 = Configurator;
10885 var Hammer$1 = Hammer;
10886 var Popup$1 = Popup;
10887 var VALIDATOR_PRINT_STYLE$1 = VALIDATOR_PRINT_STYLE;
10888 var Validator$1 = Validator;
10889
10890 /* eslint-disable no-prototype-builtins */
10891
10892 /* eslint-disable no-unused-vars */
10893
10894 /* eslint-disable no-var */
10895
10896 /**
10897 * Parse a text source containing data in DOT language into a JSON object.
10898 * The object contains two lists: one with nodes and one with edges.
10899 *
10900 * DOT language reference: http://www.graphviz.org/doc/info/lang.html
10901 *
10902 * DOT language attributes: http://graphviz.org/content/attrs
10903 *
10904 * @param {string} data Text containing a graph in DOT-notation
10905 * @returns {object} graph An object containing two parameters:
10906 * {Object[]} nodes
10907 * {Object[]} edges
10908 *
10909 * -------------------------------------------
10910 * TODO
10911 * ====
10912 *
10913 * For label handling, this is an incomplete implementation. From docs (quote #3015):
10914 *
10915 * > the escape sequences "\n", "\l" and "\r" divide the label into lines, centered,
10916 * > left-justified, and right-justified, respectively.
10917 *
10918 * Source: http://www.graphviz.org/content/attrs#kescString
10919 *
10920 * > As another aid for readability, dot allows double-quoted strings to span multiple physical
10921 * > lines using the standard C convention of a backslash immediately preceding a newline
10922 * > character
10923 * > In addition, double-quoted strings can be concatenated using a '+' operator.
10924 * > As HTML strings can contain newline characters, which are used solely for formatting,
10925 * > the language does not allow escaped newlines or concatenation operators to be used
10926 * > within them.
10927 *
10928 * - Currently, only '\\n' is handled
10929 * - Note that text explicitly says 'labels'; the dot parser currently handles escape
10930 * sequences in **all** strings.
10931 */
10932 function parseDOT(data) {
10933 dot = data;
10934 return parseGraph();
10935 } // mapping of attributes from DOT (the keys) to vis.js (the values)
10936
10937 var NODE_ATTR_MAPPING = {
10938 fontsize: "font.size",
10939 fontcolor: "font.color",
10940 labelfontcolor: "font.color",
10941 fontname: "font.face",
10942 color: ["color.border", "color.background"],
10943 fillcolor: "color.background",
10944 tooltip: "title",
10945 labeltooltip: "title"
10946 };
10947
10948 var EDGE_ATTR_MAPPING = create$4(NODE_ATTR_MAPPING);
10949
10950 EDGE_ATTR_MAPPING.color = "color.color";
10951 EDGE_ATTR_MAPPING.style = "dashes"; // token types enumeration
10952
10953 var TOKENTYPE = {
10954 NULL: 0,
10955 DELIMITER: 1,
10956 IDENTIFIER: 2,
10957 UNKNOWN: 3
10958 }; // map with all delimiters
10959
10960 var DELIMITERS = {
10961 "{": true,
10962 "}": true,
10963 "[": true,
10964 "]": true,
10965 ";": true,
10966 "=": true,
10967 ",": true,
10968 "->": true,
10969 "--": true
10970 };
10971 var dot = ""; // current dot file
10972
10973 var index = 0; // current index in dot file
10974
10975 var c = ""; // current token character in expr
10976
10977 var token = ""; // current token
10978
10979 var tokenType = TOKENTYPE.NULL; // type of the token
10980
10981 /**
10982 * Get the first character from the dot file.
10983 * The character is stored into the char c. If the end of the dot file is
10984 * reached, the function puts an empty string in c.
10985 */
10986
10987 function first() {
10988 index = 0;
10989 c = dot.charAt(0);
10990 }
10991 /**
10992 * Get the next character from the dot file.
10993 * The character is stored into the char c. If the end of the dot file is
10994 * reached, the function puts an empty string in c.
10995 */
10996
10997
10998 function next() {
10999 index++;
11000 c = dot.charAt(index);
11001 }
11002 /**
11003 * Preview the next character from the dot file.
11004 *
11005 * @returns {string} cNext
11006 */
11007
11008
11009 function nextPreview() {
11010 return dot.charAt(index + 1);
11011 }
11012 /**
11013 * Test whether given character is alphabetic or numeric ( a-zA-Z_0-9.:# )
11014 *
11015 * @param {string} c
11016 * @returns {boolean} isAlphaNumeric
11017 */
11018
11019
11020 function isAlphaNumeric(c) {
11021 var charCode = c.charCodeAt(0);
11022
11023 if (charCode < 47) {
11024 // #.
11025 return charCode === 35 || charCode === 46;
11026 }
11027
11028 if (charCode < 59) {
11029 // 0-9 and :
11030 return charCode > 47;
11031 }
11032
11033 if (charCode < 91) {
11034 // A-Z
11035 return charCode > 64;
11036 }
11037
11038 if (charCode < 96) {
11039 // _
11040 return charCode === 95;
11041 }
11042
11043 if (charCode < 123) {
11044 // a-z
11045 return charCode > 96;
11046 }
11047
11048 return false;
11049 }
11050 /**
11051 * Merge all options of object b into object b
11052 *
11053 * @param {object} a
11054 * @param {object} b
11055 * @returns {object} a
11056 */
11057
11058
11059 function merge$1(a, b) {
11060 if (!a) {
11061 a = {};
11062 }
11063
11064 if (b) {
11065 for (var name in b) {
11066 if (b.hasOwnProperty(name)) {
11067 a[name] = b[name];
11068 }
11069 }
11070 }
11071
11072 return a;
11073 }
11074 /**
11075 * Set a value in an object, where the provided parameter name can be a
11076 * path with nested parameters. For example:
11077 *
11078 * var obj = {a: 2};
11079 * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}}
11080 *
11081 * @param {object} obj
11082 * @param {string} path A parameter name or dot-separated parameter path,
11083 * like "color.highlight.border".
11084 * @param {*} value
11085 */
11086
11087
11088 function setValue(obj, path, value) {
11089 var keys = path.split(".");
11090 var o = obj;
11091
11092 while (keys.length) {
11093 var key = keys.shift();
11094
11095 if (keys.length) {
11096 // this isn't the end point
11097 if (!o[key]) {
11098 o[key] = {};
11099 }
11100
11101 o = o[key];
11102 } else {
11103 // this is the end point
11104 o[key] = value;
11105 }
11106 }
11107 }
11108 /**
11109 * Add a node to a graph object. If there is already a node with
11110 * the same id, their attributes will be merged.
11111 *
11112 * @param {object} graph
11113 * @param {object} node
11114 */
11115
11116
11117 function addNode(graph, node) {
11118 var i, len;
11119 var current = null; // find root graph (in case of subgraph)
11120
11121 var graphs = [graph]; // list with all graphs from current graph to root graph
11122
11123 var root = graph;
11124
11125 while (root.parent) {
11126 graphs.push(root.parent);
11127 root = root.parent;
11128 } // find existing node (at root level) by its id
11129
11130
11131 if (root.nodes) {
11132 for (i = 0, len = root.nodes.length; i < len; i++) {
11133 if (node.id === root.nodes[i].id) {
11134 current = root.nodes[i];
11135 break;
11136 }
11137 }
11138 }
11139
11140 if (!current) {
11141 // this is a new node
11142 current = {
11143 id: node.id
11144 };
11145
11146 if (graph.node) {
11147 // clone default attributes
11148 current.attr = merge$1(current.attr, graph.node);
11149 }
11150 } // add node to this (sub)graph and all its parent graphs
11151
11152
11153 for (i = graphs.length - 1; i >= 0; i--) {
11154 var _context;
11155
11156 var g = graphs[i];
11157
11158 if (!g.nodes) {
11159 g.nodes = [];
11160 }
11161
11162 if (indexOf(_context = g.nodes).call(_context, current) === -1) {
11163 g.nodes.push(current);
11164 }
11165 } // merge attributes
11166
11167
11168 if (node.attr) {
11169 current.attr = merge$1(current.attr, node.attr);
11170 }
11171 }
11172 /**
11173 * Add an edge to a graph object
11174 *
11175 * @param {object} graph
11176 * @param {object} edge
11177 */
11178
11179
11180 function addEdge(graph, edge) {
11181 if (!graph.edges) {
11182 graph.edges = [];
11183 }
11184
11185 graph.edges.push(edge);
11186
11187 if (graph.edge) {
11188 var attr = merge$1({}, graph.edge); // clone default attributes
11189
11190 edge.attr = merge$1(attr, edge.attr); // merge attributes
11191 }
11192 }
11193 /**
11194 * Create an edge to a graph object
11195 *
11196 * @param {object} graph
11197 * @param {string | number | object} from
11198 * @param {string | number | object} to
11199 * @param {string} type
11200 * @param {object | null} attr
11201 * @returns {object} edge
11202 */
11203
11204
11205 function createEdge(graph, from, to, type, attr) {
11206 var edge = {
11207 from: from,
11208 to: to,
11209 type: type
11210 };
11211
11212 if (graph.edge) {
11213 edge.attr = merge$1({}, graph.edge); // clone default attributes
11214 }
11215
11216 edge.attr = merge$1(edge.attr || {}, attr); // merge attributes
11217 // Move arrows attribute from attr to edge temporally created in
11218 // parseAttributeList().
11219
11220 if (attr != null) {
11221 if (attr.hasOwnProperty("arrows") && attr["arrows"] != null) {
11222 edge["arrows"] = {
11223 to: {
11224 enabled: true,
11225 type: attr.arrows.type
11226 }
11227 };
11228 attr["arrows"] = null;
11229 }
11230 }
11231
11232 return edge;
11233 }
11234 /**
11235 * Get next token in the current dot file.
11236 * The token and token type are available as token and tokenType
11237 */
11238
11239
11240 function getToken() {
11241 tokenType = TOKENTYPE.NULL;
11242 token = ""; // skip over whitespaces
11243
11244 while (c === " " || c === "\t" || c === "\n" || c === "\r") {
11245 // space, tab, enter
11246 next();
11247 }
11248
11249 do {
11250 var isComment = false; // skip comment
11251
11252 if (c === "#") {
11253 // find the previous non-space character
11254 var i = index - 1;
11255
11256 while (dot.charAt(i) === " " || dot.charAt(i) === "\t") {
11257 i--;
11258 }
11259
11260 if (dot.charAt(i) === "\n" || dot.charAt(i) === "") {
11261 // the # is at the start of a line, this is indeed a line comment
11262 while (c != "" && c != "\n") {
11263 next();
11264 }
11265
11266 isComment = true;
11267 }
11268 }
11269
11270 if (c === "/" && nextPreview() === "/") {
11271 // skip line comment
11272 while (c != "" && c != "\n") {
11273 next();
11274 }
11275
11276 isComment = true;
11277 }
11278
11279 if (c === "/" && nextPreview() === "*") {
11280 // skip block comment
11281 while (c != "") {
11282 if (c === "*" && nextPreview() === "/") {
11283 // end of block comment found. skip these last two characters
11284 next();
11285 next();
11286 break;
11287 } else {
11288 next();
11289 }
11290 }
11291
11292 isComment = true;
11293 } // skip over whitespaces
11294
11295
11296 while (c === " " || c === "\t" || c === "\n" || c === "\r") {
11297 // space, tab, enter
11298 next();
11299 }
11300 } while (isComment); // check for end of dot file
11301
11302
11303 if (c === "") {
11304 // token is still empty
11305 tokenType = TOKENTYPE.DELIMITER;
11306 return;
11307 } // check for delimiters consisting of 2 characters
11308
11309
11310 var c2 = c + nextPreview();
11311
11312 if (DELIMITERS[c2]) {
11313 tokenType = TOKENTYPE.DELIMITER;
11314 token = c2;
11315 next();
11316 next();
11317 return;
11318 } // check for delimiters consisting of 1 character
11319
11320
11321 if (DELIMITERS[c]) {
11322 tokenType = TOKENTYPE.DELIMITER;
11323 token = c;
11324 next();
11325 return;
11326 } // check for an identifier (number or string)
11327 // TODO: more precise parsing of numbers/strings (and the port separator ':')
11328
11329
11330 if (isAlphaNumeric(c) || c === "-") {
11331 token += c;
11332 next();
11333
11334 while (isAlphaNumeric(c)) {
11335 token += c;
11336 next();
11337 }
11338
11339 if (token === "false") {
11340 token = false; // convert to boolean
11341 } else if (token === "true") {
11342 token = true; // convert to boolean
11343 } else if (!isNaN(Number(token))) {
11344 token = Number(token); // convert to number
11345 }
11346
11347 tokenType = TOKENTYPE.IDENTIFIER;
11348 return;
11349 } // check for a string enclosed by double quotes
11350
11351
11352 if (c === '"') {
11353 next();
11354
11355 while (c != "" && (c != '"' || c === '"' && nextPreview() === '"')) {
11356 if (c === '"') {
11357 // skip the escape character
11358 token += c;
11359 next();
11360 } else if (c === "\\" && nextPreview() === "n") {
11361 // Honor a newline escape sequence
11362 token += "\n";
11363 next();
11364 } else {
11365 token += c;
11366 }
11367
11368 next();
11369 }
11370
11371 if (c != '"') {
11372 throw newSyntaxError('End of string " expected');
11373 }
11374
11375 next();
11376 tokenType = TOKENTYPE.IDENTIFIER;
11377 return;
11378 } // something unknown is found, wrong characters, a syntax error
11379
11380
11381 tokenType = TOKENTYPE.UNKNOWN;
11382
11383 while (c != "") {
11384 token += c;
11385 next();
11386 }
11387
11388 throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"');
11389 }
11390 /**
11391 * Parse a graph.
11392 *
11393 * @returns {object} graph
11394 */
11395
11396
11397 function parseGraph() {
11398 var graph = {};
11399 first();
11400 getToken(); // optional strict keyword
11401
11402 if (token === "strict") {
11403 graph.strict = true;
11404 getToken();
11405 } // graph or digraph keyword
11406
11407
11408 if (token === "graph" || token === "digraph") {
11409 graph.type = token;
11410 getToken();
11411 } // optional graph id
11412
11413
11414 if (tokenType === TOKENTYPE.IDENTIFIER) {
11415 graph.id = token;
11416 getToken();
11417 } // open angle bracket
11418
11419
11420 if (token != "{") {
11421 throw newSyntaxError("Angle bracket { expected");
11422 }
11423
11424 getToken(); // statements
11425
11426 parseStatements(graph); // close angle bracket
11427
11428 if (token != "}") {
11429 throw newSyntaxError("Angle bracket } expected");
11430 }
11431
11432 getToken(); // end of file
11433
11434 if (token !== "") {
11435 throw newSyntaxError("End of file expected");
11436 }
11437
11438 getToken(); // remove temporary default options
11439
11440 delete graph.node;
11441 delete graph.edge;
11442 delete graph.graph;
11443 return graph;
11444 }
11445 /**
11446 * Parse a list with statements.
11447 *
11448 * @param {object} graph
11449 */
11450
11451
11452 function parseStatements(graph) {
11453 while (token !== "" && token != "}") {
11454 parseStatement(graph);
11455
11456 if (token === ";") {
11457 getToken();
11458 }
11459 }
11460 }
11461 /**
11462 * Parse a single statement. Can be a an attribute statement, node
11463 * statement, a series of node statements and edge statements, or a
11464 * parameter.
11465 *
11466 * @param {object} graph
11467 */
11468
11469
11470 function parseStatement(graph) {
11471 // parse subgraph
11472 var subgraph = parseSubgraph(graph);
11473
11474 if (subgraph) {
11475 // edge statements
11476 parseEdge(graph, subgraph);
11477 return;
11478 } // parse an attribute statement
11479
11480
11481 var attr = parseAttributeStatement(graph);
11482
11483 if (attr) {
11484 return;
11485 } // parse node
11486
11487
11488 if (tokenType != TOKENTYPE.IDENTIFIER) {
11489 throw newSyntaxError("Identifier expected");
11490 }
11491
11492 var id = token; // id can be a string or a number
11493
11494 getToken();
11495
11496 if (token === "=") {
11497 // id statement
11498 getToken();
11499
11500 if (tokenType != TOKENTYPE.IDENTIFIER) {
11501 throw newSyntaxError("Identifier expected");
11502 }
11503
11504 graph[id] = token;
11505 getToken(); // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] "
11506 } else {
11507 parseNodeStatement(graph, id);
11508 }
11509 }
11510 /**
11511 * Parse a subgraph
11512 *
11513 * @param {object} graph parent graph object
11514 * @returns {object | null} subgraph
11515 */
11516
11517
11518 function parseSubgraph(graph) {
11519 var subgraph = null; // optional subgraph keyword
11520
11521 if (token === "subgraph") {
11522 subgraph = {};
11523 subgraph.type = "subgraph";
11524 getToken(); // optional graph id
11525
11526 if (tokenType === TOKENTYPE.IDENTIFIER) {
11527 subgraph.id = token;
11528 getToken();
11529 }
11530 } // open angle bracket
11531
11532
11533 if (token === "{") {
11534 getToken();
11535
11536 if (!subgraph) {
11537 subgraph = {};
11538 }
11539
11540 subgraph.parent = graph;
11541 subgraph.node = graph.node;
11542 subgraph.edge = graph.edge;
11543 subgraph.graph = graph.graph; // statements
11544
11545 parseStatements(subgraph); // close angle bracket
11546
11547 if (token != "}") {
11548 throw newSyntaxError("Angle bracket } expected");
11549 }
11550
11551 getToken(); // remove temporary default options
11552
11553 delete subgraph.node;
11554 delete subgraph.edge;
11555 delete subgraph.graph;
11556 delete subgraph.parent; // register at the parent graph
11557
11558 if (!graph.subgraphs) {
11559 graph.subgraphs = [];
11560 }
11561
11562 graph.subgraphs.push(subgraph);
11563 }
11564
11565 return subgraph;
11566 }
11567 /**
11568 * parse an attribute statement like "node [shape=circle fontSize=16]".
11569 * Available keywords are 'node', 'edge', 'graph'.
11570 * The previous list with default attributes will be replaced
11571 *
11572 * @param {object} graph
11573 * @returns {string | null} keyword Returns the name of the parsed attribute
11574 * (node, edge, graph), or null if nothing
11575 * is parsed.
11576 */
11577
11578
11579 function parseAttributeStatement(graph) {
11580 // attribute statements
11581 if (token === "node") {
11582 getToken(); // node attributes
11583
11584 graph.node = parseAttributeList();
11585 return "node";
11586 } else if (token === "edge") {
11587 getToken(); // edge attributes
11588
11589 graph.edge = parseAttributeList();
11590 return "edge";
11591 } else if (token === "graph") {
11592 getToken(); // graph attributes
11593
11594 graph.graph = parseAttributeList();
11595 return "graph";
11596 }
11597
11598 return null;
11599 }
11600 /**
11601 * parse a node statement
11602 *
11603 * @param {object} graph
11604 * @param {string | number} id
11605 */
11606
11607
11608 function parseNodeStatement(graph, id) {
11609 // node statement
11610 var node = {
11611 id: id
11612 };
11613 var attr = parseAttributeList();
11614
11615 if (attr) {
11616 node.attr = attr;
11617 }
11618
11619 addNode(graph, node); // edge statements
11620
11621 parseEdge(graph, id);
11622 }
11623 /**
11624 * Parse an edge or a series of edges
11625 *
11626 * @param {object} graph
11627 * @param {string | number} from Id of the from node
11628 */
11629
11630
11631 function parseEdge(graph, from) {
11632 while (token === "->" || token === "--") {
11633 var to;
11634 var type = token;
11635 getToken();
11636 var subgraph = parseSubgraph(graph);
11637
11638 if (subgraph) {
11639 to = subgraph;
11640 } else {
11641 if (tokenType != TOKENTYPE.IDENTIFIER) {
11642 throw newSyntaxError("Identifier or subgraph expected");
11643 }
11644
11645 to = token;
11646 addNode(graph, {
11647 id: to
11648 });
11649 getToken();
11650 } // parse edge attributes
11651
11652
11653 var attr = parseAttributeList(); // create edge
11654
11655 var edge = createEdge(graph, from, to, type, attr);
11656 addEdge(graph, edge);
11657 from = to;
11658 }
11659 }
11660 /**
11661 * Parse a set with attributes,
11662 * for example [label="1.000", shape=solid]
11663 *
11664 * @returns {object | null} attr
11665 */
11666
11667
11668 function parseAttributeList() {
11669 var i;
11670 var attr = null; // edge styles of dot and vis
11671
11672 var edgeStyles = {
11673 dashed: true,
11674 solid: false,
11675 dotted: [1, 5]
11676 };
11677 /**
11678 * Define arrow types.
11679 * vis currently supports types defined in 'arrowTypes'.
11680 * Details of arrow shapes are described in
11681 * http://www.graphviz.org/content/arrow-shapes
11682 */
11683
11684 var arrowTypes = {
11685 dot: "circle",
11686 box: "box",
11687 crow: "crow",
11688 curve: "curve",
11689 icurve: "inv_curve",
11690 normal: "triangle",
11691 inv: "inv_triangle",
11692 diamond: "diamond",
11693 tee: "bar",
11694 vee: "vee"
11695 };
11696 /**
11697 * 'attr_list' contains attributes for checking if some of them are affected
11698 * later. For instance, both of 'arrowhead' and 'dir' (edge style defined
11699 * in DOT) make changes to 'arrows' attribute in vis.
11700 */
11701
11702 var attr_list = new Array();
11703 var attr_names = new Array(); // used for checking the case.
11704 // parse attributes
11705
11706 while (token === "[") {
11707 getToken();
11708 attr = {};
11709
11710 while (token !== "" && token != "]") {
11711 if (tokenType != TOKENTYPE.IDENTIFIER) {
11712 throw newSyntaxError("Attribute name expected");
11713 }
11714
11715 var name = token;
11716 getToken();
11717
11718 if (token != "=") {
11719 throw newSyntaxError("Equal sign = expected");
11720 }
11721
11722 getToken();
11723
11724 if (tokenType != TOKENTYPE.IDENTIFIER) {
11725 throw newSyntaxError("Attribute value expected");
11726 }
11727
11728 var value = token; // convert from dot style to vis
11729
11730 if (name === "style") {
11731 value = edgeStyles[value];
11732 }
11733
11734 var arrowType;
11735
11736 if (name === "arrowhead") {
11737 arrowType = arrowTypes[value];
11738 name = "arrows";
11739 value = {
11740 to: {
11741 enabled: true,
11742 type: arrowType
11743 }
11744 };
11745 }
11746
11747 if (name === "arrowtail") {
11748 arrowType = arrowTypes[value];
11749 name = "arrows";
11750 value = {
11751 from: {
11752 enabled: true,
11753 type: arrowType
11754 }
11755 };
11756 }
11757
11758 attr_list.push({
11759 attr: attr,
11760 name: name,
11761 value: value
11762 });
11763 attr_names.push(name);
11764 getToken();
11765
11766 if (token == ",") {
11767 getToken();
11768 }
11769 }
11770
11771 if (token != "]") {
11772 throw newSyntaxError("Bracket ] expected");
11773 }
11774
11775 getToken();
11776 }
11777 /**
11778 * As explained in [1], graphviz has limitations for combination of
11779 * arrow[head|tail] and dir. If attribute list includes 'dir',
11780 * following cases just be supported.
11781 * 1. both or none + arrowhead, arrowtail
11782 * 2. forward + arrowhead (arrowtail is not affedted)
11783 * 3. back + arrowtail (arrowhead is not affected)
11784 * [1] https://www.graphviz.org/doc/info/attrs.html#h:undir_note
11785 */
11786
11787
11788 if (includes(attr_names).call(attr_names, "dir")) {
11789 var idx = {}; // get index of 'arrows' and 'dir'
11790
11791 idx.arrows = {};
11792
11793 for (i = 0; i < attr_list.length; i++) {
11794 if (attr_list[i].name === "arrows") {
11795 if (attr_list[i].value.to != null) {
11796 idx.arrows.to = i;
11797 } else if (attr_list[i].value.from != null) {
11798 idx.arrows.from = i;
11799 } else {
11800 throw newSyntaxError("Invalid value of arrows");
11801 }
11802 } else if (attr_list[i].name === "dir") {
11803 idx.dir = i;
11804 }
11805 } // first, add default arrow shape if it is not assigned to avoid error
11806
11807
11808 var dir_type = attr_list[idx.dir].value;
11809
11810 if (!includes(attr_names).call(attr_names, "arrows")) {
11811 if (dir_type === "both") {
11812 attr_list.push({
11813 attr: attr_list[idx.dir].attr,
11814 name: "arrows",
11815 value: {
11816 to: {
11817 enabled: true
11818 }
11819 }
11820 });
11821 idx.arrows.to = attr_list.length - 1;
11822 attr_list.push({
11823 attr: attr_list[idx.dir].attr,
11824 name: "arrows",
11825 value: {
11826 from: {
11827 enabled: true
11828 }
11829 }
11830 });
11831 idx.arrows.from = attr_list.length - 1;
11832 } else if (dir_type === "forward") {
11833 attr_list.push({
11834 attr: attr_list[idx.dir].attr,
11835 name: "arrows",
11836 value: {
11837 to: {
11838 enabled: true
11839 }
11840 }
11841 });
11842 idx.arrows.to = attr_list.length - 1;
11843 } else if (dir_type === "back") {
11844 attr_list.push({
11845 attr: attr_list[idx.dir].attr,
11846 name: "arrows",
11847 value: {
11848 from: {
11849 enabled: true
11850 }
11851 }
11852 });
11853 idx.arrows.from = attr_list.length - 1;
11854 } else if (dir_type === "none") {
11855 attr_list.push({
11856 attr: attr_list[idx.dir].attr,
11857 name: "arrows",
11858 value: ""
11859 });
11860 idx.arrows.to = attr_list.length - 1;
11861 } else {
11862 throw newSyntaxError('Invalid dir type "' + dir_type + '"');
11863 }
11864 }
11865
11866 var from_type;
11867 var to_type; // update 'arrows' attribute from 'dir'.
11868
11869 if (dir_type === "both") {
11870 // both of shapes of 'from' and 'to' are given
11871 if (idx.arrows.to && idx.arrows.from) {
11872 to_type = attr_list[idx.arrows.to].value.to.type;
11873 from_type = attr_list[idx.arrows.from].value.from.type;
11874 attr_list[idx.arrows.to] = {
11875 attr: attr_list[idx.arrows.to].attr,
11876 name: attr_list[idx.arrows.to].name,
11877 value: {
11878 to: {
11879 enabled: true,
11880 type: to_type
11881 },
11882 from: {
11883 enabled: true,
11884 type: from_type
11885 }
11886 }
11887 };
11888
11889 splice(attr_list).call(attr_list, idx.arrows.from, 1); // shape of 'to' is assigned and use default to 'from'
11890
11891 } else if (idx.arrows.to) {
11892 to_type = attr_list[idx.arrows.to].value.to.type;
11893 from_type = "arrow";
11894 attr_list[idx.arrows.to] = {
11895 attr: attr_list[idx.arrows.to].attr,
11896 name: attr_list[idx.arrows.to].name,
11897 value: {
11898 to: {
11899 enabled: true,
11900 type: to_type
11901 },
11902 from: {
11903 enabled: true,
11904 type: from_type
11905 }
11906 }
11907 }; // only shape of 'from' is assigned and use default for 'to'
11908 } else if (idx.arrows.from) {
11909 to_type = "arrow";
11910 from_type = attr_list[idx.arrows.from].value.from.type;
11911 attr_list[idx.arrows.from] = {
11912 attr: attr_list[idx.arrows.from].attr,
11913 name: attr_list[idx.arrows.from].name,
11914 value: {
11915 to: {
11916 enabled: true,
11917 type: to_type
11918 },
11919 from: {
11920 enabled: true,
11921 type: from_type
11922 }
11923 }
11924 };
11925 }
11926 } else if (dir_type === "back") {
11927 // given both of shapes, but use only 'from'
11928 if (idx.arrows.to && idx.arrows.from) {
11929 to_type = "";
11930 from_type = attr_list[idx.arrows.from].value.from.type;
11931 attr_list[idx.arrows.from] = {
11932 attr: attr_list[idx.arrows.from].attr,
11933 name: attr_list[idx.arrows.from].name,
11934 value: {
11935 to: {
11936 enabled: true,
11937 type: to_type
11938 },
11939 from: {
11940 enabled: true,
11941 type: from_type
11942 }
11943 }
11944 }; // given shape of 'to', but does not use it
11945 } else if (idx.arrows.to) {
11946 to_type = "";
11947 from_type = "arrow";
11948 idx.arrows.from = idx.arrows.to;
11949 attr_list[idx.arrows.from] = {
11950 attr: attr_list[idx.arrows.from].attr,
11951 name: attr_list[idx.arrows.from].name,
11952 value: {
11953 to: {
11954 enabled: true,
11955 type: to_type
11956 },
11957 from: {
11958 enabled: true,
11959 type: from_type
11960 }
11961 }
11962 }; // assign given 'from' shape
11963 } else if (idx.arrows.from) {
11964 to_type = "";
11965 from_type = attr_list[idx.arrows.from].value.from.type;
11966 attr_list[idx.arrows.to] = {
11967 attr: attr_list[idx.arrows.from].attr,
11968 name: attr_list[idx.arrows.from].name,
11969 value: {
11970 to: {
11971 enabled: true,
11972 type: to_type
11973 },
11974 from: {
11975 enabled: true,
11976 type: from_type
11977 }
11978 }
11979 };
11980 }
11981
11982 attr_list[idx.arrows.from] = {
11983 attr: attr_list[idx.arrows.from].attr,
11984 name: attr_list[idx.arrows.from].name,
11985 value: {
11986 from: {
11987 enabled: true,
11988 type: attr_list[idx.arrows.from].value.from.type
11989 }
11990 }
11991 };
11992 } else if (dir_type === "none") {
11993 var idx_arrow;
11994
11995 if (idx.arrows.to) {
11996 idx_arrow = idx.arrows.to;
11997 } else {
11998 idx_arrow = idx.arrows.from;
11999 }
12000
12001 attr_list[idx_arrow] = {
12002 attr: attr_list[idx_arrow].attr,
12003 name: attr_list[idx_arrow].name,
12004 value: ""
12005 };
12006 } else if (dir_type === "forward") {
12007 // given both of shapes, but use only 'to'
12008 if (idx.arrows.to && idx.arrows.from) {
12009 to_type = attr_list[idx.arrows.to].value.to.type;
12010 from_type = "";
12011 attr_list[idx.arrows.to] = {
12012 attr: attr_list[idx.arrows.to].attr,
12013 name: attr_list[idx.arrows.to].name,
12014 value: {
12015 to: {
12016 enabled: true,
12017 type: to_type
12018 },
12019 from: {
12020 enabled: true,
12021 type: from_type
12022 }
12023 }
12024 }; // assign given 'to' shape
12025 } else if (idx.arrows.to) {
12026 to_type = attr_list[idx.arrows.to].value.to.type;
12027 from_type = "";
12028 attr_list[idx.arrows.to] = {
12029 attr: attr_list[idx.arrows.to].attr,
12030 name: attr_list[idx.arrows.to].name,
12031 value: {
12032 to: {
12033 enabled: true,
12034 type: to_type
12035 },
12036 from: {
12037 enabled: true,
12038 type: from_type
12039 }
12040 }
12041 }; // given shape of 'from', but does not use it
12042 } else if (idx.arrows.from) {
12043 to_type = "arrow";
12044 from_type = "";
12045 idx.arrows.to = idx.arrows.from;
12046 attr_list[idx.arrows.to] = {
12047 attr: attr_list[idx.arrows.to].attr,
12048 name: attr_list[idx.arrows.to].name,
12049 value: {
12050 to: {
12051 enabled: true,
12052 type: to_type
12053 },
12054 from: {
12055 enabled: true,
12056 type: from_type
12057 }
12058 }
12059 };
12060 }
12061
12062 attr_list[idx.arrows.to] = {
12063 attr: attr_list[idx.arrows.to].attr,
12064 name: attr_list[idx.arrows.to].name,
12065 value: {
12066 to: {
12067 enabled: true,
12068 type: attr_list[idx.arrows.to].value.to.type
12069 }
12070 }
12071 };
12072 } else {
12073 throw newSyntaxError('Invalid dir type "' + dir_type + '"');
12074 } // remove 'dir' attribute no need anymore
12075
12076
12077 splice(attr_list).call(attr_list, idx.dir, 1);
12078 } // parse 'penwidth'
12079
12080
12081 var nof_attr_list;
12082
12083 if (includes(attr_names).call(attr_names, "penwidth")) {
12084 var tmp_attr_list = [];
12085 nof_attr_list = attr_list.length;
12086
12087 for (i = 0; i < nof_attr_list; i++) {
12088 // exclude 'width' from attr_list if 'penwidth' exists
12089 if (attr_list[i].name !== "width") {
12090 if (attr_list[i].name === "penwidth") {
12091 attr_list[i].name = "width";
12092 }
12093
12094 tmp_attr_list.push(attr_list[i]);
12095 }
12096 }
12097
12098 attr_list = tmp_attr_list;
12099 }
12100
12101 nof_attr_list = attr_list.length;
12102
12103 for (i = 0; i < nof_attr_list; i++) {
12104 setValue(attr_list[i].attr, attr_list[i].name, attr_list[i].value);
12105 }
12106
12107 return attr;
12108 }
12109 /**
12110 * Create a syntax error with extra information on current token and index.
12111 *
12112 * @param {string} message
12113 * @returns {SyntaxError} err
12114 */
12115
12116
12117 function newSyntaxError(message) {
12118 return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ")");
12119 }
12120 /**
12121 * Chop off text after a maximum length
12122 *
12123 * @param {string} text
12124 * @param {number} maxLength
12125 * @returns {string}
12126 */
12127
12128
12129 function chop(text, maxLength) {
12130 return text.length <= maxLength ? text : text.substr(0, 27) + "...";
12131 }
12132 /**
12133 * Execute a function fn for each pair of elements in two arrays
12134 *
12135 * @param {Array | *} array1
12136 * @param {Array | *} array2
12137 * @param {Function} fn
12138 */
12139
12140
12141 function forEach2(array1, array2, fn) {
12142 if (isArray$1(array1)) {
12143 forEach$2(array1).call(array1, function (elem1) {
12144 if (isArray$1(array2)) {
12145 forEach$2(array2).call(array2, function (elem2) {
12146 fn(elem1, elem2);
12147 });
12148 } else {
12149 fn(elem1, array2);
12150 }
12151 });
12152 } else {
12153 if (isArray$1(array2)) {
12154 forEach$2(array2).call(array2, function (elem2) {
12155 fn(array1, elem2);
12156 });
12157 } else {
12158 fn(array1, array2);
12159 }
12160 }
12161 }
12162 /**
12163 * Set a nested property on an object
12164 * When nested objects are missing, they will be created.
12165 * For example setProp({}, 'font.color', 'red') will return {font: {color: 'red'}}
12166 *
12167 * @param {object} object
12168 * @param {string} path A dot separated string like 'font.color'
12169 * @param {*} value Value for the property
12170 * @returns {object} Returns the original object, allows for chaining.
12171 */
12172
12173
12174 function setProp(object, path, value) {
12175 var names = path.split(".");
12176 var prop = names.pop(); // traverse over the nested objects
12177
12178 var obj = object;
12179
12180 for (var i = 0; i < names.length; i++) {
12181 var name = names[i];
12182
12183 if (!(name in obj)) {
12184 obj[name] = {};
12185 }
12186
12187 obj = obj[name];
12188 } // set the property value
12189
12190
12191 obj[prop] = value;
12192 return object;
12193 }
12194 /**
12195 * Convert an object with DOT attributes to their vis.js equivalents.
12196 *
12197 * @param {object} attr Object with DOT attributes
12198 * @param {object} mapping
12199 * @returns {object} Returns an object with vis.js attributes
12200 */
12201
12202
12203 function convertAttr(attr, mapping) {
12204 var converted = {};
12205
12206 for (var prop in attr) {
12207 if (attr.hasOwnProperty(prop)) {
12208 var visProp = mapping[prop];
12209
12210 if (isArray$1(visProp)) {
12211 forEach$2(visProp).call(visProp, function (visPropI) {
12212 setProp(converted, visPropI, attr[prop]);
12213 });
12214 } else if (typeof visProp === "string") {
12215 setProp(converted, visProp, attr[prop]);
12216 } else {
12217 setProp(converted, prop, attr[prop]);
12218 }
12219 }
12220 }
12221
12222 return converted;
12223 }
12224 /**
12225 * Convert a string containing a graph in DOT language into a map containing
12226 * with nodes and edges in the format of graph.
12227 *
12228 * @param {string} data Text containing a graph in DOT-notation
12229 * @returns {object} graphData
12230 */
12231
12232
12233 function DOTToGraph(data) {
12234 // parse the DOT file
12235 var dotData = parseDOT(data);
12236 var graphData = {
12237 nodes: [],
12238 edges: [],
12239 options: {}
12240 }; // copy the nodes
12241
12242 if (dotData.nodes) {
12243 var _context2;
12244
12245 forEach$2(_context2 = dotData.nodes).call(_context2, function (dotNode) {
12246 var graphNode = {
12247 id: dotNode.id,
12248 label: String(dotNode.label || dotNode.id)
12249 };
12250 merge$1(graphNode, convertAttr(dotNode.attr, NODE_ATTR_MAPPING));
12251
12252 if (graphNode.image) {
12253 graphNode.shape = "image";
12254 }
12255
12256 graphData.nodes.push(graphNode);
12257 });
12258 } // copy the edges
12259
12260
12261 if (dotData.edges) {
12262 var _context3;
12263
12264 /**
12265 * Convert an edge in DOT format to an edge with VisGraph format
12266 *
12267 * @param {object} dotEdge
12268 * @returns {object} graphEdge
12269 */
12270 var convertEdge = function convertEdge(dotEdge) {
12271 var graphEdge = {
12272 from: dotEdge.from,
12273 to: dotEdge.to
12274 };
12275 merge$1(graphEdge, convertAttr(dotEdge.attr, EDGE_ATTR_MAPPING)); // Add arrows attribute to default styled arrow.
12276 // The reason why default style is not added in parseAttributeList() is
12277 // because only default is cleared before here.
12278
12279 if (graphEdge.arrows == null && dotEdge.type === "->") {
12280 graphEdge.arrows = "to";
12281 }
12282
12283 return graphEdge;
12284 };
12285
12286 forEach$2(_context3 = dotData.edges).call(_context3, function (dotEdge) {
12287 var from, to;
12288
12289 if (dotEdge.from instanceof Object) {
12290 from = dotEdge.from.nodes;
12291 } else {
12292 from = {
12293 id: dotEdge.from
12294 };
12295 }
12296
12297 if (dotEdge.to instanceof Object) {
12298 to = dotEdge.to.nodes;
12299 } else {
12300 to = {
12301 id: dotEdge.to
12302 };
12303 }
12304
12305 if (dotEdge.from instanceof Object && dotEdge.from.edges) {
12306 var _context4;
12307
12308 forEach$2(_context4 = dotEdge.from.edges).call(_context4, function (subEdge) {
12309 var graphEdge = convertEdge(subEdge);
12310 graphData.edges.push(graphEdge);
12311 });
12312 }
12313
12314 forEach2(from, to, function (from, to) {
12315 var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr);
12316 var graphEdge = convertEdge(subEdge);
12317 graphData.edges.push(graphEdge);
12318 });
12319
12320 if (dotEdge.to instanceof Object && dotEdge.to.edges) {
12321 var _context5;
12322
12323 forEach$2(_context5 = dotEdge.to.edges).call(_context5, function (subEdge) {
12324 var graphEdge = convertEdge(subEdge);
12325 graphData.edges.push(graphEdge);
12326 });
12327 }
12328 });
12329 } // copy the options
12330
12331
12332 if (dotData.attr) {
12333 graphData.options = dotData.attr;
12334 }
12335
12336 return graphData;
12337 }
12338 /* eslint-enable no-var */
12339
12340 /* eslint-enable no-unused-vars */
12341
12342 /* eslint-enable no-prototype-builtins */
12343
12344 var dotparser = /*#__PURE__*/Object.freeze({
12345 __proto__: null,
12346 parseDOT: parseDOT,
12347 DOTToGraph: DOTToGraph
12348 });
12349
12350 /**
12351 * Convert Gephi to Vis.
12352 *
12353 * @param gephiJSON - The parsed JSON data in Gephi format.
12354 * @param optionsObj - Additional options.
12355 *
12356 * @returns The converted data ready to be used in Vis.
12357 */
12358 function parseGephi(gephiJSON, optionsObj) {
12359 var _context;
12360
12361 var options = {
12362 edges: {
12363 inheritColor: false
12364 },
12365 nodes: {
12366 fixed: false,
12367 parseColor: false
12368 }
12369 };
12370
12371 if (optionsObj != null) {
12372 if (optionsObj.fixed != null) {
12373 options.nodes.fixed = optionsObj.fixed;
12374 }
12375
12376 if (optionsObj.parseColor != null) {
12377 options.nodes.parseColor = optionsObj.parseColor;
12378 }
12379
12380 if (optionsObj.inheritColor != null) {
12381 options.edges.inheritColor = optionsObj.inheritColor;
12382 }
12383 }
12384
12385 var gEdges = gephiJSON.edges;
12386
12387 var vEdges = map$3(gEdges).call(gEdges, function (gEdge) {
12388 var vEdge = {
12389 from: gEdge.source,
12390 id: gEdge.id,
12391 to: gEdge.target
12392 };
12393
12394 if (gEdge.attributes != null) {
12395 vEdge.attributes = gEdge.attributes;
12396 }
12397
12398 if (gEdge.label != null) {
12399 vEdge.label = gEdge.label;
12400 }
12401
12402 if (gEdge.attributes != null && gEdge.attributes.title != null) {
12403 vEdge.title = gEdge.attributes.title;
12404 }
12405
12406 if (gEdge.type === "Directed") {
12407 vEdge.arrows = "to";
12408 } // edge['value'] = gEdge.attributes != null ? gEdge.attributes.Weight : undefined;
12409 // edge['width'] = edge['value'] != null ? undefined : edgegEdge.size;
12410
12411
12412 if (gEdge.color && options.edges.inheritColor === false) {
12413 vEdge.color = gEdge.color;
12414 }
12415
12416 return vEdge;
12417 });
12418
12419 var vNodes = map$3(_context = gephiJSON.nodes).call(_context, function (gNode) {
12420 var vNode = {
12421 id: gNode.id,
12422 fixed: options.nodes.fixed && gNode.x != null && gNode.y != null
12423 };
12424
12425 if (gNode.attributes != null) {
12426 vNode.attributes = gNode.attributes;
12427 }
12428
12429 if (gNode.label != null) {
12430 vNode.label = gNode.label;
12431 }
12432
12433 if (gNode.size != null) {
12434 vNode.size = gNode.size;
12435 }
12436
12437 if (gNode.attributes != null && gNode.attributes.title != null) {
12438 vNode.title = gNode.attributes.title;
12439 }
12440
12441 if (gNode.title != null) {
12442 vNode.title = gNode.title;
12443 }
12444
12445 if (gNode.x != null) {
12446 vNode.x = gNode.x;
12447 }
12448
12449 if (gNode.y != null) {
12450 vNode.y = gNode.y;
12451 }
12452
12453 if (gNode.color != null) {
12454 if (options.nodes.parseColor === true) {
12455 vNode.color = gNode.color;
12456 } else {
12457 vNode.color = {
12458 background: gNode.color,
12459 border: gNode.color,
12460 highlight: {
12461 background: gNode.color,
12462 border: gNode.color
12463 },
12464 hover: {
12465 background: gNode.color,
12466 border: gNode.color
12467 }
12468 };
12469 }
12470 }
12471
12472 return vNode;
12473 });
12474
12475 return {
12476 nodes: vNodes,
12477 edges: vEdges
12478 };
12479 }
12480
12481 var gephiParser = /*#__PURE__*/Object.freeze({
12482 __proto__: null,
12483 parseGephi: parseGephi
12484 });
12485
12486 // English
12487 var en = {
12488 addDescription: "Click in an empty space to place a new node.",
12489 addEdge: "Add Edge",
12490 addNode: "Add Node",
12491 back: "Back",
12492 close: "Close",
12493 createEdgeError: "Cannot link edges to a cluster.",
12494 del: "Delete selected",
12495 deleteClusterError: "Clusters cannot be deleted.",
12496 edgeDescription: "Click on a node and drag the edge to another node to connect them.",
12497 edit: "Edit",
12498 editClusterError: "Clusters cannot be edited.",
12499 editEdge: "Edit Edge",
12500 editEdgeDescription: "Click on the control points and drag them to a node to connect to it.",
12501 editNode: "Edit Node"
12502 }; // German
12503
12504 var de = {
12505 addDescription: "Klicke auf eine freie Stelle, um einen neuen Knoten zu plazieren.",
12506 addEdge: "Kante hinzuf\xFCgen",
12507 addNode: "Knoten hinzuf\xFCgen",
12508 back: "Zur\xFCck",
12509 close: "Schließen",
12510 createEdgeError: "Es ist nicht m\xF6glich, Kanten mit Clustern zu verbinden.",
12511 del: "L\xF6sche Auswahl",
12512 deleteClusterError: "Cluster k\xF6nnen nicht gel\xF6scht werden.",
12513 edgeDescription: "Klicke auf einen Knoten und ziehe die Kante zu einem anderen Knoten, um diese zu verbinden.",
12514 edit: "Editieren",
12515 editClusterError: "Cluster k\xF6nnen nicht editiert werden.",
12516 editEdge: "Kante editieren",
12517 editEdgeDescription: "Klicke auf die Verbindungspunkte und ziehe diese auf einen Knoten, um sie zu verbinden.",
12518 editNode: "Knoten editieren"
12519 }; // Spanish
12520
12521 var es = {
12522 addDescription: "Haga clic en un lugar vac\xEDo para colocar un nuevo nodo.",
12523 addEdge: "A\xF1adir arista",
12524 addNode: "A\xF1adir nodo",
12525 back: "Atr\xE1s",
12526 close: "Cerrar",
12527 createEdgeError: "No se puede conectar una arista a un grupo.",
12528 del: "Eliminar selecci\xF3n",
12529 deleteClusterError: "No es posible eliminar grupos.",
12530 edgeDescription: "Haga clic en un nodo y arrastre la arista hacia otro nodo para conectarlos.",
12531 edit: "Editar",
12532 editClusterError: "No es posible editar grupos.",
12533 editEdge: "Editar arista",
12534 editEdgeDescription: "Haga clic en un punto de control y arrastrelo a un nodo para conectarlo.",
12535 editNode: "Editar nodo"
12536 }; //Italiano
12537
12538 var it = {
12539 addDescription: "Clicca per aggiungere un nuovo nodo",
12540 addEdge: "Aggiungi un vertice",
12541 addNode: "Aggiungi un nodo",
12542 back: "Indietro",
12543 close: "Chiudere",
12544 createEdgeError: "Non si possono collegare vertici ad un cluster",
12545 del: "Cancella la selezione",
12546 deleteClusterError: "I cluster non possono essere cancellati",
12547 edgeDescription: "Clicca su un nodo e trascinalo ad un altro nodo per connetterli.",
12548 edit: "Modifica",
12549 editClusterError: "I clusters non possono essere modificati.",
12550 editEdge: "Modifica il vertice",
12551 editEdgeDescription: "Clicca sui Punti di controllo e trascinali ad un nodo per connetterli.",
12552 editNode: "Modifica il nodo"
12553 }; // Dutch
12554
12555 var nl = {
12556 addDescription: "Klik op een leeg gebied om een nieuwe node te maken.",
12557 addEdge: "Link toevoegen",
12558 addNode: "Node toevoegen",
12559 back: "Terug",
12560 close: "Sluiten",
12561 createEdgeError: "Kan geen link maken naar een cluster.",
12562 del: "Selectie verwijderen",
12563 deleteClusterError: "Clusters kunnen niet worden verwijderd.",
12564 edgeDescription: "Klik op een node en sleep de link naar een andere node om ze te verbinden.",
12565 edit: "Wijzigen",
12566 editClusterError: "Clusters kunnen niet worden aangepast.",
12567 editEdge: "Link wijzigen",
12568 editEdgeDescription: "Klik op de verbindingspunten en sleep ze naar een node om daarmee te verbinden.",
12569 editNode: "Node wijzigen"
12570 }; // Portuguese Brazil
12571
12572 var pt = {
12573 addDescription: "Clique em um espaço em branco para adicionar um novo nó",
12574 addEdge: "Adicionar aresta",
12575 addNode: "Adicionar nó",
12576 back: "Voltar",
12577 close: "Fechar",
12578 createEdgeError: "Não foi possível linkar arestas a um cluster.",
12579 del: "Remover selecionado",
12580 deleteClusterError: "Clusters não puderam ser removidos.",
12581 edgeDescription: "Clique em um nó e arraste a aresta até outro nó para conectá-los",
12582 edit: "Editar",
12583 editClusterError: "Clusters não puderam ser editados.",
12584 editEdge: "Editar aresta",
12585 editEdgeDescription: "Clique nos pontos de controle e os arraste para um nó para conectá-los",
12586 editNode: "Editar nó"
12587 }; // Russian
12588
12589 var ru = {
12590 addDescription: "Кликните в свободное место, чтобы добавить новый узел.",
12591 addEdge: "Добавить ребро",
12592 addNode: "Добавить узел",
12593 back: "Назад",
12594 close: "Закрывать",
12595 createEdgeError: "Невозможно соединить ребра в кластер.",
12596 del: "Удалить выбранное",
12597 deleteClusterError: "Кластеры не могут быть удалены",
12598 edgeDescription: "Кликните на узел и протяните ребро к другому узлу, чтобы соединить их.",
12599 edit: "Редактировать",
12600 editClusterError: "Кластеры недоступны для редактирования.",
12601 editEdge: "Редактировать ребро",
12602 editEdgeDescription: "Кликните на контрольные точки и перетащите их в узел, чтобы подключиться к нему.",
12603 editNode: "Редактировать узел"
12604 }; // Chinese
12605
12606 var cn = {
12607 addDescription: "单击空白处放置新节点。",
12608 addEdge: "添加连接线",
12609 addNode: "添加节点",
12610 back: "返回",
12611 close: "關閉",
12612 createEdgeError: "无法将连接线连接到群集。",
12613 del: "删除选定",
12614 deleteClusterError: "无法删除群集。",
12615 edgeDescription: "单击某个节点并将该连接线拖动到另一个节点以连接它们。",
12616 edit: "编辑",
12617 editClusterError: "无法编辑群集。",
12618 editEdge: "编辑连接线",
12619 editEdgeDescription: "单击控制节点并将它们拖到节点上连接。",
12620 editNode: "编辑节点"
12621 }; // Ukrainian
12622
12623 var uk = {
12624 addDescription: "Kлікніть на вільне місце, щоб додати новий вузол.",
12625 addEdge: "Додати край",
12626 addNode: "Додати вузол",
12627 back: "Назад",
12628 close: "Закрити",
12629 createEdgeError: "Не можливо об'єднати краї в групу.",
12630 del: "Видалити обране",
12631 deleteClusterError: "Групи не можуть бути видалені.",
12632 edgeDescription: "Клікніть на вузол і перетягніть край до іншого вузла, щоб їх з'єднати.",
12633 edit: "Редагувати",
12634 editClusterError: "Групи недоступні для редагування.",
12635 editEdge: "Редагувати край",
12636 editEdgeDescription: "Клікніть на контрольні точки і перетягніть їх у вузол, щоб підключитися до нього.",
12637 editNode: "Редагувати вузол"
12638 }; // French
12639
12640 var fr = {
12641 addDescription: "Cliquez dans un endroit vide pour placer un nœud.",
12642 addEdge: "Ajouter un lien",
12643 addNode: "Ajouter un nœud",
12644 back: "Retour",
12645 close: "Fermer",
12646 createEdgeError: "Impossible de créer un lien vers un cluster.",
12647 del: "Effacer la sélection",
12648 deleteClusterError: "Les clusters ne peuvent pas être effacés.",
12649 edgeDescription: "Cliquez sur un nœud et glissez le lien vers un autre nœud pour les connecter.",
12650 edit: "Éditer",
12651 editClusterError: "Les clusters ne peuvent pas être édités.",
12652 editEdge: "Éditer le lien",
12653 editEdgeDescription: "Cliquez sur les points de contrôle et glissez-les pour connecter un nœud.",
12654 editNode: "Éditer le nœud"
12655 }; // Czech
12656
12657 var cs = {
12658 addDescription: "Kluknutím do prázdného prostoru můžete přidat nový vrchol.",
12659 addEdge: "Přidat hranu",
12660 addNode: "Přidat vrchol",
12661 back: "Zpět",
12662 close: "Zavřít",
12663 createEdgeError: "Nelze připojit hranu ke shluku.",
12664 del: "Smazat výběr",
12665 deleteClusterError: "Nelze mazat shluky.",
12666 edgeDescription: "Přetažením z jednoho vrcholu do druhého můžete spojit tyto vrcholy novou hranou.",
12667 edit: "Upravit",
12668 editClusterError: "Nelze upravovat shluky.",
12669 editEdge: "Upravit hranu",
12670 editEdgeDescription: "Přetažením kontrolního vrcholu hrany ji můžete připojit k jinému vrcholu.",
12671 editNode: "Upravit vrchol"
12672 };
12673
12674 var locales = /*#__PURE__*/Object.freeze({
12675 __proto__: null,
12676 en: en,
12677 de: de,
12678 es: es,
12679 it: it,
12680 nl: nl,
12681 pt: pt,
12682 ru: ru,
12683 cn: cn,
12684 uk: uk,
12685 fr: fr,
12686 cs: cs
12687 });
12688
12689 /**
12690 * Normalizes language code into the format used internally.
12691 *
12692 * @param locales - All the available locales.
12693 * @param rawCode - The original code as supplied by the user.
12694 *
12695 * @returns Language code in the format language-COUNTRY or language, eventually
12696 * fallbacks to en.
12697 */
12698 function normalizeLanguageCode(locales, rawCode) {
12699 try {
12700 var _rawCode$split = rawCode.split(/[-_ /]/, 2),
12701 _rawCode$split2 = _slicedToArray(_rawCode$split, 2),
12702 rawLanguage = _rawCode$split2[0],
12703 rawCountry = _rawCode$split2[1];
12704
12705 var language = rawLanguage != null ? rawLanguage.toLowerCase() : null;
12706 var country = rawCountry != null ? rawCountry.toUpperCase() : null;
12707
12708 if (language && country) {
12709 var code = language + "-" + country;
12710
12711 if (Object.prototype.hasOwnProperty.call(locales, code)) {
12712 return code;
12713 } else {
12714 var _context;
12715
12716 console.warn(concat(_context = "Unknown variant ".concat(country, " of language ")).call(_context, language, "."));
12717 }
12718 }
12719
12720 if (language) {
12721 var _code = language;
12722
12723 if (Object.prototype.hasOwnProperty.call(locales, _code)) {
12724 return _code;
12725 } else {
12726 console.warn("Unknown language ".concat(language));
12727 }
12728 }
12729
12730 console.warn("Unknown locale ".concat(rawCode, ", falling back to English."));
12731 return "en";
12732 } catch (error) {
12733 console.error(error);
12734 console.warn("Unexpected error while normalizing locale ".concat(rawCode, ", falling back to English."));
12735 return "en";
12736 }
12737 }
12738
12739 /**
12740 * Associates a canvas to a given image, containing a number of renderings
12741 * of the image at various sizes.
12742 *
12743 * This technique is known as 'mipmapping'.
12744 *
12745 * NOTE: Images can also be of type 'data:svg+xml`. This code also works
12746 * for svg, but the mipmapping may not be necessary.
12747 *
12748 * @param {Image} image
12749 */
12750 var CachedImage = /*#__PURE__*/function () {
12751 /**
12752 * @ignore
12753 */
12754 function CachedImage() {
12755 _classCallCheck(this, CachedImage);
12756
12757 this.NUM_ITERATIONS = 4; // Number of items in the coordinates array
12758
12759 this.image = new Image();
12760 this.canvas = document.createElement("canvas");
12761 }
12762 /**
12763 * Called when the image has been successfully loaded.
12764 */
12765
12766
12767 _createClass(CachedImage, [{
12768 key: "init",
12769 value: function init() {
12770 if (this.initialized()) return;
12771 this.src = this.image.src; // For same interface with Image
12772
12773 var w = this.image.width;
12774 var h = this.image.height; // Ease external access
12775
12776 this.width = w;
12777 this.height = h;
12778 var h2 = Math.floor(h / 2);
12779 var h4 = Math.floor(h / 4);
12780 var h8 = Math.floor(h / 8);
12781 var h16 = Math.floor(h / 16);
12782 var w2 = Math.floor(w / 2);
12783 var w4 = Math.floor(w / 4);
12784 var w8 = Math.floor(w / 8);
12785 var w16 = Math.floor(w / 16); // Make canvas as small as possible
12786
12787 this.canvas.width = 3 * w4;
12788 this.canvas.height = h2; // Coordinates and sizes of images contained in the canvas
12789 // Values per row: [top x, left y, width, height]
12790
12791 this.coordinates = [[0, 0, w2, h2], [w2, 0, w4, h4], [w2, h4, w8, h8], [5 * w8, h4, w16, h16]];
12792
12793 this._fillMipMap();
12794 }
12795 /**
12796 * @returns {boolean} true if init() has been called, false otherwise.
12797 */
12798
12799 }, {
12800 key: "initialized",
12801 value: function initialized() {
12802 return this.coordinates !== undefined;
12803 }
12804 /**
12805 * Redraw main image in various sizes to the context.
12806 *
12807 * The rationale behind this is to reduce artefacts due to interpolation
12808 * at differing zoom levels.
12809 *
12810 * Source: http://stackoverflow.com/q/18761404/1223531
12811 *
12812 * This methods takes the resizing out of the drawing loop, in order to
12813 * reduce performance overhead.
12814 *
12815 * TODO: The code assumes that a 2D context can always be gotten. This is
12816 * not necessarily true! OTOH, if not true then usage of this class
12817 * is senseless.
12818 *
12819 * @private
12820 */
12821
12822 }, {
12823 key: "_fillMipMap",
12824 value: function _fillMipMap() {
12825 var ctx = this.canvas.getContext("2d"); // First zoom-level comes from the image
12826
12827 var to = this.coordinates[0];
12828 ctx.drawImage(this.image, to[0], to[1], to[2], to[3]); // The rest are copy actions internal to the canvas/context
12829
12830 for (var iterations = 1; iterations < this.NUM_ITERATIONS; iterations++) {
12831 var from = this.coordinates[iterations - 1];
12832 var _to = this.coordinates[iterations];
12833 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], _to[0], _to[1], _to[2], _to[3]);
12834 }
12835 }
12836 /**
12837 * Draw the image, using the mipmap if necessary.
12838 *
12839 * MipMap is only used if param factor > 2; otherwise, original bitmap
12840 * is resized. This is also used to skip mipmap usage, e.g. by setting factor = 1
12841 *
12842 * Credits to 'Alex de Mulder' for original implementation.
12843 *
12844 * @param {CanvasRenderingContext2D} ctx context on which to draw zoomed image
12845 * @param {Float} factor scale factor at which to draw
12846 * @param {number} left
12847 * @param {number} top
12848 * @param {number} width
12849 * @param {number} height
12850 */
12851
12852 }, {
12853 key: "drawImageAtPosition",
12854 value: function drawImageAtPosition(ctx, factor, left, top, width, height) {
12855 if (!this.initialized()) return; //can't draw image yet not intialized
12856
12857 if (factor > 2) {
12858 // Determine which zoomed image to use
12859 factor *= 0.5;
12860 var iterations = 0;
12861
12862 while (factor > 2 && iterations < this.NUM_ITERATIONS) {
12863 factor *= 0.5;
12864 iterations += 1;
12865 }
12866
12867 if (iterations >= this.NUM_ITERATIONS) {
12868 iterations = this.NUM_ITERATIONS - 1;
12869 } //console.log("iterations: " + iterations);
12870
12871
12872 var from = this.coordinates[iterations];
12873 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], left, top, width, height);
12874 } else {
12875 // Draw image directly
12876 ctx.drawImage(this.image, left, top, width, height);
12877 }
12878 }
12879 }]);
12880
12881 return CachedImage;
12882 }();
12883
12884 /**
12885 * This callback is a callback that accepts an Image.
12886 *
12887 * @callback ImageCallback
12888 * @param {Image} image
12889 */
12890
12891 /**
12892 * This class loads images and keeps them stored.
12893 *
12894 * @param {ImageCallback} callback
12895 */
12896
12897 var Images = /*#__PURE__*/function () {
12898 /**
12899 * @param {ImageCallback} callback
12900 */
12901 function Images(callback) {
12902 _classCallCheck(this, Images);
12903
12904 this.images = {};
12905 this.imageBroken = {};
12906 this.callback = callback;
12907 }
12908 /**
12909 * @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
12910 * @param {string} brokenUrl Url the broken image to try and load
12911 * @param {Image} imageToLoadBrokenUrlOn The image object
12912 */
12913
12914
12915 _createClass(Images, [{
12916 key: "_tryloadBrokenUrl",
12917 value: function _tryloadBrokenUrl(url, brokenUrl, imageToLoadBrokenUrlOn) {
12918 //If these parameters aren't specified then exit the function because nothing constructive can be done
12919 if (url === undefined || imageToLoadBrokenUrlOn === undefined) return;
12920
12921 if (brokenUrl === undefined) {
12922 console.warn("No broken url image defined");
12923 return;
12924 } //Clear the old subscription to the error event and put a new in place that only handle errors in loading the brokenImageUrl
12925
12926
12927 imageToLoadBrokenUrlOn.image.onerror = function () {
12928 console.error("Could not load brokenImage:", brokenUrl); // cache item will contain empty image, this should be OK for default
12929 }; //Set the source of the image to the brokenUrl, this is actually what kicks off the loading of the broken image
12930
12931
12932 imageToLoadBrokenUrlOn.image.src = brokenUrl;
12933 }
12934 /**
12935 *
12936 * @param {vis.Image} imageToRedrawWith
12937 * @private
12938 */
12939
12940 }, {
12941 key: "_redrawWithImage",
12942 value: function _redrawWithImage(imageToRedrawWith) {
12943 if (this.callback) {
12944 this.callback(imageToRedrawWith);
12945 }
12946 }
12947 /**
12948 * @param {string} url Url of the image
12949 * @param {string} brokenUrl Url of an image to use if the url image is not found
12950 * @returns {Image} img The image object
12951 */
12952
12953 }, {
12954 key: "load",
12955 value: function load(url, brokenUrl) {
12956 var _this = this;
12957
12958 //Try and get the image from the cache, if successful then return the cached image
12959 var cachedImage = this.images[url];
12960 if (cachedImage) return cachedImage; //Create a new image
12961
12962 var img = new CachedImage(); // Need to add to cache here, otherwise final return will spawn different copies of the same image,
12963 // Also, there will be multiple loads of the same image.
12964
12965 this.images[url] = img; //Subscribe to the event that is raised if the image loads successfully
12966
12967 img.image.onload = function () {
12968 // Properly init the cached item and then request a redraw
12969 _this._fixImageCoordinates(img.image);
12970
12971 img.init();
12972
12973 _this._redrawWithImage(img);
12974 }; //Subscribe to the event that is raised if the image fails to load
12975
12976
12977 img.image.onerror = function () {
12978 console.error("Could not load image:", url); //Try and load the image specified by the brokenUrl using
12979
12980 _this._tryloadBrokenUrl(url, brokenUrl, img);
12981 }; //Set the source of the image to the url, this is what actually kicks off the loading of the image
12982
12983
12984 img.image.src = url; //Return the new image
12985
12986 return img;
12987 }
12988 /**
12989 * IE11 fix -- thanks dponch!
12990 *
12991 * Local helper function
12992 *
12993 * @param {vis.Image} imageToCache
12994 * @private
12995 */
12996
12997 }, {
12998 key: "_fixImageCoordinates",
12999 value: function _fixImageCoordinates(imageToCache) {
13000 if (imageToCache.width === 0) {
13001 document.body.appendChild(imageToCache);
13002 imageToCache.width = imageToCache.offsetWidth;
13003 imageToCache.height = imageToCache.offsetHeight;
13004 document.body.removeChild(imageToCache);
13005 }
13006 }
13007 }]);
13008
13009 return Images;
13010 }();
13011
13012 var internalMetadata = {exports: {}};
13013
13014 var fails$4 = fails$m;
13015 var freezing = !fails$4(function () {
13016 // eslint-disable-next-line es/no-object-isextensible, es/no-object-preventextensions -- required for testing
13017 return Object.isExtensible(Object.preventExtensions({}));
13018 });
13019
13020 var $$d = _export;
13021 var hiddenKeys = hiddenKeys$6;
13022 var isObject$5 = isObject$j;
13023 var has$1 = has$c;
13024 var defineProperty$2 = objectDefineProperty.f;
13025 var getOwnPropertyNamesModule = objectGetOwnPropertyNames;
13026 var getOwnPropertyNamesExternalModule = objectGetOwnPropertyNamesExternal;
13027 var uid = uid$4;
13028 var FREEZING = freezing;
13029 var REQUIRED = false;
13030 var METADATA = uid('meta');
13031 var id$1 = 0; // eslint-disable-next-line es/no-object-isextensible -- safe
13032
13033 var isExtensible$1 = Object.isExtensible || function () {
13034 return true;
13035 };
13036
13037 var setMetadata = function (it) {
13038 defineProperty$2(it, METADATA, {
13039 value: {
13040 objectID: 'O' + id$1++,
13041 // object ID
13042 weakData: {} // weak collections IDs
13043
13044 }
13045 });
13046 };
13047
13048 var fastKey$1 = function (it, create) {
13049 // return a primitive with prefix
13050 if (!isObject$5(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
13051
13052 if (!has$1(it, METADATA)) {
13053 // can't set metadata to uncaught frozen object
13054 if (!isExtensible$1(it)) return 'F'; // not necessary to add metadata
13055
13056 if (!create) return 'E'; // add missing metadata
13057
13058 setMetadata(it); // return object ID
13059 }
13060
13061 return it[METADATA].objectID;
13062 };
13063
13064 var getWeakData$1 = function (it, create) {
13065 if (!has$1(it, METADATA)) {
13066 // can't set metadata to uncaught frozen object
13067 if (!isExtensible$1(it)) return true; // not necessary to add metadata
13068
13069 if (!create) return false; // add missing metadata
13070
13071 setMetadata(it); // return the store of weak collections IDs
13072 }
13073
13074 return it[METADATA].weakData;
13075 }; // add metadata on freeze-family methods calling
13076
13077
13078 var onFreeze = function (it) {
13079 if (FREEZING && REQUIRED && isExtensible$1(it) && !has$1(it, METADATA)) setMetadata(it);
13080 return it;
13081 };
13082
13083 var enable = function () {
13084 meta.enable = function () {
13085 /* empty */
13086 };
13087
13088 REQUIRED = true;
13089 var getOwnPropertyNames = getOwnPropertyNamesModule.f;
13090 var splice = [].splice;
13091 var test = {};
13092 test[METADATA] = 1; // prevent exposing of metadata key
13093
13094 if (getOwnPropertyNames(test).length) {
13095 getOwnPropertyNamesModule.f = function (it) {
13096 var result = getOwnPropertyNames(it);
13097
13098 for (var i = 0, length = result.length; i < length; i++) {
13099 if (result[i] === METADATA) {
13100 splice.call(result, i, 1);
13101 break;
13102 }
13103 }
13104
13105 return result;
13106 };
13107
13108 $$d({
13109 target: 'Object',
13110 stat: true,
13111 forced: true
13112 }, {
13113 getOwnPropertyNames: getOwnPropertyNamesExternalModule.f
13114 });
13115 }
13116 };
13117
13118 var meta = internalMetadata.exports = {
13119 enable: enable,
13120 fastKey: fastKey$1,
13121 getWeakData: getWeakData$1,
13122 onFreeze: onFreeze
13123 };
13124 hiddenKeys[METADATA] = true;
13125
13126 var anObject$3 = anObject$c;
13127 var isArrayIteratorMethod = isArrayIteratorMethod$2;
13128 var toLength$2 = toLength$a;
13129 var bind$2 = functionBindContext;
13130 var getIteratorMethod = getIteratorMethod$6;
13131 var iteratorClose = iteratorClose$2;
13132
13133 var Result = function (stopped, result) {
13134 this.stopped = stopped;
13135 this.result = result;
13136 };
13137
13138 var iterate$3 = function (iterable, unboundFunction, options) {
13139 var that = options && options.that;
13140 var AS_ENTRIES = !!(options && options.AS_ENTRIES);
13141 var IS_ITERATOR = !!(options && options.IS_ITERATOR);
13142 var INTERRUPTED = !!(options && options.INTERRUPTED);
13143 var fn = bind$2(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
13144 var iterator, iterFn, index, length, result, next, step;
13145
13146 var stop = function (condition) {
13147 if (iterator) iteratorClose(iterator);
13148 return new Result(true, condition);
13149 };
13150
13151 var callFn = function (value) {
13152 if (AS_ENTRIES) {
13153 anObject$3(value);
13154 return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
13155 }
13156
13157 return INTERRUPTED ? fn(value, stop) : fn(value);
13158 };
13159
13160 if (IS_ITERATOR) {
13161 iterator = iterable;
13162 } else {
13163 iterFn = getIteratorMethod(iterable);
13164 if (typeof iterFn != 'function') throw TypeError('Target is not iterable'); // optimisation for array iterators
13165
13166 if (isArrayIteratorMethod(iterFn)) {
13167 for (index = 0, length = toLength$2(iterable.length); length > index; index++) {
13168 result = callFn(iterable[index]);
13169 if (result && result instanceof Result) return result;
13170 }
13171
13172 return new Result(false);
13173 }
13174
13175 iterator = iterFn.call(iterable);
13176 }
13177
13178 next = iterator.next;
13179
13180 while (!(step = next.call(iterator)).done) {
13181 try {
13182 result = callFn(step.value);
13183 } catch (error) {
13184 iteratorClose(iterator);
13185 throw error;
13186 }
13187
13188 if (typeof result == 'object' && result && result instanceof Result) return result;
13189 }
13190
13191 return new Result(false);
13192 };
13193
13194 var anInstance$3 = function (it, Constructor, name) {
13195 if (!(it instanceof Constructor)) {
13196 throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
13197 }
13198
13199 return it;
13200 };
13201
13202 var $$c = _export;
13203 var global$5 = global$k;
13204 var InternalMetadataModule$1 = internalMetadata.exports;
13205 var fails$3 = fails$m;
13206 var createNonEnumerableProperty = createNonEnumerableProperty$9;
13207 var iterate$2 = iterate$3;
13208 var anInstance$2 = anInstance$3;
13209 var isObject$4 = isObject$j;
13210 var setToStringTag = setToStringTag$5;
13211 var defineProperty$1 = objectDefineProperty.f;
13212 var forEach = arrayIteration.forEach;
13213 var DESCRIPTORS$2 = descriptors;
13214 var InternalStateModule$2 = internalState;
13215 var setInternalState$2 = InternalStateModule$2.set;
13216 var internalStateGetterFor$2 = InternalStateModule$2.getterFor;
13217
13218 var collection$3 = function (CONSTRUCTOR_NAME, wrapper, common) {
13219 var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
13220 var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
13221 var ADDER = IS_MAP ? 'set' : 'add';
13222 var NativeConstructor = global$5[CONSTRUCTOR_NAME];
13223 var NativePrototype = NativeConstructor && NativeConstructor.prototype;
13224 var exported = {};
13225 var Constructor;
13226
13227 if (!DESCRIPTORS$2 || typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails$3(function () {
13228 new NativeConstructor().entries().next();
13229 }))) {
13230 // create collection constructor
13231 Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
13232 InternalMetadataModule$1.enable();
13233 } else {
13234 Constructor = wrapper(function (target, iterable) {
13235 setInternalState$2(anInstance$2(target, Constructor, CONSTRUCTOR_NAME), {
13236 type: CONSTRUCTOR_NAME,
13237 collection: new NativeConstructor()
13238 });
13239 if (iterable != undefined) iterate$2(iterable, target[ADDER], {
13240 that: target,
13241 AS_ENTRIES: IS_MAP
13242 });
13243 });
13244 var getInternalState = internalStateGetterFor$2(CONSTRUCTOR_NAME);
13245 forEach(['add', 'clear', 'delete', 'forEach', 'get', 'has', 'set', 'keys', 'values', 'entries'], function (KEY) {
13246 var IS_ADDER = KEY == 'add' || KEY == 'set';
13247
13248 if (KEY in NativePrototype && !(IS_WEAK && KEY == 'clear')) {
13249 createNonEnumerableProperty(Constructor.prototype, KEY, function (a, b) {
13250 var collection = getInternalState(this).collection;
13251 if (!IS_ADDER && IS_WEAK && !isObject$4(a)) return KEY == 'get' ? undefined : false;
13252 var result = collection[KEY](a === 0 ? 0 : a, b);
13253 return IS_ADDER ? this : result;
13254 });
13255 }
13256 });
13257 IS_WEAK || defineProperty$1(Constructor.prototype, 'size', {
13258 configurable: true,
13259 get: function () {
13260 return getInternalState(this).collection.size;
13261 }
13262 });
13263 }
13264
13265 setToStringTag(Constructor, CONSTRUCTOR_NAME, false, true);
13266 exported[CONSTRUCTOR_NAME] = Constructor;
13267 $$c({
13268 global: true,
13269 forced: true
13270 }, exported);
13271 if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
13272 return Constructor;
13273 };
13274
13275 var redefine = redefine$3;
13276
13277 var redefineAll$3 = function (target, src, options) {
13278 for (var key in src) {
13279 if (options && options.unsafe && target[key]) target[key] = src[key];else redefine(target, key, src[key], options);
13280 }
13281
13282 return target;
13283 };
13284
13285 var getBuiltIn$1 = getBuiltIn$8;
13286 var definePropertyModule = objectDefineProperty;
13287 var wellKnownSymbol = wellKnownSymbol$j;
13288 var DESCRIPTORS$1 = descriptors;
13289 var SPECIES = wellKnownSymbol('species');
13290
13291 var setSpecies$1 = function (CONSTRUCTOR_NAME) {
13292 var Constructor = getBuiltIn$1(CONSTRUCTOR_NAME);
13293 var defineProperty = definePropertyModule.f;
13294
13295 if (DESCRIPTORS$1 && Constructor && !Constructor[SPECIES]) {
13296 defineProperty(Constructor, SPECIES, {
13297 configurable: true,
13298 get: function () {
13299 return this;
13300 }
13301 });
13302 }
13303 };
13304
13305 var defineProperty = objectDefineProperty.f;
13306 var create$3 = objectCreate;
13307 var redefineAll$2 = redefineAll$3;
13308 var bind$1 = functionBindContext;
13309 var anInstance$1 = anInstance$3;
13310 var iterate$1 = iterate$3;
13311 var defineIterator = defineIterator$3;
13312 var setSpecies = setSpecies$1;
13313 var DESCRIPTORS = descriptors;
13314 var fastKey = internalMetadata.exports.fastKey;
13315 var InternalStateModule$1 = internalState;
13316 var setInternalState$1 = InternalStateModule$1.set;
13317 var internalStateGetterFor$1 = InternalStateModule$1.getterFor;
13318 var collectionStrong$2 = {
13319 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
13320 var C = wrapper(function (that, iterable) {
13321 anInstance$1(that, C, CONSTRUCTOR_NAME);
13322 setInternalState$1(that, {
13323 type: CONSTRUCTOR_NAME,
13324 index: create$3(null),
13325 first: undefined,
13326 last: undefined,
13327 size: 0
13328 });
13329 if (!DESCRIPTORS) that.size = 0;
13330 if (iterable != undefined) iterate$1(iterable, that[ADDER], {
13331 that: that,
13332 AS_ENTRIES: IS_MAP
13333 });
13334 });
13335 var getInternalState = internalStateGetterFor$1(CONSTRUCTOR_NAME);
13336
13337 var define = function (that, key, value) {
13338 var state = getInternalState(that);
13339 var entry = getEntry(that, key);
13340 var previous, index; // change existing entry
13341
13342 if (entry) {
13343 entry.value = value; // create new entry
13344 } else {
13345 state.last = entry = {
13346 index: index = fastKey(key, true),
13347 key: key,
13348 value: value,
13349 previous: previous = state.last,
13350 next: undefined,
13351 removed: false
13352 };
13353 if (!state.first) state.first = entry;
13354 if (previous) previous.next = entry;
13355 if (DESCRIPTORS) state.size++;else that.size++; // add to index
13356
13357 if (index !== 'F') state.index[index] = entry;
13358 }
13359
13360 return that;
13361 };
13362
13363 var getEntry = function (that, key) {
13364 var state = getInternalState(that); // fast case
13365
13366 var index = fastKey(key);
13367 var entry;
13368 if (index !== 'F') return state.index[index]; // frozen object case
13369
13370 for (entry = state.first; entry; entry = entry.next) {
13371 if (entry.key == key) return entry;
13372 }
13373 };
13374
13375 redefineAll$2(C.prototype, {
13376 // `{ Map, Set }.prototype.clear()` methods
13377 // https://tc39.es/ecma262/#sec-map.prototype.clear
13378 // https://tc39.es/ecma262/#sec-set.prototype.clear
13379 clear: function clear() {
13380 var that = this;
13381 var state = getInternalState(that);
13382 var data = state.index;
13383 var entry = state.first;
13384
13385 while (entry) {
13386 entry.removed = true;
13387 if (entry.previous) entry.previous = entry.previous.next = undefined;
13388 delete data[entry.index];
13389 entry = entry.next;
13390 }
13391
13392 state.first = state.last = undefined;
13393 if (DESCRIPTORS) state.size = 0;else that.size = 0;
13394 },
13395 // `{ Map, Set }.prototype.delete(key)` methods
13396 // https://tc39.es/ecma262/#sec-map.prototype.delete
13397 // https://tc39.es/ecma262/#sec-set.prototype.delete
13398 'delete': function (key) {
13399 var that = this;
13400 var state = getInternalState(that);
13401 var entry = getEntry(that, key);
13402
13403 if (entry) {
13404 var next = entry.next;
13405 var prev = entry.previous;
13406 delete state.index[entry.index];
13407 entry.removed = true;
13408 if (prev) prev.next = next;
13409 if (next) next.previous = prev;
13410 if (state.first == entry) state.first = next;
13411 if (state.last == entry) state.last = prev;
13412 if (DESCRIPTORS) state.size--;else that.size--;
13413 }
13414
13415 return !!entry;
13416 },
13417 // `{ Map, Set }.prototype.forEach(callbackfn, thisArg = undefined)` methods
13418 // https://tc39.es/ecma262/#sec-map.prototype.foreach
13419 // https://tc39.es/ecma262/#sec-set.prototype.foreach
13420 forEach: function forEach(callbackfn
13421 /* , that = undefined */
13422 ) {
13423 var state = getInternalState(this);
13424 var boundFunction = bind$1(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
13425 var entry;
13426
13427 while (entry = entry ? entry.next : state.first) {
13428 boundFunction(entry.value, entry.key, this); // revert to the last existing entry
13429
13430 while (entry && entry.removed) entry = entry.previous;
13431 }
13432 },
13433 // `{ Map, Set}.prototype.has(key)` methods
13434 // https://tc39.es/ecma262/#sec-map.prototype.has
13435 // https://tc39.es/ecma262/#sec-set.prototype.has
13436 has: function has(key) {
13437 return !!getEntry(this, key);
13438 }
13439 });
13440 redefineAll$2(C.prototype, IS_MAP ? {
13441 // `Map.prototype.get(key)` method
13442 // https://tc39.es/ecma262/#sec-map.prototype.get
13443 get: function get(key) {
13444 var entry = getEntry(this, key);
13445 return entry && entry.value;
13446 },
13447 // `Map.prototype.set(key, value)` method
13448 // https://tc39.es/ecma262/#sec-map.prototype.set
13449 set: function set(key, value) {
13450 return define(this, key === 0 ? 0 : key, value);
13451 }
13452 } : {
13453 // `Set.prototype.add(value)` method
13454 // https://tc39.es/ecma262/#sec-set.prototype.add
13455 add: function add(value) {
13456 return define(this, value = value === 0 ? 0 : value, value);
13457 }
13458 });
13459 if (DESCRIPTORS) defineProperty(C.prototype, 'size', {
13460 get: function () {
13461 return getInternalState(this).size;
13462 }
13463 });
13464 return C;
13465 },
13466 setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
13467 var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
13468 var getInternalCollectionState = internalStateGetterFor$1(CONSTRUCTOR_NAME);
13469 var getInternalIteratorState = internalStateGetterFor$1(ITERATOR_NAME); // `{ Map, Set }.prototype.{ keys, values, entries, @@iterator }()` methods
13470 // https://tc39.es/ecma262/#sec-map.prototype.entries
13471 // https://tc39.es/ecma262/#sec-map.prototype.keys
13472 // https://tc39.es/ecma262/#sec-map.prototype.values
13473 // https://tc39.es/ecma262/#sec-map.prototype-@@iterator
13474 // https://tc39.es/ecma262/#sec-set.prototype.entries
13475 // https://tc39.es/ecma262/#sec-set.prototype.keys
13476 // https://tc39.es/ecma262/#sec-set.prototype.values
13477 // https://tc39.es/ecma262/#sec-set.prototype-@@iterator
13478
13479 defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
13480 setInternalState$1(this, {
13481 type: ITERATOR_NAME,
13482 target: iterated,
13483 state: getInternalCollectionState(iterated),
13484 kind: kind,
13485 last: undefined
13486 });
13487 }, function () {
13488 var state = getInternalIteratorState(this);
13489 var kind = state.kind;
13490 var entry = state.last; // revert to the last existing entry
13491
13492 while (entry && entry.removed) entry = entry.previous; // get next entry
13493
13494
13495 if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
13496 // or finish the iteration
13497 state.target = undefined;
13498 return {
13499 value: undefined,
13500 done: true
13501 };
13502 } // return step by kind
13503
13504
13505 if (kind == 'keys') return {
13506 value: entry.key,
13507 done: false
13508 };
13509 if (kind == 'values') return {
13510 value: entry.value,
13511 done: false
13512 };
13513 return {
13514 value: [entry.key, entry.value],
13515 done: false
13516 };
13517 }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); // `{ Map, Set }.prototype[@@species]` accessors
13518 // https://tc39.es/ecma262/#sec-get-map-@@species
13519 // https://tc39.es/ecma262/#sec-get-set-@@species
13520
13521 setSpecies(CONSTRUCTOR_NAME);
13522 }
13523 };
13524
13525 var collection$2 = collection$3;
13526 var collectionStrong$1 = collectionStrong$2; // `Map` constructor
13527 // https://tc39.es/ecma262/#sec-map-objects
13528
13529 collection$2('Map', function (init) {
13530 return function Map() {
13531 return init(this, arguments.length ? arguments[0] : undefined);
13532 };
13533 }, collectionStrong$1);
13534
13535 var path$b = path$x;
13536 var map$2 = path$b.Map;
13537
13538 var parent$k = map$2;
13539 var map$1 = parent$k;
13540
13541 var map = map$1;
13542
13543 /**
13544 * This class can store groups and options specific for groups.
13545 */
13546 var Groups = /*#__PURE__*/function () {
13547 /**
13548 * @ignore
13549 */
13550 function Groups() {
13551 _classCallCheck(this, Groups);
13552
13553 this.clear();
13554 this._defaultIndex = 0;
13555 this._groupIndex = 0;
13556 this._defaultGroups = [{
13557 border: "#2B7CE9",
13558 background: "#97C2FC",
13559 highlight: {
13560 border: "#2B7CE9",
13561 background: "#D2E5FF"
13562 },
13563 hover: {
13564 border: "#2B7CE9",
13565 background: "#D2E5FF"
13566 }
13567 }, // 0: blue
13568 {
13569 border: "#FFA500",
13570 background: "#FFFF00",
13571 highlight: {
13572 border: "#FFA500",
13573 background: "#FFFFA3"
13574 },
13575 hover: {
13576 border: "#FFA500",
13577 background: "#FFFFA3"
13578 }
13579 }, // 1: yellow
13580 {
13581 border: "#FA0A10",
13582 background: "#FB7E81",
13583 highlight: {
13584 border: "#FA0A10",
13585 background: "#FFAFB1"
13586 },
13587 hover: {
13588 border: "#FA0A10",
13589 background: "#FFAFB1"
13590 }
13591 }, // 2: red
13592 {
13593 border: "#41A906",
13594 background: "#7BE141",
13595 highlight: {
13596 border: "#41A906",
13597 background: "#A1EC76"
13598 },
13599 hover: {
13600 border: "#41A906",
13601 background: "#A1EC76"
13602 }
13603 }, // 3: green
13604 {
13605 border: "#E129F0",
13606 background: "#EB7DF4",
13607 highlight: {
13608 border: "#E129F0",
13609 background: "#F0B3F5"
13610 },
13611 hover: {
13612 border: "#E129F0",
13613 background: "#F0B3F5"
13614 }
13615 }, // 4: magenta
13616 {
13617 border: "#7C29F0",
13618 background: "#AD85E4",
13619 highlight: {
13620 border: "#7C29F0",
13621 background: "#D3BDF0"
13622 },
13623 hover: {
13624 border: "#7C29F0",
13625 background: "#D3BDF0"
13626 }
13627 }, // 5: purple
13628 {
13629 border: "#C37F00",
13630 background: "#FFA807",
13631 highlight: {
13632 border: "#C37F00",
13633 background: "#FFCA66"
13634 },
13635 hover: {
13636 border: "#C37F00",
13637 background: "#FFCA66"
13638 }
13639 }, // 6: orange
13640 {
13641 border: "#4220FB",
13642 background: "#6E6EFD",
13643 highlight: {
13644 border: "#4220FB",
13645 background: "#9B9BFD"
13646 },
13647 hover: {
13648 border: "#4220FB",
13649 background: "#9B9BFD"
13650 }
13651 }, // 7: darkblue
13652 {
13653 border: "#FD5A77",
13654 background: "#FFC0CB",
13655 highlight: {
13656 border: "#FD5A77",
13657 background: "#FFD1D9"
13658 },
13659 hover: {
13660 border: "#FD5A77",
13661 background: "#FFD1D9"
13662 }
13663 }, // 8: pink
13664 {
13665 border: "#4AD63A",
13666 background: "#C2FABC",
13667 highlight: {
13668 border: "#4AD63A",
13669 background: "#E6FFE3"
13670 },
13671 hover: {
13672 border: "#4AD63A",
13673 background: "#E6FFE3"
13674 }
13675 }, // 9: mint
13676 {
13677 border: "#990000",
13678 background: "#EE0000",
13679 highlight: {
13680 border: "#BB0000",
13681 background: "#FF3333"
13682 },
13683 hover: {
13684 border: "#BB0000",
13685 background: "#FF3333"
13686 }
13687 }, // 10:bright red
13688 {
13689 border: "#FF6000",
13690 background: "#FF6000",
13691 highlight: {
13692 border: "#FF6000",
13693 background: "#FF6000"
13694 },
13695 hover: {
13696 border: "#FF6000",
13697 background: "#FF6000"
13698 }
13699 }, // 12: real orange
13700 {
13701 border: "#97C2FC",
13702 background: "#2B7CE9",
13703 highlight: {
13704 border: "#D2E5FF",
13705 background: "#2B7CE9"
13706 },
13707 hover: {
13708 border: "#D2E5FF",
13709 background: "#2B7CE9"
13710 }
13711 }, // 13: blue
13712 {
13713 border: "#399605",
13714 background: "#255C03",
13715 highlight: {
13716 border: "#399605",
13717 background: "#255C03"
13718 },
13719 hover: {
13720 border: "#399605",
13721 background: "#255C03"
13722 }
13723 }, // 14: green
13724 {
13725 border: "#B70054",
13726 background: "#FF007E",
13727 highlight: {
13728 border: "#B70054",
13729 background: "#FF007E"
13730 },
13731 hover: {
13732 border: "#B70054",
13733 background: "#FF007E"
13734 }
13735 }, // 15: magenta
13736 {
13737 border: "#AD85E4",
13738 background: "#7C29F0",
13739 highlight: {
13740 border: "#D3BDF0",
13741 background: "#7C29F0"
13742 },
13743 hover: {
13744 border: "#D3BDF0",
13745 background: "#7C29F0"
13746 }
13747 }, // 16: purple
13748 {
13749 border: "#4557FA",
13750 background: "#000EA1",
13751 highlight: {
13752 border: "#6E6EFD",
13753 background: "#000EA1"
13754 },
13755 hover: {
13756 border: "#6E6EFD",
13757 background: "#000EA1"
13758 }
13759 }, // 17: darkblue
13760 {
13761 border: "#FFC0CB",
13762 background: "#FD5A77",
13763 highlight: {
13764 border: "#FFD1D9",
13765 background: "#FD5A77"
13766 },
13767 hover: {
13768 border: "#FFD1D9",
13769 background: "#FD5A77"
13770 }
13771 }, // 18: pink
13772 {
13773 border: "#C2FABC",
13774 background: "#74D66A",
13775 highlight: {
13776 border: "#E6FFE3",
13777 background: "#74D66A"
13778 },
13779 hover: {
13780 border: "#E6FFE3",
13781 background: "#74D66A"
13782 }
13783 }, // 19: mint
13784 {
13785 border: "#EE0000",
13786 background: "#990000",
13787 highlight: {
13788 border: "#FF3333",
13789 background: "#BB0000"
13790 },
13791 hover: {
13792 border: "#FF3333",
13793 background: "#BB0000"
13794 }
13795 } // 20:bright red
13796 ];
13797 this.options = {};
13798 this.defaultOptions = {
13799 useDefaultGroups: true
13800 };
13801
13802 assign$2(this.options, this.defaultOptions);
13803 }
13804 /**
13805 *
13806 * @param {object} options
13807 */
13808
13809
13810 _createClass(Groups, [{
13811 key: "setOptions",
13812 value: function setOptions(options) {
13813 var optionFields = ["useDefaultGroups"];
13814
13815 if (options !== undefined) {
13816 for (var groupName in options) {
13817 if (Object.prototype.hasOwnProperty.call(options, groupName)) {
13818 if (indexOf(optionFields).call(optionFields, groupName) === -1) {
13819 var group = options[groupName];
13820 this.add(groupName, group);
13821 }
13822 }
13823 }
13824 }
13825 }
13826 /**
13827 * Clear all groups
13828 */
13829
13830 }, {
13831 key: "clear",
13832 value: function clear() {
13833 this._groups = new map();
13834 this._groupNames = [];
13835 }
13836 /**
13837 * Get group options of a groupname.
13838 * If groupname is not found, a new group may be created.
13839 *
13840 * @param {*} groupname Can be a number, string, Date, etc.
13841 * @param {boolean} [shouldCreate=true] If true, create a new group
13842 * @returns {object} The found or created group
13843 */
13844
13845 }, {
13846 key: "get",
13847 value: function get(groupname) {
13848 var shouldCreate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
13849
13850 var group = this._groups.get(groupname);
13851
13852 if (group === undefined && shouldCreate) {
13853 if (this.options.useDefaultGroups === false && this._groupNames.length > 0) {
13854 // create new group
13855 var index = this._groupIndex % this._groupNames.length;
13856 ++this._groupIndex;
13857 group = {};
13858 group.color = this._groups.get(this._groupNames[index]);
13859
13860 this._groups.set(groupname, group);
13861 } else {
13862 // create new group
13863 var _index = this._defaultIndex % this._defaultGroups.length;
13864
13865 this._defaultIndex++;
13866 group = {};
13867 group.color = this._defaultGroups[_index];
13868
13869 this._groups.set(groupname, group);
13870 }
13871 }
13872
13873 return group;
13874 }
13875 /**
13876 * Add custom group style.
13877 *
13878 * @param {string} groupName - The name of the group, a new group will be
13879 * created if a group with the same name doesn't exist, otherwise the old
13880 * groups style will be overwritten.
13881 * @param {object} style - An object containing borderColor, backgroundColor,
13882 * etc.
13883 * @returns {object} The created group object.
13884 */
13885
13886 }, {
13887 key: "add",
13888 value: function add(groupName, style) {
13889 // Only push group name once to prevent duplicates which would consume more
13890 // RAM and also skew the distribution towards more often updated groups,
13891 // neither of which is desirable.
13892 if (!this._groups.has(groupName)) {
13893 this._groupNames.push(groupName);
13894 }
13895
13896 this._groups.set(groupName, style);
13897
13898 return style;
13899 }
13900 }]);
13901
13902 return Groups;
13903 }();
13904
13905 var $$b = _export; // `Number.isNaN` method
13906 // https://tc39.es/ecma262/#sec-number.isnan
13907
13908 $$b({
13909 target: 'Number',
13910 stat: true
13911 }, {
13912 isNaN: function isNaN(number) {
13913 // eslint-disable-next-line no-self-compare -- NaN check
13914 return number != number;
13915 }
13916 });
13917
13918 var path$a = path$x;
13919 var isNan$2 = path$a.Number.isNaN;
13920
13921 var parent$j = isNan$2;
13922 var isNan$1 = parent$j;
13923
13924 var isNan = isNan$1;
13925
13926 var global$4 = global$k;
13927 var globalIsFinite = global$4.isFinite; // `Number.isFinite` method
13928 // https://tc39.es/ecma262/#sec-number.isfinite
13929 // eslint-disable-next-line es/no-number-isfinite -- safe
13930
13931 var numberIsFinite$1 = Number.isFinite || function isFinite(it) {
13932 return typeof it == 'number' && globalIsFinite(it);
13933 };
13934
13935 var $$a = _export;
13936 var numberIsFinite = numberIsFinite$1; // `Number.isFinite` method
13937 // https://tc39.es/ecma262/#sec-number.isfinite
13938
13939 $$a({
13940 target: 'Number',
13941 stat: true
13942 }, {
13943 isFinite: numberIsFinite
13944 });
13945
13946 var path$9 = path$x;
13947 var _isFinite$2 = path$9.Number.isFinite;
13948
13949 var parent$i = _isFinite$2;
13950 var _isFinite$1 = parent$i;
13951
13952 var _isFinite = _isFinite$1;
13953
13954 var $$9 = _export;
13955 var $some = arrayIteration.some;
13956 var arrayMethodIsStrict$3 = arrayMethodIsStrict$6;
13957 var STRICT_METHOD$3 = arrayMethodIsStrict$3('some'); // `Array.prototype.some` method
13958 // https://tc39.es/ecma262/#sec-array.prototype.some
13959
13960 $$9({
13961 target: 'Array',
13962 proto: true,
13963 forced: !STRICT_METHOD$3
13964 }, {
13965 some: function some(callbackfn
13966 /* , thisArg */
13967 ) {
13968 return $some(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
13969 }
13970 });
13971
13972 var entryVirtual$4 = entryVirtual$i;
13973 var some$3 = entryVirtual$4('Array').some;
13974
13975 var some$2 = some$3;
13976 var ArrayPrototype$4 = Array.prototype;
13977
13978 var some_1 = function (it) {
13979 var own = it.some;
13980 return it === ArrayPrototype$4 || it instanceof Array && own === ArrayPrototype$4.some ? some$2 : own;
13981 };
13982
13983 var parent$h = some_1;
13984 var some$1 = parent$h;
13985
13986 var some = some$1;
13987
13988 var global$3 = global$k;
13989 var toString$1 = toString$9;
13990 var trim = stringTrim.trim;
13991 var whitespaces = whitespaces$4;
13992 var $parseFloat = global$3.parseFloat;
13993 var FORCED$2 = 1 / $parseFloat(whitespaces + '-0') !== -Infinity; // `parseFloat` method
13994 // https://tc39.es/ecma262/#sec-parsefloat-string
13995
13996 var numberParseFloat = FORCED$2 ? function parseFloat(string) {
13997 var trimmedString = trim(toString$1(string));
13998 var result = $parseFloat(trimmedString);
13999 return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
14000 } : $parseFloat;
14001
14002 var $$8 = _export;
14003 var parseFloatImplementation = numberParseFloat; // `parseFloat` method
14004 // https://tc39.es/ecma262/#sec-parsefloat-string
14005
14006 $$8({
14007 global: true,
14008 forced: parseFloat != parseFloatImplementation
14009 }, {
14010 parseFloat: parseFloatImplementation
14011 });
14012
14013 var path$8 = path$x;
14014 var _parseFloat$2 = path$8.parseFloat;
14015
14016 var parent$g = _parseFloat$2;
14017 var _parseFloat$1 = parent$g;
14018
14019 var _parseFloat = _parseFloat$1;
14020
14021 var $$7 = _export;
14022 var fails$2 = fails$m;
14023 var getOwnPropertyNames$3 = objectGetOwnPropertyNamesExternal.f; // eslint-disable-next-line es/no-object-getownpropertynames -- required for testing
14024
14025 var FAILS_ON_PRIMITIVES = fails$2(function () {
14026 return !Object.getOwnPropertyNames(1);
14027 }); // `Object.getOwnPropertyNames` method
14028 // https://tc39.es/ecma262/#sec-object.getownpropertynames
14029
14030 $$7({
14031 target: 'Object',
14032 stat: true,
14033 forced: FAILS_ON_PRIMITIVES
14034 }, {
14035 getOwnPropertyNames: getOwnPropertyNames$3
14036 });
14037
14038 var path$7 = path$x;
14039 var Object$1 = path$7.Object;
14040
14041 var getOwnPropertyNames$2 = function getOwnPropertyNames(it) {
14042 return Object$1.getOwnPropertyNames(it);
14043 };
14044
14045 var parent$f = getOwnPropertyNames$2;
14046 var getOwnPropertyNames$1 = parent$f;
14047
14048 var getOwnPropertyNames = getOwnPropertyNames$1;
14049
14050 /**
14051 * Helper functions for components
14052 */
14053
14054 /**
14055 * Determine values to use for (sub)options of 'chosen'.
14056 *
14057 * This option is either a boolean or an object whose values should be examined further.
14058 * The relevant structures are:
14059 *
14060 * - chosen: <boolean value>
14061 * - chosen: { subOption: <boolean or function> }
14062 *
14063 * Where subOption is 'node', 'edge' or 'label'.
14064 *
14065 * The intention of this method appears to be to set a specific priority to the options;
14066 * Since most properties are either bridged or merged into the local options objects, there
14067 * is not much point in handling them separately.
14068 * TODO: examine if 'most' in previous sentence can be replaced with 'all'. In that case, we
14069 * should be able to get rid of this method.
14070 *
14071 * @param {string} subOption option within object 'chosen' to consider; either 'node', 'edge' or 'label'
14072 * @param {object} pile array of options objects to consider
14073 *
14074 * @returns {boolean | Function} value for passed subOption of 'chosen' to use
14075 */
14076
14077 function choosify(subOption, pile) {
14078 // allowed values for subOption
14079 var allowed = ["node", "edge", "label"];
14080 var value = true;
14081 var chosen = topMost(pile, "chosen");
14082
14083 if (typeof chosen === "boolean") {
14084 value = chosen;
14085 } else if (_typeof(chosen) === "object") {
14086 if (indexOf(allowed).call(allowed, subOption) === -1) {
14087 throw new Error("choosify: subOption '" + subOption + "' should be one of " + "'" + allowed.join("', '") + "'");
14088 }
14089
14090 var chosenEdge = topMost(pile, ["chosen", subOption]);
14091
14092 if (typeof chosenEdge === "boolean" || typeof chosenEdge === "function") {
14093 value = chosenEdge;
14094 }
14095 }
14096
14097 return value;
14098 }
14099 /**
14100 * Check if the point falls within the given rectangle.
14101 *
14102 * @param {rect} rect
14103 * @param {point} point
14104 * @param {rotationPoint} [rotationPoint] if specified, the rotation that applies to the rectangle.
14105 * @returns {boolean} true if point within rectangle, false otherwise
14106 */
14107
14108 function pointInRect(rect, point, rotationPoint) {
14109 if (rect.width <= 0 || rect.height <= 0) {
14110 return false; // early out
14111 }
14112
14113 if (rotationPoint !== undefined) {
14114 // Rotate the point the same amount as the rectangle
14115 var tmp = {
14116 x: point.x - rotationPoint.x,
14117 y: point.y - rotationPoint.y
14118 };
14119
14120 if (rotationPoint.angle !== 0) {
14121 // In order to get the coordinates the same, you need to
14122 // rotate in the reverse direction
14123 var angle = -rotationPoint.angle;
14124 var tmp2 = {
14125 x: Math.cos(angle) * tmp.x - Math.sin(angle) * tmp.y,
14126 y: Math.sin(angle) * tmp.x + Math.cos(angle) * tmp.y
14127 };
14128 point = tmp2;
14129 } else {
14130 point = tmp;
14131 } // Note that if a rotation is specified, the rectangle coordinates
14132 // are **not* the full canvas coordinates. They are relative to the
14133 // rotationPoint. Hence, the point coordinates need not be translated
14134 // back in this case.
14135
14136 }
14137
14138 var right = rect.x + rect.width;
14139 var bottom = rect.y + rect.width;
14140 return rect.left < point.x && right > point.x && rect.top < point.y && bottom > point.y;
14141 }
14142 /**
14143 * Check if given value is acceptable as a label text.
14144 *
14145 * @param {*} text value to check; can be anything at this point
14146 * @returns {boolean} true if valid label value, false otherwise
14147 */
14148
14149 function isValidLabel(text) {
14150 // Note that this is quite strict: types that *might* be converted to string are disallowed
14151 return typeof text === "string" && text !== "";
14152 }
14153 /**
14154 * Returns x, y of self reference circle based on provided angle
14155 *
14156 * @param {object} ctx
14157 * @param {number} angle
14158 * @param {number} radius
14159 * @param {VisNode} node
14160 *
14161 * @returns {object} x and y coordinates
14162 */
14163
14164 function getSelfRefCoordinates(ctx, angle, radius, node) {
14165 var x = node.x;
14166 var y = node.y;
14167
14168 if (typeof node.distanceToBorder === "function") {
14169 //calculating opposite and adjacent
14170 //distaneToBorder becomes Hypotenuse.
14171 //Formulas sin(a) = Opposite / Hypotenuse and cos(a) = Adjacent / Hypotenuse
14172 var toBorderDist = node.distanceToBorder(ctx, angle);
14173 var yFromNodeCenter = Math.sin(angle) * toBorderDist;
14174 var xFromNodeCenter = Math.cos(angle) * toBorderDist; //xFromNodeCenter is basically x and if xFromNodeCenter equals to the distance to border then it means
14175 //that y does not need calculation because it is equal node.height / 2 or node.y
14176 //same thing with yFromNodeCenter and if yFromNodeCenter equals to the distance to border then it means
14177 //that x is equal node.width / 2 or node.x
14178
14179 if (xFromNodeCenter === toBorderDist) {
14180 x += toBorderDist;
14181 y = node.y;
14182 } else if (yFromNodeCenter === toBorderDist) {
14183 x = node.x;
14184 y -= toBorderDist;
14185 } else {
14186 x += xFromNodeCenter;
14187 y -= yFromNodeCenter;
14188 }
14189 } else if (node.shape.width > node.shape.height) {
14190 x = node.x + node.shape.width * 0.5;
14191 y = node.y - radius;
14192 } else {
14193 x = node.x + radius;
14194 y = node.y - node.shape.height * 0.5;
14195 }
14196
14197 return {
14198 x: x,
14199 y: y
14200 };
14201 }
14202
14203 var entryVirtual$3 = entryVirtual$i;
14204 var values$3 = entryVirtual$3('Array').values;
14205
14206 var parent$e = values$3;
14207 var values$2 = parent$e;
14208
14209 var values$1 = values$2;
14210 var classof$1 = classof$8;
14211 var ArrayPrototype$3 = Array.prototype;
14212 var DOMIterables = {
14213 DOMTokenList: true,
14214 NodeList: true
14215 };
14216
14217 var values_1 = function (it) {
14218 var own = it.values;
14219 return it === ArrayPrototype$3 || it instanceof Array && own === ArrayPrototype$3.values // eslint-disable-next-line no-prototype-builtins -- safe
14220 || DOMIterables.hasOwnProperty(classof$1(it)) ? values$1 : own;
14221 };
14222
14223 var values = values_1;
14224
14225 /**
14226 * Callback to determine text dimensions, using the parent label settings.
14227 *
14228 * @callback MeasureText
14229 * @param {text} text
14230 * @param {text} mod
14231 * @returns {object} { width, values} width in pixels and font attributes
14232 */
14233
14234 /**
14235 * Helper class for Label which collects results of splitting labels into lines and blocks.
14236 *
14237 * @private
14238 */
14239 var LabelAccumulator = /*#__PURE__*/function () {
14240 /**
14241 * @param {MeasureText} measureText
14242 */
14243 function LabelAccumulator(measureText) {
14244 _classCallCheck(this, LabelAccumulator);
14245
14246 this.measureText = measureText;
14247 this.current = 0;
14248 this.width = 0;
14249 this.height = 0;
14250 this.lines = [];
14251 }
14252 /**
14253 * Append given text to the given line.
14254 *
14255 * @param {number} l index of line to add to
14256 * @param {string} text string to append to line
14257 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
14258 * @private
14259 */
14260
14261
14262 _createClass(LabelAccumulator, [{
14263 key: "_add",
14264 value: function _add(l, text) {
14265 var mod = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "normal";
14266
14267 if (this.lines[l] === undefined) {
14268 this.lines[l] = {
14269 width: 0,
14270 height: 0,
14271 blocks: []
14272 };
14273 } // We still need to set a block for undefined and empty texts, hence return at this point
14274 // This is necessary because we don't know at this point if we're at the
14275 // start of an empty line or not.
14276 // To compensate, empty blocks are removed in `finalize()`.
14277 //
14278 // Empty strings should still have a height
14279
14280
14281 var tmpText = text;
14282 if (text === undefined || text === "") tmpText = " "; // Determine width and get the font properties
14283
14284 var result = this.measureText(tmpText, mod);
14285
14286 var block = assign$2({}, values(result));
14287
14288 block.text = text;
14289 block.width = result.width;
14290 block.mod = mod;
14291
14292 if (text === undefined || text === "") {
14293 block.width = 0;
14294 }
14295
14296 this.lines[l].blocks.push(block); // Update the line width. We need this for determining if a string goes over max width
14297
14298 this.lines[l].width += block.width;
14299 }
14300 /**
14301 * Returns the width in pixels of the current line.
14302 *
14303 * @returns {number}
14304 */
14305
14306 }, {
14307 key: "curWidth",
14308 value: function curWidth() {
14309 var line = this.lines[this.current];
14310 if (line === undefined) return 0;
14311 return line.width;
14312 }
14313 /**
14314 * Add text in block to current line
14315 *
14316 * @param {string} text
14317 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
14318 */
14319
14320 }, {
14321 key: "append",
14322 value: function append(text) {
14323 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "normal";
14324
14325 this._add(this.current, text, mod);
14326 }
14327 /**
14328 * Add text in block to current line and start a new line
14329 *
14330 * @param {string} text
14331 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
14332 */
14333
14334 }, {
14335 key: "newLine",
14336 value: function newLine(text) {
14337 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "normal";
14338
14339 this._add(this.current, text, mod);
14340
14341 this.current++;
14342 }
14343 /**
14344 * Determine and set the heights of all the lines currently contained in this instance
14345 *
14346 * Note that width has already been set.
14347 *
14348 * @private
14349 */
14350
14351 }, {
14352 key: "determineLineHeights",
14353 value: function determineLineHeights() {
14354 for (var k = 0; k < this.lines.length; k++) {
14355 var line = this.lines[k]; // Looking for max height of blocks in line
14356
14357 var height = 0;
14358
14359 if (line.blocks !== undefined) {
14360 // Can happen if text contains e.g. '\n '
14361 for (var l = 0; l < line.blocks.length; l++) {
14362 var block = line.blocks[l];
14363
14364 if (height < block.height) {
14365 height = block.height;
14366 }
14367 }
14368 }
14369
14370 line.height = height;
14371 }
14372 }
14373 /**
14374 * Determine the full size of the label text, as determined by current lines and blocks
14375 *
14376 * @private
14377 */
14378
14379 }, {
14380 key: "determineLabelSize",
14381 value: function determineLabelSize() {
14382 var width = 0;
14383 var height = 0;
14384
14385 for (var k = 0; k < this.lines.length; k++) {
14386 var line = this.lines[k];
14387
14388 if (line.width > width) {
14389 width = line.width;
14390 }
14391
14392 height += line.height;
14393 }
14394
14395 this.width = width;
14396 this.height = height;
14397 }
14398 /**
14399 * Remove all empty blocks and empty lines we don't need
14400 *
14401 * This must be done after the width/height determination,
14402 * so that these are set properly for processing here.
14403 *
14404 * @returns {Array<Line>} Lines with empty blocks (and some empty lines) removed
14405 * @private
14406 */
14407
14408 }, {
14409 key: "removeEmptyBlocks",
14410 value: function removeEmptyBlocks() {
14411 var tmpLines = [];
14412
14413 for (var k = 0; k < this.lines.length; k++) {
14414 var line = this.lines[k]; // Note: an empty line in between text has width zero but is still relevant to layout.
14415 // So we can't use width for testing empty line here
14416
14417 if (line.blocks.length === 0) continue; // Discard final empty line always
14418
14419 if (k === this.lines.length - 1) {
14420 if (line.width === 0) continue;
14421 }
14422
14423 var tmpLine = {};
14424
14425 assign$2(tmpLine, line);
14426
14427 tmpLine.blocks = [];
14428 var firstEmptyBlock = void 0;
14429 var tmpBlocks = [];
14430
14431 for (var l = 0; l < line.blocks.length; l++) {
14432 var block = line.blocks[l];
14433
14434 if (block.width !== 0) {
14435 tmpBlocks.push(block);
14436 } else {
14437 if (firstEmptyBlock === undefined) {
14438 firstEmptyBlock = block;
14439 }
14440 }
14441 } // Ensure that there is *some* text present
14442
14443
14444 if (tmpBlocks.length === 0 && firstEmptyBlock !== undefined) {
14445 tmpBlocks.push(firstEmptyBlock);
14446 }
14447
14448 tmpLine.blocks = tmpBlocks;
14449 tmpLines.push(tmpLine);
14450 }
14451
14452 return tmpLines;
14453 }
14454 /**
14455 * Set the sizes for all lines and the whole thing.
14456 *
14457 * @returns {{width: (number|*), height: (number|*), lines: Array}}
14458 */
14459
14460 }, {
14461 key: "finalize",
14462 value: function finalize() {
14463 //console.log(JSON.stringify(this.lines, null, 2));
14464 this.determineLineHeights();
14465 this.determineLabelSize();
14466 var tmpLines = this.removeEmptyBlocks(); // Return a simple hash object for further processing.
14467
14468 return {
14469 width: this.width,
14470 height: this.height,
14471 lines: tmpLines
14472 };
14473 }
14474 }]);
14475
14476 return LabelAccumulator;
14477 }();
14478
14479 var tagPattern = {
14480 // HTML
14481 "<b>": /<b>/,
14482 "<i>": /<i>/,
14483 "<code>": /<code>/,
14484 "</b>": /<\/b>/,
14485 "</i>": /<\/i>/,
14486 "</code>": /<\/code>/,
14487 // Markdown
14488 "*": /\*/,
14489 // bold
14490 _: /_/,
14491 // ital
14492 "`": /`/,
14493 // mono
14494 afterBold: /[^*]/,
14495 afterItal: /[^_]/,
14496 afterMono: /[^`]/
14497 };
14498 /**
14499 * Internal helper class for parsing the markup tags for HTML and Markdown.
14500 *
14501 * NOTE: Sequences of tabs and spaces are reduced to single space.
14502 * Scan usage of `this.spacing` within method
14503 */
14504
14505 var MarkupAccumulator = /*#__PURE__*/function () {
14506 /**
14507 * Create an instance
14508 *
14509 * @param {string} text text to parse for markup
14510 */
14511 function MarkupAccumulator(text) {
14512 _classCallCheck(this, MarkupAccumulator);
14513
14514 this.text = text;
14515 this.bold = false;
14516 this.ital = false;
14517 this.mono = false;
14518 this.spacing = false;
14519 this.position = 0;
14520 this.buffer = "";
14521 this.modStack = [];
14522 this.blocks = [];
14523 }
14524 /**
14525 * Return the mod label currently on the top of the stack
14526 *
14527 * @returns {string} label of topmost mod
14528 * @private
14529 */
14530
14531
14532 _createClass(MarkupAccumulator, [{
14533 key: "mod",
14534 value: function mod() {
14535 return this.modStack.length === 0 ? "normal" : this.modStack[0];
14536 }
14537 /**
14538 * Return the mod label currently active
14539 *
14540 * @returns {string} label of active mod
14541 * @private
14542 */
14543
14544 }, {
14545 key: "modName",
14546 value: function modName() {
14547 if (this.modStack.length === 0) return "normal";else if (this.modStack[0] === "mono") return "mono";else {
14548 if (this.bold && this.ital) {
14549 return "boldital";
14550 } else if (this.bold) {
14551 return "bold";
14552 } else if (this.ital) {
14553 return "ital";
14554 }
14555 }
14556 }
14557 /**
14558 * @private
14559 */
14560
14561 }, {
14562 key: "emitBlock",
14563 value: function emitBlock() {
14564 if (this.spacing) {
14565 this.add(" ");
14566 this.spacing = false;
14567 }
14568
14569 if (this.buffer.length > 0) {
14570 this.blocks.push({
14571 text: this.buffer,
14572 mod: this.modName()
14573 });
14574 this.buffer = "";
14575 }
14576 }
14577 /**
14578 * Output text to buffer
14579 *
14580 * @param {string} text text to add
14581 * @private
14582 */
14583
14584 }, {
14585 key: "add",
14586 value: function add(text) {
14587 if (text === " ") {
14588 this.spacing = true;
14589 }
14590
14591 if (this.spacing) {
14592 this.buffer += " ";
14593 this.spacing = false;
14594 }
14595
14596 if (text != " ") {
14597 this.buffer += text;
14598 }
14599 }
14600 /**
14601 * Handle parsing of whitespace
14602 *
14603 * @param {string} ch the character to check
14604 * @returns {boolean} true if the character was processed as whitespace, false otherwise
14605 */
14606
14607 }, {
14608 key: "parseWS",
14609 value: function parseWS(ch) {
14610 if (/[ \t]/.test(ch)) {
14611 if (!this.mono) {
14612 this.spacing = true;
14613 } else {
14614 this.add(ch);
14615 }
14616
14617 return true;
14618 }
14619
14620 return false;
14621 }
14622 /**
14623 * @param {string} tagName label for block type to set
14624 * @private
14625 */
14626
14627 }, {
14628 key: "setTag",
14629 value: function setTag(tagName) {
14630 this.emitBlock();
14631 this[tagName] = true;
14632 this.modStack.unshift(tagName);
14633 }
14634 /**
14635 * @param {string} tagName label for block type to unset
14636 * @private
14637 */
14638
14639 }, {
14640 key: "unsetTag",
14641 value: function unsetTag(tagName) {
14642 this.emitBlock();
14643 this[tagName] = false;
14644 this.modStack.shift();
14645 }
14646 /**
14647 * @param {string} tagName label for block type we are currently processing
14648 * @param {string|RegExp} tag string to match in text
14649 * @returns {boolean} true if the tag was processed, false otherwise
14650 */
14651
14652 }, {
14653 key: "parseStartTag",
14654 value: function parseStartTag(tagName, tag) {
14655 // Note: if 'mono' passed as tagName, there is a double check here. This is OK
14656 if (!this.mono && !this[tagName] && this.match(tag)) {
14657 this.setTag(tagName);
14658 return true;
14659 }
14660
14661 return false;
14662 }
14663 /**
14664 * @param {string|RegExp} tag
14665 * @param {number} [advance=true] if set, advance current position in text
14666 * @returns {boolean} true if match at given position, false otherwise
14667 * @private
14668 */
14669
14670 }, {
14671 key: "match",
14672 value: function match(tag) {
14673 var advance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
14674
14675 var _this$prepareRegExp = this.prepareRegExp(tag),
14676 _this$prepareRegExp2 = _slicedToArray(_this$prepareRegExp, 2),
14677 regExp = _this$prepareRegExp2[0],
14678 length = _this$prepareRegExp2[1];
14679
14680 var matched = regExp.test(this.text.substr(this.position, length));
14681
14682 if (matched && advance) {
14683 this.position += length - 1;
14684 }
14685
14686 return matched;
14687 }
14688 /**
14689 * @param {string} tagName label for block type we are currently processing
14690 * @param {string|RegExp} tag string to match in text
14691 * @param {RegExp} [nextTag] regular expression to match for characters *following* the current tag
14692 * @returns {boolean} true if the tag was processed, false otherwise
14693 */
14694
14695 }, {
14696 key: "parseEndTag",
14697 value: function parseEndTag(tagName, tag, nextTag) {
14698 var checkTag = this.mod() === tagName;
14699
14700 if (tagName === "mono") {
14701 // special handling for 'mono'
14702 checkTag = checkTag && this.mono;
14703 } else {
14704 checkTag = checkTag && !this.mono;
14705 }
14706
14707 if (checkTag && this.match(tag)) {
14708 if (nextTag !== undefined) {
14709 // Purpose of the following match is to prevent a direct unset/set of a given tag
14710 // E.g. '*bold **still bold*' => '*bold still bold*'
14711 if (this.position === this.text.length - 1 || this.match(nextTag, false)) {
14712 this.unsetTag(tagName);
14713 }
14714 } else {
14715 this.unsetTag(tagName);
14716 }
14717
14718 return true;
14719 }
14720
14721 return false;
14722 }
14723 /**
14724 * @param {string|RegExp} tag string to match in text
14725 * @param {value} value string to replace tag with, if found at current position
14726 * @returns {boolean} true if the tag was processed, false otherwise
14727 */
14728
14729 }, {
14730 key: "replace",
14731 value: function replace(tag, value) {
14732 if (this.match(tag)) {
14733 this.add(value);
14734 this.position += length - 1;
14735 return true;
14736 }
14737
14738 return false;
14739 }
14740 /**
14741 * Create a regular expression for the tag if it isn't already one.
14742 *
14743 * The return value is an array `[RegExp, number]`, with exactly two value, where:
14744 * - RegExp is the regular expression to use
14745 * - number is the lenth of the input string to match
14746 *
14747 * @param {string|RegExp} tag string to match in text
14748 * @returns {Array} regular expression to use and length of input string to match
14749 * @private
14750 */
14751
14752 }, {
14753 key: "prepareRegExp",
14754 value: function prepareRegExp(tag) {
14755 var length;
14756 var regExp;
14757
14758 if (tag instanceof RegExp) {
14759 regExp = tag;
14760 length = 1; // ASSUMPTION: regexp only tests one character
14761 } else {
14762 // use prepared regexp if present
14763 var prepared = tagPattern[tag];
14764
14765 if (prepared !== undefined) {
14766 regExp = prepared;
14767 } else {
14768 regExp = new RegExp(tag);
14769 }
14770
14771 length = tag.length;
14772 }
14773
14774 return [regExp, length];
14775 }
14776 }]);
14777
14778 return MarkupAccumulator;
14779 }();
14780 /**
14781 * Helper class for Label which explodes the label text into lines and blocks within lines
14782 *
14783 * @private
14784 */
14785
14786
14787 var LabelSplitter = /*#__PURE__*/function () {
14788 /**
14789 * @param {CanvasRenderingContext2D} ctx Canvas rendering context
14790 * @param {Label} parent reference to the Label instance using current instance
14791 * @param {boolean} selected
14792 * @param {boolean} hover
14793 */
14794 function LabelSplitter(ctx, parent, selected, hover) {
14795 var _this = this;
14796
14797 _classCallCheck(this, LabelSplitter);
14798
14799 this.ctx = ctx;
14800 this.parent = parent;
14801 this.selected = selected;
14802 this.hover = hover;
14803 /**
14804 * Callback to determine text width; passed to LabelAccumulator instance
14805 *
14806 * @param {string} text string to determine width of
14807 * @param {string} mod font type to use for this text
14808 * @returns {object} { width, values} width in pixels and font attributes
14809 */
14810
14811 var textWidth = function textWidth(text, mod) {
14812 if (text === undefined) return 0; // TODO: This can be done more efficiently with caching
14813 // This will set the ctx.font correctly, depending on selected/hover and mod - so that ctx.measureText() will be accurate.
14814
14815 var values = _this.parent.getFormattingValues(ctx, selected, hover, mod);
14816
14817 var width = 0;
14818
14819 if (text !== "") {
14820 var measure = _this.ctx.measureText(text);
14821
14822 width = measure.width;
14823 }
14824
14825 return {
14826 width: width,
14827 values: values
14828 };
14829 };
14830
14831 this.lines = new LabelAccumulator(textWidth);
14832 }
14833 /**
14834 * Split passed text of a label into lines and blocks.
14835 *
14836 * # NOTE
14837 *
14838 * The handling of spacing is option dependent:
14839 *
14840 * - if `font.multi : false`, all spaces are retained
14841 * - if `font.multi : true`, every sequence of spaces is compressed to a single space
14842 *
14843 * This might not be the best way to do it, but this is as it has been working till now.
14844 * In order not to break existing functionality, for the time being this behaviour will
14845 * be retained in any code changes.
14846 *
14847 * @param {string} text text to split
14848 * @returns {Array<line>}
14849 */
14850
14851
14852 _createClass(LabelSplitter, [{
14853 key: "process",
14854 value: function process(text) {
14855 if (!isValidLabel(text)) {
14856 return this.lines.finalize();
14857 }
14858
14859 var font = this.parent.fontOptions; // Normalize the end-of-line's to a single representation - order important
14860
14861 text = text.replace(/\r\n/g, "\n"); // Dos EOL's
14862
14863 text = text.replace(/\r/g, "\n"); // Mac EOL's
14864 // Note that at this point, there can be no \r's in the text.
14865 // This is used later on splitStringIntoLines() to split multifont texts.
14866
14867 var nlLines = String(text).split("\n");
14868 var lineCount = nlLines.length;
14869
14870 if (font.multi) {
14871 // Multi-font case: styling tags active
14872 for (var i = 0; i < lineCount; i++) {
14873 var blocks = this.splitBlocks(nlLines[i], font.multi); // Post: Sequences of tabs and spaces are reduced to single space
14874
14875 if (blocks === undefined) continue;
14876
14877 if (blocks.length === 0) {
14878 this.lines.newLine("");
14879 continue;
14880 }
14881
14882 if (font.maxWdt > 0) {
14883 // widthConstraint.maximum defined
14884 //console.log('Running widthConstraint multi, max: ' + this.fontOptions.maxWdt);
14885 for (var j = 0; j < blocks.length; j++) {
14886 var mod = blocks[j].mod;
14887 var _text = blocks[j].text;
14888 this.splitStringIntoLines(_text, mod, true);
14889 }
14890 } else {
14891 // widthConstraint.maximum NOT defined
14892 for (var _j = 0; _j < blocks.length; _j++) {
14893 var _mod = blocks[_j].mod;
14894 var _text2 = blocks[_j].text;
14895 this.lines.append(_text2, _mod);
14896 }
14897 }
14898
14899 this.lines.newLine();
14900 }
14901 } else {
14902 // Single-font case
14903 if (font.maxWdt > 0) {
14904 // widthConstraint.maximum defined
14905 // console.log('Running widthConstraint normal, max: ' + this.fontOptions.maxWdt);
14906 for (var _i = 0; _i < lineCount; _i++) {
14907 this.splitStringIntoLines(nlLines[_i]);
14908 }
14909 } else {
14910 // widthConstraint.maximum NOT defined
14911 for (var _i2 = 0; _i2 < lineCount; _i2++) {
14912 this.lines.newLine(nlLines[_i2]);
14913 }
14914 }
14915 }
14916
14917 return this.lines.finalize();
14918 }
14919 /**
14920 * normalize the markup system
14921 *
14922 * @param {boolean|'md'|'markdown'|'html'} markupSystem
14923 * @returns {string}
14924 */
14925
14926 }, {
14927 key: "decodeMarkupSystem",
14928 value: function decodeMarkupSystem(markupSystem) {
14929 var system = "none";
14930
14931 if (markupSystem === "markdown" || markupSystem === "md") {
14932 system = "markdown";
14933 } else if (markupSystem === true || markupSystem === "html") {
14934 system = "html";
14935 }
14936
14937 return system;
14938 }
14939 /**
14940 *
14941 * @param {string} text
14942 * @returns {Array}
14943 */
14944
14945 }, {
14946 key: "splitHtmlBlocks",
14947 value: function splitHtmlBlocks(text) {
14948 var s = new MarkupAccumulator(text);
14949
14950 var parseEntities = function parseEntities(ch) {
14951 if (/&/.test(ch)) {
14952 var parsed = s.replace(s.text, "&lt;", "<") || s.replace(s.text, "&amp;", "&");
14953
14954 if (!parsed) {
14955 s.add("&");
14956 }
14957
14958 return true;
14959 }
14960
14961 return false;
14962 };
14963
14964 while (s.position < s.text.length) {
14965 var ch = s.text.charAt(s.position);
14966 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);
14967
14968 if (!parsed) {
14969 s.add(ch);
14970 }
14971
14972 s.position++;
14973 }
14974
14975 s.emitBlock();
14976 return s.blocks;
14977 }
14978 /**
14979 *
14980 * @param {string} text
14981 * @returns {Array}
14982 */
14983
14984 }, {
14985 key: "splitMarkdownBlocks",
14986 value: function splitMarkdownBlocks(text) {
14987 var _this2 = this;
14988
14989 var s = new MarkupAccumulator(text);
14990 var beginable = true;
14991
14992 var parseOverride = function parseOverride(ch) {
14993 if (/\\/.test(ch)) {
14994 if (s.position < _this2.text.length + 1) {
14995 s.position++;
14996 ch = _this2.text.charAt(s.position);
14997
14998 if (/ \t/.test(ch)) {
14999 s.spacing = true;
15000 } else {
15001 s.add(ch);
15002 beginable = false;
15003 }
15004 }
15005
15006 return true;
15007 }
15008
15009 return false;
15010 };
15011
15012 while (s.position < s.text.length) {
15013 var ch = s.text.charAt(s.position);
15014 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");
15015
15016 if (!parsed) {
15017 s.add(ch);
15018 beginable = false;
15019 }
15020
15021 s.position++;
15022 }
15023
15024 s.emitBlock();
15025 return s.blocks;
15026 }
15027 /**
15028 * Explodes a piece of text into single-font blocks using a given markup
15029 *
15030 * @param {string} text
15031 * @param {boolean|'md'|'markdown'|'html'} markupSystem
15032 * @returns {Array.<{text: string, mod: string}>}
15033 * @private
15034 */
15035
15036 }, {
15037 key: "splitBlocks",
15038 value: function splitBlocks(text, markupSystem) {
15039 var system = this.decodeMarkupSystem(markupSystem);
15040
15041 if (system === "none") {
15042 return [{
15043 text: text,
15044 mod: "normal"
15045 }];
15046 } else if (system === "markdown") {
15047 return this.splitMarkdownBlocks(text);
15048 } else if (system === "html") {
15049 return this.splitHtmlBlocks(text);
15050 }
15051 }
15052 /**
15053 * @param {string} text
15054 * @returns {boolean} true if text length over the current max with
15055 * @private
15056 */
15057
15058 }, {
15059 key: "overMaxWidth",
15060 value: function overMaxWidth(text) {
15061 var width = this.ctx.measureText(text).width;
15062 return this.lines.curWidth() + width > this.parent.fontOptions.maxWdt;
15063 }
15064 /**
15065 * Determine the longest part of the sentence which still fits in the
15066 * current max width.
15067 *
15068 * @param {Array} words Array of strings signifying a text lines
15069 * @returns {number} index of first item in string making string go over max
15070 * @private
15071 */
15072
15073 }, {
15074 key: "getLongestFit",
15075 value: function getLongestFit(words) {
15076 var text = "";
15077 var w = 0;
15078
15079 while (w < words.length) {
15080 var pre = text === "" ? "" : " ";
15081 var newText = text + pre + words[w];
15082 if (this.overMaxWidth(newText)) break;
15083 text = newText;
15084 w++;
15085 }
15086
15087 return w;
15088 }
15089 /**
15090 * Determine the longest part of the string which still fits in the
15091 * current max width.
15092 *
15093 * @param {Array} words Array of strings signifying a text lines
15094 * @returns {number} index of first item in string making string go over max
15095 */
15096
15097 }, {
15098 key: "getLongestFitWord",
15099 value: function getLongestFitWord(words) {
15100 var w = 0;
15101
15102 while (w < words.length) {
15103 if (this.overMaxWidth(slice$1(words).call(words, 0, w))) break;
15104 w++;
15105 }
15106
15107 return w;
15108 }
15109 /**
15110 * Split the passed text into lines, according to width constraint (if any).
15111 *
15112 * The method assumes that the input string is a single line, i.e. without lines break.
15113 *
15114 * This method retains spaces, if still present (case `font.multi: false`).
15115 * A space which falls on an internal line break, will be replaced by a newline.
15116 * There is no special handling of tabs; these go along with the flow.
15117 *
15118 * @param {string} str
15119 * @param {string} [mod='normal']
15120 * @param {boolean} [appendLast=false]
15121 * @private
15122 */
15123
15124 }, {
15125 key: "splitStringIntoLines",
15126 value: function splitStringIntoLines(str) {
15127 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "normal";
15128 var appendLast = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
15129 // Set the canvas context font, based upon the current selected/hover state
15130 // and the provided mod, so the text measurement performed by getLongestFit
15131 // will be accurate - and not just use the font of whoever last used the canvas.
15132 this.parent.getFormattingValues(this.ctx, this.selected, this.hover, mod); // Still-present spaces are relevant, retain them
15133
15134 str = str.replace(/^( +)/g, "$1\r");
15135 str = str.replace(/([^\r][^ ]*)( +)/g, "$1\r$2\r");
15136 var words = str.split("\r");
15137
15138 while (words.length > 0) {
15139 var w = this.getLongestFit(words);
15140
15141 if (w === 0) {
15142 // Special case: the first word is already larger than the max width.
15143 var word = words[0]; // Break the word to the largest part that fits the line
15144
15145 var x = this.getLongestFitWord(word);
15146 this.lines.newLine(slice$1(word).call(word, 0, x), mod); // Adjust the word, so that the rest will be done next iteration
15147
15148 words[0] = slice$1(word).call(word, x);
15149 } else {
15150 // skip any space that is replaced by a newline
15151 var newW = w;
15152
15153 if (words[w - 1] === " ") {
15154 w--;
15155 } else if (words[newW] === " ") {
15156 newW++;
15157 }
15158
15159 var text = slice$1(words).call(words, 0, w).join("");
15160
15161 if (w == words.length && appendLast) {
15162 this.lines.append(text, mod);
15163 } else {
15164 this.lines.newLine(text, mod);
15165 } // Adjust the word, so that the rest will be done next iteration
15166
15167
15168 words = slice$1(words).call(words, newW);
15169 }
15170 }
15171 }
15172 }]);
15173
15174 return LabelSplitter;
15175 }();
15176
15177 /**
15178 * List of special styles for multi-fonts
15179 *
15180 * @private
15181 */
15182
15183 var multiFontStyle = ["bold", "ital", "boldital", "mono"];
15184 /**
15185 * A Label to be used for Nodes or Edges.
15186 */
15187
15188 var Label = /*#__PURE__*/function () {
15189 /**
15190 * @param {object} body
15191 * @param {object} options
15192 * @param {boolean} [edgelabel=false]
15193 */
15194 function Label(body, options) {
15195 var edgelabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
15196
15197 _classCallCheck(this, Label);
15198
15199 this.body = body;
15200 this.pointToSelf = false;
15201 this.baseSize = undefined;
15202 this.fontOptions = {}; // instance variable containing the *instance-local* font options
15203
15204 this.setOptions(options);
15205 this.size = {
15206 top: 0,
15207 left: 0,
15208 width: 0,
15209 height: 0,
15210 yLine: 0
15211 };
15212 this.isEdgeLabel = edgelabel;
15213 }
15214 /**
15215 * @param {object} options the options of the parent Node-instance
15216 */
15217
15218
15219 _createClass(Label, [{
15220 key: "setOptions",
15221 value: function setOptions(options) {
15222 this.elementOptions = options; // Reference to the options of the parent Node-instance
15223
15224 this.initFontOptions(options.font);
15225
15226 if (isValidLabel(options.label)) {
15227 this.labelDirty = true;
15228 } else {
15229 // Bad label! Change the option value to prevent bad stuff happening
15230 options.label = undefined;
15231 }
15232
15233 if (options.font !== undefined && options.font !== null) {
15234 // font options can be deleted at various levels
15235 if (typeof options.font === "string") {
15236 this.baseSize = this.fontOptions.size;
15237 } else if (_typeof(options.font) === "object") {
15238 var size = options.font.size;
15239
15240 if (size !== undefined) {
15241 this.baseSize = size;
15242 }
15243 }
15244 }
15245 }
15246 /**
15247 * Init the font Options structure.
15248 *
15249 * Member fontOptions serves as an accumulator for the current font options.
15250 * As such, it needs to be completely separated from the node options.
15251 *
15252 * @param {object} newFontOptions the new font options to process
15253 * @private
15254 */
15255
15256 }, {
15257 key: "initFontOptions",
15258 value: function initFontOptions(newFontOptions) {
15259 var _this = this;
15260
15261 // Prepare the multi-font option objects.
15262 // These will be filled in propagateFonts(), if required
15263 forEach$1(multiFontStyle, function (style) {
15264 _this.fontOptions[style] = {};
15265 }); // Handle shorthand option, if present
15266
15267 if (Label.parseFontString(this.fontOptions, newFontOptions)) {
15268 this.fontOptions.vadjust = 0;
15269 return;
15270 } // Copy over the non-multifont options, if specified
15271
15272
15273 forEach$1(newFontOptions, function (prop, n) {
15274 if (prop !== undefined && prop !== null && _typeof(prop) !== "object") {
15275 _this.fontOptions[n] = prop;
15276 }
15277 });
15278 }
15279 /**
15280 * If in-variable is a string, parse it as a font specifier.
15281 *
15282 * Note that following is not done here and have to be done after the call:
15283 * - Not all font options are set (vadjust, mod)
15284 *
15285 * @param {object} outOptions out-parameter, object in which to store the parse results (if any)
15286 * @param {object} inOptions font options to parse
15287 * @returns {boolean} true if font parsed as string, false otherwise
15288 * @static
15289 */
15290
15291 }, {
15292 key: "constrain",
15293 value:
15294 /**
15295 * Set the width and height constraints based on 'nearest' value
15296 *
15297 * @param {Array} pile array of option objects to consider
15298 * @returns {object} the actual constraint values to use
15299 * @private
15300 */
15301 function constrain(pile) {
15302 // NOTE: constrainWidth and constrainHeight never set!
15303 // NOTE: for edge labels, only 'maxWdt' set
15304 // Node labels can set all the fields
15305 var fontOptions = {
15306 constrainWidth: false,
15307 maxWdt: -1,
15308 minWdt: -1,
15309 constrainHeight: false,
15310 minHgt: -1,
15311 valign: "middle"
15312 };
15313 var widthConstraint = topMost(pile, "widthConstraint");
15314
15315 if (typeof widthConstraint === "number") {
15316 fontOptions.maxWdt = Number(widthConstraint);
15317 fontOptions.minWdt = Number(widthConstraint);
15318 } else if (_typeof(widthConstraint) === "object") {
15319 var widthConstraintMaximum = topMost(pile, ["widthConstraint", "maximum"]);
15320
15321 if (typeof widthConstraintMaximum === "number") {
15322 fontOptions.maxWdt = Number(widthConstraintMaximum);
15323 }
15324
15325 var widthConstraintMinimum = topMost(pile, ["widthConstraint", "minimum"]);
15326
15327 if (typeof widthConstraintMinimum === "number") {
15328 fontOptions.minWdt = Number(widthConstraintMinimum);
15329 }
15330 }
15331
15332 var heightConstraint = topMost(pile, "heightConstraint");
15333
15334 if (typeof heightConstraint === "number") {
15335 fontOptions.minHgt = Number(heightConstraint);
15336 } else if (_typeof(heightConstraint) === "object") {
15337 var heightConstraintMinimum = topMost(pile, ["heightConstraint", "minimum"]);
15338
15339 if (typeof heightConstraintMinimum === "number") {
15340 fontOptions.minHgt = Number(heightConstraintMinimum);
15341 }
15342
15343 var heightConstraintValign = topMost(pile, ["heightConstraint", "valign"]);
15344
15345 if (typeof heightConstraintValign === "string") {
15346 if (heightConstraintValign === "top" || heightConstraintValign === "bottom") {
15347 fontOptions.valign = heightConstraintValign;
15348 }
15349 }
15350 }
15351
15352 return fontOptions;
15353 }
15354 /**
15355 * Set options and update internal state
15356 *
15357 * @param {object} options options to set
15358 * @param {Array} pile array of option objects to consider for option 'chosen'
15359 */
15360
15361 }, {
15362 key: "update",
15363 value: function update(options, pile) {
15364 this.setOptions(options, true);
15365 this.propagateFonts(pile);
15366 deepExtend(this.fontOptions, this.constrain(pile));
15367 this.fontOptions.chooser = choosify("label", pile);
15368 }
15369 /**
15370 * When margins are set in an element, adjust sizes is called to remove them
15371 * from the width/height constraints. This must be done prior to label sizing.
15372 *
15373 * @param {{top: number, right: number, bottom: number, left: number}} margins
15374 */
15375
15376 }, {
15377 key: "adjustSizes",
15378 value: function adjustSizes(margins) {
15379 var widthBias = margins ? margins.right + margins.left : 0;
15380
15381 if (this.fontOptions.constrainWidth) {
15382 this.fontOptions.maxWdt -= widthBias;
15383 this.fontOptions.minWdt -= widthBias;
15384 }
15385
15386 var heightBias = margins ? margins.top + margins.bottom : 0;
15387
15388 if (this.fontOptions.constrainHeight) {
15389 this.fontOptions.minHgt -= heightBias;
15390 }
15391 } /////////////////////////////////////////////////////////
15392 // Methods for handling options piles
15393 // Eventually, these will be moved to a separate class
15394 /////////////////////////////////////////////////////////
15395
15396 /**
15397 * Add the font members of the passed list of option objects to the pile.
15398 *
15399 * @param {Pile} dstPile pile of option objects add to
15400 * @param {Pile} srcPile pile of option objects to take font options from
15401 * @private
15402 */
15403
15404 }, {
15405 key: "addFontOptionsToPile",
15406 value: function addFontOptionsToPile(dstPile, srcPile) {
15407 for (var i = 0; i < srcPile.length; ++i) {
15408 this.addFontToPile(dstPile, srcPile[i]);
15409 }
15410 }
15411 /**
15412 * Add given font option object to the list of objects (the 'pile') to consider for determining
15413 * multi-font option values.
15414 *
15415 * @param {Pile} pile pile of option objects to use
15416 * @param {object} options instance to add to pile
15417 * @private
15418 */
15419
15420 }, {
15421 key: "addFontToPile",
15422 value: function addFontToPile(pile, options) {
15423 if (options === undefined) return;
15424 if (options.font === undefined || options.font === null) return;
15425 var item = options.font;
15426 pile.push(item);
15427 }
15428 /**
15429 * Collect all own-property values from the font pile that aren't multi-font option objectss.
15430 *
15431 * @param {Pile} pile pile of option objects to use
15432 * @returns {object} object with all current own basic font properties
15433 * @private
15434 */
15435
15436 }, {
15437 key: "getBasicOptions",
15438 value: function getBasicOptions(pile) {
15439 var ret = {}; // Scans the whole pile to get all options present
15440
15441 for (var n = 0; n < pile.length; ++n) {
15442 var fontOptions = pile[n]; // Convert shorthand if necessary
15443
15444 var tmpShorthand = {};
15445
15446 if (Label.parseFontString(tmpShorthand, fontOptions)) {
15447 fontOptions = tmpShorthand;
15448 }
15449
15450 forEach$1(fontOptions, function (opt, name) {
15451 if (opt === undefined) return; // multi-font option need not be present
15452
15453 if (Object.prototype.hasOwnProperty.call(ret, name)) return; // Keep first value we encounter
15454
15455 if (indexOf(multiFontStyle).call(multiFontStyle, name) !== -1) {
15456 // Skip multi-font properties but we do need the structure
15457 ret[name] = {};
15458 } else {
15459 ret[name] = opt;
15460 }
15461 });
15462 }
15463
15464 return ret;
15465 }
15466 /**
15467 * Return the value for given option for the given multi-font.
15468 *
15469 * All available option objects are trawled in the set order to construct the option values.
15470 *
15471 * ---------------------------------------------------------------------
15472 * ## Traversal of pile for multi-fonts
15473 *
15474 * The determination of multi-font option values is a special case, because any values not
15475 * present in the multi-font options should by definition be taken from the main font options,
15476 * i.e. from the current 'parent' object of the multi-font option.
15477 *
15478 * ### Search order for multi-fonts
15479 *
15480 * 'bold' used as example:
15481 *
15482 * - search in option group 'bold' in local properties
15483 * - search in main font option group in local properties
15484 *
15485 * ---------------------------------------------------------------------
15486 *
15487 * @param {Pile} pile pile of option objects to use
15488 * @param {MultiFontStyle} multiName sub path for the multi-font
15489 * @param {string} option the option to search for, for the given multi-font
15490 * @returns {string|number} the value for the given option
15491 * @private
15492 */
15493
15494 }, {
15495 key: "getFontOption",
15496 value: function getFontOption(pile, multiName, option) {
15497 var multiFont; // Search multi font in local properties
15498
15499 for (var n = 0; n < pile.length; ++n) {
15500 var fontOptions = pile[n];
15501
15502 if (Object.prototype.hasOwnProperty.call(fontOptions, multiName)) {
15503 multiFont = fontOptions[multiName];
15504 if (multiFont === undefined || multiFont === null) continue; // Convert shorthand if necessary
15505 // TODO: inefficient to do this conversion every time; find a better way.
15506
15507 var tmpShorthand = {};
15508
15509 if (Label.parseFontString(tmpShorthand, multiFont)) {
15510 multiFont = tmpShorthand;
15511 }
15512
15513 if (Object.prototype.hasOwnProperty.call(multiFont, option)) {
15514 return multiFont[option];
15515 }
15516 }
15517 } // Option is not mentioned in the multi font options; take it from the parent font options.
15518 // These have already been converted with getBasicOptions(), so use the converted values.
15519
15520
15521 if (Object.prototype.hasOwnProperty.call(this.fontOptions, option)) {
15522 return this.fontOptions[option];
15523 } // A value **must** be found; you should never get here.
15524
15525
15526 throw new Error("Did not find value for multi-font for property: '" + option + "'");
15527 }
15528 /**
15529 * Return all options values for the given multi-font.
15530 *
15531 * All available option objects are trawled in the set order to construct the option values.
15532 *
15533 * @param {Pile} pile pile of option objects to use
15534 * @param {MultiFontStyle} multiName sub path for the mod-font
15535 * @returns {MultiFontOptions}
15536 * @private
15537 */
15538
15539 }, {
15540 key: "getFontOptions",
15541 value: function getFontOptions(pile, multiName) {
15542 var result = {};
15543 var optionNames = ["color", "size", "face", "mod", "vadjust"]; // List of allowed options per multi-font
15544
15545 for (var i = 0; i < optionNames.length; ++i) {
15546 var mod = optionNames[i];
15547 result[mod] = this.getFontOption(pile, multiName, mod);
15548 }
15549
15550 return result;
15551 } /////////////////////////////////////////////////////////
15552 // End methods for handling options piles
15553 /////////////////////////////////////////////////////////
15554
15555 /**
15556 * Collapse the font options for the multi-font to single objects, from
15557 * the chain of option objects passed (the 'pile').
15558 *
15559 * @param {Pile} pile sequence of option objects to consider.
15560 * First item in list assumed to be the newly set options.
15561 */
15562
15563 }, {
15564 key: "propagateFonts",
15565 value: function propagateFonts(pile) {
15566 var _this2 = this;
15567
15568 var fontPile = []; // sequence of font objects to consider, order important
15569 // Note that this.elementOptions is not used here.
15570
15571 this.addFontOptionsToPile(fontPile, pile);
15572 this.fontOptions = this.getBasicOptions(fontPile); // We set multifont values even if multi === false, for consistency (things break otherwise)
15573
15574 var _loop = function _loop(i) {
15575 var mod = multiFontStyle[i];
15576 var modOptions = _this2.fontOptions[mod];
15577
15578 var tmpMultiFontOptions = _this2.getFontOptions(fontPile, mod); // Copy over found values
15579
15580
15581 forEach$1(tmpMultiFontOptions, function (option, n) {
15582 modOptions[n] = option;
15583 });
15584 modOptions.size = Number(modOptions.size);
15585 modOptions.vadjust = Number(modOptions.vadjust);
15586 };
15587
15588 for (var i = 0; i < multiFontStyle.length; ++i) {
15589 _loop(i);
15590 }
15591 }
15592 /**
15593 * Main function. This is called from anything that wants to draw a label.
15594 *
15595 * @param {CanvasRenderingContext2D} ctx
15596 * @param {number} x
15597 * @param {number} y
15598 * @param {boolean} selected
15599 * @param {boolean} hover
15600 * @param {string} [baseline='middle']
15601 */
15602
15603 }, {
15604 key: "draw",
15605 value: function draw(ctx, x, y, selected, hover) {
15606 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : "middle";
15607 // if no label, return
15608 if (this.elementOptions.label === undefined) return; // check if we have to render the label
15609
15610 var viewFontSize = this.fontOptions.size * this.body.view.scale;
15611 if (this.elementOptions.label && viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) return; // This ensures that there will not be HUGE letters on screen
15612 // by setting an upper limit on the visible text size (regardless of zoomLevel)
15613
15614 if (viewFontSize >= this.elementOptions.scaling.label.maxVisible) {
15615 viewFontSize = Number(this.elementOptions.scaling.label.maxVisible) / this.body.view.scale;
15616 } // update the size cache if required
15617
15618
15619 this.calculateLabelSize(ctx, selected, hover, x, y, baseline);
15620
15621 this._drawBackground(ctx);
15622
15623 this._drawText(ctx, x, this.size.yLine, baseline, viewFontSize);
15624 }
15625 /**
15626 * Draws the label background
15627 *
15628 * @param {CanvasRenderingContext2D} ctx
15629 * @private
15630 */
15631
15632 }, {
15633 key: "_drawBackground",
15634 value: function _drawBackground(ctx) {
15635 if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") {
15636 ctx.fillStyle = this.fontOptions.background;
15637 var size = this.getSize();
15638 ctx.fillRect(size.left, size.top, size.width, size.height);
15639 }
15640 }
15641 /**
15642 *
15643 * @param {CanvasRenderingContext2D} ctx
15644 * @param {number} x
15645 * @param {number} y
15646 * @param {string} [baseline='middle']
15647 * @param {number} viewFontSize
15648 * @private
15649 */
15650
15651 }, {
15652 key: "_drawText",
15653 value: function _drawText(ctx, x, y) {
15654 var baseline = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "middle";
15655 var viewFontSize = arguments.length > 4 ? arguments[4] : undefined;
15656
15657 var _this$_setAlignment = this._setAlignment(ctx, x, y, baseline);
15658
15659 var _this$_setAlignment2 = _slicedToArray(_this$_setAlignment, 2);
15660
15661 x = _this$_setAlignment2[0];
15662 y = _this$_setAlignment2[1];
15663 ctx.textAlign = "left";
15664 x = x - this.size.width / 2; // Shift label 1/2-distance to the left
15665
15666 if (this.fontOptions.valign && this.size.height > this.size.labelHeight) {
15667 if (this.fontOptions.valign === "top") {
15668 y -= (this.size.height - this.size.labelHeight) / 2;
15669 }
15670
15671 if (this.fontOptions.valign === "bottom") {
15672 y += (this.size.height - this.size.labelHeight) / 2;
15673 }
15674 } // draw the text
15675
15676
15677 for (var i = 0; i < this.lineCount; i++) {
15678 var line = this.lines[i];
15679
15680 if (line && line.blocks) {
15681 var width = 0;
15682
15683 if (this.isEdgeLabel || this.fontOptions.align === "center") {
15684 width += (this.size.width - line.width) / 2;
15685 } else if (this.fontOptions.align === "right") {
15686 width += this.size.width - line.width;
15687 }
15688
15689 for (var j = 0; j < line.blocks.length; j++) {
15690 var block = line.blocks[j];
15691 ctx.font = block.font;
15692
15693 var _this$_getColor = this._getColor(block.color, viewFontSize, block.strokeColor),
15694 _this$_getColor2 = _slicedToArray(_this$_getColor, 2),
15695 fontColor = _this$_getColor2[0],
15696 strokeColor = _this$_getColor2[1];
15697
15698 if (block.strokeWidth > 0) {
15699 ctx.lineWidth = block.strokeWidth;
15700 ctx.strokeStyle = strokeColor;
15701 ctx.lineJoin = "round";
15702 }
15703
15704 ctx.fillStyle = fontColor;
15705
15706 if (block.strokeWidth > 0) {
15707 ctx.strokeText(block.text, x + width, y + block.vadjust);
15708 }
15709
15710 ctx.fillText(block.text, x + width, y + block.vadjust);
15711 width += block.width;
15712 }
15713
15714 y += line.height;
15715 }
15716 }
15717 }
15718 /**
15719 *
15720 * @param {CanvasRenderingContext2D} ctx
15721 * @param {number} x
15722 * @param {number} y
15723 * @param {string} baseline
15724 * @returns {Array.<number>}
15725 * @private
15726 */
15727
15728 }, {
15729 key: "_setAlignment",
15730 value: function _setAlignment(ctx, x, y, baseline) {
15731 // check for label alignment (for edges)
15732 // TODO: make alignment for nodes
15733 if (this.isEdgeLabel && this.fontOptions.align !== "horizontal" && this.pointToSelf === false) {
15734 x = 0;
15735 y = 0;
15736 var lineMargin = 2;
15737
15738 if (this.fontOptions.align === "top") {
15739 ctx.textBaseline = "alphabetic";
15740 y -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
15741 } else if (this.fontOptions.align === "bottom") {
15742 ctx.textBaseline = "hanging";
15743 y += 2 * lineMargin; // distance from edge, required because we use hanging. Hanging has less difference between browsers
15744 } else {
15745 ctx.textBaseline = "middle";
15746 }
15747 } else {
15748 ctx.textBaseline = baseline;
15749 }
15750
15751 return [x, y];
15752 }
15753 /**
15754 * fade in when relative scale is between threshold and threshold - 1.
15755 * If the relative scale would be smaller than threshold -1 the draw function would have returned before coming here.
15756 *
15757 * @param {string} color The font color to use
15758 * @param {number} viewFontSize
15759 * @param {string} initialStrokeColor
15760 * @returns {Array.<string>} An array containing the font color and stroke color
15761 * @private
15762 */
15763
15764 }, {
15765 key: "_getColor",
15766 value: function _getColor(color, viewFontSize, initialStrokeColor) {
15767 var fontColor = color || "#000000";
15768 var strokeColor = initialStrokeColor || "#ffffff";
15769
15770 if (viewFontSize <= this.elementOptions.scaling.label.drawThreshold) {
15771 var opacity = Math.max(0, Math.min(1, 1 - (this.elementOptions.scaling.label.drawThreshold - viewFontSize)));
15772 fontColor = overrideOpacity(fontColor, opacity);
15773 strokeColor = overrideOpacity(strokeColor, opacity);
15774 }
15775
15776 return [fontColor, strokeColor];
15777 }
15778 /**
15779 *
15780 * @param {CanvasRenderingContext2D} ctx
15781 * @param {boolean} selected
15782 * @param {boolean} hover
15783 * @returns {{width: number, height: number}}
15784 */
15785
15786 }, {
15787 key: "getTextSize",
15788 value: function getTextSize(ctx) {
15789 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
15790 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
15791
15792 this._processLabel(ctx, selected, hover);
15793
15794 return {
15795 width: this.size.width,
15796 height: this.size.height,
15797 lineCount: this.lineCount
15798 };
15799 }
15800 /**
15801 * Get the current dimensions of the label
15802 *
15803 * @returns {rect}
15804 */
15805
15806 }, {
15807 key: "getSize",
15808 value: function getSize() {
15809 var lineMargin = 2;
15810 var x = this.size.left; // default values which might be overridden below
15811
15812 var y = this.size.top - 0.5 * lineMargin; // idem
15813
15814 if (this.isEdgeLabel) {
15815 var x2 = -this.size.width * 0.5;
15816
15817 switch (this.fontOptions.align) {
15818 case "middle":
15819 x = x2;
15820 y = -this.size.height * 0.5;
15821 break;
15822
15823 case "top":
15824 x = x2;
15825 y = -(this.size.height + lineMargin);
15826 break;
15827
15828 case "bottom":
15829 x = x2;
15830 y = lineMargin;
15831 break;
15832 }
15833 }
15834
15835 var ret = {
15836 left: x,
15837 top: y,
15838 width: this.size.width,
15839 height: this.size.height
15840 };
15841 return ret;
15842 }
15843 /**
15844 *
15845 * @param {CanvasRenderingContext2D} ctx
15846 * @param {boolean} selected
15847 * @param {boolean} hover
15848 * @param {number} [x=0]
15849 * @param {number} [y=0]
15850 * @param {'middle'|'hanging'} [baseline='middle']
15851 */
15852
15853 }, {
15854 key: "calculateLabelSize",
15855 value: function calculateLabelSize(ctx, selected, hover) {
15856 var x = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
15857 var y = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
15858 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : "middle";
15859
15860 this._processLabel(ctx, selected, hover);
15861
15862 this.size.left = x - this.size.width * 0.5;
15863 this.size.top = y - this.size.height * 0.5;
15864 this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size;
15865
15866 if (baseline === "hanging") {
15867 this.size.top += 0.5 * this.fontOptions.size;
15868 this.size.top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
15869
15870 this.size.yLine += 4; // distance from node
15871 }
15872 }
15873 /**
15874 *
15875 * @param {CanvasRenderingContext2D} ctx
15876 * @param {boolean} selected
15877 * @param {boolean} hover
15878 * @param {string} mod
15879 * @returns {{color, size, face, mod, vadjust, strokeWidth: *, strokeColor: (*|string|allOptions.edges.font.strokeColor|{string}|allOptions.nodes.font.strokeColor|Array)}}
15880 */
15881
15882 }, {
15883 key: "getFormattingValues",
15884 value: function getFormattingValues(ctx, selected, hover, mod) {
15885 var getValue = function getValue(fontOptions, mod, option) {
15886 if (mod === "normal") {
15887 if (option === "mod") return "";
15888 return fontOptions[option];
15889 }
15890
15891 if (fontOptions[mod][option] !== undefined) {
15892 // Grumbl leaving out test on undefined equals false for ""
15893 return fontOptions[mod][option];
15894 } else {
15895 // Take from parent font option
15896 return fontOptions[option];
15897 }
15898 };
15899
15900 var values = {
15901 color: getValue(this.fontOptions, mod, "color"),
15902 size: getValue(this.fontOptions, mod, "size"),
15903 face: getValue(this.fontOptions, mod, "face"),
15904 mod: getValue(this.fontOptions, mod, "mod"),
15905 vadjust: getValue(this.fontOptions, mod, "vadjust"),
15906 strokeWidth: this.fontOptions.strokeWidth,
15907 strokeColor: this.fontOptions.strokeColor
15908 };
15909
15910 if (selected || hover) {
15911 if (mod === "normal" && this.fontOptions.chooser === true && this.elementOptions.labelHighlightBold) {
15912 values.mod = "bold";
15913 } else {
15914 if (typeof this.fontOptions.chooser === "function") {
15915 this.fontOptions.chooser(values, this.elementOptions.id, selected, hover);
15916 }
15917 }
15918 }
15919
15920 var fontString = "";
15921
15922 if (values.mod !== undefined && values.mod !== "") {
15923 // safeguard for undefined - this happened
15924 fontString += values.mod + " ";
15925 }
15926
15927 fontString += values.size + "px " + values.face;
15928 ctx.font = fontString.replace(/"/g, "");
15929 values.font = ctx.font;
15930 values.height = values.size;
15931 return values;
15932 }
15933 /**
15934 *
15935 * @param {boolean} selected
15936 * @param {boolean} hover
15937 * @returns {boolean}
15938 */
15939
15940 }, {
15941 key: "differentState",
15942 value: function differentState(selected, hover) {
15943 return selected !== this.selectedState || hover !== this.hoverState;
15944 }
15945 /**
15946 * This explodes the passed text into lines and determines the width, height and number of lines.
15947 *
15948 * @param {CanvasRenderingContext2D} ctx
15949 * @param {boolean} selected
15950 * @param {boolean} hover
15951 * @param {string} inText the text to explode
15952 * @returns {{width, height, lines}|*}
15953 * @private
15954 */
15955
15956 }, {
15957 key: "_processLabelText",
15958 value: function _processLabelText(ctx, selected, hover, inText) {
15959 var splitter = new LabelSplitter(ctx, this, selected, hover);
15960 return splitter.process(inText);
15961 }
15962 /**
15963 * This explodes the label string into lines and sets the width, height and number of lines.
15964 *
15965 * @param {CanvasRenderingContext2D} ctx
15966 * @param {boolean} selected
15967 * @param {boolean} hover
15968 * @private
15969 */
15970
15971 }, {
15972 key: "_processLabel",
15973 value: function _processLabel(ctx, selected, hover) {
15974 if (this.labelDirty === false && !this.differentState(selected, hover)) return;
15975
15976 var state = this._processLabelText(ctx, selected, hover, this.elementOptions.label);
15977
15978 if (this.fontOptions.minWdt > 0 && state.width < this.fontOptions.minWdt) {
15979 state.width = this.fontOptions.minWdt;
15980 }
15981
15982 this.size.labelHeight = state.height;
15983
15984 if (this.fontOptions.minHgt > 0 && state.height < this.fontOptions.minHgt) {
15985 state.height = this.fontOptions.minHgt;
15986 }
15987
15988 this.lines = state.lines;
15989 this.lineCount = state.lines.length;
15990 this.size.width = state.width;
15991 this.size.height = state.height;
15992 this.selectedState = selected;
15993 this.hoverState = hover;
15994 this.labelDirty = false;
15995 }
15996 /**
15997 * Check if this label is visible
15998 *
15999 * @returns {boolean} true if this label will be show, false otherwise
16000 */
16001
16002 }, {
16003 key: "visible",
16004 value: function visible() {
16005 if (this.size.width === 0 || this.size.height === 0 || this.elementOptions.label === undefined) {
16006 return false; // nothing to display
16007 }
16008
16009 var viewFontSize = this.fontOptions.size * this.body.view.scale;
16010
16011 if (viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) {
16012 return false; // Too small or too far away to show
16013 }
16014
16015 return true;
16016 }
16017 }], [{
16018 key: "parseFontString",
16019 value: function parseFontString(outOptions, inOptions) {
16020 if (!inOptions || typeof inOptions !== "string") return false;
16021 var newOptionsArray = inOptions.split(" ");
16022 outOptions.size = +newOptionsArray[0].replace("px", "");
16023 outOptions.face = newOptionsArray[1];
16024 outOptions.color = newOptionsArray[2];
16025 return true;
16026 }
16027 }]);
16028
16029 return Label;
16030 }();
16031
16032 var $$6 = _export;
16033 var getBuiltIn = getBuiltIn$8;
16034 var aFunction$2 = aFunction$5;
16035 var anObject$2 = anObject$c;
16036 var isObject$3 = isObject$j;
16037 var create$2 = objectCreate;
16038 var bind = functionBind;
16039 var fails$1 = fails$m;
16040 var nativeConstruct = getBuiltIn('Reflect', 'construct'); // `Reflect.construct` method
16041 // https://tc39.es/ecma262/#sec-reflect.construct
16042 // MS Edge supports only 2 arguments and argumentsList argument is optional
16043 // FF Nightly sets third argument as `new.target`, but does not create `this` from it
16044
16045 var NEW_TARGET_BUG = fails$1(function () {
16046 function F() {
16047 /* empty */
16048 }
16049
16050 return !(nativeConstruct(function () {
16051 /* empty */
16052 }, [], F) instanceof F);
16053 });
16054 var ARGS_BUG = !fails$1(function () {
16055 nativeConstruct(function () {
16056 /* empty */
16057 });
16058 });
16059 var FORCED$1 = NEW_TARGET_BUG || ARGS_BUG;
16060 $$6({
16061 target: 'Reflect',
16062 stat: true,
16063 forced: FORCED$1,
16064 sham: FORCED$1
16065 }, {
16066 construct: function construct(Target, args
16067 /* , newTarget */
16068 ) {
16069 aFunction$2(Target);
16070 anObject$2(args);
16071 var newTarget = arguments.length < 3 ? Target : aFunction$2(arguments[2]);
16072 if (ARGS_BUG && !NEW_TARGET_BUG) return nativeConstruct(Target, args, newTarget);
16073
16074 if (Target == newTarget) {
16075 // w/o altered newTarget, optimization for 0-4 arguments
16076 switch (args.length) {
16077 case 0:
16078 return new Target();
16079
16080 case 1:
16081 return new Target(args[0]);
16082
16083 case 2:
16084 return new Target(args[0], args[1]);
16085
16086 case 3:
16087 return new Target(args[0], args[1], args[2]);
16088
16089 case 4:
16090 return new Target(args[0], args[1], args[2], args[3]);
16091 } // w/o altered newTarget, lot of arguments case
16092
16093
16094 var $args = [null];
16095 $args.push.apply($args, args);
16096 return new (bind.apply(Target, $args))();
16097 } // with altered newTarget, not support built-in constructors
16098
16099
16100 var proto = newTarget.prototype;
16101 var instance = create$2(isObject$3(proto) ? proto : Object.prototype);
16102 var result = Function.apply.call(Target, instance, args);
16103 return isObject$3(result) ? result : instance;
16104 }
16105 });
16106
16107 var path$6 = path$x;
16108 var construct$2 = path$6.Reflect.construct;
16109
16110 var parent$d = construct$2;
16111 var construct$1 = parent$d;
16112
16113 var construct = construct$1;
16114
16115 var parent$c = create$5;
16116 var create$1 = parent$c;
16117
16118 var create = create$1;
16119
16120 var $$5 = _export;
16121 var setPrototypeOf$4 = objectSetPrototypeOf; // `Object.setPrototypeOf` method
16122 // https://tc39.es/ecma262/#sec-object.setprototypeof
16123
16124 $$5({
16125 target: 'Object',
16126 stat: true
16127 }, {
16128 setPrototypeOf: setPrototypeOf$4
16129 });
16130
16131 var path$5 = path$x;
16132 var setPrototypeOf$3 = path$5.Object.setPrototypeOf;
16133
16134 var parent$b = setPrototypeOf$3;
16135 var setPrototypeOf$2 = parent$b;
16136
16137 var parent$a = setPrototypeOf$2;
16138 var setPrototypeOf$1 = parent$a;
16139
16140 var setPrototypeOf = setPrototypeOf$1;
16141
16142 function _setPrototypeOf(o, p) {
16143 _setPrototypeOf = setPrototypeOf || function _setPrototypeOf(o, p) {
16144 o.__proto__ = p;
16145 return o;
16146 };
16147
16148 return _setPrototypeOf(o, p);
16149 }
16150
16151 function _inherits(subClass, superClass) {
16152 if (typeof superClass !== "function" && superClass !== null) {
16153 throw new TypeError("Super expression must either be null or a function");
16154 }
16155
16156 subClass.prototype = create(superClass && superClass.prototype, {
16157 constructor: {
16158 value: subClass,
16159 writable: true,
16160 configurable: true
16161 }
16162 });
16163 if (superClass) _setPrototypeOf(subClass, superClass);
16164 }
16165
16166 function _assertThisInitialized(self) {
16167 if (self === void 0) {
16168 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
16169 }
16170
16171 return self;
16172 }
16173
16174 function _possibleConstructorReturn(self, call) {
16175 if (call && (_typeof(call) === "object" || typeof call === "function")) {
16176 return call;
16177 } else if (call !== void 0) {
16178 throw new TypeError("Derived constructors may only return object or undefined");
16179 }
16180
16181 return _assertThisInitialized(self);
16182 }
16183
16184 var parent$9 = getPrototypeOf$4;
16185 var getPrototypeOf$2 = parent$9;
16186
16187 var getPrototypeOf$1 = getPrototypeOf$2;
16188
16189 function _getPrototypeOf(o) {
16190 _getPrototypeOf = setPrototypeOf ? getPrototypeOf$1 : function _getPrototypeOf(o) {
16191 return o.__proto__ || getPrototypeOf$1(o);
16192 };
16193 return _getPrototypeOf(o);
16194 }
16195
16196 /**
16197 * The Base class for all Nodes.
16198 */
16199 var NodeBase = /*#__PURE__*/function () {
16200 /**
16201 * @param {object} options
16202 * @param {object} body
16203 * @param {Label} labelModule
16204 */
16205 function NodeBase(options, body, labelModule) {
16206 _classCallCheck(this, NodeBase);
16207
16208 this.body = body;
16209 this.labelModule = labelModule;
16210 this.setOptions(options);
16211 this.top = undefined;
16212 this.left = undefined;
16213 this.height = undefined;
16214 this.width = undefined;
16215 this.radius = undefined;
16216 this.margin = undefined;
16217 this.refreshNeeded = true;
16218 this.boundingBox = {
16219 top: 0,
16220 left: 0,
16221 right: 0,
16222 bottom: 0
16223 };
16224 }
16225 /**
16226 *
16227 * @param {object} options
16228 */
16229
16230
16231 _createClass(NodeBase, [{
16232 key: "setOptions",
16233 value: function setOptions(options) {
16234 this.options = options;
16235 }
16236 /**
16237 *
16238 * @param {Label} labelModule
16239 * @private
16240 */
16241
16242 }, {
16243 key: "_setMargins",
16244 value: function _setMargins(labelModule) {
16245 this.margin = {};
16246
16247 if (this.options.margin) {
16248 if (_typeof(this.options.margin) == "object") {
16249 this.margin.top = this.options.margin.top;
16250 this.margin.right = this.options.margin.right;
16251 this.margin.bottom = this.options.margin.bottom;
16252 this.margin.left = this.options.margin.left;
16253 } else {
16254 this.margin.top = this.options.margin;
16255 this.margin.right = this.options.margin;
16256 this.margin.bottom = this.options.margin;
16257 this.margin.left = this.options.margin;
16258 }
16259 }
16260
16261 labelModule.adjustSizes(this.margin);
16262 }
16263 /**
16264 *
16265 * @param {CanvasRenderingContext2D} ctx
16266 * @param {number} angle
16267 * @returns {number}
16268 * @private
16269 */
16270
16271 }, {
16272 key: "_distanceToBorder",
16273 value: function _distanceToBorder(ctx, angle) {
16274 var borderWidth = this.options.borderWidth;
16275
16276 if (ctx) {
16277 this.resize(ctx);
16278 }
16279
16280 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
16281 }
16282 /**
16283 *
16284 * @param {CanvasRenderingContext2D} ctx
16285 * @param {ArrowOptions} values
16286 */
16287
16288 }, {
16289 key: "enableShadow",
16290 value: function enableShadow(ctx, values) {
16291 if (values.shadow) {
16292 ctx.shadowColor = values.shadowColor;
16293 ctx.shadowBlur = values.shadowSize;
16294 ctx.shadowOffsetX = values.shadowX;
16295 ctx.shadowOffsetY = values.shadowY;
16296 }
16297 }
16298 /**
16299 *
16300 * @param {CanvasRenderingContext2D} ctx
16301 * @param {ArrowOptions} values
16302 */
16303
16304 }, {
16305 key: "disableShadow",
16306 value: function disableShadow(ctx, values) {
16307 if (values.shadow) {
16308 ctx.shadowColor = "rgba(0,0,0,0)";
16309 ctx.shadowBlur = 0;
16310 ctx.shadowOffsetX = 0;
16311 ctx.shadowOffsetY = 0;
16312 }
16313 }
16314 /**
16315 *
16316 * @param {CanvasRenderingContext2D} ctx
16317 * @param {ArrowOptions} values
16318 */
16319
16320 }, {
16321 key: "enableBorderDashes",
16322 value: function enableBorderDashes(ctx, values) {
16323 if (values.borderDashes !== false) {
16324 if (ctx.setLineDash !== undefined) {
16325 var dashes = values.borderDashes;
16326
16327 if (dashes === true) {
16328 dashes = [5, 15];
16329 }
16330
16331 ctx.setLineDash(dashes);
16332 } else {
16333 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
16334 this.options.shapeProperties.borderDashes = false;
16335 values.borderDashes = false;
16336 }
16337 }
16338 }
16339 /**
16340 *
16341 * @param {CanvasRenderingContext2D} ctx
16342 * @param {ArrowOptions} values
16343 */
16344
16345 }, {
16346 key: "disableBorderDashes",
16347 value: function disableBorderDashes(ctx, values) {
16348 if (values.borderDashes !== false) {
16349 if (ctx.setLineDash !== undefined) {
16350 ctx.setLineDash([0]);
16351 } else {
16352 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
16353 this.options.shapeProperties.borderDashes = false;
16354 values.borderDashes = false;
16355 }
16356 }
16357 }
16358 /**
16359 * Determine if the shape of a node needs to be recalculated.
16360 *
16361 * @param {boolean} selected
16362 * @param {boolean} hover
16363 * @returns {boolean}
16364 * @protected
16365 */
16366
16367 }, {
16368 key: "needsRefresh",
16369 value: function needsRefresh(selected, hover) {
16370 if (this.refreshNeeded === true) {
16371 // This is probably not the best location to reset this member.
16372 // However, in the current logic, it is the most convenient one.
16373 this.refreshNeeded = false;
16374 return true;
16375 }
16376
16377 return this.width === undefined || this.labelModule.differentState(selected, hover);
16378 }
16379 /**
16380 *
16381 * @param {CanvasRenderingContext2D} ctx
16382 * @param {ArrowOptions} values
16383 */
16384
16385 }, {
16386 key: "initContextForDraw",
16387 value: function initContextForDraw(ctx, values) {
16388 var borderWidth = values.borderWidth / this.body.view.scale;
16389 ctx.lineWidth = Math.min(this.width, borderWidth);
16390 ctx.strokeStyle = values.borderColor;
16391 ctx.fillStyle = values.color;
16392 }
16393 /**
16394 *
16395 * @param {CanvasRenderingContext2D} ctx
16396 * @param {ArrowOptions} values
16397 */
16398
16399 }, {
16400 key: "performStroke",
16401 value: function performStroke(ctx, values) {
16402 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.
16403
16404 ctx.save(); // if borders are zero width, they will be drawn with width 1 by default. This prevents that
16405
16406 if (borderWidth > 0) {
16407 this.enableBorderDashes(ctx, values); //draw the border
16408
16409 ctx.stroke(); //disable dashed border for other elements
16410
16411 this.disableBorderDashes(ctx, values);
16412 }
16413
16414 ctx.restore();
16415 }
16416 /**
16417 *
16418 * @param {CanvasRenderingContext2D} ctx
16419 * @param {ArrowOptions} values
16420 */
16421
16422 }, {
16423 key: "performFill",
16424 value: function performFill(ctx, values) {
16425 ctx.save();
16426 ctx.fillStyle = values.color; // draw shadow if enabled
16427
16428 this.enableShadow(ctx, values); // draw the background
16429
16430 fill(ctx).call(ctx); // disable shadows for other elements.
16431
16432
16433 this.disableShadow(ctx, values);
16434 ctx.restore();
16435 this.performStroke(ctx, values);
16436 }
16437 /**
16438 *
16439 * @param {number} margin
16440 * @private
16441 */
16442
16443 }, {
16444 key: "_addBoundingBoxMargin",
16445 value: function _addBoundingBoxMargin(margin) {
16446 this.boundingBox.left -= margin;
16447 this.boundingBox.top -= margin;
16448 this.boundingBox.bottom += margin;
16449 this.boundingBox.right += margin;
16450 }
16451 /**
16452 * Actual implementation of this method call.
16453 *
16454 * Doing it like this makes it easier to override
16455 * in the child classes.
16456 *
16457 * @param {number} x width
16458 * @param {number} y height
16459 * @param {CanvasRenderingContext2D} ctx
16460 * @param {boolean} selected
16461 * @param {boolean} hover
16462 * @private
16463 */
16464
16465 }, {
16466 key: "_updateBoundingBox",
16467 value: function _updateBoundingBox(x, y, ctx, selected, hover) {
16468 if (ctx !== undefined) {
16469 this.resize(ctx, selected, hover);
16470 }
16471
16472 this.left = x - this.width / 2;
16473 this.top = y - this.height / 2;
16474 this.boundingBox.left = this.left;
16475 this.boundingBox.top = this.top;
16476 this.boundingBox.bottom = this.top + this.height;
16477 this.boundingBox.right = this.left + this.width;
16478 }
16479 /**
16480 * Default implementation of this method call.
16481 * This acts as a stub which can be overridden.
16482 *
16483 * @param {number} x width
16484 * @param {number} y height
16485 * @param {CanvasRenderingContext2D} ctx
16486 * @param {boolean} selected
16487 * @param {boolean} hover
16488 */
16489
16490 }, {
16491 key: "updateBoundingBox",
16492 value: function updateBoundingBox(x, y, ctx, selected, hover) {
16493 this._updateBoundingBox(x, y, ctx, selected, hover);
16494 }
16495 /**
16496 * Determine the dimensions to use for nodes with an internal label
16497 *
16498 * Currently, these are: Circle, Ellipse, Database, Box
16499 * The other nodes have external labels, and will not call this method
16500 *
16501 * If there is no label, decent default values are supplied.
16502 *
16503 * @param {CanvasRenderingContext2D} ctx
16504 * @param {boolean} [selected]
16505 * @param {boolean} [hover]
16506 * @returns {{width:number, height:number}}
16507 */
16508
16509 }, {
16510 key: "getDimensionsFromLabel",
16511 value: function getDimensionsFromLabel(ctx, selected, hover) {
16512 // NOTE: previously 'textSize' was not put in 'this' for Ellipse
16513 // TODO: examine the consequences.
16514 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
16515 var width = this.textSize.width;
16516 var height = this.textSize.height;
16517 var DEFAULT_SIZE = 14;
16518
16519 if (width === 0) {
16520 // This happens when there is no label text set
16521 width = DEFAULT_SIZE; // use a decent default
16522
16523 height = DEFAULT_SIZE; // if width zero, then height also always zero
16524 }
16525
16526 return {
16527 width: width,
16528 height: height
16529 };
16530 }
16531 }]);
16532
16533 return NodeBase;
16534 }();
16535
16536 function _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); }; }
16537
16538 function _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; } }
16539 /**
16540 * A Box Node/Cluster shape.
16541 *
16542 * @augments NodeBase
16543 */
16544
16545 var Box$1 = /*#__PURE__*/function (_NodeBase) {
16546 _inherits(Box, _NodeBase);
16547
16548 var _super = _createSuper$s(Box);
16549
16550 /**
16551 * @param {object} options
16552 * @param {object} body
16553 * @param {Label} labelModule
16554 */
16555 function Box(options, body, labelModule) {
16556 var _this;
16557
16558 _classCallCheck(this, Box);
16559
16560 _this = _super.call(this, options, body, labelModule);
16561
16562 _this._setMargins(labelModule);
16563
16564 return _this;
16565 }
16566 /**
16567 *
16568 * @param {CanvasRenderingContext2D} ctx
16569 * @param {boolean} [selected]
16570 * @param {boolean} [hover]
16571 */
16572
16573
16574 _createClass(Box, [{
16575 key: "resize",
16576 value: function resize(ctx) {
16577 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
16578 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
16579
16580 if (this.needsRefresh(selected, hover)) {
16581 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
16582 this.width = dimensions.width + this.margin.right + this.margin.left;
16583 this.height = dimensions.height + this.margin.top + this.margin.bottom;
16584 this.radius = this.width / 2;
16585 }
16586 }
16587 /**
16588 *
16589 * @param {CanvasRenderingContext2D} ctx
16590 * @param {number} x width
16591 * @param {number} y height
16592 * @param {boolean} selected
16593 * @param {boolean} hover
16594 * @param {ArrowOptions} values
16595 */
16596
16597 }, {
16598 key: "draw",
16599 value: function draw(ctx, x, y, selected, hover, values) {
16600 this.resize(ctx, selected, hover);
16601 this.left = x - this.width / 2;
16602 this.top = y - this.height / 2;
16603 this.initContextForDraw(ctx, values);
16604 drawRoundRect(ctx, this.left, this.top, this.width, this.height, values.borderRadius);
16605 this.performFill(ctx, values);
16606 this.updateBoundingBox(x, y, ctx, selected, hover);
16607 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
16608 }
16609 /**
16610 *
16611 * @param {number} x width
16612 * @param {number} y height
16613 * @param {CanvasRenderingContext2D} ctx
16614 * @param {boolean} selected
16615 * @param {boolean} hover
16616 */
16617
16618 }, {
16619 key: "updateBoundingBox",
16620 value: function updateBoundingBox(x, y, ctx, selected, hover) {
16621 this._updateBoundingBox(x, y, ctx, selected, hover);
16622
16623 var borderRadius = this.options.shapeProperties.borderRadius; // only effective for box
16624
16625 this._addBoundingBoxMargin(borderRadius);
16626 }
16627 /**
16628 *
16629 * @param {CanvasRenderingContext2D} ctx
16630 * @param {number} angle
16631 * @returns {number}
16632 */
16633
16634 }, {
16635 key: "distanceToBorder",
16636 value: function distanceToBorder(ctx, angle) {
16637 if (ctx) {
16638 this.resize(ctx);
16639 }
16640
16641 var borderWidth = this.options.borderWidth;
16642 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
16643 }
16644 }]);
16645
16646 return Box;
16647 }(NodeBase);
16648
16649 function _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); }; }
16650
16651 function _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; } }
16652 /**
16653 * NOTE: This is a bad base class
16654 *
16655 * Child classes are:
16656 *
16657 * Image - uses *only* image methods
16658 * Circle - uses *only* _drawRawCircle
16659 * CircleImage - uses all
16660 *
16661 * TODO: Refactor, move _drawRawCircle to different module, derive Circle from NodeBase
16662 * Rename this to ImageBase
16663 * Consolidate common code in Image and CircleImage to base class
16664 *
16665 * @augments NodeBase
16666 */
16667
16668 var CircleImageBase = /*#__PURE__*/function (_NodeBase) {
16669 _inherits(CircleImageBase, _NodeBase);
16670
16671 var _super = _createSuper$r(CircleImageBase);
16672
16673 /**
16674 * @param {object} options
16675 * @param {object} body
16676 * @param {Label} labelModule
16677 */
16678 function CircleImageBase(options, body, labelModule) {
16679 var _this;
16680
16681 _classCallCheck(this, CircleImageBase);
16682
16683 _this = _super.call(this, options, body, labelModule);
16684 _this.labelOffset = 0;
16685 _this.selected = false;
16686 return _this;
16687 }
16688 /**
16689 *
16690 * @param {object} options
16691 * @param {object} [imageObj]
16692 * @param {object} [imageObjAlt]
16693 */
16694
16695
16696 _createClass(CircleImageBase, [{
16697 key: "setOptions",
16698 value: function setOptions(options, imageObj, imageObjAlt) {
16699 this.options = options;
16700
16701 if (!(imageObj === undefined && imageObjAlt === undefined)) {
16702 this.setImages(imageObj, imageObjAlt);
16703 }
16704 }
16705 /**
16706 * Set the images for this node.
16707 *
16708 * The images can be updated after the initial setting of options;
16709 * therefore, this method needs to be reentrant.
16710 *
16711 * For correct working in error cases, it is necessary to properly set
16712 * field 'nodes.brokenImage' in the options.
16713 *
16714 * @param {Image} imageObj required; main image to show for this node
16715 * @param {Image|undefined} imageObjAlt optional; image to show when node is selected
16716 */
16717
16718 }, {
16719 key: "setImages",
16720 value: function setImages(imageObj, imageObjAlt) {
16721 if (imageObjAlt && this.selected) {
16722 this.imageObj = imageObjAlt;
16723 this.imageObjAlt = imageObj;
16724 } else {
16725 this.imageObj = imageObj;
16726 this.imageObjAlt = imageObjAlt;
16727 }
16728 }
16729 /**
16730 * Set selection and switch between the base and the selected image.
16731 *
16732 * Do the switch only if imageObjAlt exists.
16733 *
16734 * @param {boolean} selected value of new selected state for current node
16735 */
16736
16737 }, {
16738 key: "switchImages",
16739 value: function switchImages(selected) {
16740 var selection_changed = selected && !this.selected || !selected && this.selected;
16741 this.selected = selected; // Remember new selection
16742
16743 if (this.imageObjAlt !== undefined && selection_changed) {
16744 var imageTmp = this.imageObj;
16745 this.imageObj = this.imageObjAlt;
16746 this.imageObjAlt = imageTmp;
16747 }
16748 }
16749 /**
16750 * Returns Image Padding from node options
16751 *
16752 * @returns {{top: number,left: number,bottom: number,right: number}} image padding inside this shape
16753 * @private
16754 */
16755
16756 }, {
16757 key: "_getImagePadding",
16758 value: function _getImagePadding() {
16759 var imgPadding = {
16760 top: 0,
16761 right: 0,
16762 bottom: 0,
16763 left: 0
16764 };
16765
16766 if (this.options.imagePadding) {
16767 var optImgPadding = this.options.imagePadding;
16768
16769 if (_typeof(optImgPadding) == "object") {
16770 imgPadding.top = optImgPadding.top;
16771 imgPadding.right = optImgPadding.right;
16772 imgPadding.bottom = optImgPadding.bottom;
16773 imgPadding.left = optImgPadding.left;
16774 } else {
16775 imgPadding.top = optImgPadding;
16776 imgPadding.right = optImgPadding;
16777 imgPadding.bottom = optImgPadding;
16778 imgPadding.left = optImgPadding;
16779 }
16780 }
16781
16782 return imgPadding;
16783 }
16784 /**
16785 * Adjust the node dimensions for a loaded image.
16786 *
16787 * Pre: this.imageObj is valid
16788 */
16789
16790 }, {
16791 key: "_resizeImage",
16792 value: function _resizeImage() {
16793 var width, height;
16794
16795 if (this.options.shapeProperties.useImageSize === false) {
16796 // Use the size property
16797 var ratio_width = 1;
16798 var ratio_height = 1; // Only calculate the proper ratio if both width and height not zero
16799
16800 if (this.imageObj.width && this.imageObj.height) {
16801 if (this.imageObj.width > this.imageObj.height) {
16802 ratio_width = this.imageObj.width / this.imageObj.height;
16803 } else {
16804 ratio_height = this.imageObj.height / this.imageObj.width;
16805 }
16806 }
16807
16808 width = this.options.size * 2 * ratio_width;
16809 height = this.options.size * 2 * ratio_height;
16810 } else {
16811 // Use the image size with image padding
16812 var imgPadding = this._getImagePadding();
16813
16814 width = this.imageObj.width + imgPadding.left + imgPadding.right;
16815 height = this.imageObj.height + imgPadding.top + imgPadding.bottom;
16816 }
16817
16818 this.width = width;
16819 this.height = height;
16820 this.radius = 0.5 * this.width;
16821 }
16822 /**
16823 *
16824 * @param {CanvasRenderingContext2D} ctx
16825 * @param {number} x width
16826 * @param {number} y height
16827 * @param {ArrowOptions} values
16828 * @private
16829 */
16830
16831 }, {
16832 key: "_drawRawCircle",
16833 value: function _drawRawCircle(ctx, x, y, values) {
16834 this.initContextForDraw(ctx, values);
16835 drawCircle(ctx, x, y, values.size);
16836 this.performFill(ctx, values);
16837 }
16838 /**
16839 *
16840 * @param {CanvasRenderingContext2D} ctx
16841 * @param {ArrowOptions} values
16842 * @private
16843 */
16844
16845 }, {
16846 key: "_drawImageAtPosition",
16847 value: function _drawImageAtPosition(ctx, values) {
16848 if (this.imageObj.width != 0) {
16849 // draw the image
16850 ctx.globalAlpha = values.opacity !== undefined ? values.opacity : 1; // draw shadow if enabled
16851
16852 this.enableShadow(ctx, values);
16853 var factor = 1;
16854
16855 if (this.options.shapeProperties.interpolation === true) {
16856 factor = this.imageObj.width / this.width / this.body.view.scale;
16857 }
16858
16859 var imgPadding = this._getImagePadding();
16860
16861 var imgPosLeft = this.left + imgPadding.left;
16862 var imgPosTop = this.top + imgPadding.top;
16863 var imgWidth = this.width - imgPadding.left - imgPadding.right;
16864 var imgHeight = this.height - imgPadding.top - imgPadding.bottom;
16865 this.imageObj.drawImageAtPosition(ctx, factor, imgPosLeft, imgPosTop, imgWidth, imgHeight); // disable shadows for other elements.
16866
16867 this.disableShadow(ctx, values);
16868 }
16869 }
16870 /**
16871 *
16872 * @param {CanvasRenderingContext2D} ctx
16873 * @param {number} x width
16874 * @param {number} y height
16875 * @param {boolean} selected
16876 * @param {boolean} hover
16877 * @private
16878 */
16879
16880 }, {
16881 key: "_drawImageLabel",
16882 value: function _drawImageLabel(ctx, x, y, selected, hover) {
16883 var offset = 0;
16884
16885 if (this.height !== undefined) {
16886 offset = this.height * 0.5;
16887 var labelDimensions = this.labelModule.getTextSize(ctx, selected, hover);
16888
16889 if (labelDimensions.lineCount >= 1) {
16890 offset += labelDimensions.height / 2;
16891 }
16892 }
16893
16894 var yLabel = y + offset;
16895
16896 if (this.options.label) {
16897 this.labelOffset = offset;
16898 }
16899
16900 this.labelModule.draw(ctx, x, yLabel, selected, hover, "hanging");
16901 }
16902 }]);
16903
16904 return CircleImageBase;
16905 }(NodeBase);
16906
16907 function _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); }; }
16908
16909 function _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; } }
16910 /**
16911 * A Circle Node/Cluster shape.
16912 *
16913 * @augments CircleImageBase
16914 */
16915
16916 var Circle$1 = /*#__PURE__*/function (_CircleImageBase) {
16917 _inherits(Circle, _CircleImageBase);
16918
16919 var _super = _createSuper$q(Circle);
16920
16921 /**
16922 * @param {object} options
16923 * @param {object} body
16924 * @param {Label} labelModule
16925 */
16926 function Circle(options, body, labelModule) {
16927 var _this;
16928
16929 _classCallCheck(this, Circle);
16930
16931 _this = _super.call(this, options, body, labelModule);
16932
16933 _this._setMargins(labelModule);
16934
16935 return _this;
16936 }
16937 /**
16938 *
16939 * @param {CanvasRenderingContext2D} ctx
16940 * @param {boolean} [selected]
16941 * @param {boolean} [hover]
16942 */
16943
16944
16945 _createClass(Circle, [{
16946 key: "resize",
16947 value: function resize(ctx) {
16948 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
16949 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
16950
16951 if (this.needsRefresh(selected, hover)) {
16952 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
16953 var diameter = Math.max(dimensions.width + this.margin.right + this.margin.left, dimensions.height + this.margin.top + this.margin.bottom);
16954 this.options.size = diameter / 2; // NOTE: this size field only set here, not in Ellipse, Database, Box
16955
16956 this.width = diameter;
16957 this.height = diameter;
16958 this.radius = this.width / 2;
16959 }
16960 }
16961 /**
16962 *
16963 * @param {CanvasRenderingContext2D} ctx
16964 * @param {number} x width
16965 * @param {number} y height
16966 * @param {boolean} selected
16967 * @param {boolean} hover
16968 * @param {ArrowOptions} values
16969 */
16970
16971 }, {
16972 key: "draw",
16973 value: function draw(ctx, x, y, selected, hover, values) {
16974 this.resize(ctx, selected, hover);
16975 this.left = x - this.width / 2;
16976 this.top = y - this.height / 2;
16977
16978 this._drawRawCircle(ctx, x, y, values);
16979
16980 this.updateBoundingBox(x, y);
16981 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, y, selected, hover);
16982 }
16983 /**
16984 *
16985 * @param {number} x width
16986 * @param {number} y height
16987 */
16988
16989 }, {
16990 key: "updateBoundingBox",
16991 value: function updateBoundingBox(x, y) {
16992 this.boundingBox.top = y - this.options.size;
16993 this.boundingBox.left = x - this.options.size;
16994 this.boundingBox.right = x + this.options.size;
16995 this.boundingBox.bottom = y + this.options.size;
16996 }
16997 /**
16998 *
16999 * @param {CanvasRenderingContext2D} ctx
17000 * @returns {number}
17001 */
17002
17003 }, {
17004 key: "distanceToBorder",
17005 value: function distanceToBorder(ctx) {
17006 if (ctx) {
17007 this.resize(ctx);
17008 }
17009
17010 return this.width * 0.5;
17011 }
17012 }]);
17013
17014 return Circle;
17015 }(CircleImageBase);
17016
17017 function _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); }; }
17018
17019 function _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; } }
17020 /**
17021 * A CircularImage Node/Cluster shape.
17022 *
17023 * @augments CircleImageBase
17024 */
17025
17026 var CircularImage = /*#__PURE__*/function (_CircleImageBase) {
17027 _inherits(CircularImage, _CircleImageBase);
17028
17029 var _super = _createSuper$p(CircularImage);
17030
17031 /**
17032 * @param {object} options
17033 * @param {object} body
17034 * @param {Label} labelModule
17035 * @param {Image} imageObj
17036 * @param {Image} imageObjAlt
17037 */
17038 function CircularImage(options, body, labelModule, imageObj, imageObjAlt) {
17039 var _this;
17040
17041 _classCallCheck(this, CircularImage);
17042
17043 _this = _super.call(this, options, body, labelModule);
17044
17045 _this.setImages(imageObj, imageObjAlt);
17046
17047 return _this;
17048 }
17049 /**
17050 *
17051 * @param {CanvasRenderingContext2D} ctx
17052 * @param {boolean} [selected]
17053 * @param {boolean} [hover]
17054 */
17055
17056
17057 _createClass(CircularImage, [{
17058 key: "resize",
17059 value: function resize(ctx) {
17060 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
17061 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
17062 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
17063
17064 if (imageAbsent) {
17065 var diameter = this.options.size * 2;
17066 this.width = diameter;
17067 this.height = diameter;
17068 this.radius = 0.5 * this.width;
17069 return;
17070 } // At this point, an image is present, i.e. this.imageObj is valid.
17071
17072
17073 if (this.needsRefresh(selected, hover)) {
17074 this._resizeImage();
17075 }
17076 }
17077 /**
17078 *
17079 * @param {CanvasRenderingContext2D} ctx
17080 * @param {number} x width
17081 * @param {number} y height
17082 * @param {boolean} selected
17083 * @param {boolean} hover
17084 * @param {ArrowOptions} values
17085 */
17086
17087 }, {
17088 key: "draw",
17089 value: function draw(ctx, x, y, selected, hover, values) {
17090 this.switchImages(selected);
17091 this.resize();
17092 var labelX = x,
17093 labelY = y;
17094
17095 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
17096 this.left = x;
17097 this.top = y;
17098 labelX += this.width / 2;
17099 labelY += this.height / 2;
17100 } else {
17101 this.left = x - this.width / 2;
17102 this.top = y - this.height / 2;
17103 } // draw the background circle. IMPORTANT: the stroke in this method is used by the clip method below.
17104
17105
17106 this._drawRawCircle(ctx, labelX, labelY, values); // now we draw in the circle, we save so we can revert the clip operation after drawing.
17107
17108
17109 ctx.save(); // clip is used to use the stroke in drawRawCircle as an area that we can draw in.
17110
17111 ctx.clip(); // draw the image
17112
17113 this._drawImageAtPosition(ctx, values); // restore so we can again draw on the full canvas
17114
17115
17116 ctx.restore();
17117
17118 this._drawImageLabel(ctx, labelX, labelY, selected, hover);
17119
17120 this.updateBoundingBox(x, y);
17121 } // TODO: compare with Circle.updateBoundingBox(), consolidate? More stuff is happening here
17122
17123 /**
17124 *
17125 * @param {number} x width
17126 * @param {number} y height
17127 */
17128
17129 }, {
17130 key: "updateBoundingBox",
17131 value: function updateBoundingBox(x, y) {
17132 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
17133 this.boundingBox.top = y;
17134 this.boundingBox.left = x;
17135 this.boundingBox.right = x + this.options.size * 2;
17136 this.boundingBox.bottom = y + this.options.size * 2;
17137 } else {
17138 this.boundingBox.top = y - this.options.size;
17139 this.boundingBox.left = x - this.options.size;
17140 this.boundingBox.right = x + this.options.size;
17141 this.boundingBox.bottom = y + this.options.size;
17142 } // TODO: compare with Image.updateBoundingBox(), consolidate?
17143
17144
17145 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
17146 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
17147 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
17148 }
17149 /**
17150 *
17151 * @param {CanvasRenderingContext2D} ctx
17152 * @returns {number}
17153 */
17154
17155 }, {
17156 key: "distanceToBorder",
17157 value: function distanceToBorder(ctx) {
17158 if (ctx) {
17159 this.resize(ctx);
17160 }
17161
17162 return this.width * 0.5;
17163 }
17164 }]);
17165
17166 return CircularImage;
17167 }(CircleImageBase);
17168
17169 function _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); }; }
17170
17171 function _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; } }
17172 /**
17173 * Base class for constructing Node/Cluster Shapes.
17174 *
17175 * @augments NodeBase
17176 */
17177
17178 var ShapeBase = /*#__PURE__*/function (_NodeBase) {
17179 _inherits(ShapeBase, _NodeBase);
17180
17181 var _super = _createSuper$o(ShapeBase);
17182
17183 /**
17184 * @param {object} options
17185 * @param {object} body
17186 * @param {Label} labelModule
17187 */
17188 function ShapeBase(options, body, labelModule) {
17189 _classCallCheck(this, ShapeBase);
17190
17191 return _super.call(this, options, body, labelModule);
17192 }
17193 /**
17194 *
17195 * @param {CanvasRenderingContext2D} ctx
17196 * @param {boolean} [selected]
17197 * @param {boolean} [hover]
17198 * @param {object} [values={size: this.options.size}]
17199 */
17200
17201
17202 _createClass(ShapeBase, [{
17203 key: "resize",
17204 value: function resize(ctx) {
17205 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
17206 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
17207 var values = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {
17208 size: this.options.size
17209 };
17210
17211 if (this.needsRefresh(selected, hover)) {
17212 var _this$customSizeWidth, _this$customSizeHeigh;
17213
17214 this.labelModule.getTextSize(ctx, selected, hover);
17215 var size = 2 * values.size;
17216 this.width = (_this$customSizeWidth = this.customSizeWidth) !== null && _this$customSizeWidth !== void 0 ? _this$customSizeWidth : size;
17217 this.height = (_this$customSizeHeigh = this.customSizeHeight) !== null && _this$customSizeHeigh !== void 0 ? _this$customSizeHeigh : size;
17218 this.radius = 0.5 * this.width;
17219 }
17220 }
17221 /**
17222 *
17223 * @param {CanvasRenderingContext2D} ctx
17224 * @param {string} shape
17225 * @param {number} sizeMultiplier - Unused! TODO: Remove next major release
17226 * @param {number} x
17227 * @param {number} y
17228 * @param {boolean} selected
17229 * @param {boolean} hover
17230 * @param {ArrowOptions} values
17231 * @private
17232 *
17233 * @returns {object} Callbacks to draw later on higher layers.
17234 */
17235
17236 }, {
17237 key: "_drawShape",
17238 value: function _drawShape(ctx, shape, sizeMultiplier, x, y, selected, hover, values) {
17239 var _this = this;
17240
17241 this.resize(ctx, selected, hover, values);
17242 this.left = x - this.width / 2;
17243 this.top = y - this.height / 2;
17244 this.initContextForDraw(ctx, values);
17245 getShape(shape)(ctx, x, y, values.size);
17246 this.performFill(ctx, values);
17247
17248 if (this.options.icon !== undefined) {
17249 if (this.options.icon.code !== undefined) {
17250 ctx.font = (selected ? "bold " : "") + this.height / 2 + "px " + (this.options.icon.face || "FontAwesome");
17251 ctx.fillStyle = this.options.icon.color || "black";
17252 ctx.textAlign = "center";
17253 ctx.textBaseline = "middle";
17254 ctx.fillText(this.options.icon.code, x, y);
17255 }
17256 }
17257
17258 return {
17259 drawExternalLabel: function drawExternalLabel() {
17260 if (_this.options.label !== undefined) {
17261 // Need to call following here in order to ensure value for
17262 // `this.labelModule.size.height`.
17263 _this.labelModule.calculateLabelSize(ctx, selected, hover, x, y, "hanging");
17264
17265 var yLabel = y + 0.5 * _this.height + 0.5 * _this.labelModule.size.height;
17266
17267 _this.labelModule.draw(ctx, x, yLabel, selected, hover, "hanging");
17268 }
17269
17270 _this.updateBoundingBox(x, y);
17271 }
17272 };
17273 }
17274 /**
17275 *
17276 * @param {number} x
17277 * @param {number} y
17278 */
17279
17280 }, {
17281 key: "updateBoundingBox",
17282 value: function updateBoundingBox(x, y) {
17283 this.boundingBox.top = y - this.options.size;
17284 this.boundingBox.left = x - this.options.size;
17285 this.boundingBox.right = x + this.options.size;
17286 this.boundingBox.bottom = y + this.options.size;
17287
17288 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
17289 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
17290 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
17291 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
17292 }
17293 }
17294 }]);
17295
17296 return ShapeBase;
17297 }(NodeBase);
17298
17299 function ownKeys$3(object, enumerableOnly) { var keys$1 = keys(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys$1.push.apply(keys$1, symbols); } return keys$1; }
17300
17301 function _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; }
17302
17303 function _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); }; }
17304
17305 function _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; } }
17306 /**
17307 * A CustomShape Node/Cluster shape.
17308 *
17309 * @augments ShapeBase
17310 */
17311
17312 var CustomShape = /*#__PURE__*/function (_ShapeBase) {
17313 _inherits(CustomShape, _ShapeBase);
17314
17315 var _super = _createSuper$n(CustomShape);
17316
17317 /**
17318 * @param {object} options
17319 * @param {object} body
17320 * @param {Label} labelModule
17321 * @param {Function} ctxRenderer
17322
17323 */
17324 function CustomShape(options, body, labelModule, ctxRenderer) {
17325 var _this;
17326
17327 _classCallCheck(this, CustomShape);
17328
17329 _this = _super.call(this, options, body, labelModule, ctxRenderer);
17330 _this.ctxRenderer = ctxRenderer;
17331 return _this;
17332 }
17333 /**
17334 *
17335 * @param {CanvasRenderingContext2D} ctx
17336 * @param {number} x width
17337 * @param {number} y height
17338 * @param {boolean} selected
17339 * @param {boolean} hover
17340 * @param {ArrowOptions} values
17341 *
17342 * @returns {object} Callbacks to draw later on different layers.
17343 */
17344
17345
17346 _createClass(CustomShape, [{
17347 key: "draw",
17348 value: function draw(ctx, x, y, selected, hover, values) {
17349 this.resize(ctx, selected, hover, values);
17350 this.left = x - this.width / 2;
17351 this.top = y - this.height / 2; // Guard right away because someone may just draw in the function itself.
17352
17353 ctx.save();
17354 var drawLater = this.ctxRenderer({
17355 ctx: ctx,
17356 id: this.options.id,
17357 x: x,
17358 y: y,
17359 state: {
17360 selected: selected,
17361 hover: hover
17362 },
17363 style: _objectSpread$3({}, values),
17364 label: this.options.label
17365 }); // Render the node shape bellow arrows.
17366
17367 if (drawLater.drawNode != null) {
17368 drawLater.drawNode();
17369 }
17370
17371 ctx.restore();
17372
17373 if (drawLater.drawExternalLabel) {
17374 // Guard the external label (above arrows) drawing function.
17375 var drawExternalLabel = drawLater.drawExternalLabel;
17376
17377 drawLater.drawExternalLabel = function () {
17378 ctx.save();
17379 drawExternalLabel();
17380 ctx.restore();
17381 };
17382 }
17383
17384 if (drawLater.nodeDimensions) {
17385 this.customSizeWidth = drawLater.nodeDimensions.width;
17386 this.customSizeHeight = drawLater.nodeDimensions.height;
17387 }
17388
17389 return drawLater;
17390 }
17391 /**
17392 *
17393 * @param {CanvasRenderingContext2D} ctx
17394 * @param {number} angle
17395 * @returns {number}
17396 */
17397
17398 }, {
17399 key: "distanceToBorder",
17400 value: function distanceToBorder(ctx, angle) {
17401 return this._distanceToBorder(ctx, angle);
17402 }
17403 }]);
17404
17405 return CustomShape;
17406 }(ShapeBase);
17407
17408 function _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); }; }
17409
17410 function _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; } }
17411 /**
17412 * A Database Node/Cluster shape.
17413 *
17414 * @augments NodeBase
17415 */
17416
17417 var Database = /*#__PURE__*/function (_NodeBase) {
17418 _inherits(Database, _NodeBase);
17419
17420 var _super = _createSuper$m(Database);
17421
17422 /**
17423 * @param {object} options
17424 * @param {object} body
17425 * @param {Label} labelModule
17426 */
17427 function Database(options, body, labelModule) {
17428 var _this;
17429
17430 _classCallCheck(this, Database);
17431
17432 _this = _super.call(this, options, body, labelModule);
17433
17434 _this._setMargins(labelModule);
17435
17436 return _this;
17437 }
17438 /**
17439 *
17440 * @param {CanvasRenderingContext2D} ctx
17441 * @param {boolean} selected
17442 * @param {boolean} hover
17443 */
17444
17445
17446 _createClass(Database, [{
17447 key: "resize",
17448 value: function resize(ctx, selected, hover) {
17449 if (this.needsRefresh(selected, hover)) {
17450 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
17451 var size = dimensions.width + this.margin.right + this.margin.left;
17452 this.width = size;
17453 this.height = size;
17454 this.radius = this.width / 2;
17455 }
17456 }
17457 /**
17458 *
17459 * @param {CanvasRenderingContext2D} ctx
17460 * @param {number} x width
17461 * @param {number} y height
17462 * @param {boolean} selected
17463 * @param {boolean} hover
17464 * @param {ArrowOptions} values
17465 */
17466
17467 }, {
17468 key: "draw",
17469 value: function draw(ctx, x, y, selected, hover, values) {
17470 this.resize(ctx, selected, hover);
17471 this.left = x - this.width / 2;
17472 this.top = y - this.height / 2;
17473 this.initContextForDraw(ctx, values);
17474 drawDatabase(ctx, x - this.width / 2, y - this.height / 2, this.width, this.height);
17475 this.performFill(ctx, values);
17476 this.updateBoundingBox(x, y, ctx, selected, hover);
17477 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
17478 }
17479 /**
17480 *
17481 * @param {CanvasRenderingContext2D} ctx
17482 * @param {number} angle
17483 * @returns {number}
17484 */
17485
17486 }, {
17487 key: "distanceToBorder",
17488 value: function distanceToBorder(ctx, angle) {
17489 return this._distanceToBorder(ctx, angle);
17490 }
17491 }]);
17492
17493 return Database;
17494 }(NodeBase);
17495
17496 function _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); }; }
17497
17498 function _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; } }
17499 /**
17500 * A Diamond Node/Cluster shape.
17501 *
17502 * @augments ShapeBase
17503 */
17504
17505 var Diamond$1 = /*#__PURE__*/function (_ShapeBase) {
17506 _inherits(Diamond, _ShapeBase);
17507
17508 var _super = _createSuper$l(Diamond);
17509
17510 /**
17511 * @param {object} options
17512 * @param {object} body
17513 * @param {Label} labelModule
17514 */
17515 function Diamond(options, body, labelModule) {
17516 _classCallCheck(this, Diamond);
17517
17518 return _super.call(this, options, body, labelModule);
17519 }
17520 /**
17521 *
17522 * @param {CanvasRenderingContext2D} ctx
17523 * @param {number} x width
17524 * @param {number} y height
17525 * @param {boolean} selected
17526 * @param {boolean} hover
17527 * @param {ArrowOptions} values
17528 *
17529 * @returns {object} Callbacks to draw later on higher layers.
17530 */
17531
17532
17533 _createClass(Diamond, [{
17534 key: "draw",
17535 value: function draw(ctx, x, y, selected, hover, values) {
17536 return this._drawShape(ctx, "diamond", 4, x, y, selected, hover, values);
17537 }
17538 /**
17539 *
17540 * @param {CanvasRenderingContext2D} ctx
17541 * @param {number} angle
17542 * @returns {number}
17543 */
17544
17545 }, {
17546 key: "distanceToBorder",
17547 value: function distanceToBorder(ctx, angle) {
17548 return this._distanceToBorder(ctx, angle);
17549 }
17550 }]);
17551
17552 return Diamond;
17553 }(ShapeBase);
17554
17555 function _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); }; }
17556
17557 function _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; } }
17558 /**
17559 * A Dot Node/Cluster shape.
17560 *
17561 * @augments ShapeBase
17562 */
17563
17564 var Dot = /*#__PURE__*/function (_ShapeBase) {
17565 _inherits(Dot, _ShapeBase);
17566
17567 var _super = _createSuper$k(Dot);
17568
17569 /**
17570 * @param {object} options
17571 * @param {object} body
17572 * @param {Label} labelModule
17573 */
17574 function Dot(options, body, labelModule) {
17575 _classCallCheck(this, Dot);
17576
17577 return _super.call(this, options, body, labelModule);
17578 }
17579 /**
17580 *
17581 * @param {CanvasRenderingContext2D} ctx
17582 * @param {number} x width
17583 * @param {number} y height
17584 * @param {boolean} selected
17585 * @param {boolean} hover
17586 * @param {ArrowOptions} values
17587 *
17588 * @returns {object} Callbacks to draw later on higher layers.
17589 */
17590
17591
17592 _createClass(Dot, [{
17593 key: "draw",
17594 value: function draw(ctx, x, y, selected, hover, values) {
17595 return this._drawShape(ctx, "circle", 2, x, y, selected, hover, values);
17596 }
17597 /**
17598 *
17599 * @param {CanvasRenderingContext2D} ctx
17600 * @returns {number}
17601 */
17602
17603 }, {
17604 key: "distanceToBorder",
17605 value: function distanceToBorder(ctx) {
17606 if (ctx) {
17607 this.resize(ctx);
17608 }
17609
17610 return this.options.size;
17611 }
17612 }]);
17613
17614 return Dot;
17615 }(ShapeBase);
17616
17617 function _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); }; }
17618
17619 function _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; } }
17620 /**
17621 * Am Ellipse Node/Cluster shape.
17622 *
17623 * @augments NodeBase
17624 */
17625
17626 var Ellipse = /*#__PURE__*/function (_NodeBase) {
17627 _inherits(Ellipse, _NodeBase);
17628
17629 var _super = _createSuper$j(Ellipse);
17630
17631 /**
17632 * @param {object} options
17633 * @param {object} body
17634 * @param {Label} labelModule
17635 */
17636 function Ellipse(options, body, labelModule) {
17637 _classCallCheck(this, Ellipse);
17638
17639 return _super.call(this, options, body, labelModule);
17640 }
17641 /**
17642 *
17643 * @param {CanvasRenderingContext2D} ctx
17644 * @param {boolean} [selected]
17645 * @param {boolean} [hover]
17646 */
17647
17648
17649 _createClass(Ellipse, [{
17650 key: "resize",
17651 value: function resize(ctx) {
17652 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
17653 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
17654
17655 if (this.needsRefresh(selected, hover)) {
17656 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
17657 this.height = dimensions.height * 2;
17658 this.width = dimensions.width + dimensions.height;
17659 this.radius = 0.5 * this.width;
17660 }
17661 }
17662 /**
17663 *
17664 * @param {CanvasRenderingContext2D} ctx
17665 * @param {number} x width
17666 * @param {number} y height
17667 * @param {boolean} selected
17668 * @param {boolean} hover
17669 * @param {ArrowOptions} values
17670 */
17671
17672 }, {
17673 key: "draw",
17674 value: function draw(ctx, x, y, selected, hover, values) {
17675 this.resize(ctx, selected, hover);
17676 this.left = x - this.width * 0.5;
17677 this.top = y - this.height * 0.5;
17678 this.initContextForDraw(ctx, values);
17679 drawEllipse(ctx, this.left, this.top, this.width, this.height);
17680 this.performFill(ctx, values);
17681 this.updateBoundingBox(x, y, ctx, selected, hover);
17682 this.labelModule.draw(ctx, x, y, selected, hover);
17683 }
17684 /**
17685 *
17686 * @param {CanvasRenderingContext2D} ctx
17687 * @param {number} angle
17688 * @returns {number}
17689 */
17690
17691 }, {
17692 key: "distanceToBorder",
17693 value: function distanceToBorder(ctx, angle) {
17694 if (ctx) {
17695 this.resize(ctx);
17696 }
17697
17698 var a = this.width * 0.5;
17699 var b = this.height * 0.5;
17700 var w = Math.sin(angle) * a;
17701 var h = Math.cos(angle) * b;
17702 return a * b / Math.sqrt(w * w + h * h);
17703 }
17704 }]);
17705
17706 return Ellipse;
17707 }(NodeBase);
17708
17709 function _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); }; }
17710
17711 function _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; } }
17712 /**
17713 * An icon replacement for the default Node shape.
17714 *
17715 * @augments NodeBase
17716 */
17717
17718 var Icon = /*#__PURE__*/function (_NodeBase) {
17719 _inherits(Icon, _NodeBase);
17720
17721 var _super = _createSuper$i(Icon);
17722
17723 /**
17724 * @param {object} options
17725 * @param {object} body
17726 * @param {Label} labelModule
17727 */
17728 function Icon(options, body, labelModule) {
17729 var _this;
17730
17731 _classCallCheck(this, Icon);
17732
17733 _this = _super.call(this, options, body, labelModule);
17734
17735 _this._setMargins(labelModule);
17736
17737 return _this;
17738 }
17739 /**
17740 *
17741 * @param {CanvasRenderingContext2D} ctx - Unused.
17742 * @param {boolean} [selected]
17743 * @param {boolean} [hover]
17744 */
17745
17746
17747 _createClass(Icon, [{
17748 key: "resize",
17749 value: function resize(ctx, selected, hover) {
17750 if (this.needsRefresh(selected, hover)) {
17751 this.iconSize = {
17752 width: Number(this.options.icon.size),
17753 height: Number(this.options.icon.size)
17754 };
17755 this.width = this.iconSize.width + this.margin.right + this.margin.left;
17756 this.height = this.iconSize.height + this.margin.top + this.margin.bottom;
17757 this.radius = 0.5 * this.width;
17758 }
17759 }
17760 /**
17761 *
17762 * @param {CanvasRenderingContext2D} ctx
17763 * @param {number} x width
17764 * @param {number} y height
17765 * @param {boolean} selected
17766 * @param {boolean} hover
17767 * @param {ArrowOptions} values
17768 *
17769 * @returns {object} Callbacks to draw later on higher layers.
17770 */
17771
17772 }, {
17773 key: "draw",
17774 value: function draw(ctx, x, y, selected, hover, values) {
17775 var _this2 = this;
17776
17777 this.resize(ctx, selected, hover);
17778 this.options.icon.size = this.options.icon.size || 50;
17779 this.left = x - this.width / 2;
17780 this.top = y - this.height / 2;
17781
17782 this._icon(ctx, x, y, selected, hover, values);
17783
17784 return {
17785 drawExternalLabel: function drawExternalLabel() {
17786 if (_this2.options.label !== undefined) {
17787 var iconTextSpacing = 5;
17788
17789 _this2.labelModule.draw(ctx, _this2.left + _this2.iconSize.width / 2 + _this2.margin.left, y + _this2.height / 2 + iconTextSpacing, selected);
17790 }
17791
17792 _this2.updateBoundingBox(x, y);
17793 }
17794 };
17795 }
17796 /**
17797 *
17798 * @param {number} x
17799 * @param {number} y
17800 */
17801
17802 }, {
17803 key: "updateBoundingBox",
17804 value: function updateBoundingBox(x, y) {
17805 this.boundingBox.top = y - this.options.icon.size * 0.5;
17806 this.boundingBox.left = x - this.options.icon.size * 0.5;
17807 this.boundingBox.right = x + this.options.icon.size * 0.5;
17808 this.boundingBox.bottom = y + this.options.icon.size * 0.5;
17809
17810 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
17811 var iconTextSpacing = 5;
17812 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
17813 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
17814 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height + iconTextSpacing);
17815 }
17816 }
17817 /**
17818 *
17819 * @param {CanvasRenderingContext2D} ctx
17820 * @param {number} x width
17821 * @param {number} y height
17822 * @param {boolean} selected
17823 * @param {boolean} hover - Unused
17824 * @param {ArrowOptions} values
17825 */
17826
17827 }, {
17828 key: "_icon",
17829 value: function _icon(ctx, x, y, selected, hover, values) {
17830 var iconSize = Number(this.options.icon.size);
17831
17832 if (this.options.icon.code !== undefined) {
17833 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
17834 // properly) substitute slightly bigger size for bold font face.
17835 (this.options.icon.weight != null && selected ? 5 : 0) + iconSize + "px", this.options.icon.face].join(" "); // draw icon
17836
17837 ctx.fillStyle = this.options.icon.color || "black";
17838 ctx.textAlign = "center";
17839 ctx.textBaseline = "middle"; // draw shadow if enabled
17840
17841 this.enableShadow(ctx, values);
17842 ctx.fillText(this.options.icon.code, x, y); // disable shadows for other elements.
17843
17844 this.disableShadow(ctx, values);
17845 } else {
17846 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.");
17847 }
17848 }
17849 /**
17850 *
17851 * @param {CanvasRenderingContext2D} ctx
17852 * @param {number} angle
17853 * @returns {number}
17854 */
17855
17856 }, {
17857 key: "distanceToBorder",
17858 value: function distanceToBorder(ctx, angle) {
17859 return this._distanceToBorder(ctx, angle);
17860 }
17861 }]);
17862
17863 return Icon;
17864 }(NodeBase);
17865
17866 function _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); }; }
17867
17868 function _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; } }
17869 /**
17870 * An image-based replacement for the default Node shape.
17871 *
17872 * @augments CircleImageBase
17873 */
17874
17875 var Image$2 = /*#__PURE__*/function (_CircleImageBase) {
17876 _inherits(Image, _CircleImageBase);
17877
17878 var _super = _createSuper$h(Image);
17879
17880 /**
17881 * @param {object} options
17882 * @param {object} body
17883 * @param {Label} labelModule
17884 * @param {Image} imageObj
17885 * @param {Image} imageObjAlt
17886 */
17887 function Image(options, body, labelModule, imageObj, imageObjAlt) {
17888 var _this;
17889
17890 _classCallCheck(this, Image);
17891
17892 _this = _super.call(this, options, body, labelModule);
17893
17894 _this.setImages(imageObj, imageObjAlt);
17895
17896 return _this;
17897 }
17898 /**
17899 *
17900 * @param {CanvasRenderingContext2D} ctx - Unused.
17901 * @param {boolean} [selected]
17902 * @param {boolean} [hover]
17903 */
17904
17905
17906 _createClass(Image, [{
17907 key: "resize",
17908 value: function resize(ctx) {
17909 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
17910 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
17911 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
17912
17913 if (imageAbsent) {
17914 var side = this.options.size * 2;
17915 this.width = side;
17916 this.height = side;
17917 return;
17918 }
17919
17920 if (this.needsRefresh(selected, hover)) {
17921 this._resizeImage();
17922 }
17923 }
17924 /**
17925 *
17926 * @param {CanvasRenderingContext2D} ctx
17927 * @param {number} x width
17928 * @param {number} y height
17929 * @param {boolean} selected
17930 * @param {boolean} hover
17931 * @param {ArrowOptions} values
17932 */
17933
17934 }, {
17935 key: "draw",
17936 value: function draw(ctx, x, y, selected, hover, values) {
17937 ctx.save();
17938 this.switchImages(selected);
17939 this.resize();
17940 var labelX = x,
17941 labelY = y;
17942
17943 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
17944 this.left = x;
17945 this.top = y;
17946 labelX += this.width / 2;
17947 labelY += this.height / 2;
17948 } else {
17949 this.left = x - this.width / 2;
17950 this.top = y - this.height / 2;
17951 }
17952
17953 if (this.options.shapeProperties.useBorderWithImage === true) {
17954 var neutralborderWidth = this.options.borderWidth;
17955 var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
17956 var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
17957 ctx.lineWidth = Math.min(this.width, borderWidth);
17958 ctx.beginPath();
17959 var strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
17960 var fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
17961
17962 if (values.opacity !== undefined) {
17963 strokeStyle = overrideOpacity(strokeStyle, values.opacity);
17964 fillStyle = overrideOpacity(fillStyle, values.opacity);
17965 } // setup the line properties.
17966
17967
17968 ctx.strokeStyle = strokeStyle; // set a fillstyle
17969
17970 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
17971
17972 ctx.rect(this.left - 0.5 * ctx.lineWidth, this.top - 0.5 * ctx.lineWidth, this.width + ctx.lineWidth, this.height + ctx.lineWidth);
17973
17974 fill(ctx).call(ctx);
17975
17976 this.performStroke(ctx, values);
17977 ctx.closePath();
17978 }
17979
17980 this._drawImageAtPosition(ctx, values);
17981
17982 this._drawImageLabel(ctx, labelX, labelY, selected, hover);
17983
17984 this.updateBoundingBox(x, y);
17985 ctx.restore();
17986 }
17987 /**
17988 *
17989 * @param {number} x
17990 * @param {number} y
17991 */
17992
17993 }, {
17994 key: "updateBoundingBox",
17995 value: function updateBoundingBox(x, y) {
17996 this.resize();
17997
17998 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
17999 this.left = x;
18000 this.top = y;
18001 } else {
18002 this.left = x - this.width / 2;
18003 this.top = y - this.height / 2;
18004 }
18005
18006 this.boundingBox.left = this.left;
18007 this.boundingBox.top = this.top;
18008 this.boundingBox.bottom = this.top + this.height;
18009 this.boundingBox.right = this.left + this.width;
18010
18011 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
18012 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
18013 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
18014 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
18015 }
18016 }
18017 /**
18018 *
18019 * @param {CanvasRenderingContext2D} ctx
18020 * @param {number} angle
18021 * @returns {number}
18022 */
18023
18024 }, {
18025 key: "distanceToBorder",
18026 value: function distanceToBorder(ctx, angle) {
18027 return this._distanceToBorder(ctx, angle);
18028 }
18029 }]);
18030
18031 return Image;
18032 }(CircleImageBase);
18033
18034 function _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); }; }
18035
18036 function _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; } }
18037 /**
18038 * A Square Node/Cluster shape.
18039 *
18040 * @augments ShapeBase
18041 */
18042
18043 var Square = /*#__PURE__*/function (_ShapeBase) {
18044 _inherits(Square, _ShapeBase);
18045
18046 var _super = _createSuper$g(Square);
18047
18048 /**
18049 * @param {object} options
18050 * @param {object} body
18051 * @param {Label} labelModule
18052 */
18053 function Square(options, body, labelModule) {
18054 _classCallCheck(this, Square);
18055
18056 return _super.call(this, options, body, labelModule);
18057 }
18058 /**
18059 *
18060 * @param {CanvasRenderingContext2D} ctx
18061 * @param {number} x width
18062 * @param {number} y height
18063 * @param {boolean} selected
18064 * @param {boolean} hover
18065 * @param {ArrowOptions} values
18066 *
18067 * @returns {object} Callbacks to draw later on higher layers.
18068 */
18069
18070
18071 _createClass(Square, [{
18072 key: "draw",
18073 value: function draw(ctx, x, y, selected, hover, values) {
18074 return this._drawShape(ctx, "square", 2, x, y, selected, hover, values);
18075 }
18076 /**
18077 *
18078 * @param {CanvasRenderingContext2D} ctx
18079 * @param {number} angle
18080 * @returns {number}
18081 */
18082
18083 }, {
18084 key: "distanceToBorder",
18085 value: function distanceToBorder(ctx, angle) {
18086 return this._distanceToBorder(ctx, angle);
18087 }
18088 }]);
18089
18090 return Square;
18091 }(ShapeBase);
18092
18093 function _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); }; }
18094
18095 function _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; } }
18096 /**
18097 * A Hexagon Node/Cluster shape.
18098 *
18099 * @augments ShapeBase
18100 */
18101
18102 var Hexagon = /*#__PURE__*/function (_ShapeBase) {
18103 _inherits(Hexagon, _ShapeBase);
18104
18105 var _super = _createSuper$f(Hexagon);
18106
18107 /**
18108 * @param {object} options
18109 * @param {object} body
18110 * @param {Label} labelModule
18111 */
18112 function Hexagon(options, body, labelModule) {
18113 _classCallCheck(this, Hexagon);
18114
18115 return _super.call(this, options, body, labelModule);
18116 }
18117 /**
18118 *
18119 * @param {CanvasRenderingContext2D} ctx
18120 * @param {number} x width
18121 * @param {number} y height
18122 * @param {boolean} selected
18123 * @param {boolean} hover
18124 * @param {ArrowOptions} values
18125 *
18126 * @returns {object} Callbacks to draw later on higher layers.
18127 */
18128
18129
18130 _createClass(Hexagon, [{
18131 key: "draw",
18132 value: function draw(ctx, x, y, selected, hover, values) {
18133 return this._drawShape(ctx, "hexagon", 4, x, y, selected, hover, values);
18134 }
18135 /**
18136 *
18137 * @param {CanvasRenderingContext2D} ctx
18138 * @param {number} angle
18139 * @returns {number}
18140 */
18141
18142 }, {
18143 key: "distanceToBorder",
18144 value: function distanceToBorder(ctx, angle) {
18145 return this._distanceToBorder(ctx, angle);
18146 }
18147 }]);
18148
18149 return Hexagon;
18150 }(ShapeBase);
18151
18152 function _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); }; }
18153
18154 function _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; } }
18155 /**
18156 * A Star Node/Cluster shape.
18157 *
18158 * @augments ShapeBase
18159 */
18160
18161 var Star = /*#__PURE__*/function (_ShapeBase) {
18162 _inherits(Star, _ShapeBase);
18163
18164 var _super = _createSuper$e(Star);
18165
18166 /**
18167 * @param {object} options
18168 * @param {object} body
18169 * @param {Label} labelModule
18170 */
18171 function Star(options, body, labelModule) {
18172 _classCallCheck(this, Star);
18173
18174 return _super.call(this, options, body, labelModule);
18175 }
18176 /**
18177 *
18178 * @param {CanvasRenderingContext2D} ctx
18179 * @param {number} x width
18180 * @param {number} y height
18181 * @param {boolean} selected
18182 * @param {boolean} hover
18183 * @param {ArrowOptions} values
18184 *
18185 * @returns {object} Callbacks to draw later on higher layers.
18186 */
18187
18188
18189 _createClass(Star, [{
18190 key: "draw",
18191 value: function draw(ctx, x, y, selected, hover, values) {
18192 return this._drawShape(ctx, "star", 4, x, y, selected, hover, values);
18193 }
18194 /**
18195 *
18196 * @param {CanvasRenderingContext2D} ctx
18197 * @param {number} angle
18198 * @returns {number}
18199 */
18200
18201 }, {
18202 key: "distanceToBorder",
18203 value: function distanceToBorder(ctx, angle) {
18204 return this._distanceToBorder(ctx, angle);
18205 }
18206 }]);
18207
18208 return Star;
18209 }(ShapeBase);
18210
18211 function _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); }; }
18212
18213 function _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; } }
18214 /**
18215 * A text-based replacement for the default Node shape.
18216 *
18217 * @augments NodeBase
18218 */
18219
18220 var Text = /*#__PURE__*/function (_NodeBase) {
18221 _inherits(Text, _NodeBase);
18222
18223 var _super = _createSuper$d(Text);
18224
18225 /**
18226 * @param {object} options
18227 * @param {object} body
18228 * @param {Label} labelModule
18229 */
18230 function Text(options, body, labelModule) {
18231 var _this;
18232
18233 _classCallCheck(this, Text);
18234
18235 _this = _super.call(this, options, body, labelModule);
18236
18237 _this._setMargins(labelModule);
18238
18239 return _this;
18240 }
18241 /**
18242 *
18243 * @param {CanvasRenderingContext2D} ctx
18244 * @param {boolean} selected
18245 * @param {boolean} hover
18246 */
18247
18248
18249 _createClass(Text, [{
18250 key: "resize",
18251 value: function resize(ctx, selected, hover) {
18252 if (this.needsRefresh(selected, hover)) {
18253 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
18254 this.width = this.textSize.width + this.margin.right + this.margin.left;
18255 this.height = this.textSize.height + this.margin.top + this.margin.bottom;
18256 this.radius = 0.5 * this.width;
18257 }
18258 }
18259 /**
18260 *
18261 * @param {CanvasRenderingContext2D} ctx
18262 * @param {number} x width
18263 * @param {number} y height
18264 * @param {boolean} selected
18265 * @param {boolean} hover
18266 * @param {ArrowOptions} values
18267 */
18268
18269 }, {
18270 key: "draw",
18271 value: function draw(ctx, x, y, selected, hover, values) {
18272 this.resize(ctx, selected, hover);
18273 this.left = x - this.width / 2;
18274 this.top = y - this.height / 2; // draw shadow if enabled
18275
18276 this.enableShadow(ctx, values);
18277 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.
18278
18279 this.disableShadow(ctx, values);
18280 this.updateBoundingBox(x, y, ctx, selected, hover);
18281 }
18282 /**
18283 *
18284 * @param {CanvasRenderingContext2D} ctx
18285 * @param {number} angle
18286 * @returns {number}
18287 */
18288
18289 }, {
18290 key: "distanceToBorder",
18291 value: function distanceToBorder(ctx, angle) {
18292 return this._distanceToBorder(ctx, angle);
18293 }
18294 }]);
18295
18296 return Text;
18297 }(NodeBase);
18298
18299 function _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); }; }
18300
18301 function _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; } }
18302 /**
18303 * A Triangle Node/Cluster shape.
18304 *
18305 * @augments ShapeBase
18306 */
18307
18308 var Triangle$1 = /*#__PURE__*/function (_ShapeBase) {
18309 _inherits(Triangle, _ShapeBase);
18310
18311 var _super = _createSuper$c(Triangle);
18312
18313 /**
18314 * @param {object} options
18315 * @param {object} body
18316 * @param {Label} labelModule
18317 */
18318 function Triangle(options, body, labelModule) {
18319 _classCallCheck(this, Triangle);
18320
18321 return _super.call(this, options, body, labelModule);
18322 }
18323 /**
18324 *
18325 * @param {CanvasRenderingContext2D} ctx
18326 * @param {number} x
18327 * @param {number} y
18328 * @param {boolean} selected
18329 * @param {boolean} hover
18330 * @param {ArrowOptions} values
18331 *
18332 * @returns {object} Callbacks to draw later on higher layers.
18333 */
18334
18335
18336 _createClass(Triangle, [{
18337 key: "draw",
18338 value: function draw(ctx, x, y, selected, hover, values) {
18339 return this._drawShape(ctx, "triangle", 3, x, y, selected, hover, values);
18340 }
18341 /**
18342 *
18343 * @param {CanvasRenderingContext2D} ctx
18344 * @param {number} angle
18345 * @returns {number}
18346 */
18347
18348 }, {
18349 key: "distanceToBorder",
18350 value: function distanceToBorder(ctx, angle) {
18351 return this._distanceToBorder(ctx, angle);
18352 }
18353 }]);
18354
18355 return Triangle;
18356 }(ShapeBase);
18357
18358 function _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); }; }
18359
18360 function _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; } }
18361 /**
18362 * A downward facing Triangle Node/Cluster shape.
18363 *
18364 * @augments ShapeBase
18365 */
18366
18367 var TriangleDown = /*#__PURE__*/function (_ShapeBase) {
18368 _inherits(TriangleDown, _ShapeBase);
18369
18370 var _super = _createSuper$b(TriangleDown);
18371
18372 /**
18373 * @param {object} options
18374 * @param {object} body
18375 * @param {Label} labelModule
18376 */
18377 function TriangleDown(options, body, labelModule) {
18378 _classCallCheck(this, TriangleDown);
18379
18380 return _super.call(this, options, body, labelModule);
18381 }
18382 /**
18383 *
18384 * @param {CanvasRenderingContext2D} ctx
18385 * @param {number} x
18386 * @param {number} y
18387 * @param {boolean} selected
18388 * @param {boolean} hover
18389 * @param {ArrowOptions} values
18390 *
18391 * @returns {object} Callbacks to draw later on higher layers.
18392 */
18393
18394
18395 _createClass(TriangleDown, [{
18396 key: "draw",
18397 value: function draw(ctx, x, y, selected, hover, values) {
18398 return this._drawShape(ctx, "triangleDown", 3, x, y, selected, hover, values);
18399 }
18400 /**
18401 *
18402 * @param {CanvasRenderingContext2D} ctx
18403 * @param {number} angle
18404 * @returns {number}
18405 */
18406
18407 }, {
18408 key: "distanceToBorder",
18409 value: function distanceToBorder(ctx, angle) {
18410 return this._distanceToBorder(ctx, angle);
18411 }
18412 }]);
18413
18414 return TriangleDown;
18415 }(ShapeBase);
18416
18417 function ownKeys$2(object, enumerableOnly) { var keys$1 = keys(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys$1.push.apply(keys$1, symbols); } return keys$1; }
18418
18419 function _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; }
18420 /**
18421 * A node. A node can be connected to other nodes via one or multiple edges.
18422 */
18423
18424 var Node = /*#__PURE__*/function () {
18425 /**
18426 *
18427 * @param {object} options An object containing options for the node. All
18428 * options are optional, except for the id.
18429 * {number} id Id of the node. Required
18430 * {string} label Text label for the node
18431 * {number} x Horizontal position of the node
18432 * {number} y Vertical position of the node
18433 * {string} shape Node shape
18434 * {string} image An image url
18435 * {string} title A title text, can be HTML
18436 * {anytype} group A group name or number
18437 *
18438 * @param {object} body Shared state of current network instance
18439 * @param {Network.Images} imagelist A list with images. Only needed when the node has an image
18440 * @param {Groups} grouplist A list with groups. Needed for retrieving group options
18441 * @param {object} globalOptions Current global node options; these serve as defaults for the node instance
18442 * @param {object} defaultOptions Global default options for nodes; note that this is also the prototype
18443 * for parameter `globalOptions`.
18444 */
18445 function Node(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
18446 _classCallCheck(this, Node);
18447
18448 this.options = bridgeObject(globalOptions);
18449 this.globalOptions = globalOptions;
18450 this.defaultOptions = defaultOptions;
18451 this.body = body;
18452 this.edges = []; // all edges connected to this node
18453 // set defaults for the options
18454
18455 this.id = undefined;
18456 this.imagelist = imagelist;
18457 this.grouplist = grouplist; // state options
18458
18459 this.x = undefined;
18460 this.y = undefined;
18461 this.baseSize = this.options.size;
18462 this.baseFontSize = this.options.font.size;
18463 this.predefinedPosition = false; // used to check if initial fit should just take the range or approximate
18464
18465 this.selected = false;
18466 this.hover = false;
18467 this.labelModule = new Label(this.body, this.options, false
18468 /* Not edge label */
18469 );
18470 this.setOptions(options);
18471 }
18472 /**
18473 * Attach a edge to the node
18474 *
18475 * @param {Edge} edge
18476 */
18477
18478
18479 _createClass(Node, [{
18480 key: "attachEdge",
18481 value: function attachEdge(edge) {
18482 var _context;
18483
18484 if (indexOf(_context = this.edges).call(_context, edge) === -1) {
18485 this.edges.push(edge);
18486 }
18487 }
18488 /**
18489 * Detach a edge from the node
18490 *
18491 * @param {Edge} edge
18492 */
18493
18494 }, {
18495 key: "detachEdge",
18496 value: function detachEdge(edge) {
18497 var _context2;
18498
18499 var index = indexOf(_context2 = this.edges).call(_context2, edge);
18500
18501 if (index != -1) {
18502 var _context3;
18503
18504 splice(_context3 = this.edges).call(_context3, index, 1);
18505 }
18506 }
18507 /**
18508 * Set or overwrite options for the node
18509 *
18510 * @param {object} options an object with options
18511 * @returns {null|boolean}
18512 */
18513
18514 }, {
18515 key: "setOptions",
18516 value: function setOptions(options) {
18517 var currentShape = this.options.shape;
18518
18519 if (!options) {
18520 return; // Note that the return value will be 'undefined'! This is OK.
18521 } // Save the color for later.
18522 // This is necessary in order to prevent local color from being overwritten by group color.
18523 // TODO: To prevent such workarounds the way options are handled should be rewritten from scratch.
18524 // This is not the only problem with current options handling.
18525
18526
18527 if (typeof options.color !== "undefined") {
18528 this._localColor = options.color;
18529 } // basic options
18530
18531
18532 if (options.id !== undefined) {
18533 this.id = options.id;
18534 }
18535
18536 if (this.id === undefined) {
18537 throw new Error("Node must have an id");
18538 }
18539
18540 Node.checkMass(options, this.id); // set these options locally
18541 // clear x and y positions
18542
18543 if (options.x !== undefined) {
18544 if (options.x === null) {
18545 this.x = undefined;
18546 this.predefinedPosition = false;
18547 } else {
18548 this.x = _parseInt(options.x);
18549 this.predefinedPosition = true;
18550 }
18551 }
18552
18553 if (options.y !== undefined) {
18554 if (options.y === null) {
18555 this.y = undefined;
18556 this.predefinedPosition = false;
18557 } else {
18558 this.y = _parseInt(options.y);
18559 this.predefinedPosition = true;
18560 }
18561 }
18562
18563 if (options.size !== undefined) {
18564 this.baseSize = options.size;
18565 }
18566
18567 if (options.value !== undefined) {
18568 options.value = _parseFloat(options.value);
18569 } // this transforms all shorthands into fully defined options
18570
18571
18572 Node.parseOptions(this.options, options, true, this.globalOptions, this.grouplist);
18573 var pile = [options, this.options, this.defaultOptions];
18574 this.chooser = choosify("node", pile);
18575
18576 this._load_images();
18577
18578 this.updateLabelModule(options); // Need to set local opacity after `this.updateLabelModule(options);` because `this.updateLabelModule(options);` overrites local opacity with group opacity
18579
18580 if (options.opacity !== undefined && Node.checkOpacity(options.opacity)) {
18581 this.options.opacity = options.opacity;
18582 }
18583
18584 this.updateShape(currentShape);
18585 return options.hidden !== undefined || options.physics !== undefined;
18586 }
18587 /**
18588 * Load the images from the options, for the nodes that need them.
18589 *
18590 * Images are always loaded, even if they are not used in the current shape.
18591 * The user may switch to an image shape later on.
18592 *
18593 * @private
18594 */
18595
18596 }, {
18597 key: "_load_images",
18598 value: function _load_images() {
18599 if (this.options.shape === "circularImage" || this.options.shape === "image") {
18600 if (this.options.image === undefined) {
18601 throw new Error("Option image must be defined for node type '" + this.options.shape + "'");
18602 }
18603 }
18604
18605 if (this.options.image === undefined) {
18606 return;
18607 }
18608
18609 if (this.imagelist === undefined) {
18610 throw new Error("Internal Error: No images provided");
18611 }
18612
18613 if (typeof this.options.image === "string") {
18614 this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
18615 } else {
18616 if (this.options.image.unselected === undefined) {
18617 throw new Error("No unselected image provided");
18618 }
18619
18620 this.imageObj = this.imagelist.load(this.options.image.unselected, this.options.brokenImage, this.id);
18621
18622 if (this.options.image.selected !== undefined) {
18623 this.imageObjAlt = this.imagelist.load(this.options.image.selected, this.options.brokenImage, this.id);
18624 } else {
18625 this.imageObjAlt = undefined;
18626 }
18627 }
18628 }
18629 /**
18630 * Check that opacity is only between 0 and 1
18631 *
18632 * @param {number} opacity
18633 * @returns {boolean}
18634 */
18635
18636 }, {
18637 key: "getFormattingValues",
18638 value:
18639 /**
18640 *
18641 * @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: *}}
18642 */
18643 function getFormattingValues() {
18644 var values = {
18645 color: this.options.color.background,
18646 opacity: this.options.opacity,
18647 borderWidth: this.options.borderWidth,
18648 borderColor: this.options.color.border,
18649 size: this.options.size,
18650 borderDashes: this.options.shapeProperties.borderDashes,
18651 borderRadius: this.options.shapeProperties.borderRadius,
18652 shadow: this.options.shadow.enabled,
18653 shadowColor: this.options.shadow.color,
18654 shadowSize: this.options.shadow.size,
18655 shadowX: this.options.shadow.x,
18656 shadowY: this.options.shadow.y
18657 };
18658
18659 if (this.selected || this.hover) {
18660 if (this.chooser === true) {
18661 if (this.selected) {
18662 if (this.options.borderWidthSelected != null) {
18663 values.borderWidth = this.options.borderWidthSelected;
18664 } else {
18665 values.borderWidth *= 2;
18666 }
18667
18668 values.color = this.options.color.highlight.background;
18669 values.borderColor = this.options.color.highlight.border;
18670 values.shadow = this.options.shadow.enabled;
18671 } else if (this.hover) {
18672 values.color = this.options.color.hover.background;
18673 values.borderColor = this.options.color.hover.border;
18674 values.shadow = this.options.shadow.enabled;
18675 }
18676 } else if (typeof this.chooser === "function") {
18677 this.chooser(values, this.options.id, this.selected, this.hover);
18678
18679 if (values.shadow === false) {
18680 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) {
18681 values.shadow = true;
18682 }
18683 }
18684 }
18685 } else {
18686 values.shadow = this.options.shadow.enabled;
18687 }
18688
18689 if (this.options.opacity !== undefined) {
18690 var opacity = this.options.opacity;
18691 values.borderColor = overrideOpacity(values.borderColor, opacity);
18692 values.color = overrideOpacity(values.color, opacity);
18693 values.shadowColor = overrideOpacity(values.shadowColor, opacity);
18694 }
18695
18696 return values;
18697 }
18698 /**
18699 *
18700 * @param {object} options
18701 */
18702
18703 }, {
18704 key: "updateLabelModule",
18705 value: function updateLabelModule(options) {
18706 if (this.options.label === undefined || this.options.label === null) {
18707 this.options.label = "";
18708 }
18709
18710 Node.updateGroupOptions(this.options, _objectSpread$2(_objectSpread$2({}, options), {}, {
18711 color: options && options.color || this._localColor || undefined
18712 }), this.grouplist); //
18713 // Note:The prototype chain for this.options is:
18714 //
18715 // this.options -> NodesHandler.options -> NodesHandler.defaultOptions
18716 // (also: this.globalOptions)
18717 //
18718 // Note that the prototypes are mentioned explicitly in the pile list below;
18719 // WE DON'T WANT THE ORDER OF THE PROTOTYPES!!!! At least, not for font handling of labels.
18720 // This is a good indication that the prototype usage of options is deficient.
18721 //
18722
18723 var currentGroup = this.grouplist.get(this.options.group, false);
18724 var pile = [options, // new options
18725 this.options, // current node options, see comment above for prototype
18726 currentGroup, // group options, if any
18727 this.globalOptions, // Currently set global node options
18728 this.defaultOptions // Default global node options
18729 ];
18730 this.labelModule.update(this.options, pile);
18731
18732 if (this.labelModule.baseSize !== undefined) {
18733 this.baseFontSize = this.labelModule.baseSize;
18734 }
18735 }
18736 /**
18737 *
18738 * @param {string} currentShape
18739 */
18740
18741 }, {
18742 key: "updateShape",
18743 value: function updateShape(currentShape) {
18744 if (currentShape === this.options.shape && this.shape) {
18745 this.shape.setOptions(this.options, this.imageObj, this.imageObjAlt);
18746 } else {
18747 // choose draw method depending on the shape
18748 switch (this.options.shape) {
18749 case "box":
18750 this.shape = new Box$1(this.options, this.body, this.labelModule);
18751 break;
18752
18753 case "circle":
18754 this.shape = new Circle$1(this.options, this.body, this.labelModule);
18755 break;
18756
18757 case "circularImage":
18758 this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
18759 break;
18760
18761 case "custom":
18762 this.shape = new CustomShape(this.options, this.body, this.labelModule, this.options.ctxRenderer);
18763 break;
18764
18765 case "database":
18766 this.shape = new Database(this.options, this.body, this.labelModule);
18767 break;
18768
18769 case "diamond":
18770 this.shape = new Diamond$1(this.options, this.body, this.labelModule);
18771 break;
18772
18773 case "dot":
18774 this.shape = new Dot(this.options, this.body, this.labelModule);
18775 break;
18776
18777 case "ellipse":
18778 this.shape = new Ellipse(this.options, this.body, this.labelModule);
18779 break;
18780
18781 case "icon":
18782 this.shape = new Icon(this.options, this.body, this.labelModule);
18783 break;
18784
18785 case "image":
18786 this.shape = new Image$2(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
18787 break;
18788
18789 case "square":
18790 this.shape = new Square(this.options, this.body, this.labelModule);
18791 break;
18792
18793 case "hexagon":
18794 this.shape = new Hexagon(this.options, this.body, this.labelModule);
18795 break;
18796
18797 case "star":
18798 this.shape = new Star(this.options, this.body, this.labelModule);
18799 break;
18800
18801 case "text":
18802 this.shape = new Text(this.options, this.body, this.labelModule);
18803 break;
18804
18805 case "triangle":
18806 this.shape = new Triangle$1(this.options, this.body, this.labelModule);
18807 break;
18808
18809 case "triangleDown":
18810 this.shape = new TriangleDown(this.options, this.body, this.labelModule);
18811 break;
18812
18813 default:
18814 this.shape = new Ellipse(this.options, this.body, this.labelModule);
18815 break;
18816 }
18817 }
18818
18819 this.needsRefresh();
18820 }
18821 /**
18822 * select this node
18823 */
18824
18825 }, {
18826 key: "select",
18827 value: function select() {
18828 this.selected = true;
18829 this.needsRefresh();
18830 }
18831 /**
18832 * unselect this node
18833 */
18834
18835 }, {
18836 key: "unselect",
18837 value: function unselect() {
18838 this.selected = false;
18839 this.needsRefresh();
18840 }
18841 /**
18842 * Reset the calculated size of the node, forces it to recalculate its size
18843 */
18844
18845 }, {
18846 key: "needsRefresh",
18847 value: function needsRefresh() {
18848 this.shape.refreshNeeded = true;
18849 }
18850 /**
18851 * get the title of this node.
18852 *
18853 * @returns {string} title The title of the node, or undefined when no title
18854 * has been set.
18855 */
18856
18857 }, {
18858 key: "getTitle",
18859 value: function getTitle() {
18860 return this.options.title;
18861 }
18862 /**
18863 * Calculate the distance to the border of the Node
18864 *
18865 * @param {CanvasRenderingContext2D} ctx
18866 * @param {number} angle Angle in radians
18867 * @returns {number} distance Distance to the border in pixels
18868 */
18869
18870 }, {
18871 key: "distanceToBorder",
18872 value: function distanceToBorder(ctx, angle) {
18873 return this.shape.distanceToBorder(ctx, angle);
18874 }
18875 /**
18876 * Check if this node has a fixed x and y position
18877 *
18878 * @returns {boolean} true if fixed, false if not
18879 */
18880
18881 }, {
18882 key: "isFixed",
18883 value: function isFixed() {
18884 return this.options.fixed.x && this.options.fixed.y;
18885 }
18886 /**
18887 * check if this node is selecte
18888 *
18889 * @returns {boolean} selected True if node is selected, else false
18890 */
18891
18892 }, {
18893 key: "isSelected",
18894 value: function isSelected() {
18895 return this.selected;
18896 }
18897 /**
18898 * Retrieve the value of the node. Can be undefined
18899 *
18900 * @returns {number} value
18901 */
18902
18903 }, {
18904 key: "getValue",
18905 value: function getValue() {
18906 return this.options.value;
18907 }
18908 /**
18909 * Get the current dimensions of the label
18910 *
18911 * @returns {rect}
18912 */
18913
18914 }, {
18915 key: "getLabelSize",
18916 value: function getLabelSize() {
18917 return this.labelModule.size();
18918 }
18919 /**
18920 * Adjust the value range of the node. The node will adjust it's size
18921 * based on its value.
18922 *
18923 * @param {number} min
18924 * @param {number} max
18925 * @param {number} total
18926 */
18927
18928 }, {
18929 key: "setValueRange",
18930 value: function setValueRange(min, max, total) {
18931 if (this.options.value !== undefined) {
18932 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
18933 var sizeDiff = this.options.scaling.max - this.options.scaling.min;
18934
18935 if (this.options.scaling.label.enabled === true) {
18936 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
18937 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
18938 }
18939
18940 this.options.size = this.options.scaling.min + scale * sizeDiff;
18941 } else {
18942 this.options.size = this.baseSize;
18943 this.options.font.size = this.baseFontSize;
18944 }
18945
18946 this.updateLabelModule();
18947 }
18948 /**
18949 * Draw this node in the given canvas
18950 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
18951 *
18952 * @param {CanvasRenderingContext2D} ctx
18953 *
18954 * @returns {object} Callbacks to draw later on higher layers.
18955 */
18956
18957 }, {
18958 key: "draw",
18959 value: function draw(ctx) {
18960 var values = this.getFormattingValues();
18961 return this.shape.draw(ctx, this.x, this.y, this.selected, this.hover, values) || {};
18962 }
18963 /**
18964 * Update the bounding box of the shape
18965 *
18966 * @param {CanvasRenderingContext2D} ctx
18967 */
18968
18969 }, {
18970 key: "updateBoundingBox",
18971 value: function updateBoundingBox(ctx) {
18972 this.shape.updateBoundingBox(this.x, this.y, ctx);
18973 }
18974 /**
18975 * Recalculate the size of this node in the given canvas
18976 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
18977 *
18978 * @param {CanvasRenderingContext2D} ctx
18979 */
18980
18981 }, {
18982 key: "resize",
18983 value: function resize(ctx) {
18984 var values = this.getFormattingValues();
18985 this.shape.resize(ctx, this.selected, this.hover, values);
18986 }
18987 /**
18988 * Determine all visual elements of this node instance, in which the given
18989 * point falls within the bounding shape.
18990 *
18991 * @param {point} point
18992 * @returns {Array.<nodeClickItem|nodeLabelClickItem>} list with the items which are on the point
18993 */
18994
18995 }, {
18996 key: "getItemsOnPoint",
18997 value: function getItemsOnPoint(point) {
18998 var ret = [];
18999
19000 if (this.labelModule.visible()) {
19001 if (pointInRect(this.labelModule.getSize(), point)) {
19002 ret.push({
19003 nodeId: this.id,
19004 labelId: 0
19005 });
19006 }
19007 }
19008
19009 if (pointInRect(this.shape.boundingBox, point)) {
19010 ret.push({
19011 nodeId: this.id
19012 });
19013 }
19014
19015 return ret;
19016 }
19017 /**
19018 * Check if this object is overlapping with the provided object
19019 *
19020 * @param {object} obj an object with parameters left, top, right, bottom
19021 * @returns {boolean} True if location is located on node
19022 */
19023
19024 }, {
19025 key: "isOverlappingWith",
19026 value: function isOverlappingWith(obj) {
19027 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;
19028 }
19029 /**
19030 * Check if this object is overlapping with the provided object
19031 *
19032 * @param {object} obj an object with parameters left, top, right, bottom
19033 * @returns {boolean} True if location is located on node
19034 */
19035
19036 }, {
19037 key: "isBoundingBoxOverlappingWith",
19038 value: function isBoundingBoxOverlappingWith(obj) {
19039 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;
19040 }
19041 /**
19042 * Check valid values for mass
19043 *
19044 * The mass may not be negative or zero. If it is, reset to 1
19045 *
19046 * @param {object} options
19047 * @param {Node.id} id
19048 * @static
19049 */
19050
19051 }], [{
19052 key: "checkOpacity",
19053 value: function checkOpacity(opacity) {
19054 return 0 <= opacity && opacity <= 1;
19055 }
19056 /**
19057 * Check that origin is 'center' or 'top-left'
19058 *
19059 * @param {string} origin
19060 * @returns {boolean}
19061 */
19062
19063 }, {
19064 key: "checkCoordinateOrigin",
19065 value: function checkCoordinateOrigin(origin) {
19066 return origin === undefined || origin === "center" || origin === "top-left";
19067 }
19068 /**
19069 * Copy group option values into the node options.
19070 *
19071 * The group options override the global node options, so the copy of group options
19072 * must happen *after* the global node options have been set.
19073 *
19074 * This method must also be called also if the global node options have changed and the group options did not.
19075 *
19076 * @param {object} parentOptions
19077 * @param {object} newOptions new values for the options, currently only passed in for check
19078 * @param {object} groupList
19079 */
19080
19081 }, {
19082 key: "updateGroupOptions",
19083 value: function updateGroupOptions(parentOptions, newOptions, groupList) {
19084 var _context4;
19085
19086 if (groupList === undefined) return; // No groups, nothing to do
19087
19088 var group = parentOptions.group; // paranoia: the selected group is already merged into node options, check.
19089
19090 if (newOptions !== undefined && newOptions.group !== undefined && group !== newOptions.group) {
19091 throw new Error("updateGroupOptions: group values in options don't match.");
19092 }
19093
19094 var hasGroup = typeof group === "number" || typeof group === "string" && group != "";
19095 if (!hasGroup) return; // current node has no group, no need to merge
19096
19097 var groupObj = groupList.get(group);
19098
19099 if (groupObj.opacity !== undefined && newOptions.opacity === undefined) {
19100 if (!Node.checkOpacity(groupObj.opacity)) {
19101 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + groupObj.opacity);
19102 groupObj.opacity = undefined;
19103 }
19104 } // Skip any new option to avoid them being overridden by the group options.
19105
19106
19107 var skipProperties = filter(_context4 = getOwnPropertyNames(newOptions)).call(_context4, function (p) {
19108 return newOptions[p] != null;
19109 }); // Always skip merging group font options into parent; these are required to be distinct for labels
19110
19111
19112 skipProperties.push("font");
19113 selectiveNotDeepExtend(skipProperties, parentOptions, groupObj); // the color object needs to be completely defined.
19114 // Since groups can partially overwrite the colors, we parse it again, just in case.
19115
19116 parentOptions.color = parseColor(parentOptions.color);
19117 }
19118 /**
19119 * This process all possible shorthands in the new options and makes sure that the parentOptions are fully defined.
19120 * Static so it can also be used by the handler.
19121 *
19122 * @param {object} parentOptions
19123 * @param {object} newOptions
19124 * @param {boolean} [allowDeletion=false]
19125 * @param {object} [globalOptions={}]
19126 * @param {object} [groupList]
19127 * @static
19128 */
19129
19130 }, {
19131 key: "parseOptions",
19132 value: function parseOptions(parentOptions, newOptions) {
19133 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
19134 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
19135 var groupList = arguments.length > 4 ? arguments[4] : undefined;
19136 var fields = ["color", "fixed", "shadow"];
19137 selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);
19138 Node.checkMass(newOptions);
19139
19140 if (parentOptions.opacity !== undefined) {
19141 if (!Node.checkOpacity(parentOptions.opacity)) {
19142 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + parentOptions.opacity);
19143 parentOptions.opacity = undefined;
19144 }
19145 }
19146
19147 if (newOptions.opacity !== undefined) {
19148 if (!Node.checkOpacity(newOptions.opacity)) {
19149 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + newOptions.opacity);
19150 newOptions.opacity = undefined;
19151 }
19152 }
19153
19154 if (newOptions.shapeProperties && !Node.checkCoordinateOrigin(newOptions.shapeProperties.coordinateOrigin)) {
19155 console.error("Invalid option for node coordinateOrigin, found: " + newOptions.shapeProperties.coordinateOrigin);
19156 } // merge the shadow options into the parent.
19157
19158
19159 mergeOptions(parentOptions, newOptions, "shadow", globalOptions); // individual shape newOptions
19160
19161 if (newOptions.color !== undefined && newOptions.color !== null) {
19162 var parsedColor = parseColor(newOptions.color);
19163 fillIfDefined(parentOptions.color, parsedColor);
19164 } else if (allowDeletion === true && newOptions.color === null) {
19165 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
19166 } // handle the fixed options
19167
19168
19169 if (newOptions.fixed !== undefined && newOptions.fixed !== null) {
19170 if (typeof newOptions.fixed === "boolean") {
19171 parentOptions.fixed.x = newOptions.fixed;
19172 parentOptions.fixed.y = newOptions.fixed;
19173 } else {
19174 if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === "boolean") {
19175 parentOptions.fixed.x = newOptions.fixed.x;
19176 }
19177
19178 if (newOptions.fixed.y !== undefined && typeof newOptions.fixed.y === "boolean") {
19179 parentOptions.fixed.y = newOptions.fixed.y;
19180 }
19181 }
19182 }
19183
19184 if (allowDeletion === true && newOptions.font === null) {
19185 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
19186 }
19187
19188 Node.updateGroupOptions(parentOptions, newOptions, groupList); // handle the scaling options, specifically the label part
19189
19190 if (newOptions.scaling !== undefined) {
19191 mergeOptions(parentOptions.scaling, newOptions.scaling, "label", globalOptions.scaling);
19192 }
19193 }
19194 }, {
19195 key: "checkMass",
19196 value: function checkMass(options, id) {
19197 if (options.mass !== undefined && options.mass <= 0) {
19198 var strId = "";
19199
19200 if (id !== undefined) {
19201 strId = " in node id: " + id;
19202 }
19203
19204 console.error("%cNegative or zero mass disallowed" + strId + ", setting mass to 1.", VALIDATOR_PRINT_STYLE$1);
19205 options.mass = 1;
19206 }
19207 }
19208 }]);
19209
19210 return Node;
19211 }();
19212
19213 function _createForOfIteratorHelper$6(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$1(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; } } }; }
19214
19215 function _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$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$6(o, minLen); }
19216
19217 function _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; }
19218 /**
19219 * Handler for Nodes
19220 */
19221
19222 var NodesHandler = /*#__PURE__*/function () {
19223 /**
19224 * @param {object} body
19225 * @param {Images} images
19226 * @param {Array.<Group>} groups
19227 * @param {LayoutEngine} layoutEngine
19228 */
19229 function NodesHandler(body, images, groups, layoutEngine) {
19230 var _context,
19231 _this = this;
19232
19233 _classCallCheck(this, NodesHandler);
19234
19235 this.body = body;
19236 this.images = images;
19237 this.groups = groups;
19238 this.layoutEngine = layoutEngine; // create the node API in the body container
19239
19240 this.body.functions.createNode = bind$5(_context = this.create).call(_context, this);
19241 this.nodesListeners = {
19242 add: function add(event, params) {
19243 _this.add(params.items);
19244 },
19245 update: function update(event, params) {
19246 _this.update(params.items, params.data, params.oldData);
19247 },
19248 remove: function remove(event, params) {
19249 _this.remove(params.items);
19250 }
19251 };
19252 this.defaultOptions = {
19253 borderWidth: 1,
19254 borderWidthSelected: undefined,
19255 brokenImage: undefined,
19256 color: {
19257 border: "#2B7CE9",
19258 background: "#97C2FC",
19259 highlight: {
19260 border: "#2B7CE9",
19261 background: "#D2E5FF"
19262 },
19263 hover: {
19264 border: "#2B7CE9",
19265 background: "#D2E5FF"
19266 }
19267 },
19268 opacity: undefined,
19269 // number between 0 and 1
19270 fixed: {
19271 x: false,
19272 y: false
19273 },
19274 font: {
19275 color: "#343434",
19276 size: 14,
19277 // px
19278 face: "arial",
19279 background: "none",
19280 strokeWidth: 0,
19281 // px
19282 strokeColor: "#ffffff",
19283 align: "center",
19284 vadjust: 0,
19285 multi: false,
19286 bold: {
19287 mod: "bold"
19288 },
19289 boldital: {
19290 mod: "bold italic"
19291 },
19292 ital: {
19293 mod: "italic"
19294 },
19295 mono: {
19296 mod: "",
19297 size: 15,
19298 // px
19299 face: "monospace",
19300 vadjust: 2
19301 }
19302 },
19303 group: undefined,
19304 hidden: false,
19305 icon: {
19306 face: "FontAwesome",
19307 //'FontAwesome',
19308 code: undefined,
19309 //'\uf007',
19310 size: 50,
19311 //50,
19312 color: "#2B7CE9" //'#aa00ff'
19313
19314 },
19315 image: undefined,
19316 // --> URL
19317 imagePadding: {
19318 // only for image shape
19319 top: 0,
19320 right: 0,
19321 bottom: 0,
19322 left: 0
19323 },
19324 label: undefined,
19325 labelHighlightBold: true,
19326 level: undefined,
19327 margin: {
19328 top: 5,
19329 right: 5,
19330 bottom: 5,
19331 left: 5
19332 },
19333 mass: 1,
19334 physics: true,
19335 scaling: {
19336 min: 10,
19337 max: 30,
19338 label: {
19339 enabled: false,
19340 min: 14,
19341 max: 30,
19342 maxVisible: 30,
19343 drawThreshold: 5
19344 },
19345 customScalingFunction: function customScalingFunction(min, max, total, value) {
19346 if (max === min) {
19347 return 0.5;
19348 } else {
19349 var scale = 1 / (max - min);
19350 return Math.max(0, (value - min) * scale);
19351 }
19352 }
19353 },
19354 shadow: {
19355 enabled: false,
19356 color: "rgba(0,0,0,0.5)",
19357 size: 10,
19358 x: 5,
19359 y: 5
19360 },
19361 shape: "ellipse",
19362 shapeProperties: {
19363 borderDashes: false,
19364 // only for borders
19365 borderRadius: 6,
19366 // only for box shape
19367 interpolation: true,
19368 // only for image and circularImage shapes
19369 useImageSize: false,
19370 // only for image and circularImage shapes
19371 useBorderWithImage: false,
19372 // only for image shape
19373 coordinateOrigin: "center" // only for image and circularImage shapes
19374
19375 },
19376 size: 25,
19377 title: undefined,
19378 value: undefined,
19379 x: undefined,
19380 y: undefined
19381 }; // Protect from idiocy
19382
19383 if (this.defaultOptions.mass <= 0) {
19384 throw "Internal error: mass in defaultOptions of NodesHandler may not be zero or negative";
19385 }
19386
19387 this.options = bridgeObject(this.defaultOptions);
19388 this.bindEventListeners();
19389 }
19390 /**
19391 * Binds event listeners
19392 */
19393
19394
19395 _createClass(NodesHandler, [{
19396 key: "bindEventListeners",
19397 value: function bindEventListeners() {
19398 var _context2,
19399 _context3,
19400 _this2 = this;
19401
19402 // refresh the nodes. Used when reverting from hierarchical layout
19403 this.body.emitter.on("refreshNodes", bind$5(_context2 = this.refresh).call(_context2, this));
19404 this.body.emitter.on("refresh", bind$5(_context3 = this.refresh).call(_context3, this));
19405 this.body.emitter.on("destroy", function () {
19406 forEach$1(_this2.nodesListeners, function (callback, event) {
19407 if (_this2.body.data.nodes) _this2.body.data.nodes.off(event, callback);
19408 });
19409 delete _this2.body.functions.createNode;
19410 delete _this2.nodesListeners.add;
19411 delete _this2.nodesListeners.update;
19412 delete _this2.nodesListeners.remove;
19413 delete _this2.nodesListeners;
19414 });
19415 }
19416 /**
19417 *
19418 * @param {object} options
19419 */
19420
19421 }, {
19422 key: "setOptions",
19423 value: function setOptions(options) {
19424 if (options !== undefined) {
19425 Node.parseOptions(this.options, options); // Need to set opacity here because Node.parseOptions is also used for groups,
19426 // if you set opacity in Node.parseOptions it overwrites group opacity.
19427
19428 if (options.opacity !== undefined) {
19429 if (isNan(options.opacity) || !_isFinite(options.opacity) || options.opacity < 0 || options.opacity > 1) {
19430 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + options.opacity);
19431 } else {
19432 this.options.opacity = options.opacity;
19433 }
19434 } // update the shape in all nodes
19435
19436
19437 if (options.shape !== undefined) {
19438 for (var nodeId in this.body.nodes) {
19439 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
19440 this.body.nodes[nodeId].updateShape();
19441 }
19442 }
19443 } // Update the labels of nodes if any relevant options changed.
19444
19445
19446 if (typeof options.font !== "undefined" || typeof options.widthConstraint !== "undefined" || typeof options.heightConstraint !== "undefined") {
19447 for (var _i = 0, _Object$keys = keys(this.body.nodes); _i < _Object$keys.length; _i++) {
19448 var _nodeId = _Object$keys[_i];
19449
19450 this.body.nodes[_nodeId].updateLabelModule();
19451
19452 this.body.nodes[_nodeId].needsRefresh();
19453 }
19454 } // update the shape size in all nodes
19455
19456
19457 if (options.size !== undefined) {
19458 for (var _nodeId2 in this.body.nodes) {
19459 if (Object.prototype.hasOwnProperty.call(this.body.nodes, _nodeId2)) {
19460 this.body.nodes[_nodeId2].needsRefresh();
19461 }
19462 }
19463 } // update the state of the variables if needed
19464
19465
19466 if (options.hidden !== undefined || options.physics !== undefined) {
19467 this.body.emitter.emit("_dataChanged");
19468 }
19469 }
19470 }
19471 /**
19472 * Set a data set with nodes for the network
19473 *
19474 * @param {Array | DataSet | DataView} nodes The data containing the nodes.
19475 * @param {boolean} [doNotEmit=false] - Suppress data changed event.
19476 * @private
19477 */
19478
19479 }, {
19480 key: "setData",
19481 value: function setData(nodes) {
19482 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
19483 var oldNodesData = this.body.data.nodes;
19484
19485 if (esnext.isDataViewLike("id", nodes)) {
19486 this.body.data.nodes = nodes;
19487 } else if (isArray$1(nodes)) {
19488 this.body.data.nodes = new esnext.DataSet();
19489 this.body.data.nodes.add(nodes);
19490 } else if (!nodes) {
19491 this.body.data.nodes = new esnext.DataSet();
19492 } else {
19493 throw new TypeError("Array or DataSet expected");
19494 }
19495
19496 if (oldNodesData) {
19497 // unsubscribe from old dataset
19498 forEach$1(this.nodesListeners, function (callback, event) {
19499 oldNodesData.off(event, callback);
19500 });
19501 } // remove drawn nodes
19502
19503
19504 this.body.nodes = {};
19505
19506 if (this.body.data.nodes) {
19507 // subscribe to new dataset
19508 var me = this;
19509 forEach$1(this.nodesListeners, function (callback, event) {
19510 me.body.data.nodes.on(event, callback);
19511 }); // draw all new nodes
19512
19513 var ids = this.body.data.nodes.getIds();
19514 this.add(ids, true);
19515 }
19516
19517 if (doNotEmit === false) {
19518 this.body.emitter.emit("_dataChanged");
19519 }
19520 }
19521 /**
19522 * Add nodes
19523 *
19524 * @param {number[] | string[]} ids
19525 * @param {boolean} [doNotEmit=false]
19526 * @private
19527 */
19528
19529 }, {
19530 key: "add",
19531 value: function add(ids) {
19532 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
19533 var id;
19534 var newNodes = [];
19535
19536 for (var i = 0; i < ids.length; i++) {
19537 id = ids[i];
19538 var properties = this.body.data.nodes.get(id);
19539 var node = this.create(properties);
19540 newNodes.push(node);
19541 this.body.nodes[id] = node; // note: this may replace an existing node
19542 }
19543
19544 this.layoutEngine.positionInitially(newNodes);
19545
19546 if (doNotEmit === false) {
19547 this.body.emitter.emit("_dataChanged");
19548 }
19549 }
19550 /**
19551 * Update existing nodes, or create them when not yet existing
19552 *
19553 * @param {number[] | string[]} ids id's of changed nodes
19554 * @param {Array} changedData array with changed data
19555 * @param {Array|undefined} oldData optional; array with previous data
19556 * @private
19557 */
19558
19559 }, {
19560 key: "update",
19561 value: function update(ids, changedData, oldData) {
19562 var nodes = this.body.nodes;
19563 var dataChanged = false;
19564
19565 for (var i = 0; i < ids.length; i++) {
19566 var id = ids[i];
19567 var node = nodes[id];
19568 var data = changedData[i];
19569
19570 if (node !== undefined) {
19571 // update node
19572 if (node.setOptions(data)) {
19573 dataChanged = true;
19574 }
19575 } else {
19576 dataChanged = true; // create node
19577
19578 node = this.create(data);
19579 nodes[id] = node;
19580 }
19581 }
19582
19583 if (!dataChanged && oldData !== undefined) {
19584 // Check for any changes which should trigger a layout recalculation
19585 // For now, this is just 'level' for hierarchical layout
19586 // Assumption: old and new data arranged in same order; at time of writing, this holds.
19587 dataChanged = some(changedData).call(changedData, function (newValue, index) {
19588 var oldValue = oldData[index];
19589 return oldValue && oldValue.level !== newValue.level;
19590 });
19591 }
19592
19593 if (dataChanged === true) {
19594 this.body.emitter.emit("_dataChanged");
19595 } else {
19596 this.body.emitter.emit("_dataUpdated");
19597 }
19598 }
19599 /**
19600 * Remove existing nodes. If nodes do not exist, the method will just ignore it.
19601 *
19602 * @param {number[] | string[]} ids
19603 * @private
19604 */
19605
19606 }, {
19607 key: "remove",
19608 value: function remove(ids) {
19609 var nodes = this.body.nodes;
19610
19611 for (var i = 0; i < ids.length; i++) {
19612 var id = ids[i];
19613 delete nodes[id];
19614 }
19615
19616 this.body.emitter.emit("_dataChanged");
19617 }
19618 /**
19619 * create a node
19620 *
19621 * @param {object} properties
19622 * @param {class} [constructorClass=Node.default]
19623 * @returns {*}
19624 */
19625
19626 }, {
19627 key: "create",
19628 value: function create(properties) {
19629 var constructorClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Node;
19630 return new constructorClass(properties, this.body, this.images, this.groups, this.options, this.defaultOptions);
19631 }
19632 /**
19633 *
19634 * @param {boolean} [clearPositions=false]
19635 */
19636
19637 }, {
19638 key: "refresh",
19639 value: function refresh() {
19640 var _this3 = this;
19641
19642 var clearPositions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
19643 forEach$1(this.body.nodes, function (node, nodeId) {
19644 var data = _this3.body.data.nodes.get(nodeId);
19645
19646 if (data !== undefined) {
19647 if (clearPositions === true) {
19648 node.setOptions({
19649 x: null,
19650 y: null
19651 });
19652 }
19653
19654 node.setOptions({
19655 fixed: false
19656 });
19657 node.setOptions(data);
19658 }
19659 });
19660 }
19661 /**
19662 * Returns the positions of the nodes.
19663 *
19664 * @param {Array.<Node.id> | string} [ids] --> optional, can be array of nodeIds, can be string
19665 * @returns {{}}
19666 */
19667
19668 }, {
19669 key: "getPositions",
19670 value: function getPositions(ids) {
19671 var dataArray = {};
19672
19673 if (ids !== undefined) {
19674 if (isArray$1(ids) === true) {
19675 for (var i = 0; i < ids.length; i++) {
19676 if (this.body.nodes[ids[i]] !== undefined) {
19677 var node = this.body.nodes[ids[i]];
19678 dataArray[ids[i]] = {
19679 x: Math.round(node.x),
19680 y: Math.round(node.y)
19681 };
19682 }
19683 }
19684 } else {
19685 if (this.body.nodes[ids] !== undefined) {
19686 var _node = this.body.nodes[ids];
19687 dataArray[ids] = {
19688 x: Math.round(_node.x),
19689 y: Math.round(_node.y)
19690 };
19691 }
19692 }
19693 } else {
19694 for (var _i2 = 0; _i2 < this.body.nodeIndices.length; _i2++) {
19695 var _node2 = this.body.nodes[this.body.nodeIndices[_i2]];
19696 dataArray[this.body.nodeIndices[_i2]] = {
19697 x: Math.round(_node2.x),
19698 y: Math.round(_node2.y)
19699 };
19700 }
19701 }
19702
19703 return dataArray;
19704 }
19705 /**
19706 * Retrieves the x y position of a specific id.
19707 *
19708 * @param {string} id The id to retrieve.
19709 *
19710 * @throws {TypeError} If no id is included.
19711 * @throws {ReferenceError} If an invalid id is provided.
19712 *
19713 * @returns {{ x: number, y: number }} Returns X, Y canvas position of the node with given id.
19714 */
19715
19716 }, {
19717 key: "getPosition",
19718 value: function getPosition(id) {
19719 if (id == undefined) {
19720 throw new TypeError("No id was specified for getPosition method.");
19721 } else if (this.body.nodes[id] == undefined) {
19722 throw new ReferenceError("NodeId provided for getPosition does not exist. Provided: ".concat(id));
19723 } else {
19724 return {
19725 x: Math.round(this.body.nodes[id].x),
19726 y: Math.round(this.body.nodes[id].y)
19727 };
19728 }
19729 }
19730 /**
19731 * Load the XY positions of the nodes into the dataset.
19732 */
19733
19734 }, {
19735 key: "storePositions",
19736 value: function storePositions() {
19737 // todo: add support for clusters and hierarchical.
19738 var dataArray = [];
19739 var dataset = this.body.data.nodes.getDataSet();
19740
19741 var _iterator = _createForOfIteratorHelper$6(dataset.get()),
19742 _step;
19743
19744 try {
19745 for (_iterator.s(); !(_step = _iterator.n()).done;) {
19746 var dsNode = _step.value;
19747 var id = dsNode.id;
19748 var bodyNode = this.body.nodes[id];
19749 var x = Math.round(bodyNode.x);
19750 var y = Math.round(bodyNode.y);
19751
19752 if (dsNode.x !== x || dsNode.y !== y) {
19753 dataArray.push({
19754 id: id,
19755 x: x,
19756 y: y
19757 });
19758 }
19759 }
19760 } catch (err) {
19761 _iterator.e(err);
19762 } finally {
19763 _iterator.f();
19764 }
19765
19766 dataset.update(dataArray);
19767 }
19768 /**
19769 * get the bounding box of a node.
19770 *
19771 * @param {Node.id} nodeId
19772 * @returns {j|*}
19773 */
19774
19775 }, {
19776 key: "getBoundingBox",
19777 value: function getBoundingBox(nodeId) {
19778 if (this.body.nodes[nodeId] !== undefined) {
19779 return this.body.nodes[nodeId].shape.boundingBox;
19780 }
19781 }
19782 /**
19783 * Get the Ids of nodes connected to this node.
19784 *
19785 * @param {Node.id} nodeId
19786 * @param {'to'|'from'|undefined} direction values 'from' and 'to' select respectively parent and child nodes only.
19787 * Any other value returns both parent and child nodes.
19788 * @returns {Array}
19789 */
19790
19791 }, {
19792 key: "getConnectedNodes",
19793 value: function getConnectedNodes(nodeId, direction) {
19794 var nodeList = [];
19795
19796 if (this.body.nodes[nodeId] !== undefined) {
19797 var node = this.body.nodes[nodeId];
19798 var nodeObj = {}; // used to quickly check if node already exists
19799
19800 for (var i = 0; i < node.edges.length; i++) {
19801 var edge = node.edges[i];
19802
19803 if (direction !== "to" && edge.toId == node.id) {
19804 // these are double equals since ids can be numeric or string
19805 if (nodeObj[edge.fromId] === undefined) {
19806 nodeList.push(edge.fromId);
19807 nodeObj[edge.fromId] = true;
19808 }
19809 } else if (direction !== "from" && edge.fromId == node.id) {
19810 // these are double equals since ids can be numeric or string
19811 if (nodeObj[edge.toId] === undefined) {
19812 nodeList.push(edge.toId);
19813 nodeObj[edge.toId] = true;
19814 }
19815 }
19816 }
19817 }
19818
19819 return nodeList;
19820 }
19821 /**
19822 * Get the ids of the edges connected to this node.
19823 *
19824 * @param {Node.id} nodeId
19825 * @returns {*}
19826 */
19827
19828 }, {
19829 key: "getConnectedEdges",
19830 value: function getConnectedEdges(nodeId) {
19831 var edgeList = [];
19832
19833 if (this.body.nodes[nodeId] !== undefined) {
19834 var node = this.body.nodes[nodeId];
19835
19836 for (var i = 0; i < node.edges.length; i++) {
19837 edgeList.push(node.edges[i].id);
19838 }
19839 } else {
19840 console.error("NodeId provided for getConnectedEdges does not exist. Provided: ", nodeId);
19841 }
19842
19843 return edgeList;
19844 }
19845 /**
19846 * Move a node.
19847 *
19848 * @param {Node.id} nodeId
19849 * @param {number} x
19850 * @param {number} y
19851 */
19852
19853 }, {
19854 key: "moveNode",
19855 value: function moveNode(nodeId, x, y) {
19856 var _this4 = this;
19857
19858 if (this.body.nodes[nodeId] !== undefined) {
19859 this.body.nodes[nodeId].x = Number(x);
19860 this.body.nodes[nodeId].y = Number(y);
19861
19862 setTimeout$1(function () {
19863 _this4.body.emitter.emit("startSimulation");
19864 }, 0);
19865 } else {
19866 console.error("Node id supplied to moveNode does not exist. Provided: ", nodeId);
19867 }
19868 }
19869 }]);
19870
19871 return NodesHandler;
19872 }();
19873
19874 var $$4 = _export;
19875 var isObject$2 = isObject$j;
19876 var anObject$1 = anObject$c;
19877 var has = has$c;
19878 var getOwnPropertyDescriptorModule = objectGetOwnPropertyDescriptor;
19879 var getPrototypeOf = objectGetPrototypeOf; // `Reflect.get` method
19880 // https://tc39.es/ecma262/#sec-reflect.get
19881
19882 function get$4(target, propertyKey
19883 /* , receiver */
19884 ) {
19885 var receiver = arguments.length < 3 ? target : arguments[2];
19886 var descriptor, prototype;
19887 if (anObject$1(target) === receiver) return target[propertyKey];
19888 if (descriptor = getOwnPropertyDescriptorModule.f(target, propertyKey)) return has(descriptor, 'value') ? descriptor.value : descriptor.get === undefined ? undefined : descriptor.get.call(receiver);
19889 if (isObject$2(prototype = getPrototypeOf(target))) return get$4(prototype, propertyKey, receiver);
19890 }
19891
19892 $$4({
19893 target: 'Reflect',
19894 stat: true
19895 }, {
19896 get: get$4
19897 });
19898
19899 var path$4 = path$x;
19900 var get$3 = path$4.Reflect.get;
19901
19902 var parent$8 = get$3;
19903 var get$2 = parent$8;
19904
19905 var parent$7 = get$2;
19906 var get$1 = parent$7;
19907
19908 var get = get$1;
19909
19910 var parent$6 = getOwnPropertyDescriptor$3;
19911 var getOwnPropertyDescriptor$1 = parent$6;
19912
19913 var getOwnPropertyDescriptor = getOwnPropertyDescriptor$1;
19914
19915 function _superPropBase(object, property) {
19916 while (!Object.prototype.hasOwnProperty.call(object, property)) {
19917 object = _getPrototypeOf(object);
19918 if (object === null) break;
19919 }
19920
19921 return object;
19922 }
19923
19924 function _get(target, property, receiver) {
19925 if (typeof Reflect !== "undefined" && get) {
19926 _get = get;
19927 } else {
19928 _get = function _get(target, property, receiver) {
19929 var base = _superPropBase(target, property);
19930 if (!base) return;
19931
19932 var desc = getOwnPropertyDescriptor(base, property);
19933
19934 if (desc.get) {
19935 return desc.get.call(receiver);
19936 }
19937
19938 return desc.value;
19939 };
19940 }
19941
19942 return _get(target, property, receiver || target);
19943 }
19944
19945 var $$3 = _export; // eslint-disable-next-line es/no-math-hypot -- required for testing
19946
19947 var $hypot = Math.hypot;
19948 var abs = Math.abs;
19949 var sqrt = Math.sqrt; // Chrome 77 bug
19950 // https://bugs.chromium.org/p/v8/issues/detail?id=9546
19951
19952 var BUGGY = !!$hypot && $hypot(Infinity, NaN) !== Infinity; // `Math.hypot` method
19953 // https://tc39.es/ecma262/#sec-math.hypot
19954
19955 $$3({
19956 target: 'Math',
19957 stat: true,
19958 forced: BUGGY
19959 }, {
19960 // eslint-disable-next-line no-unused-vars -- required for `.length`
19961 hypot: function hypot(value1, value2) {
19962 var sum = 0;
19963 var i = 0;
19964 var aLen = arguments.length;
19965 var larg = 0;
19966 var arg, div;
19967
19968 while (i < aLen) {
19969 arg = abs(arguments[i++]);
19970
19971 if (larg < arg) {
19972 div = larg / arg;
19973 sum = sum * div * div + 1;
19974 larg = arg;
19975 } else if (arg > 0) {
19976 div = arg / larg;
19977 sum += div * div;
19978 } else sum += arg;
19979 }
19980
19981 return larg === Infinity ? Infinity : larg * sqrt(sum);
19982 }
19983 });
19984
19985 var path$3 = path$x;
19986 var hypot$2 = path$3.Math.hypot;
19987
19988 var parent$5 = hypot$2;
19989 var hypot$1 = parent$5;
19990
19991 var hypot = hypot$1;
19992
19993 function _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); }; }
19994
19995 function _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; } }
19996 /**
19997 * Common methods for endpoints
19998 *
19999 * @class
20000 */
20001
20002 var EndPoint = /*#__PURE__*/function () {
20003 function EndPoint() {
20004 _classCallCheck(this, EndPoint);
20005 }
20006
20007 _createClass(EndPoint, null, [{
20008 key: "transform",
20009 value:
20010 /**
20011 * Apply transformation on points for display.
20012 *
20013 * The following is done:
20014 * - rotate by the specified angle
20015 * - multiply the (normalized) coordinates by the passed length
20016 * - offset by the target coordinates
20017 *
20018 * @param points - The point(s) to be transformed.
20019 * @param arrowData - The data determining the result of the transformation.
20020 */
20021 function transform(points, arrowData) {
20022 if (!isArray$1(points)) {
20023 points = [points];
20024 }
20025
20026 var x = arrowData.point.x;
20027 var y = arrowData.point.y;
20028 var angle = arrowData.angle;
20029 var length = arrowData.length;
20030
20031 for (var i = 0; i < points.length; ++i) {
20032 var p = points[i];
20033 var xt = p.x * Math.cos(angle) - p.y * Math.sin(angle);
20034 var yt = p.x * Math.sin(angle) + p.y * Math.cos(angle);
20035 p.x = x + length * xt;
20036 p.y = y + length * yt;
20037 }
20038 }
20039 /**
20040 * Draw a closed path using the given real coordinates.
20041 *
20042 * @param ctx - The path will be rendered into this context.
20043 * @param points - The points of the path.
20044 */
20045
20046 }, {
20047 key: "drawPath",
20048 value: function drawPath(ctx, points) {
20049 ctx.beginPath();
20050 ctx.moveTo(points[0].x, points[0].y);
20051
20052 for (var i = 1; i < points.length; ++i) {
20053 ctx.lineTo(points[i].x, points[i].y);
20054 }
20055
20056 ctx.closePath();
20057 }
20058 }]);
20059
20060 return EndPoint;
20061 }();
20062 /**
20063 * Drawing methods for the arrow endpoint.
20064 */
20065
20066
20067 var Image$1 = /*#__PURE__*/function (_EndPoint) {
20068 _inherits(Image, _EndPoint);
20069
20070 var _super = _createSuper$a(Image);
20071
20072 function Image() {
20073 _classCallCheck(this, Image);
20074
20075 return _super.apply(this, arguments);
20076 }
20077
20078 _createClass(Image, null, [{
20079 key: "draw",
20080 value:
20081 /**
20082 * Draw this shape at the end of a line.
20083 *
20084 * @param ctx - The shape will be rendered into this context.
20085 * @param arrowData - The data determining the shape.
20086 *
20087 * @returns False as there is no way to fill an image.
20088 */
20089 function draw(ctx, arrowData) {
20090 if (arrowData.image) {
20091 ctx.save();
20092 ctx.translate(arrowData.point.x, arrowData.point.y);
20093 ctx.rotate(Math.PI / 2 + arrowData.angle);
20094 var width = arrowData.imageWidth != null ? arrowData.imageWidth : arrowData.image.width;
20095 var height = arrowData.imageHeight != null ? arrowData.imageHeight : arrowData.image.height;
20096 arrowData.image.drawImageAtPosition(ctx, 1, // scale
20097 -width / 2, // x
20098 0, // y
20099 width, height);
20100 ctx.restore();
20101 }
20102
20103 return false;
20104 }
20105 }]);
20106
20107 return Image;
20108 }(EndPoint);
20109 /**
20110 * Drawing methods for the arrow endpoint.
20111 */
20112
20113
20114 var Arrow = /*#__PURE__*/function (_EndPoint2) {
20115 _inherits(Arrow, _EndPoint2);
20116
20117 var _super2 = _createSuper$a(Arrow);
20118
20119 function Arrow() {
20120 _classCallCheck(this, Arrow);
20121
20122 return _super2.apply(this, arguments);
20123 }
20124
20125 _createClass(Arrow, null, [{
20126 key: "draw",
20127 value:
20128 /**
20129 * Draw this shape at the end of a line.
20130 *
20131 * @param ctx - The shape will be rendered into this context.
20132 * @param arrowData - The data determining the shape.
20133 *
20134 * @returns True because ctx.fill() can be used to fill the arrow.
20135 */
20136 function draw(ctx, arrowData) {
20137 // Normalized points of closed path, in the order that they should be drawn.
20138 // (0, 0) is the attachment point, and the point around which should be rotated
20139 var points = [{
20140 x: 0,
20141 y: 0
20142 }, {
20143 x: -1,
20144 y: 0.3
20145 }, {
20146 x: -0.9,
20147 y: 0
20148 }, {
20149 x: -1,
20150 y: -0.3
20151 }];
20152 EndPoint.transform(points, arrowData);
20153 EndPoint.drawPath(ctx, points);
20154 return true;
20155 }
20156 }]);
20157
20158 return Arrow;
20159 }(EndPoint);
20160 /**
20161 * Drawing methods for the crow endpoint.
20162 */
20163
20164
20165 var Crow = /*#__PURE__*/function () {
20166 function Crow() {
20167 _classCallCheck(this, Crow);
20168 }
20169
20170 _createClass(Crow, null, [{
20171 key: "draw",
20172 value:
20173 /**
20174 * Draw this shape at the end of a line.
20175 *
20176 * @param ctx - The shape will be rendered into this context.
20177 * @param arrowData - The data determining the shape.
20178 *
20179 * @returns True because ctx.fill() can be used to fill the arrow.
20180 */
20181 function draw(ctx, arrowData) {
20182 // Normalized points of closed path, in the order that they should be drawn.
20183 // (0, 0) is the attachment point, and the point around which should be rotated
20184 var points = [{
20185 x: -1,
20186 y: 0
20187 }, {
20188 x: 0,
20189 y: 0.3
20190 }, {
20191 x: -0.4,
20192 y: 0
20193 }, {
20194 x: 0,
20195 y: -0.3
20196 }];
20197 EndPoint.transform(points, arrowData);
20198 EndPoint.drawPath(ctx, points);
20199 return true;
20200 }
20201 }]);
20202
20203 return Crow;
20204 }();
20205 /**
20206 * Drawing methods for the curve endpoint.
20207 */
20208
20209
20210 var Curve = /*#__PURE__*/function () {
20211 function Curve() {
20212 _classCallCheck(this, Curve);
20213 }
20214
20215 _createClass(Curve, null, [{
20216 key: "draw",
20217 value:
20218 /**
20219 * Draw this shape at the end of a line.
20220 *
20221 * @param ctx - The shape will be rendered into this context.
20222 * @param arrowData - The data determining the shape.
20223 *
20224 * @returns True because ctx.fill() can be used to fill the arrow.
20225 */
20226 function draw(ctx, arrowData) {
20227 // Normalized points of closed path, in the order that they should be drawn.
20228 // (0, 0) is the attachment point, and the point around which should be rotated
20229 var point = {
20230 x: -0.4,
20231 y: 0
20232 };
20233 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
20234
20235 ctx.strokeStyle = ctx.fillStyle;
20236 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define curve endpoint as semicircle.
20237
20238 var pi = Math.PI;
20239 var startAngle = arrowData.angle - pi / 2;
20240 var endAngle = arrowData.angle + pi / 2;
20241 ctx.beginPath();
20242 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
20243 ctx.stroke();
20244 return true;
20245 }
20246 }]);
20247
20248 return Curve;
20249 }();
20250 /**
20251 * Drawing methods for the inverted curve endpoint.
20252 */
20253
20254
20255 var InvertedCurve = /*#__PURE__*/function () {
20256 function InvertedCurve() {
20257 _classCallCheck(this, InvertedCurve);
20258 }
20259
20260 _createClass(InvertedCurve, null, [{
20261 key: "draw",
20262 value:
20263 /**
20264 * Draw this shape at the end of a line.
20265 *
20266 * @param ctx - The shape will be rendered into this context.
20267 * @param arrowData - The data determining the shape.
20268 *
20269 * @returns True because ctx.fill() can be used to fill the arrow.
20270 */
20271 function draw(ctx, arrowData) {
20272 // Normalized points of closed path, in the order that they should be drawn.
20273 // (0, 0) is the attachment point, and the point around which should be rotated
20274 var point = {
20275 x: -0.3,
20276 y: 0
20277 };
20278 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
20279
20280 ctx.strokeStyle = ctx.fillStyle;
20281 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define inverted curve endpoint as semicircle.
20282
20283 var pi = Math.PI;
20284 var startAngle = arrowData.angle + pi / 2;
20285 var endAngle = arrowData.angle + 3 * pi / 2;
20286 ctx.beginPath();
20287 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
20288 ctx.stroke();
20289 return true;
20290 }
20291 }]);
20292
20293 return InvertedCurve;
20294 }();
20295 /**
20296 * Drawing methods for the trinagle endpoint.
20297 */
20298
20299
20300 var Triangle = /*#__PURE__*/function () {
20301 function Triangle() {
20302 _classCallCheck(this, Triangle);
20303 }
20304
20305 _createClass(Triangle, null, [{
20306 key: "draw",
20307 value:
20308 /**
20309 * Draw this shape at the end of a line.
20310 *
20311 * @param ctx - The shape will be rendered into this context.
20312 * @param arrowData - The data determining the shape.
20313 *
20314 * @returns True because ctx.fill() can be used to fill the arrow.
20315 */
20316 function draw(ctx, arrowData) {
20317 // Normalized points of closed path, in the order that they should be drawn.
20318 // (0, 0) is the attachment point, and the point around which should be rotated
20319 var points = [{
20320 x: 0.02,
20321 y: 0
20322 }, {
20323 x: -1,
20324 y: 0.3
20325 }, {
20326 x: -1,
20327 y: -0.3
20328 }];
20329 EndPoint.transform(points, arrowData);
20330 EndPoint.drawPath(ctx, points);
20331 return true;
20332 }
20333 }]);
20334
20335 return Triangle;
20336 }();
20337 /**
20338 * Drawing methods for the inverted trinagle endpoint.
20339 */
20340
20341
20342 var InvertedTriangle = /*#__PURE__*/function () {
20343 function InvertedTriangle() {
20344 _classCallCheck(this, InvertedTriangle);
20345 }
20346
20347 _createClass(InvertedTriangle, null, [{
20348 key: "draw",
20349 value:
20350 /**
20351 * Draw this shape at the end of a line.
20352 *
20353 * @param ctx - The shape will be rendered into this context.
20354 * @param arrowData - The data determining the shape.
20355 *
20356 * @returns True because ctx.fill() can be used to fill the arrow.
20357 */
20358 function draw(ctx, arrowData) {
20359 // Normalized points of closed path, in the order that they should be drawn.
20360 // (0, 0) is the attachment point, and the point around which should be rotated
20361 var points = [{
20362 x: 0,
20363 y: 0.3
20364 }, {
20365 x: 0,
20366 y: -0.3
20367 }, {
20368 x: -1,
20369 y: 0
20370 }];
20371 EndPoint.transform(points, arrowData);
20372 EndPoint.drawPath(ctx, points);
20373 return true;
20374 }
20375 }]);
20376
20377 return InvertedTriangle;
20378 }();
20379 /**
20380 * Drawing methods for the circle endpoint.
20381 */
20382
20383
20384 var Circle = /*#__PURE__*/function () {
20385 function Circle() {
20386 _classCallCheck(this, Circle);
20387 }
20388
20389 _createClass(Circle, null, [{
20390 key: "draw",
20391 value:
20392 /**
20393 * Draw this shape at the end of a line.
20394 *
20395 * @param ctx - The shape will be rendered into this context.
20396 * @param arrowData - The data determining the shape.
20397 *
20398 * @returns True because ctx.fill() can be used to fill the arrow.
20399 */
20400 function draw(ctx, arrowData) {
20401 var point = {
20402 x: -0.4,
20403 y: 0
20404 };
20405 EndPoint.transform(point, arrowData);
20406 drawCircle(ctx, point.x, point.y, arrowData.length * 0.4);
20407 return true;
20408 }
20409 }]);
20410
20411 return Circle;
20412 }();
20413 /**
20414 * Drawing methods for the bar endpoint.
20415 */
20416
20417
20418 var Bar = /*#__PURE__*/function () {
20419 function Bar() {
20420 _classCallCheck(this, Bar);
20421 }
20422
20423 _createClass(Bar, null, [{
20424 key: "draw",
20425 value:
20426 /**
20427 * Draw this shape at the end of a line.
20428 *
20429 * @param ctx - The shape will be rendered into this context.
20430 * @param arrowData - The data determining the shape.
20431 *
20432 * @returns True because ctx.fill() can be used to fill the arrow.
20433 */
20434 function draw(ctx, arrowData) {
20435 /*
20436 var points = [
20437 {x:0, y:0.5},
20438 {x:0, y:-0.5}
20439 ];
20440 EndPoint.transform(points, arrowData);
20441 ctx.beginPath();
20442 ctx.moveTo(points[0].x, points[0].y);
20443 ctx.lineTo(points[1].x, points[1].y);
20444 ctx.stroke();
20445 */
20446 var points = [{
20447 x: 0,
20448 y: 0.5
20449 }, {
20450 x: 0,
20451 y: -0.5
20452 }, {
20453 x: -0.15,
20454 y: -0.5
20455 }, {
20456 x: -0.15,
20457 y: 0.5
20458 }];
20459 EndPoint.transform(points, arrowData);
20460 EndPoint.drawPath(ctx, points);
20461 return true;
20462 }
20463 }]);
20464
20465 return Bar;
20466 }();
20467 /**
20468 * Drawing methods for the box endpoint.
20469 */
20470
20471
20472 var Box = /*#__PURE__*/function () {
20473 function Box() {
20474 _classCallCheck(this, Box);
20475 }
20476
20477 _createClass(Box, null, [{
20478 key: "draw",
20479 value:
20480 /**
20481 * Draw this shape at the end of a line.
20482 *
20483 * @param ctx - The shape will be rendered into this context.
20484 * @param arrowData - The data determining the shape.
20485 *
20486 * @returns True because ctx.fill() can be used to fill the arrow.
20487 */
20488 function draw(ctx, arrowData) {
20489 var points = [{
20490 x: 0,
20491 y: 0.3
20492 }, {
20493 x: 0,
20494 y: -0.3
20495 }, {
20496 x: -0.6,
20497 y: -0.3
20498 }, {
20499 x: -0.6,
20500 y: 0.3
20501 }];
20502 EndPoint.transform(points, arrowData);
20503 EndPoint.drawPath(ctx, points);
20504 return true;
20505 }
20506 }]);
20507
20508 return Box;
20509 }();
20510 /**
20511 * Drawing methods for the diamond endpoint.
20512 */
20513
20514
20515 var Diamond = /*#__PURE__*/function () {
20516 function Diamond() {
20517 _classCallCheck(this, Diamond);
20518 }
20519
20520 _createClass(Diamond, null, [{
20521 key: "draw",
20522 value:
20523 /**
20524 * Draw this shape at the end of a line.
20525 *
20526 * @param ctx - The shape will be rendered into this context.
20527 * @param arrowData - The data determining the shape.
20528 *
20529 * @returns True because ctx.fill() can be used to fill the arrow.
20530 */
20531 function draw(ctx, arrowData) {
20532 var points = [{
20533 x: 0,
20534 y: 0
20535 }, {
20536 x: -0.5,
20537 y: -0.3
20538 }, {
20539 x: -1,
20540 y: 0
20541 }, {
20542 x: -0.5,
20543 y: 0.3
20544 }];
20545 EndPoint.transform(points, arrowData);
20546 EndPoint.drawPath(ctx, points);
20547 return true;
20548 }
20549 }]);
20550
20551 return Diamond;
20552 }();
20553 /**
20554 * Drawing methods for the vee endpoint.
20555 */
20556
20557
20558 var Vee = /*#__PURE__*/function () {
20559 function Vee() {
20560 _classCallCheck(this, Vee);
20561 }
20562
20563 _createClass(Vee, null, [{
20564 key: "draw",
20565 value:
20566 /**
20567 * Draw this shape at the end of a line.
20568 *
20569 * @param ctx - The shape will be rendered into this context.
20570 * @param arrowData - The data determining the shape.
20571 *
20572 * @returns True because ctx.fill() can be used to fill the arrow.
20573 */
20574 function draw(ctx, arrowData) {
20575 // Normalized points of closed path, in the order that they should be drawn.
20576 // (0, 0) is the attachment point, and the point around which should be rotated
20577 var points = [{
20578 x: -1,
20579 y: 0.3
20580 }, {
20581 x: -0.5,
20582 y: 0
20583 }, {
20584 x: -1,
20585 y: -0.3
20586 }, {
20587 x: 0,
20588 y: 0
20589 }];
20590 EndPoint.transform(points, arrowData);
20591 EndPoint.drawPath(ctx, points);
20592 return true;
20593 }
20594 }]);
20595
20596 return Vee;
20597 }();
20598 /**
20599 * Drawing methods for the endpoints.
20600 */
20601
20602
20603 var EndPoints = /*#__PURE__*/function () {
20604 function EndPoints() {
20605 _classCallCheck(this, EndPoints);
20606 }
20607
20608 _createClass(EndPoints, null, [{
20609 key: "draw",
20610 value:
20611 /**
20612 * Draw an endpoint.
20613 *
20614 * @param ctx - The shape will be rendered into this context.
20615 * @param arrowData - The data determining the shape.
20616 *
20617 * @returns True if ctx.fill() can be used to fill the arrow, false otherwise.
20618 */
20619 function draw(ctx, arrowData) {
20620 var type;
20621
20622 if (arrowData.type) {
20623 type = arrowData.type.toLowerCase();
20624 }
20625
20626 switch (type) {
20627 case "image":
20628 return Image$1.draw(ctx, arrowData);
20629
20630 case "circle":
20631 return Circle.draw(ctx, arrowData);
20632
20633 case "box":
20634 return Box.draw(ctx, arrowData);
20635
20636 case "crow":
20637 return Crow.draw(ctx, arrowData);
20638
20639 case "curve":
20640 return Curve.draw(ctx, arrowData);
20641
20642 case "diamond":
20643 return Diamond.draw(ctx, arrowData);
20644
20645 case "inv_curve":
20646 return InvertedCurve.draw(ctx, arrowData);
20647
20648 case "triangle":
20649 return Triangle.draw(ctx, arrowData);
20650
20651 case "inv_triangle":
20652 return InvertedTriangle.draw(ctx, arrowData);
20653
20654 case "bar":
20655 return Bar.draw(ctx, arrowData);
20656
20657 case "vee":
20658 return Vee.draw(ctx, arrowData);
20659
20660 case "arrow": // fall-through
20661
20662 default:
20663 return Arrow.draw(ctx, arrowData);
20664 }
20665 }
20666 }]);
20667
20668 return EndPoints;
20669 }();
20670
20671 function ownKeys$1(object, enumerableOnly) { var keys$1 = keys(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys$1.push.apply(keys$1, symbols); } return keys$1; }
20672
20673 function _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; }
20674 /**
20675 * The Base Class for all edges.
20676 */
20677
20678 var EdgeBase = /*#__PURE__*/function () {
20679 /**
20680 * Create a new instance.
20681 *
20682 * @param options - The options object of given edge.
20683 * @param _body - The body of the network.
20684 * @param _labelModule - Label module.
20685 */
20686 function EdgeBase(options, _body, _labelModule) {
20687 _classCallCheck(this, EdgeBase);
20688
20689 this._body = _body;
20690 this._labelModule = _labelModule;
20691 this.color = {};
20692 this.colorDirty = true;
20693 this.hoverWidth = 1.5;
20694 this.selectionWidth = 2;
20695 this.setOptions(options);
20696 this.fromPoint = this.from;
20697 this.toPoint = this.to;
20698 }
20699 /** @inheritDoc */
20700
20701
20702 _createClass(EdgeBase, [{
20703 key: "connect",
20704 value: function connect() {
20705 this.from = this._body.nodes[this.options.from];
20706 this.to = this._body.nodes[this.options.to];
20707 }
20708 /** @inheritDoc */
20709
20710 }, {
20711 key: "cleanup",
20712 value: function cleanup() {
20713 return false;
20714 }
20715 /**
20716 * Set new edge options.
20717 *
20718 * @param options - The new edge options object.
20719 */
20720
20721 }, {
20722 key: "setOptions",
20723 value: function setOptions(options) {
20724 this.options = options;
20725 this.from = this._body.nodes[this.options.from];
20726 this.to = this._body.nodes[this.options.to];
20727 this.id = this.options.id;
20728 }
20729 /** @inheritDoc */
20730
20731 }, {
20732 key: "drawLine",
20733 value: function drawLine(ctx, values, _selected, _hover) {
20734 var viaNode = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : this.getViaNode();
20735 // set style
20736 ctx.strokeStyle = this.getColor(ctx, values);
20737 ctx.lineWidth = values.width;
20738
20739 if (values.dashes !== false) {
20740 this._drawDashedLine(ctx, values, viaNode);
20741 } else {
20742 this._drawLine(ctx, values, viaNode);
20743 }
20744 }
20745 /**
20746 * Draw a line with given style between two nodes through supplied node(s).
20747 *
20748 * @param ctx - The context that will be used for rendering.
20749 * @param values - Formatting values like color, opacity or shadow.
20750 * @param viaNode - Additional control point(s) for the edge.
20751 * @param fromPoint - TODO: Seems ignored, remove?
20752 * @param toPoint - TODO: Seems ignored, remove?
20753 */
20754
20755 }, {
20756 key: "_drawLine",
20757 value: function _drawLine(ctx, values, viaNode, fromPoint, toPoint) {
20758 if (this.from != this.to) {
20759 // draw line
20760 this._line(ctx, values, viaNode, fromPoint, toPoint);
20761 } else {
20762 var _this$_getCircleData = this._getCircleData(ctx),
20763 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
20764 x = _this$_getCircleData2[0],
20765 y = _this$_getCircleData2[1],
20766 radius = _this$_getCircleData2[2];
20767
20768 this._circle(ctx, values, x, y, radius);
20769 }
20770 }
20771 /**
20772 * Draw a dashed line with given style between two nodes through supplied node(s).
20773 *
20774 * @param ctx - The context that will be used for rendering.
20775 * @param values - Formatting values like color, opacity or shadow.
20776 * @param viaNode - Additional control point(s) for the edge.
20777 * @param _fromPoint - Ignored (TODO: remove in the future).
20778 * @param _toPoint - Ignored (TODO: remove in the future).
20779 */
20780
20781 }, {
20782 key: "_drawDashedLine",
20783 value: function _drawDashedLine(ctx, values, viaNode, _fromPoint, _toPoint) {
20784 ctx.lineCap = "round";
20785 var pattern = isArray$1(values.dashes) ? values.dashes : [5, 5]; // only firefox and chrome support this method, else we use the legacy one.
20786
20787 if (ctx.setLineDash !== undefined) {
20788 ctx.save(); // set dash settings for chrome or firefox
20789
20790 ctx.setLineDash(pattern);
20791 ctx.lineDashOffset = 0; // draw the line
20792
20793 if (this.from != this.to) {
20794 // draw line
20795 this._line(ctx, values, viaNode);
20796 } else {
20797 var _this$_getCircleData3 = this._getCircleData(ctx),
20798 _this$_getCircleData4 = _slicedToArray(_this$_getCircleData3, 3),
20799 x = _this$_getCircleData4[0],
20800 y = _this$_getCircleData4[1],
20801 radius = _this$_getCircleData4[2];
20802
20803 this._circle(ctx, values, x, y, radius);
20804 } // restore the dash settings.
20805
20806
20807 ctx.setLineDash([0]);
20808 ctx.lineDashOffset = 0;
20809 ctx.restore();
20810 } else {
20811 // unsupporting smooth lines
20812 if (this.from != this.to) {
20813 // draw line
20814 drawDashedLine(ctx, this.from.x, this.from.y, this.to.x, this.to.y, pattern);
20815 } else {
20816 var _this$_getCircleData5 = this._getCircleData(ctx),
20817 _this$_getCircleData6 = _slicedToArray(_this$_getCircleData5, 3),
20818 _x = _this$_getCircleData6[0],
20819 _y = _this$_getCircleData6[1],
20820 _radius = _this$_getCircleData6[2];
20821
20822 this._circle(ctx, values, _x, _y, _radius);
20823 } // draw shadow if enabled
20824
20825
20826 this.enableShadow(ctx, values);
20827 ctx.stroke(); // disable shadows for other elements.
20828
20829 this.disableShadow(ctx, values);
20830 }
20831 }
20832 /**
20833 * Find the intersection between the border of the node and the edge.
20834 *
20835 * @param node - The node (either from or to node of the edge).
20836 * @param ctx - The context that will be used for rendering.
20837 * @param options - Additional options.
20838 *
20839 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
20840 */
20841
20842 }, {
20843 key: "findBorderPosition",
20844 value: function findBorderPosition(node, ctx, options) {
20845 if (this.from != this.to) {
20846 return this._findBorderPosition(node, ctx, options);
20847 } else {
20848 return this._findBorderPositionCircle(node, ctx, options);
20849 }
20850 }
20851 /** @inheritDoc */
20852
20853 }, {
20854 key: "findBorderPositions",
20855 value: function findBorderPositions(ctx) {
20856 if (this.from != this.to) {
20857 return {
20858 from: this._findBorderPosition(this.from, ctx),
20859 to: this._findBorderPosition(this.to, ctx)
20860 };
20861 } else {
20862 var _context;
20863
20864 var _this$_getCircleData$ = slice$1(_context = this._getCircleData(ctx)).call(_context, 0, 2),
20865 _this$_getCircleData$2 = _slicedToArray(_this$_getCircleData$, 2),
20866 x = _this$_getCircleData$2[0],
20867 y = _this$_getCircleData$2[1];
20868
20869 return {
20870 from: this._findBorderPositionCircle(this.from, ctx, {
20871 x: x,
20872 y: y,
20873 low: 0.25,
20874 high: 0.6,
20875 direction: -1
20876 }),
20877 to: this._findBorderPositionCircle(this.from, ctx, {
20878 x: x,
20879 y: y,
20880 low: 0.6,
20881 high: 0.8,
20882 direction: 1
20883 })
20884 };
20885 }
20886 }
20887 /**
20888 * Compute the center point and radius of an edge connected to the same node at both ends.
20889 *
20890 * @param ctx - The context that will be used for rendering.
20891 *
20892 * @returns `[x, y, radius]`
20893 */
20894
20895 }, {
20896 key: "_getCircleData",
20897 value: function _getCircleData(ctx) {
20898 var radius = this.options.selfReference.size;
20899
20900 if (ctx !== undefined) {
20901 if (this.from.shape.width === undefined) {
20902 this.from.shape.resize(ctx);
20903 }
20904 } // get circle coordinates
20905
20906
20907 var coordinates = getSelfRefCoordinates(ctx, this.options.selfReference.angle, radius, this.from);
20908 return [coordinates.x, coordinates.y, radius];
20909 }
20910 /**
20911 * Get a point on a circle.
20912 *
20913 * @param x - Center of the circle on the x axis.
20914 * @param y - Center of the circle on the y axis.
20915 * @param radius - Radius of the circle.
20916 * @param position - Value between 0 (line start) and 1 (line end).
20917 *
20918 * @returns Cartesian coordinates of requested point on the circle.
20919 */
20920
20921 }, {
20922 key: "_pointOnCircle",
20923 value: function _pointOnCircle(x, y, radius, position) {
20924 var angle = position * 2 * Math.PI;
20925 return {
20926 x: x + radius * Math.cos(angle),
20927 y: y - radius * Math.sin(angle)
20928 };
20929 }
20930 /**
20931 * Find the intersection between the border of the node and the edge.
20932 *
20933 * @remarks
20934 * This function uses binary search to look for the point where the circle crosses the border of the node.
20935 *
20936 * @param nearNode - The node (either from or to node of the edge).
20937 * @param ctx - The context that will be used for rendering.
20938 * @param options - Additional options.
20939 *
20940 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
20941 */
20942
20943 }, {
20944 key: "_findBorderPositionCircle",
20945 value: function _findBorderPositionCircle(nearNode, ctx, options) {
20946 var x = options.x;
20947 var y = options.y;
20948 var low = options.low;
20949 var high = options.high;
20950 var direction = options.direction;
20951 var maxIterations = 10;
20952 var radius = this.options.selfReference.size;
20953 var threshold = 0.05;
20954 var pos;
20955 var middle = (low + high) * 0.5;
20956 var endPointOffset = 0;
20957
20958 if (this.options.arrowStrikethrough === true) {
20959 if (direction === -1) {
20960 endPointOffset = this.options.endPointOffset.from;
20961 } else if (direction === 1) {
20962 endPointOffset = this.options.endPointOffset.to;
20963 }
20964 }
20965
20966 var iteration = 0;
20967
20968 do {
20969 middle = (low + high) * 0.5;
20970 pos = this._pointOnCircle(x, y, radius, middle);
20971 var angle = Math.atan2(nearNode.y - pos.y, nearNode.x - pos.x);
20972 var distanceToBorder = nearNode.distanceToBorder(ctx, angle) + endPointOffset;
20973 var distanceToPoint = Math.sqrt(Math.pow(pos.x - nearNode.x, 2) + Math.pow(pos.y - nearNode.y, 2));
20974 var difference = distanceToBorder - distanceToPoint;
20975
20976 if (Math.abs(difference) < threshold) {
20977 break; // found
20978 } else if (difference > 0) {
20979 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
20980 if (direction > 0) {
20981 low = middle;
20982 } else {
20983 high = middle;
20984 }
20985 } else {
20986 if (direction > 0) {
20987 high = middle;
20988 } else {
20989 low = middle;
20990 }
20991 }
20992
20993 ++iteration;
20994 } while (low <= high && iteration < maxIterations);
20995
20996 return _objectSpread$1(_objectSpread$1({}, pos), {}, {
20997 t: middle
20998 });
20999 }
21000 /**
21001 * Get the line width of the edge. Depends on width and whether one of the connected nodes is selected.
21002 *
21003 * @param selected - Determines wheter the line is selected.
21004 * @param hover - Determines wheter the line is being hovered, only applies if selected is false.
21005 *
21006 * @returns The width of the line.
21007 */
21008
21009 }, {
21010 key: "getLineWidth",
21011 value: function getLineWidth(selected, hover) {
21012 if (selected === true) {
21013 return Math.max(this.selectionWidth, 0.3 / this._body.view.scale);
21014 } else if (hover === true) {
21015 return Math.max(this.hoverWidth, 0.3 / this._body.view.scale);
21016 } else {
21017 return Math.max(this.options.width, 0.3 / this._body.view.scale);
21018 }
21019 }
21020 /**
21021 * Compute the color or gradient for given edge.
21022 *
21023 * @param ctx - The context that will be used for rendering.
21024 * @param values - Formatting values like color, opacity or shadow.
21025 * @param _selected - Ignored (TODO: remove in the future).
21026 * @param _hover - Ignored (TODO: remove in the future).
21027 *
21028 * @returns Color string if single color is inherited or gradient if two.
21029 */
21030
21031 }, {
21032 key: "getColor",
21033 value: function getColor(ctx, values) {
21034 if (values.inheritsColor !== false) {
21035 // when this is a loop edge, just use the 'from' method
21036 if (values.inheritsColor === "both" && this.from.id !== this.to.id) {
21037 var grd = ctx.createLinearGradient(this.from.x, this.from.y, this.to.x, this.to.y);
21038 var fromColor = this.from.options.color.highlight.border;
21039 var toColor = this.to.options.color.highlight.border;
21040
21041 if (this.from.selected === false && this.to.selected === false) {
21042 fromColor = overrideOpacity(this.from.options.color.border, values.opacity);
21043 toColor = overrideOpacity(this.to.options.color.border, values.opacity);
21044 } else if (this.from.selected === true && this.to.selected === false) {
21045 toColor = this.to.options.color.border;
21046 } else if (this.from.selected === false && this.to.selected === true) {
21047 fromColor = this.from.options.color.border;
21048 }
21049
21050 grd.addColorStop(0, fromColor);
21051 grd.addColorStop(1, toColor); // -------------------- this returns -------------------- //
21052
21053 return grd;
21054 }
21055
21056 if (values.inheritsColor === "to") {
21057 return overrideOpacity(this.to.options.color.border, values.opacity);
21058 } else {
21059 // "from"
21060 return overrideOpacity(this.from.options.color.border, values.opacity);
21061 }
21062 } else {
21063 return overrideOpacity(values.color, values.opacity);
21064 }
21065 }
21066 /**
21067 * Draw a line from a node to itself, a circle.
21068 *
21069 * @param ctx - The context that will be used for rendering.
21070 * @param values - Formatting values like color, opacity or shadow.
21071 * @param x - Center of the circle on the x axis.
21072 * @param y - Center of the circle on the y axis.
21073 * @param radius - Radius of the circle.
21074 */
21075
21076 }, {
21077 key: "_circle",
21078 value: function _circle(ctx, values, x, y, radius) {
21079 // draw shadow if enabled
21080 this.enableShadow(ctx, values); //full circle
21081
21082 var angleFrom = 0;
21083 var angleTo = Math.PI * 2;
21084
21085 if (!this.options.selfReference.renderBehindTheNode) {
21086 //render only parts which are not overlaping with parent node
21087 //need to find x,y of from point and x,y to point
21088 //calculating radians
21089 var low = this.options.selfReference.angle;
21090 var high = this.options.selfReference.angle + Math.PI;
21091
21092 var pointTFrom = this._findBorderPositionCircle(this.from, ctx, {
21093 x: x,
21094 y: y,
21095 low: low,
21096 high: high,
21097 direction: -1
21098 });
21099
21100 var pointTTo = this._findBorderPositionCircle(this.from, ctx, {
21101 x: x,
21102 y: y,
21103 low: low,
21104 high: high,
21105 direction: 1
21106 });
21107
21108 angleFrom = Math.atan2(pointTFrom.y - y, pointTFrom.x - x);
21109 angleTo = Math.atan2(pointTTo.y - y, pointTTo.x - x);
21110 } // draw a circle
21111
21112
21113 ctx.beginPath();
21114 ctx.arc(x, y, radius, angleFrom, angleTo, false);
21115 ctx.stroke(); // disable shadows for other elements.
21116
21117 this.disableShadow(ctx, values);
21118 }
21119 /**
21120 * @inheritDoc
21121 *
21122 * @remarks
21123 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
21124 */
21125
21126 }, {
21127 key: "getDistanceToEdge",
21128 value: function getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
21129 if (this.from != this.to) {
21130 return this._getDistanceToEdge(x1, y1, x2, y2, x3, y3);
21131 } else {
21132 var _this$_getCircleData7 = this._getCircleData(undefined),
21133 _this$_getCircleData8 = _slicedToArray(_this$_getCircleData7, 3),
21134 x = _this$_getCircleData8[0],
21135 y = _this$_getCircleData8[1],
21136 radius = _this$_getCircleData8[2];
21137
21138 var dx = x - x3;
21139 var dy = y - y3;
21140 return Math.abs(Math.sqrt(dx * dx + dy * dy) - radius);
21141 }
21142 }
21143 /**
21144 * Calculate the distance between a point (x3, y3) and a line segment from (x1, y1) to (x2, y2).
21145 *
21146 * @param x1 - First end of the line segment on the x axis.
21147 * @param y1 - First end of the line segment on the y axis.
21148 * @param x2 - Second end of the line segment on the x axis.
21149 * @param y2 - Second end of the line segment on the y axis.
21150 * @param x3 - Position of the point on the x axis.
21151 * @param y3 - Position of the point on the y axis.
21152 *
21153 * @returns The distance between the line segment and the point.
21154 */
21155
21156 }, {
21157 key: "_getDistanceToLine",
21158 value: function _getDistanceToLine(x1, y1, x2, y2, x3, y3) {
21159 var px = x2 - x1;
21160 var py = y2 - y1;
21161 var something = px * px + py * py;
21162 var u = ((x3 - x1) * px + (y3 - y1) * py) / something;
21163
21164 if (u > 1) {
21165 u = 1;
21166 } else if (u < 0) {
21167 u = 0;
21168 }
21169
21170 var x = x1 + u * px;
21171 var y = y1 + u * py;
21172 var dx = x - x3;
21173 var dy = y - y3; //# Note: If the actual distance does not matter,
21174 //# if you only want to compare what this function
21175 //# returns to other results of this function, you
21176 //# can just return the squared distance instead
21177 //# (i.e. remove the sqrt) to gain a little performance
21178
21179 return Math.sqrt(dx * dx + dy * dy);
21180 }
21181 /** @inheritDoc */
21182
21183 }, {
21184 key: "getArrowData",
21185 value: function getArrowData(ctx, position, viaNode, _selected, _hover, values) {
21186 // set lets
21187 var angle;
21188 var arrowPoint;
21189 var node1;
21190 var node2;
21191 var reversed;
21192 var scaleFactor;
21193 var type;
21194 var lineWidth = values.width;
21195
21196 if (position === "from") {
21197 node1 = this.from;
21198 node2 = this.to;
21199 reversed = values.fromArrowScale < 0;
21200 scaleFactor = Math.abs(values.fromArrowScale);
21201 type = values.fromArrowType;
21202 } else if (position === "to") {
21203 node1 = this.to;
21204 node2 = this.from;
21205 reversed = values.toArrowScale < 0;
21206 scaleFactor = Math.abs(values.toArrowScale);
21207 type = values.toArrowType;
21208 } else {
21209 node1 = this.to;
21210 node2 = this.from;
21211 reversed = values.middleArrowScale < 0;
21212 scaleFactor = Math.abs(values.middleArrowScale);
21213 type = values.middleArrowType;
21214 }
21215
21216 var length = 15 * scaleFactor + 3 * lineWidth; // 3* lineWidth is the width of the edge.
21217 // if not connected to itself
21218
21219 if (node1 != node2) {
21220 var approximateEdgeLength = hypot(node1.x - node2.x, node1.y - node2.y);
21221
21222 var relativeLength = length / approximateEdgeLength;
21223
21224 if (position !== "middle") {
21225 // draw arrow head
21226 if (this.options.smooth.enabled === true) {
21227 var pointT = this._findBorderPosition(node1, ctx, {
21228 via: viaNode
21229 });
21230
21231 var guidePos = this.getPoint(pointT.t + relativeLength * (position === "from" ? 1 : -1), viaNode);
21232 angle = Math.atan2(pointT.y - guidePos.y, pointT.x - guidePos.x);
21233 arrowPoint = pointT;
21234 } else {
21235 angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
21236 arrowPoint = this._findBorderPosition(node1, ctx);
21237 }
21238 } else {
21239 // Negative half length reverses arrow direction.
21240 var halfLength = (reversed ? -relativeLength : relativeLength) / 2;
21241 var guidePos1 = this.getPoint(0.5 + halfLength, viaNode);
21242 var guidePos2 = this.getPoint(0.5 - halfLength, viaNode);
21243 angle = Math.atan2(guidePos1.y - guidePos2.y, guidePos1.x - guidePos2.x);
21244 arrowPoint = this.getPoint(0.5, viaNode);
21245 }
21246 } else {
21247 // draw circle
21248 var _this$_getCircleData9 = this._getCircleData(ctx),
21249 _this$_getCircleData10 = _slicedToArray(_this$_getCircleData9, 3),
21250 x = _this$_getCircleData10[0],
21251 y = _this$_getCircleData10[1],
21252 radius = _this$_getCircleData10[2];
21253
21254 if (position === "from") {
21255 var low = this.options.selfReference.angle;
21256 var high = this.options.selfReference.angle + Math.PI;
21257
21258 var _pointT = this._findBorderPositionCircle(this.from, ctx, {
21259 x: x,
21260 y: y,
21261 low: low,
21262 high: high,
21263 direction: -1
21264 });
21265
21266 angle = _pointT.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
21267 arrowPoint = _pointT;
21268 } else if (position === "to") {
21269 var _low = this.options.selfReference.angle;
21270
21271 var _high = this.options.selfReference.angle + Math.PI;
21272
21273 var _pointT2 = this._findBorderPositionCircle(this.from, ctx, {
21274 x: x,
21275 y: y,
21276 low: _low,
21277 high: _high,
21278 direction: 1
21279 });
21280
21281 angle = _pointT2.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI;
21282 arrowPoint = _pointT2;
21283 } else {
21284 var pos = this.options.selfReference.angle / (2 * Math.PI);
21285 arrowPoint = this._pointOnCircle(x, y, radius, pos);
21286 angle = pos * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
21287 }
21288 }
21289
21290 var xi = arrowPoint.x - length * 0.9 * Math.cos(angle);
21291 var yi = arrowPoint.y - length * 0.9 * Math.sin(angle);
21292 var arrowCore = {
21293 x: xi,
21294 y: yi
21295 };
21296 return {
21297 point: arrowPoint,
21298 core: arrowCore,
21299 angle: angle,
21300 length: length,
21301 type: type
21302 };
21303 }
21304 /** @inheritDoc */
21305
21306 }, {
21307 key: "drawArrowHead",
21308 value: function drawArrowHead(ctx, values, _selected, _hover, arrowData) {
21309 // set style
21310 ctx.strokeStyle = this.getColor(ctx, values);
21311 ctx.fillStyle = ctx.strokeStyle;
21312 ctx.lineWidth = values.width;
21313 var canFill = EndPoints.draw(ctx, arrowData);
21314
21315 if (canFill) {
21316 // draw shadow if enabled
21317 this.enableShadow(ctx, values);
21318
21319 fill(ctx).call(ctx); // disable shadows for other elements.
21320
21321
21322 this.disableShadow(ctx, values);
21323 }
21324 }
21325 /**
21326 * Set the shadow formatting values in the context if enabled, do nothing otherwise.
21327 *
21328 * @param ctx - The context that will be used for rendering.
21329 * @param values - Formatting values for the shadow.
21330 */
21331
21332 }, {
21333 key: "enableShadow",
21334 value: function enableShadow(ctx, values) {
21335 if (values.shadow === true) {
21336 ctx.shadowColor = values.shadowColor;
21337 ctx.shadowBlur = values.shadowSize;
21338 ctx.shadowOffsetX = values.shadowX;
21339 ctx.shadowOffsetY = values.shadowY;
21340 }
21341 }
21342 /**
21343 * Reset the shadow formatting values in the context if enabled, do nothing otherwise.
21344 *
21345 * @param ctx - The context that will be used for rendering.
21346 * @param values - Formatting values for the shadow.
21347 */
21348
21349 }, {
21350 key: "disableShadow",
21351 value: function disableShadow(ctx, values) {
21352 if (values.shadow === true) {
21353 ctx.shadowColor = "rgba(0,0,0,0)";
21354 ctx.shadowBlur = 0;
21355 ctx.shadowOffsetX = 0;
21356 ctx.shadowOffsetY = 0;
21357 }
21358 }
21359 /**
21360 * Render the background according to the formatting values.
21361 *
21362 * @param ctx - The context that will be used for rendering.
21363 * @param values - Formatting values for the background.
21364 */
21365
21366 }, {
21367 key: "drawBackground",
21368 value: function drawBackground(ctx, values) {
21369 if (values.background !== false) {
21370 // save original line attrs
21371 var origCtxAttr = {
21372 strokeStyle: ctx.strokeStyle,
21373 lineWidth: ctx.lineWidth,
21374 dashes: ctx.dashes
21375 };
21376 ctx.strokeStyle = values.backgroundColor;
21377 ctx.lineWidth = values.backgroundSize;
21378 this.setStrokeDashed(ctx, values.backgroundDashes);
21379 ctx.stroke(); // restore original line attrs
21380
21381 ctx.strokeStyle = origCtxAttr.strokeStyle;
21382 ctx.lineWidth = origCtxAttr.lineWidth;
21383 ctx.dashes = origCtxAttr.dashes;
21384 this.setStrokeDashed(ctx, values.dashes);
21385 }
21386 }
21387 /**
21388 * Set the line dash pattern if supported. Logs a warning to the console if it isn't supported.
21389 *
21390 * @param ctx - The context that will be used for rendering.
21391 * @param dashes - The pattern [line, space, line…], true for default dashed line or false for normal line.
21392 */
21393
21394 }, {
21395 key: "setStrokeDashed",
21396 value: function setStrokeDashed(ctx, dashes) {
21397 if (dashes !== false) {
21398 if (ctx.setLineDash !== undefined) {
21399 var pattern = isArray$1(dashes) ? dashes : [5, 5];
21400 ctx.setLineDash(pattern);
21401 } else {
21402 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
21403 }
21404 } else {
21405 if (ctx.setLineDash !== undefined) {
21406 ctx.setLineDash([]);
21407 } else {
21408 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
21409 }
21410 }
21411 }
21412 }]);
21413
21414 return EdgeBase;
21415 }();
21416
21417 function ownKeys(object, enumerableOnly) { var keys$1 = keys(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); if (enumerableOnly) { symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$2(object, sym).enumerable; }); } keys$1.push.apply(keys$1, symbols); } return keys$1; }
21418
21419 function _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; }
21420
21421 function _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); }; }
21422
21423 function _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; } }
21424 /**
21425 * The Base Class for all Bezier edges.
21426 * Bezier curves are used to model smooth gradual curves in paths between nodes.
21427 */
21428
21429 var BezierEdgeBase = /*#__PURE__*/function (_EdgeBase) {
21430 _inherits(BezierEdgeBase, _EdgeBase);
21431
21432 var _super = _createSuper$9(BezierEdgeBase);
21433
21434 /**
21435 * Create a new instance.
21436 *
21437 * @param options - The options object of given edge.
21438 * @param body - The body of the network.
21439 * @param labelModule - Label module.
21440 */
21441 function BezierEdgeBase(options, body, labelModule) {
21442 _classCallCheck(this, BezierEdgeBase);
21443
21444 return _super.call(this, options, body, labelModule);
21445 }
21446 /**
21447 * Find the intersection between the border of the node and the edge.
21448 *
21449 * @remarks
21450 * This function uses binary search to look for the point where the bezier curve crosses the border of the node.
21451 *
21452 * @param nearNode - The node (either from or to node of the edge).
21453 * @param ctx - The context that will be used for rendering.
21454 * @param viaNode - Additional node(s) the edge passes through.
21455 *
21456 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
21457 */
21458
21459
21460 _createClass(BezierEdgeBase, [{
21461 key: "_findBorderPositionBezier",
21462 value: function _findBorderPositionBezier(nearNode, ctx) {
21463 var viaNode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this._getViaCoordinates();
21464 var maxIterations = 10;
21465 var threshold = 0.2;
21466 var from = false;
21467 var high = 1;
21468 var low = 0;
21469 var node = this.to;
21470 var pos;
21471 var middle;
21472 var endPointOffset = this.options.endPointOffset ? this.options.endPointOffset.to : 0;
21473
21474 if (nearNode.id === this.from.id) {
21475 node = this.from;
21476 from = true;
21477 endPointOffset = this.options.endPointOffset ? this.options.endPointOffset.from : 0;
21478 }
21479
21480 if (this.options.arrowStrikethrough === false) {
21481 endPointOffset = 0;
21482 }
21483
21484 var iteration = 0;
21485
21486 do {
21487 middle = (low + high) * 0.5;
21488 pos = this.getPoint(middle, viaNode);
21489 var angle = Math.atan2(node.y - pos.y, node.x - pos.x);
21490 var distanceToBorder = node.distanceToBorder(ctx, angle) + endPointOffset;
21491 var distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2));
21492 var difference = distanceToBorder - distanceToPoint;
21493
21494 if (Math.abs(difference) < threshold) {
21495 break; // found
21496 } else if (difference < 0) {
21497 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
21498 if (from === false) {
21499 low = middle;
21500 } else {
21501 high = middle;
21502 }
21503 } else {
21504 if (from === false) {
21505 high = middle;
21506 } else {
21507 low = middle;
21508 }
21509 }
21510
21511 ++iteration;
21512 } while (low <= high && iteration < maxIterations);
21513
21514 return _objectSpread(_objectSpread({}, pos), {}, {
21515 t: middle
21516 });
21517 }
21518 /**
21519 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
21520 *
21521 * @remarks
21522 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
21523 *
21524 * @param x1 - First end of the line segment on the x axis.
21525 * @param y1 - First end of the line segment on the y axis.
21526 * @param x2 - Second end of the line segment on the x axis.
21527 * @param y2 - Second end of the line segment on the y axis.
21528 * @param x3 - Position of the point on the x axis.
21529 * @param y3 - Position of the point on the y axis.
21530 * @param via - The control point for the edge.
21531 *
21532 * @returns The distance between the line segment and the point.
21533 */
21534
21535 }, {
21536 key: "_getDistanceToBezierEdge",
21537 value: function _getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via) {
21538 // x3,y3 is the point
21539 var minDistance = 1e9;
21540 var distance;
21541 var i, t, x, y;
21542 var lastX = x1;
21543 var lastY = y1;
21544
21545 for (i = 1; i < 10; i++) {
21546 t = 0.1 * i;
21547 x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * via.x + Math.pow(t, 2) * x2;
21548 y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * via.y + Math.pow(t, 2) * y2;
21549
21550 if (i > 0) {
21551 distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
21552 minDistance = distance < minDistance ? distance : minDistance;
21553 }
21554
21555 lastX = x;
21556 lastY = y;
21557 }
21558
21559 return minDistance;
21560 }
21561 /**
21562 * Render a bezier curve between two nodes.
21563 *
21564 * @remarks
21565 * The method accepts zero, one or two control points.
21566 * Passing zero control points just draws a straight line.
21567 *
21568 * @param ctx - The context that will be used for rendering.
21569 * @param values - Style options for edge drawing.
21570 * @param viaNode1 - First control point for curve drawing.
21571 * @param viaNode2 - Second control point for curve drawing.
21572 */
21573
21574 }, {
21575 key: "_bezierCurve",
21576 value: function _bezierCurve(ctx, values, viaNode1, viaNode2) {
21577 ctx.beginPath();
21578 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
21579
21580 if (viaNode1 != null && viaNode1.x != null) {
21581 if (viaNode2 != null && viaNode2.x != null) {
21582 ctx.bezierCurveTo(viaNode1.x, viaNode1.y, viaNode2.x, viaNode2.y, this.toPoint.x, this.toPoint.y);
21583 } else {
21584 ctx.quadraticCurveTo(viaNode1.x, viaNode1.y, this.toPoint.x, this.toPoint.y);
21585 }
21586 } else {
21587 // fallback to normal straight edge
21588 ctx.lineTo(this.toPoint.x, this.toPoint.y);
21589 } // draw a background
21590
21591
21592 this.drawBackground(ctx, values); // draw shadow if enabled
21593
21594 this.enableShadow(ctx, values);
21595 ctx.stroke();
21596 this.disableShadow(ctx, values);
21597 }
21598 /** @inheritDoc */
21599
21600 }, {
21601 key: "getViaNode",
21602 value: function getViaNode() {
21603 return this._getViaCoordinates();
21604 }
21605 }]);
21606
21607 return BezierEdgeBase;
21608 }(EdgeBase);
21609
21610 function _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); }; }
21611
21612 function _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; } }
21613 /**
21614 * A Dynamic Bezier Edge. Bezier curves are used to model smooth gradual
21615 * curves in paths between nodes. The Dynamic piece refers to how the curve
21616 * reacts to physics changes.
21617 *
21618 * @augments BezierEdgeBase
21619 */
21620
21621 var BezierEdgeDynamic = /*#__PURE__*/function (_BezierEdgeBase) {
21622 _inherits(BezierEdgeDynamic, _BezierEdgeBase);
21623
21624 var _super = _createSuper$8(BezierEdgeDynamic);
21625
21626 /**
21627 * Create a new instance.
21628 *
21629 * @param options - The options object of given edge.
21630 * @param body - The body of the network.
21631 * @param labelModule - Label module.
21632 */
21633 function BezierEdgeDynamic(options, body, labelModule) {
21634 var _this;
21635
21636 _classCallCheck(this, BezierEdgeDynamic);
21637
21638 //this.via = undefined; // Here for completeness but not allowed to defined before super() is invoked.
21639 _this = _super.call(this, options, body, labelModule); // --> this calls the setOptions below
21640
21641 _this.via = _this.via; // constructor → super → super → setOptions → setupSupportNode
21642
21643 _this._boundFunction = function () {
21644 _this.positionBezierNode();
21645 };
21646
21647 _this._body.emitter.on("_repositionBezierNodes", _this._boundFunction);
21648
21649 return _this;
21650 }
21651 /** @inheritDoc */
21652
21653
21654 _createClass(BezierEdgeDynamic, [{
21655 key: "setOptions",
21656 value: function setOptions(options) {
21657 _get(_getPrototypeOf(BezierEdgeDynamic.prototype), "setOptions", this).call(this, options); // check if the physics has changed.
21658
21659
21660 var physicsChange = false;
21661
21662 if (this.options.physics !== options.physics) {
21663 physicsChange = true;
21664 } // set the options and the to and from nodes
21665
21666
21667 this.options = options;
21668 this.id = this.options.id;
21669 this.from = this._body.nodes[this.options.from];
21670 this.to = this._body.nodes[this.options.to]; // setup the support node and connect
21671
21672 this.setupSupportNode();
21673 this.connect(); // when we change the physics state of the edge, we reposition the support node.
21674
21675 if (physicsChange === true) {
21676 this.via.setOptions({
21677 physics: this.options.physics
21678 });
21679 this.positionBezierNode();
21680 }
21681 }
21682 /** @inheritDoc */
21683
21684 }, {
21685 key: "connect",
21686 value: function connect() {
21687 this.from = this._body.nodes[this.options.from];
21688 this.to = this._body.nodes[this.options.to];
21689
21690 if (this.from === undefined || this.to === undefined || this.options.physics === false) {
21691 this.via.setOptions({
21692 physics: false
21693 });
21694 } else {
21695 // fix weird behaviour where a self referencing node has physics enabled
21696 if (this.from.id === this.to.id) {
21697 this.via.setOptions({
21698 physics: false
21699 });
21700 } else {
21701 this.via.setOptions({
21702 physics: true
21703 });
21704 }
21705 }
21706 }
21707 /** @inheritDoc */
21708
21709 }, {
21710 key: "cleanup",
21711 value: function cleanup() {
21712 this._body.emitter.off("_repositionBezierNodes", this._boundFunction);
21713
21714 if (this.via !== undefined) {
21715 delete this._body.nodes[this.via.id];
21716 this.via = undefined;
21717 return true;
21718 }
21719
21720 return false;
21721 }
21722 /**
21723 * Create and add a support node if not already present.
21724 *
21725 * @remarks
21726 * Bezier curves require an anchor point to calculate the smooth flow.
21727 * These points are nodes.
21728 * These nodes are invisible but are used for the force calculation.
21729 *
21730 * The changed data is not called, if needed, it is returned by the main edge constructor.
21731 */
21732
21733 }, {
21734 key: "setupSupportNode",
21735 value: function setupSupportNode() {
21736 if (this.via === undefined) {
21737 var nodeId = "edgeId:" + this.id;
21738
21739 var node = this._body.functions.createNode({
21740 id: nodeId,
21741 shape: "circle",
21742 physics: true,
21743 hidden: true
21744 });
21745
21746 this._body.nodes[nodeId] = node;
21747 this.via = node;
21748 this.via.parentEdgeId = this.id;
21749 this.positionBezierNode();
21750 }
21751 }
21752 /**
21753 * Position bezier node.
21754 */
21755
21756 }, {
21757 key: "positionBezierNode",
21758 value: function positionBezierNode() {
21759 if (this.via !== undefined && this.from !== undefined && this.to !== undefined) {
21760 this.via.x = 0.5 * (this.from.x + this.to.x);
21761 this.via.y = 0.5 * (this.from.y + this.to.y);
21762 } else if (this.via !== undefined) {
21763 this.via.x = 0;
21764 this.via.y = 0;
21765 }
21766 }
21767 /** @inheritDoc */
21768
21769 }, {
21770 key: "_line",
21771 value: function _line(ctx, values, viaNode) {
21772 this._bezierCurve(ctx, values, viaNode);
21773 }
21774 /** @inheritDoc */
21775
21776 }, {
21777 key: "_getViaCoordinates",
21778 value: function _getViaCoordinates() {
21779 return this.via;
21780 }
21781 /** @inheritDoc */
21782
21783 }, {
21784 key: "getViaNode",
21785 value: function getViaNode() {
21786 return this.via;
21787 }
21788 /** @inheritDoc */
21789
21790 }, {
21791 key: "getPoint",
21792 value: function getPoint(position) {
21793 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.via;
21794
21795 if (this.from === this.to) {
21796 var _this$_getCircleData = this._getCircleData(),
21797 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
21798 cx = _this$_getCircleData2[0],
21799 cy = _this$_getCircleData2[1],
21800 cr = _this$_getCircleData2[2];
21801
21802 var a = 2 * Math.PI * (1 - position);
21803 return {
21804 x: cx + cr * Math.sin(a),
21805 y: cy + cr - cr * (1 - Math.cos(a))
21806 };
21807 } else {
21808 return {
21809 x: Math.pow(1 - position, 2) * this.fromPoint.x + 2 * position * (1 - position) * viaNode.x + Math.pow(position, 2) * this.toPoint.x,
21810 y: Math.pow(1 - position, 2) * this.fromPoint.y + 2 * position * (1 - position) * viaNode.y + Math.pow(position, 2) * this.toPoint.y
21811 };
21812 }
21813 }
21814 /** @inheritDoc */
21815
21816 }, {
21817 key: "_findBorderPosition",
21818 value: function _findBorderPosition(nearNode, ctx) {
21819 return this._findBorderPositionBezier(nearNode, ctx, this.via);
21820 }
21821 /** @inheritDoc */
21822
21823 }, {
21824 key: "_getDistanceToEdge",
21825 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
21826 // x3,y3 is the point
21827 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, this.via);
21828 }
21829 }]);
21830
21831 return BezierEdgeDynamic;
21832 }(BezierEdgeBase);
21833
21834 function _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); }; }
21835
21836 function _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; } }
21837 /**
21838 * A Static Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
21839 */
21840
21841 var BezierEdgeStatic = /*#__PURE__*/function (_BezierEdgeBase) {
21842 _inherits(BezierEdgeStatic, _BezierEdgeBase);
21843
21844 var _super = _createSuper$7(BezierEdgeStatic);
21845
21846 /**
21847 * Create a new instance.
21848 *
21849 * @param options - The options object of given edge.
21850 * @param body - The body of the network.
21851 * @param labelModule - Label module.
21852 */
21853 function BezierEdgeStatic(options, body, labelModule) {
21854 _classCallCheck(this, BezierEdgeStatic);
21855
21856 return _super.call(this, options, body, labelModule);
21857 }
21858 /** @inheritDoc */
21859
21860
21861 _createClass(BezierEdgeStatic, [{
21862 key: "_line",
21863 value: function _line(ctx, values, viaNode) {
21864 this._bezierCurve(ctx, values, viaNode);
21865 }
21866 /** @inheritDoc */
21867
21868 }, {
21869 key: "getViaNode",
21870 value: function getViaNode() {
21871 return this._getViaCoordinates();
21872 }
21873 /**
21874 * Compute the coordinates of the via node.
21875 *
21876 * @remarks
21877 * We do not use the to and fromPoints here to make the via nodes the same as edges without arrows.
21878 *
21879 * @returns Cartesian coordinates of the via node.
21880 */
21881
21882 }, {
21883 key: "_getViaCoordinates",
21884 value: function _getViaCoordinates() {
21885 // Assumption: x/y coordinates in from/to always defined
21886 var factor = this.options.smooth.roundness;
21887 var type = this.options.smooth.type;
21888 var dx = Math.abs(this.from.x - this.to.x);
21889 var dy = Math.abs(this.from.y - this.to.y);
21890
21891 if (type === "discrete" || type === "diagonalCross") {
21892 var stepX;
21893 var stepY;
21894
21895 if (dx <= dy) {
21896 stepX = stepY = factor * dy;
21897 } else {
21898 stepX = stepY = factor * dx;
21899 }
21900
21901 if (this.from.x > this.to.x) {
21902 stepX = -stepX;
21903 }
21904
21905 if (this.from.y >= this.to.y) {
21906 stepY = -stepY;
21907 }
21908
21909 var xVia = this.from.x + stepX;
21910 var yVia = this.from.y + stepY;
21911
21912 if (type === "discrete") {
21913 if (dx <= dy) {
21914 xVia = dx < factor * dy ? this.from.x : xVia;
21915 } else {
21916 yVia = dy < factor * dx ? this.from.y : yVia;
21917 }
21918 }
21919
21920 return {
21921 x: xVia,
21922 y: yVia
21923 };
21924 } else if (type === "straightCross") {
21925 var _stepX = (1 - factor) * dx;
21926
21927 var _stepY = (1 - factor) * dy;
21928
21929 if (dx <= dy) {
21930 // up - down
21931 _stepX = 0;
21932
21933 if (this.from.y < this.to.y) {
21934 _stepY = -_stepY;
21935 }
21936 } else {
21937 // left - right
21938 if (this.from.x < this.to.x) {
21939 _stepX = -_stepX;
21940 }
21941
21942 _stepY = 0;
21943 }
21944
21945 return {
21946 x: this.to.x + _stepX,
21947 y: this.to.y + _stepY
21948 };
21949 } else if (type === "horizontal") {
21950 var _stepX2 = (1 - factor) * dx;
21951
21952 if (this.from.x < this.to.x) {
21953 _stepX2 = -_stepX2;
21954 }
21955
21956 return {
21957 x: this.to.x + _stepX2,
21958 y: this.from.y
21959 };
21960 } else if (type === "vertical") {
21961 var _stepY2 = (1 - factor) * dy;
21962
21963 if (this.from.y < this.to.y) {
21964 _stepY2 = -_stepY2;
21965 }
21966
21967 return {
21968 x: this.from.x,
21969 y: this.to.y + _stepY2
21970 };
21971 } else if (type === "curvedCW") {
21972 dx = this.to.x - this.from.x;
21973 dy = this.from.y - this.to.y;
21974 var radius = Math.sqrt(dx * dx + dy * dy);
21975 var pi = Math.PI;
21976 var originalAngle = Math.atan2(dy, dx);
21977 var myAngle = (originalAngle + (factor * 0.5 + 0.5) * pi) % (2 * pi);
21978 return {
21979 x: this.from.x + (factor * 0.5 + 0.5) * radius * Math.sin(myAngle),
21980 y: this.from.y + (factor * 0.5 + 0.5) * radius * Math.cos(myAngle)
21981 };
21982 } else if (type === "curvedCCW") {
21983 dx = this.to.x - this.from.x;
21984 dy = this.from.y - this.to.y;
21985
21986 var _radius = Math.sqrt(dx * dx + dy * dy);
21987
21988 var _pi = Math.PI;
21989
21990 var _originalAngle = Math.atan2(dy, dx);
21991
21992 var _myAngle = (_originalAngle + (-factor * 0.5 + 0.5) * _pi) % (2 * _pi);
21993
21994 return {
21995 x: this.from.x + (factor * 0.5 + 0.5) * _radius * Math.sin(_myAngle),
21996 y: this.from.y + (factor * 0.5 + 0.5) * _radius * Math.cos(_myAngle)
21997 };
21998 } else {
21999 // continuous
22000 var _stepX3;
22001
22002 var _stepY3;
22003
22004 if (dx <= dy) {
22005 _stepX3 = _stepY3 = factor * dy;
22006 } else {
22007 _stepX3 = _stepY3 = factor * dx;
22008 }
22009
22010 if (this.from.x > this.to.x) {
22011 _stepX3 = -_stepX3;
22012 }
22013
22014 if (this.from.y >= this.to.y) {
22015 _stepY3 = -_stepY3;
22016 }
22017
22018 var _xVia = this.from.x + _stepX3;
22019
22020 var _yVia = this.from.y + _stepY3;
22021
22022 if (dx <= dy) {
22023 if (this.from.x <= this.to.x) {
22024 _xVia = this.to.x < _xVia ? this.to.x : _xVia;
22025 } else {
22026 _xVia = this.to.x > _xVia ? this.to.x : _xVia;
22027 }
22028 } else {
22029 if (this.from.y >= this.to.y) {
22030 _yVia = this.to.y > _yVia ? this.to.y : _yVia;
22031 } else {
22032 _yVia = this.to.y < _yVia ? this.to.y : _yVia;
22033 }
22034 }
22035
22036 return {
22037 x: _xVia,
22038 y: _yVia
22039 };
22040 }
22041 }
22042 /** @inheritDoc */
22043
22044 }, {
22045 key: "_findBorderPosition",
22046 value: function _findBorderPosition(nearNode, ctx) {
22047 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
22048 return this._findBorderPositionBezier(nearNode, ctx, options.via);
22049 }
22050 /** @inheritDoc */
22051
22052 }, {
22053 key: "_getDistanceToEdge",
22054 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
22055 var viaNode = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates();
22056 // x3,y3 is the point
22057 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, viaNode);
22058 }
22059 /** @inheritDoc */
22060
22061 }, {
22062 key: "getPoint",
22063 value: function getPoint(position) {
22064 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates();
22065 var t = position;
22066 var x = Math.pow(1 - t, 2) * this.fromPoint.x + 2 * t * (1 - t) * viaNode.x + Math.pow(t, 2) * this.toPoint.x;
22067 var y = Math.pow(1 - t, 2) * this.fromPoint.y + 2 * t * (1 - t) * viaNode.y + Math.pow(t, 2) * this.toPoint.y;
22068 return {
22069 x: x,
22070 y: y
22071 };
22072 }
22073 }]);
22074
22075 return BezierEdgeStatic;
22076 }(BezierEdgeBase);
22077
22078 function _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); }; }
22079
22080 function _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; } }
22081 /**
22082 * A Base Class for all Cubic Bezier Edges. Bezier curves are used to model
22083 * smooth gradual curves in paths between nodes.
22084 *
22085 * @augments BezierEdgeBase
22086 */
22087
22088 var CubicBezierEdgeBase = /*#__PURE__*/function (_BezierEdgeBase) {
22089 _inherits(CubicBezierEdgeBase, _BezierEdgeBase);
22090
22091 var _super = _createSuper$6(CubicBezierEdgeBase);
22092
22093 /**
22094 * Create a new instance.
22095 *
22096 * @param options - The options object of given edge.
22097 * @param body - The body of the network.
22098 * @param labelModule - Label module.
22099 */
22100 function CubicBezierEdgeBase(options, body, labelModule) {
22101 _classCallCheck(this, CubicBezierEdgeBase);
22102
22103 return _super.call(this, options, body, labelModule);
22104 }
22105 /**
22106 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
22107 *
22108 * @remarks
22109 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
22110 * https://en.wikipedia.org/wiki/B%C3%A9zier_curve
22111 *
22112 * @param x1 - First end of the line segment on the x axis.
22113 * @param y1 - First end of the line segment on the y axis.
22114 * @param x2 - Second end of the line segment on the x axis.
22115 * @param y2 - Second end of the line segment on the y axis.
22116 * @param x3 - Position of the point on the x axis.
22117 * @param y3 - Position of the point on the y axis.
22118 * @param via1 - The first point this edge passes through.
22119 * @param via2 - The second point this edge passes through.
22120 *
22121 * @returns The distance between the line segment and the point.
22122 */
22123
22124
22125 _createClass(CubicBezierEdgeBase, [{
22126 key: "_getDistanceToBezierEdge2",
22127 value: function _getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2) {
22128 // x3,y3 is the point
22129 var minDistance = 1e9;
22130 var lastX = x1;
22131 var lastY = y1;
22132 var vec = [0, 0, 0, 0];
22133
22134 for (var i = 1; i < 10; i++) {
22135 var t = 0.1 * i;
22136 vec[0] = Math.pow(1 - t, 3);
22137 vec[1] = 3 * t * Math.pow(1 - t, 2);
22138 vec[2] = 3 * Math.pow(t, 2) * (1 - t);
22139 vec[3] = Math.pow(t, 3);
22140 var x = vec[0] * x1 + vec[1] * via1.x + vec[2] * via2.x + vec[3] * x2;
22141 var y = vec[0] * y1 + vec[1] * via1.y + vec[2] * via2.y + vec[3] * y2;
22142
22143 if (i > 0) {
22144 var distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
22145
22146 minDistance = distance < minDistance ? distance : minDistance;
22147 }
22148
22149 lastX = x;
22150 lastY = y;
22151 }
22152
22153 return minDistance;
22154 }
22155 }]);
22156
22157 return CubicBezierEdgeBase;
22158 }(BezierEdgeBase);
22159
22160 function _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); }; }
22161
22162 function _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; } }
22163 /**
22164 * A Cubic Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
22165 */
22166
22167 var CubicBezierEdge = /*#__PURE__*/function (_CubicBezierEdgeBase) {
22168 _inherits(CubicBezierEdge, _CubicBezierEdgeBase);
22169
22170 var _super = _createSuper$5(CubicBezierEdge);
22171
22172 /**
22173 * Create a new instance.
22174 *
22175 * @param options - The options object of given edge.
22176 * @param body - The body of the network.
22177 * @param labelModule - Label module.
22178 */
22179 function CubicBezierEdge(options, body, labelModule) {
22180 _classCallCheck(this, CubicBezierEdge);
22181
22182 return _super.call(this, options, body, labelModule);
22183 }
22184 /** @inheritDoc */
22185
22186
22187 _createClass(CubicBezierEdge, [{
22188 key: "_line",
22189 value: function _line(ctx, values, viaNodes) {
22190 // get the coordinates of the support points.
22191 var via1 = viaNodes[0];
22192 var via2 = viaNodes[1];
22193
22194 this._bezierCurve(ctx, values, via1, via2);
22195 }
22196 /**
22197 * Compute the additional points the edge passes through.
22198 *
22199 * @returns Cartesian coordinates of the points the edge passes through.
22200 */
22201
22202 }, {
22203 key: "_getViaCoordinates",
22204 value: function _getViaCoordinates() {
22205 var dx = this.from.x - this.to.x;
22206 var dy = this.from.y - this.to.y;
22207 var x1;
22208 var y1;
22209 var x2;
22210 var y2;
22211 var roundness = this.options.smooth.roundness; // horizontal if x > y or if direction is forced or if direction is horizontal
22212
22213 if ((Math.abs(dx) > Math.abs(dy) || this.options.smooth.forceDirection === true || this.options.smooth.forceDirection === "horizontal") && this.options.smooth.forceDirection !== "vertical") {
22214 y1 = this.from.y;
22215 y2 = this.to.y;
22216 x1 = this.from.x - roundness * dx;
22217 x2 = this.to.x + roundness * dx;
22218 } else {
22219 y1 = this.from.y - roundness * dy;
22220 y2 = this.to.y + roundness * dy;
22221 x1 = this.from.x;
22222 x2 = this.to.x;
22223 }
22224
22225 return [{
22226 x: x1,
22227 y: y1
22228 }, {
22229 x: x2,
22230 y: y2
22231 }];
22232 }
22233 /** @inheritDoc */
22234
22235 }, {
22236 key: "getViaNode",
22237 value: function getViaNode() {
22238 return this._getViaCoordinates();
22239 }
22240 /** @inheritDoc */
22241
22242 }, {
22243 key: "_findBorderPosition",
22244 value: function _findBorderPosition(nearNode, ctx) {
22245 return this._findBorderPositionBezier(nearNode, ctx);
22246 }
22247 /** @inheritDoc */
22248
22249 }, {
22250 key: "_getDistanceToEdge",
22251 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
22252 var _ref = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates(),
22253 _ref2 = _slicedToArray(_ref, 2),
22254 via1 = _ref2[0],
22255 via2 = _ref2[1];
22256
22257 // x3,y3 is the point
22258 return this._getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2);
22259 }
22260 /** @inheritDoc */
22261
22262 }, {
22263 key: "getPoint",
22264 value: function getPoint(position) {
22265 var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates(),
22266 _ref4 = _slicedToArray(_ref3, 2),
22267 via1 = _ref4[0],
22268 via2 = _ref4[1];
22269
22270 var t = position;
22271 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)];
22272 var x = vec[0] * this.fromPoint.x + vec[1] * via1.x + vec[2] * via2.x + vec[3] * this.toPoint.x;
22273 var y = vec[0] * this.fromPoint.y + vec[1] * via1.y + vec[2] * via2.y + vec[3] * this.toPoint.y;
22274 return {
22275 x: x,
22276 y: y
22277 };
22278 }
22279 }]);
22280
22281 return CubicBezierEdge;
22282 }(CubicBezierEdgeBase);
22283
22284 function _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); }; }
22285
22286 function _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; } }
22287 /**
22288 * A Straight Edge.
22289 */
22290
22291 var StraightEdge = /*#__PURE__*/function (_EdgeBase) {
22292 _inherits(StraightEdge, _EdgeBase);
22293
22294 var _super = _createSuper$4(StraightEdge);
22295
22296 /**
22297 * Create a new instance.
22298 *
22299 * @param options - The options object of given edge.
22300 * @param body - The body of the network.
22301 * @param labelModule - Label module.
22302 */
22303 function StraightEdge(options, body, labelModule) {
22304 _classCallCheck(this, StraightEdge);
22305
22306 return _super.call(this, options, body, labelModule);
22307 }
22308 /** @inheritDoc */
22309
22310
22311 _createClass(StraightEdge, [{
22312 key: "_line",
22313 value: function _line(ctx, values) {
22314 // draw a straight line
22315 ctx.beginPath();
22316 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
22317 ctx.lineTo(this.toPoint.x, this.toPoint.y); // draw shadow if enabled
22318
22319 this.enableShadow(ctx, values);
22320 ctx.stroke();
22321 this.disableShadow(ctx, values);
22322 }
22323 /** @inheritDoc */
22324
22325 }, {
22326 key: "getViaNode",
22327 value: function getViaNode() {
22328 return undefined;
22329 }
22330 /** @inheritDoc */
22331
22332 }, {
22333 key: "getPoint",
22334 value: function getPoint(position) {
22335 return {
22336 x: (1 - position) * this.fromPoint.x + position * this.toPoint.x,
22337 y: (1 - position) * this.fromPoint.y + position * this.toPoint.y
22338 };
22339 }
22340 /** @inheritDoc */
22341
22342 }, {
22343 key: "_findBorderPosition",
22344 value: function _findBorderPosition(nearNode, ctx) {
22345 var node1 = this.to;
22346 var node2 = this.from;
22347
22348 if (nearNode.id === this.from.id) {
22349 node1 = this.from;
22350 node2 = this.to;
22351 }
22352
22353 var angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
22354 var dx = node1.x - node2.x;
22355 var dy = node1.y - node2.y;
22356 var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
22357 var toBorderDist = nearNode.distanceToBorder(ctx, angle);
22358 var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
22359 return {
22360 x: (1 - toBorderPoint) * node2.x + toBorderPoint * node1.x,
22361 y: (1 - toBorderPoint) * node2.y + toBorderPoint * node1.y,
22362 t: 0
22363 };
22364 }
22365 /** @inheritDoc */
22366
22367 }, {
22368 key: "_getDistanceToEdge",
22369 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
22370 // x3,y3 is the point
22371 return this._getDistanceToLine(x1, y1, x2, y2, x3, y3);
22372 }
22373 }]);
22374
22375 return StraightEdge;
22376 }(EdgeBase);
22377
22378 /**
22379 * An edge connects two nodes and has a specific direction.
22380 */
22381
22382 var Edge = /*#__PURE__*/function () {
22383 /**
22384 * @param {object} options values specific to this edge, must contain at least 'from' and 'to'
22385 * @param {object} body shared state from Network instance
22386 * @param {Network.Images} imagelist A list with images. Only needed when the edge has image arrows.
22387 * @param {object} globalOptions options from the EdgesHandler instance
22388 * @param {object} defaultOptions default options from the EdgeHandler instance. Value and reference are constant
22389 */
22390 function Edge(options, body, imagelist, globalOptions, defaultOptions) {
22391 _classCallCheck(this, Edge);
22392
22393 if (body === undefined) {
22394 throw new Error("No body provided");
22395 } // Since globalOptions is constant in values as well as reference,
22396 // Following needs to be done only once.
22397
22398
22399 this.options = bridgeObject(globalOptions);
22400 this.globalOptions = globalOptions;
22401 this.defaultOptions = defaultOptions;
22402 this.body = body;
22403 this.imagelist = imagelist; // initialize variables
22404
22405 this.id = undefined;
22406 this.fromId = undefined;
22407 this.toId = undefined;
22408 this.selected = false;
22409 this.hover = false;
22410 this.labelDirty = true;
22411 this.baseWidth = this.options.width;
22412 this.baseFontSize = this.options.font.size;
22413 this.from = undefined; // a node
22414
22415 this.to = undefined; // a node
22416
22417 this.edgeType = undefined;
22418 this.connected = false;
22419 this.labelModule = new Label(this.body, this.options, true
22420 /* It's an edge label */
22421 );
22422 this.setOptions(options);
22423 }
22424 /**
22425 * Set or overwrite options for the edge
22426 *
22427 * @param {object} options an object with options
22428 * @returns {undefined|boolean} undefined if no options, true if layout affecting data changed, false otherwise.
22429 */
22430
22431
22432 _createClass(Edge, [{
22433 key: "setOptions",
22434 value: function setOptions(options) {
22435 if (!options) {
22436 return;
22437 } // Following options if changed affect the layout.
22438
22439
22440 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;
22441 Edge.parseOptions(this.options, options, true, this.globalOptions);
22442
22443 if (options.id !== undefined) {
22444 this.id = options.id;
22445 }
22446
22447 if (options.from !== undefined) {
22448 this.fromId = options.from;
22449 }
22450
22451 if (options.to !== undefined) {
22452 this.toId = options.to;
22453 }
22454
22455 if (options.title !== undefined) {
22456 this.title = options.title;
22457 }
22458
22459 if (options.value !== undefined) {
22460 options.value = _parseFloat(options.value);
22461 }
22462
22463 var pile = [options, this.options, this.defaultOptions];
22464 this.chooser = choosify("edge", pile); // update label Module
22465
22466 this.updateLabelModule(options); // Update edge type, this if changed affects the layout.
22467
22468 affectsLayout = this.updateEdgeType() || affectsLayout; // if anything has been updates, reset the selection width and the hover width
22469
22470 this._setInteractionWidths(); // A node is connected when it has a from and to node that both exist in the network.body.nodes.
22471
22472
22473 this.connect();
22474 return affectsLayout;
22475 }
22476 /**
22477 *
22478 * @param {object} parentOptions
22479 * @param {object} newOptions
22480 * @param {boolean} [allowDeletion=false]
22481 * @param {object} [globalOptions={}]
22482 * @param {boolean} [copyFromGlobals=false]
22483 */
22484
22485 }, {
22486 key: "getFormattingValues",
22487 value:
22488 /**
22489 *
22490 * @returns {ArrowOptions}
22491 */
22492 function getFormattingValues() {
22493 var toArrow = this.options.arrows.to === true || this.options.arrows.to.enabled === true;
22494 var fromArrow = this.options.arrows.from === true || this.options.arrows.from.enabled === true;
22495 var middleArrow = this.options.arrows.middle === true || this.options.arrows.middle.enabled === true;
22496 var inheritsColor = this.options.color.inherit;
22497 var values = {
22498 toArrow: toArrow,
22499 toArrowScale: this.options.arrows.to.scaleFactor,
22500 toArrowType: this.options.arrows.to.type,
22501 toArrowSrc: this.options.arrows.to.src,
22502 toArrowImageWidth: this.options.arrows.to.imageWidth,
22503 toArrowImageHeight: this.options.arrows.to.imageHeight,
22504 middleArrow: middleArrow,
22505 middleArrowScale: this.options.arrows.middle.scaleFactor,
22506 middleArrowType: this.options.arrows.middle.type,
22507 middleArrowSrc: this.options.arrows.middle.src,
22508 middleArrowImageWidth: this.options.arrows.middle.imageWidth,
22509 middleArrowImageHeight: this.options.arrows.middle.imageHeight,
22510 fromArrow: fromArrow,
22511 fromArrowScale: this.options.arrows.from.scaleFactor,
22512 fromArrowType: this.options.arrows.from.type,
22513 fromArrowSrc: this.options.arrows.from.src,
22514 fromArrowImageWidth: this.options.arrows.from.imageWidth,
22515 fromArrowImageHeight: this.options.arrows.from.imageHeight,
22516 arrowStrikethrough: this.options.arrowStrikethrough,
22517 color: inheritsColor ? undefined : this.options.color.color,
22518 inheritsColor: inheritsColor,
22519 opacity: this.options.color.opacity,
22520 hidden: this.options.hidden,
22521 length: this.options.length,
22522 shadow: this.options.shadow.enabled,
22523 shadowColor: this.options.shadow.color,
22524 shadowSize: this.options.shadow.size,
22525 shadowX: this.options.shadow.x,
22526 shadowY: this.options.shadow.y,
22527 dashes: this.options.dashes,
22528 width: this.options.width,
22529 background: this.options.background.enabled,
22530 backgroundColor: this.options.background.color,
22531 backgroundSize: this.options.background.size,
22532 backgroundDashes: this.options.background.dashes
22533 };
22534
22535 if (this.selected || this.hover) {
22536 if (this.chooser === true) {
22537 if (this.selected) {
22538 var selectedWidth = this.options.selectionWidth;
22539
22540 if (typeof selectedWidth === "function") {
22541 values.width = selectedWidth(values.width);
22542 } else if (typeof selectedWidth === "number") {
22543 values.width += selectedWidth;
22544 }
22545
22546 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
22547 values.color = this.options.color.highlight;
22548 values.shadow = this.options.shadow.enabled;
22549 } else if (this.hover) {
22550 var hoverWidth = this.options.hoverWidth;
22551
22552 if (typeof hoverWidth === "function") {
22553 values.width = hoverWidth(values.width);
22554 } else if (typeof hoverWidth === "number") {
22555 values.width += hoverWidth;
22556 }
22557
22558 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
22559 values.color = this.options.color.hover;
22560 values.shadow = this.options.shadow.enabled;
22561 }
22562 } else if (typeof this.chooser === "function") {
22563 this.chooser(values, this.options.id, this.selected, this.hover);
22564
22565 if (values.color !== undefined) {
22566 values.inheritsColor = false;
22567 }
22568
22569 if (values.shadow === false) {
22570 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) {
22571 values.shadow = true;
22572 }
22573 }
22574 }
22575 } else {
22576 values.shadow = this.options.shadow.enabled;
22577 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
22578 }
22579
22580 return values;
22581 }
22582 /**
22583 * update the options in the label module
22584 *
22585 * @param {object} options
22586 */
22587
22588 }, {
22589 key: "updateLabelModule",
22590 value: function updateLabelModule(options) {
22591 var pile = [options, this.options, this.globalOptions, // Currently set global edge options
22592 this.defaultOptions];
22593 this.labelModule.update(this.options, pile);
22594
22595 if (this.labelModule.baseSize !== undefined) {
22596 this.baseFontSize = this.labelModule.baseSize;
22597 }
22598 }
22599 /**
22600 * update the edge type, set the options
22601 *
22602 * @returns {boolean}
22603 */
22604
22605 }, {
22606 key: "updateEdgeType",
22607 value: function updateEdgeType() {
22608 var smooth = this.options.smooth;
22609 var dataChanged = false;
22610 var changeInType = true;
22611
22612 if (this.edgeType !== undefined) {
22613 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) {
22614 changeInType = false;
22615 }
22616
22617 if (changeInType === true) {
22618 dataChanged = this.cleanup();
22619 }
22620 }
22621
22622 if (changeInType === true) {
22623 if (smooth.enabled === true) {
22624 if (smooth.type === "dynamic") {
22625 dataChanged = true;
22626 this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
22627 } else if (smooth.type === "cubicBezier") {
22628 this.edgeType = new CubicBezierEdge(this.options, this.body, this.labelModule);
22629 } else {
22630 this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
22631 }
22632 } else {
22633 this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
22634 }
22635 } else {
22636 // if nothing changes, we just set the options.
22637 this.edgeType.setOptions(this.options);
22638 }
22639
22640 return dataChanged;
22641 }
22642 /**
22643 * Connect an edge to its nodes
22644 */
22645
22646 }, {
22647 key: "connect",
22648 value: function connect() {
22649 this.disconnect();
22650 this.from = this.body.nodes[this.fromId] || undefined;
22651 this.to = this.body.nodes[this.toId] || undefined;
22652 this.connected = this.from !== undefined && this.to !== undefined;
22653
22654 if (this.connected === true) {
22655 this.from.attachEdge(this);
22656 this.to.attachEdge(this);
22657 } else {
22658 if (this.from) {
22659 this.from.detachEdge(this);
22660 }
22661
22662 if (this.to) {
22663 this.to.detachEdge(this);
22664 }
22665 }
22666
22667 this.edgeType.connect();
22668 }
22669 /**
22670 * Disconnect an edge from its nodes
22671 */
22672
22673 }, {
22674 key: "disconnect",
22675 value: function disconnect() {
22676 if (this.from) {
22677 this.from.detachEdge(this);
22678 this.from = undefined;
22679 }
22680
22681 if (this.to) {
22682 this.to.detachEdge(this);
22683 this.to = undefined;
22684 }
22685
22686 this.connected = false;
22687 }
22688 /**
22689 * get the title of this edge.
22690 *
22691 * @returns {string} title The title of the edge, or undefined when no title
22692 * has been set.
22693 */
22694
22695 }, {
22696 key: "getTitle",
22697 value: function getTitle() {
22698 return this.title;
22699 }
22700 /**
22701 * check if this node is selecte
22702 *
22703 * @returns {boolean} selected True if node is selected, else false
22704 */
22705
22706 }, {
22707 key: "isSelected",
22708 value: function isSelected() {
22709 return this.selected;
22710 }
22711 /**
22712 * Retrieve the value of the edge. Can be undefined
22713 *
22714 * @returns {number} value
22715 */
22716
22717 }, {
22718 key: "getValue",
22719 value: function getValue() {
22720 return this.options.value;
22721 }
22722 /**
22723 * Adjust the value range of the edge. The edge will adjust it's width
22724 * based on its value.
22725 *
22726 * @param {number} min
22727 * @param {number} max
22728 * @param {number} total
22729 */
22730
22731 }, {
22732 key: "setValueRange",
22733 value: function setValueRange(min, max, total) {
22734 if (this.options.value !== undefined) {
22735 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
22736 var widthDiff = this.options.scaling.max - this.options.scaling.min;
22737
22738 if (this.options.scaling.label.enabled === true) {
22739 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
22740 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
22741 }
22742
22743 this.options.width = this.options.scaling.min + scale * widthDiff;
22744 } else {
22745 this.options.width = this.baseWidth;
22746 this.options.font.size = this.baseFontSize;
22747 }
22748
22749 this._setInteractionWidths();
22750
22751 this.updateLabelModule();
22752 }
22753 /**
22754 *
22755 * @private
22756 */
22757
22758 }, {
22759 key: "_setInteractionWidths",
22760 value: function _setInteractionWidths() {
22761 if (typeof this.options.hoverWidth === "function") {
22762 this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
22763 } else {
22764 this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
22765 }
22766
22767 if (typeof this.options.selectionWidth === "function") {
22768 this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
22769 } else {
22770 this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
22771 }
22772 }
22773 /**
22774 * Redraw a edge
22775 * Draw this edge in the given canvas
22776 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
22777 *
22778 * @param {CanvasRenderingContext2D} ctx
22779 */
22780
22781 }, {
22782 key: "draw",
22783 value: function draw(ctx) {
22784 var values = this.getFormattingValues();
22785
22786 if (values.hidden) {
22787 return;
22788 } // get the via node from the edge type
22789
22790
22791 var viaNode = this.edgeType.getViaNode(); // draw line and label
22792
22793 this.edgeType.drawLine(ctx, values, this.selected, this.hover, viaNode);
22794 this.drawLabel(ctx, viaNode);
22795 }
22796 /**
22797 * Redraw arrows
22798 * Draw this arrows in the given canvas
22799 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
22800 *
22801 * @param {CanvasRenderingContext2D} ctx
22802 */
22803
22804 }, {
22805 key: "drawArrows",
22806 value: function drawArrows(ctx) {
22807 var values = this.getFormattingValues();
22808
22809 if (values.hidden) {
22810 return;
22811 } // get the via node from the edge type
22812
22813
22814 var viaNode = this.edgeType.getViaNode();
22815 var arrowData = {}; // restore edge targets to defaults
22816
22817 this.edgeType.fromPoint = this.edgeType.from;
22818 this.edgeType.toPoint = this.edgeType.to; // from and to arrows give a different end point for edges. we set them here
22819
22820 if (values.fromArrow) {
22821 arrowData.from = this.edgeType.getArrowData(ctx, "from", viaNode, this.selected, this.hover, values);
22822 if (values.arrowStrikethrough === false) this.edgeType.fromPoint = arrowData.from.core;
22823
22824 if (values.fromArrowSrc) {
22825 arrowData.from.image = this.imagelist.load(values.fromArrowSrc);
22826 }
22827
22828 if (values.fromArrowImageWidth) {
22829 arrowData.from.imageWidth = values.fromArrowImageWidth;
22830 }
22831
22832 if (values.fromArrowImageHeight) {
22833 arrowData.from.imageHeight = values.fromArrowImageHeight;
22834 }
22835 }
22836
22837 if (values.toArrow) {
22838 arrowData.to = this.edgeType.getArrowData(ctx, "to", viaNode, this.selected, this.hover, values);
22839 if (values.arrowStrikethrough === false) this.edgeType.toPoint = arrowData.to.core;
22840
22841 if (values.toArrowSrc) {
22842 arrowData.to.image = this.imagelist.load(values.toArrowSrc);
22843 }
22844
22845 if (values.toArrowImageWidth) {
22846 arrowData.to.imageWidth = values.toArrowImageWidth;
22847 }
22848
22849 if (values.toArrowImageHeight) {
22850 arrowData.to.imageHeight = values.toArrowImageHeight;
22851 }
22852 } // the middle arrow depends on the line, which can depend on the to and from arrows so we do this one lastly.
22853
22854
22855 if (values.middleArrow) {
22856 arrowData.middle = this.edgeType.getArrowData(ctx, "middle", viaNode, this.selected, this.hover, values);
22857
22858 if (values.middleArrowSrc) {
22859 arrowData.middle.image = this.imagelist.load(values.middleArrowSrc);
22860 }
22861
22862 if (values.middleArrowImageWidth) {
22863 arrowData.middle.imageWidth = values.middleArrowImageWidth;
22864 }
22865
22866 if (values.middleArrowImageHeight) {
22867 arrowData.middle.imageHeight = values.middleArrowImageHeight;
22868 }
22869 }
22870
22871 if (values.fromArrow) {
22872 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.from);
22873 }
22874
22875 if (values.middleArrow) {
22876 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.middle);
22877 }
22878
22879 if (values.toArrow) {
22880 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.to);
22881 }
22882 }
22883 /**
22884 *
22885 * @param {CanvasRenderingContext2D} ctx
22886 * @param {Node} viaNode
22887 */
22888
22889 }, {
22890 key: "drawLabel",
22891 value: function drawLabel(ctx, viaNode) {
22892 if (this.options.label !== undefined) {
22893 // set style
22894 var node1 = this.from;
22895 var node2 = this.to;
22896
22897 if (this.labelModule.differentState(this.selected, this.hover)) {
22898 this.labelModule.getTextSize(ctx, this.selected, this.hover);
22899 }
22900
22901 var point;
22902
22903 if (node1.id != node2.id) {
22904 this.labelModule.pointToSelf = false;
22905 point = this.edgeType.getPoint(0.5, viaNode);
22906 ctx.save();
22907
22908 var rotationPoint = this._getRotation(ctx);
22909
22910 if (rotationPoint.angle != 0) {
22911 ctx.translate(rotationPoint.x, rotationPoint.y);
22912 ctx.rotate(rotationPoint.angle);
22913 } // draw the label
22914
22915
22916 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
22917 /*
22918 // Useful debug code: draw a border around the label
22919 // This should **not** be enabled in production!
22920 var size = this.labelModule.getSize();; // ;; intentional so lint catches it
22921 ctx.strokeStyle = "#ff0000";
22922 ctx.strokeRect(size.left, size.top, size.width, size.height);
22923 // End debug code
22924 */
22925
22926 ctx.restore();
22927 } else {
22928 // Ignore the orientations.
22929 this.labelModule.pointToSelf = true; // get circle coordinates
22930
22931 var coordinates = getSelfRefCoordinates(ctx, this.options.selfReference.angle, this.options.selfReference.size, node1);
22932 point = this._pointOnCircle(coordinates.x, coordinates.y, this.options.selfReference.size, this.options.selfReference.angle);
22933 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
22934 }
22935 }
22936 }
22937 /**
22938 * Determine all visual elements of this edge instance, in which the given
22939 * point falls within the bounding shape.
22940 *
22941 * @param {point} point
22942 * @returns {Array.<edgeClickItem|edgeLabelClickItem>} list with the items which are on the point
22943 */
22944
22945 }, {
22946 key: "getItemsOnPoint",
22947 value: function getItemsOnPoint(point) {
22948 var ret = [];
22949
22950 if (this.labelModule.visible()) {
22951 var rotationPoint = this._getRotation();
22952
22953 if (pointInRect(this.labelModule.getSize(), point, rotationPoint)) {
22954 ret.push({
22955 edgeId: this.id,
22956 labelId: 0
22957 });
22958 }
22959 }
22960
22961 var obj = {
22962 left: point.x,
22963 top: point.y
22964 };
22965
22966 if (this.isOverlappingWith(obj)) {
22967 ret.push({
22968 edgeId: this.id
22969 });
22970 }
22971
22972 return ret;
22973 }
22974 /**
22975 * Check if this object is overlapping with the provided object
22976 *
22977 * @param {object} obj an object with parameters left, top
22978 * @returns {boolean} True if location is located on the edge
22979 */
22980
22981 }, {
22982 key: "isOverlappingWith",
22983 value: function isOverlappingWith(obj) {
22984 if (this.connected) {
22985 var distMax = 10;
22986 var xFrom = this.from.x;
22987 var yFrom = this.from.y;
22988 var xTo = this.to.x;
22989 var yTo = this.to.y;
22990 var xObj = obj.left;
22991 var yObj = obj.top;
22992 var dist = this.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);
22993 return dist < distMax;
22994 } else {
22995 return false;
22996 }
22997 }
22998 /**
22999 * Determine the rotation point, if any.
23000 *
23001 * @param {CanvasRenderingContext2D} [ctx] if passed, do a recalculation of the label size
23002 * @returns {rotationPoint} the point to rotate around and the angle in radians to rotate
23003 * @private
23004 */
23005
23006 }, {
23007 key: "_getRotation",
23008 value: function _getRotation(ctx) {
23009 var viaNode = this.edgeType.getViaNode();
23010 var point = this.edgeType.getPoint(0.5, viaNode);
23011
23012 if (ctx !== undefined) {
23013 this.labelModule.calculateLabelSize(ctx, this.selected, this.hover, point.x, point.y);
23014 }
23015
23016 var ret = {
23017 x: point.x,
23018 y: this.labelModule.size.yLine,
23019 angle: 0
23020 };
23021
23022 if (!this.labelModule.visible()) {
23023 return ret; // Don't even bother doing the atan2, there's nothing to draw
23024 }
23025
23026 if (this.options.font.align === "horizontal") {
23027 return ret; // No need to calculate angle
23028 }
23029
23030 var dy = this.from.y - this.to.y;
23031 var dx = this.from.x - this.to.x;
23032 var angle = Math.atan2(dy, dx); // radians
23033 // rotate so that label is readable
23034
23035 if (angle < -1 && dx < 0 || angle > 0 && dx < 0) {
23036 angle += Math.PI;
23037 }
23038
23039 ret.angle = angle;
23040 return ret;
23041 }
23042 /**
23043 * Get a point on a circle
23044 *
23045 * @param {number} x
23046 * @param {number} y
23047 * @param {number} radius
23048 * @param {number} angle
23049 * @returns {object} point
23050 * @private
23051 */
23052
23053 }, {
23054 key: "_pointOnCircle",
23055 value: function _pointOnCircle(x, y, radius, angle) {
23056 return {
23057 x: x + radius * Math.cos(angle),
23058 y: y - radius * Math.sin(angle)
23059 };
23060 }
23061 /**
23062 * Sets selected state to true
23063 */
23064
23065 }, {
23066 key: "select",
23067 value: function select() {
23068 this.selected = true;
23069 }
23070 /**
23071 * Sets selected state to false
23072 */
23073
23074 }, {
23075 key: "unselect",
23076 value: function unselect() {
23077 this.selected = false;
23078 }
23079 /**
23080 * cleans all required things on delete
23081 *
23082 * @returns {*}
23083 */
23084
23085 }, {
23086 key: "cleanup",
23087 value: function cleanup() {
23088 return this.edgeType.cleanup();
23089 }
23090 /**
23091 * Remove edge from the list and perform necessary cleanup.
23092 */
23093
23094 }, {
23095 key: "remove",
23096 value: function remove() {
23097 this.cleanup();
23098 this.disconnect();
23099 delete this.body.edges[this.id];
23100 }
23101 /**
23102 * Check if both connecting nodes exist
23103 *
23104 * @returns {boolean}
23105 */
23106
23107 }, {
23108 key: "endPointsValid",
23109 value: function endPointsValid() {
23110 return this.body.nodes[this.fromId] !== undefined && this.body.nodes[this.toId] !== undefined;
23111 }
23112 }], [{
23113 key: "parseOptions",
23114 value: function parseOptions(parentOptions, newOptions) {
23115 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
23116 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
23117 var copyFromGlobals = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
23118 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.
23119
23120 selectiveDeepExtend(fields, parentOptions, newOptions, allowDeletion); // Only use endPointOffset values (from and to) if it's valid values
23121
23122 if (newOptions.endPointOffset !== undefined && newOptions.endPointOffset.from !== undefined) {
23123 if (_isFinite(newOptions.endPointOffset.from)) {
23124 parentOptions.endPointOffset.from = newOptions.endPointOffset.from;
23125 } else {
23126 parentOptions.endPointOffset.from = globalOptions.endPointOffset.from !== undefined ? globalOptions.endPointOffset.from : 0;
23127 console.error("endPointOffset.from is not a valid number");
23128 }
23129 }
23130
23131 if (newOptions.endPointOffset !== undefined && newOptions.endPointOffset.to !== undefined) {
23132 if (_isFinite(newOptions.endPointOffset.to)) {
23133 parentOptions.endPointOffset.to = newOptions.endPointOffset.to;
23134 } else {
23135 parentOptions.endPointOffset.to = globalOptions.endPointOffset.to !== undefined ? globalOptions.endPointOffset.to : 0;
23136 console.error("endPointOffset.to is not a valid number");
23137 }
23138 } // Only copy label if it's a legal value.
23139
23140
23141 if (isValidLabel(newOptions.label)) {
23142 parentOptions.label = newOptions.label;
23143 } else if (!isValidLabel(parentOptions.label)) {
23144 parentOptions.label = undefined;
23145 }
23146
23147 mergeOptions(parentOptions, newOptions, "smooth", globalOptions);
23148 mergeOptions(parentOptions, newOptions, "shadow", globalOptions);
23149 mergeOptions(parentOptions, newOptions, "background", globalOptions);
23150
23151 if (newOptions.dashes !== undefined && newOptions.dashes !== null) {
23152 parentOptions.dashes = newOptions.dashes;
23153 } else if (allowDeletion === true && newOptions.dashes === null) {
23154 parentOptions.dashes = create$4(globalOptions.dashes); // this sets the pointer of the option back to the global option.
23155 } // set the scaling newOptions
23156
23157
23158 if (newOptions.scaling !== undefined && newOptions.scaling !== null) {
23159 if (newOptions.scaling.min !== undefined) {
23160 parentOptions.scaling.min = newOptions.scaling.min;
23161 }
23162
23163 if (newOptions.scaling.max !== undefined) {
23164 parentOptions.scaling.max = newOptions.scaling.max;
23165 }
23166
23167 mergeOptions(parentOptions.scaling, newOptions.scaling, "label", globalOptions.scaling);
23168 } else if (allowDeletion === true && newOptions.scaling === null) {
23169 parentOptions.scaling = create$4(globalOptions.scaling); // this sets the pointer of the option back to the global option.
23170 } // handle multiple input cases for arrows
23171
23172
23173 if (newOptions.arrows !== undefined && newOptions.arrows !== null) {
23174 if (typeof newOptions.arrows === "string") {
23175 var arrows = newOptions.arrows.toLowerCase();
23176 parentOptions.arrows.to.enabled = indexOf(arrows).call(arrows, "to") != -1;
23177 parentOptions.arrows.middle.enabled = indexOf(arrows).call(arrows, "middle") != -1;
23178 parentOptions.arrows.from.enabled = indexOf(arrows).call(arrows, "from") != -1;
23179 } else if (_typeof(newOptions.arrows) === "object") {
23180 mergeOptions(parentOptions.arrows, newOptions.arrows, "to", globalOptions.arrows);
23181 mergeOptions(parentOptions.arrows, newOptions.arrows, "middle", globalOptions.arrows);
23182 mergeOptions(parentOptions.arrows, newOptions.arrows, "from", globalOptions.arrows);
23183 } else {
23184 throw new Error("The arrow newOptions can only be an object or a string. Refer to the documentation. You used:" + stringify$1(newOptions.arrows));
23185 }
23186 } else if (allowDeletion === true && newOptions.arrows === null) {
23187 parentOptions.arrows = create$4(globalOptions.arrows); // this sets the pointer of the option back to the global option.
23188 } // handle multiple input cases for color
23189
23190
23191 if (newOptions.color !== undefined && newOptions.color !== null) {
23192 var fromColor = isString(newOptions.color) ? {
23193 color: newOptions.color,
23194 highlight: newOptions.color,
23195 hover: newOptions.color,
23196 inherit: false,
23197 opacity: 1
23198 } : newOptions.color;
23199 var toColor = parentOptions.color; // If passed, fill in values from default options - required in the case of no prototype bridging
23200
23201 if (copyFromGlobals) {
23202 deepExtend(toColor, globalOptions.color, false, allowDeletion);
23203 } else {
23204 // Clear local properties - need to do it like this in order to retain prototype bridges
23205 for (var i in toColor) {
23206 if (Object.prototype.hasOwnProperty.call(toColor, i)) {
23207 delete toColor[i];
23208 }
23209 }
23210 }
23211
23212 if (isString(toColor)) {
23213 toColor.color = toColor;
23214 toColor.highlight = toColor;
23215 toColor.hover = toColor;
23216 toColor.inherit = false;
23217
23218 if (fromColor.opacity === undefined) {
23219 toColor.opacity = 1.0; // set default
23220 }
23221 } else {
23222 var colorsDefined = false;
23223
23224 if (fromColor.color !== undefined) {
23225 toColor.color = fromColor.color;
23226 colorsDefined = true;
23227 }
23228
23229 if (fromColor.highlight !== undefined) {
23230 toColor.highlight = fromColor.highlight;
23231 colorsDefined = true;
23232 }
23233
23234 if (fromColor.hover !== undefined) {
23235 toColor.hover = fromColor.hover;
23236 colorsDefined = true;
23237 }
23238
23239 if (fromColor.inherit !== undefined) {
23240 toColor.inherit = fromColor.inherit;
23241 }
23242
23243 if (fromColor.opacity !== undefined) {
23244 toColor.opacity = Math.min(1, Math.max(0, fromColor.opacity));
23245 }
23246
23247 if (colorsDefined === true) {
23248 toColor.inherit = false;
23249 } else {
23250 if (toColor.inherit === undefined) {
23251 toColor.inherit = "from"; // Set default
23252 }
23253 }
23254 }
23255 } else if (allowDeletion === true && newOptions.color === null) {
23256 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
23257 }
23258
23259 if (allowDeletion === true && newOptions.font === null) {
23260 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
23261 }
23262
23263 if (Object.prototype.hasOwnProperty.call(newOptions, "selfReferenceSize")) {
23264 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}");
23265 parentOptions.selfReference.size = newOptions.selfReferenceSize;
23266 }
23267 }
23268 }]);
23269
23270 return Edge;
23271 }();
23272
23273 /**
23274 * Handler for Edges
23275 */
23276
23277 var EdgesHandler = /*#__PURE__*/function () {
23278 /**
23279 * @param {object} body
23280 * @param {Array.<Image>} images
23281 * @param {Array.<Group>} groups
23282 */
23283 function EdgesHandler(body, images, groups) {
23284 var _context,
23285 _this = this;
23286
23287 _classCallCheck(this, EdgesHandler);
23288
23289 this.body = body;
23290 this.images = images;
23291 this.groups = groups; // create the edge API in the body container
23292
23293 this.body.functions.createEdge = bind$5(_context = this.create).call(_context, this);
23294 this.edgesListeners = {
23295 add: function add(event, params) {
23296 _this.add(params.items);
23297 },
23298 update: function update(event, params) {
23299 _this.update(params.items);
23300 },
23301 remove: function remove(event, params) {
23302 _this.remove(params.items);
23303 }
23304 };
23305 this.options = {};
23306 this.defaultOptions = {
23307 arrows: {
23308 to: {
23309 enabled: false,
23310 scaleFactor: 1,
23311 type: "arrow"
23312 },
23313 // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
23314 middle: {
23315 enabled: false,
23316 scaleFactor: 1,
23317 type: "arrow"
23318 },
23319 from: {
23320 enabled: false,
23321 scaleFactor: 1,
23322 type: "arrow"
23323 }
23324 },
23325 endPointOffset: {
23326 from: 0,
23327 to: 0
23328 },
23329 arrowStrikethrough: true,
23330 color: {
23331 color: "#848484",
23332 highlight: "#848484",
23333 hover: "#848484",
23334 inherit: "from",
23335 opacity: 1.0
23336 },
23337 dashes: false,
23338 font: {
23339 color: "#343434",
23340 size: 14,
23341 // px
23342 face: "arial",
23343 background: "none",
23344 strokeWidth: 2,
23345 // px
23346 strokeColor: "#ffffff",
23347 align: "horizontal",
23348 multi: false,
23349 vadjust: 0,
23350 bold: {
23351 mod: "bold"
23352 },
23353 boldital: {
23354 mod: "bold italic"
23355 },
23356 ital: {
23357 mod: "italic"
23358 },
23359 mono: {
23360 mod: "",
23361 size: 15,
23362 // px
23363 face: "courier new",
23364 vadjust: 2
23365 }
23366 },
23367 hidden: false,
23368 hoverWidth: 1.5,
23369 label: undefined,
23370 labelHighlightBold: true,
23371 length: undefined,
23372 physics: true,
23373 scaling: {
23374 min: 1,
23375 max: 15,
23376 label: {
23377 enabled: true,
23378 min: 14,
23379 max: 30,
23380 maxVisible: 30,
23381 drawThreshold: 5
23382 },
23383 customScalingFunction: function customScalingFunction(min, max, total, value) {
23384 if (max === min) {
23385 return 0.5;
23386 } else {
23387 var scale = 1 / (max - min);
23388 return Math.max(0, (value - min) * scale);
23389 }
23390 }
23391 },
23392 selectionWidth: 1.5,
23393 selfReference: {
23394 size: 20,
23395 angle: Math.PI / 4,
23396 renderBehindTheNode: true
23397 },
23398 shadow: {
23399 enabled: false,
23400 color: "rgba(0,0,0,0.5)",
23401 size: 10,
23402 x: 5,
23403 y: 5
23404 },
23405 background: {
23406 enabled: false,
23407 color: "rgba(111,111,111,1)",
23408 size: 10,
23409 dashes: false
23410 },
23411 smooth: {
23412 enabled: true,
23413 type: "dynamic",
23414 forceDirection: "none",
23415 roundness: 0.5
23416 },
23417 title: undefined,
23418 width: 1,
23419 value: undefined
23420 };
23421 deepExtend(this.options, this.defaultOptions);
23422 this.bindEventListeners();
23423 }
23424 /**
23425 * Binds event listeners
23426 */
23427
23428
23429 _createClass(EdgesHandler, [{
23430 key: "bindEventListeners",
23431 value: function bindEventListeners() {
23432 var _this2 = this,
23433 _context2,
23434 _context3;
23435
23436 // this allows external modules to force all dynamic curves to turn static.
23437 this.body.emitter.on("_forceDisableDynamicCurves", function (type) {
23438 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
23439
23440 if (type === "dynamic") {
23441 type = "continuous";
23442 }
23443
23444 var dataChanged = false;
23445
23446 for (var edgeId in _this2.body.edges) {
23447 if (Object.prototype.hasOwnProperty.call(_this2.body.edges, edgeId)) {
23448 var edge = _this2.body.edges[edgeId];
23449
23450 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.
23451 // this is because a change in the global would not affect these curves.
23452
23453
23454 if (edgeData != null) {
23455 var smoothOptions = edgeData.smooth;
23456
23457 if (smoothOptions !== undefined) {
23458 if (smoothOptions.enabled === true && smoothOptions.type === "dynamic") {
23459 if (type === undefined) {
23460 edge.setOptions({
23461 smooth: false
23462 });
23463 } else {
23464 edge.setOptions({
23465 smooth: {
23466 type: type
23467 }
23468 });
23469 }
23470
23471 dataChanged = true;
23472 }
23473 }
23474 }
23475 }
23476 }
23477
23478 if (emit === true && dataChanged === true) {
23479 _this2.body.emitter.emit("_dataChanged");
23480 }
23481 }); // this is called when options of EXISTING nodes or edges have changed.
23482 //
23483 // NOTE: Not true, called when options have NOT changed, for both existing as well as new nodes.
23484 // See update() for logic.
23485 // TODO: Verify and examine the consequences of this. It might still trigger when
23486 // non-option fields have changed, but then reconnecting edges is still useless.
23487 // Alternatively, it might also be called when edges are removed.
23488 //
23489
23490 this.body.emitter.on("_dataUpdated", function () {
23491 _this2.reconnectEdges();
23492 }); // refresh the edges. Used when reverting from hierarchical layout
23493
23494 this.body.emitter.on("refreshEdges", bind$5(_context2 = this.refresh).call(_context2, this));
23495 this.body.emitter.on("refresh", bind$5(_context3 = this.refresh).call(_context3, this));
23496 this.body.emitter.on("destroy", function () {
23497 forEach$1(_this2.edgesListeners, function (callback, event) {
23498 if (_this2.body.data.edges) _this2.body.data.edges.off(event, callback);
23499 });
23500 delete _this2.body.functions.createEdge;
23501 delete _this2.edgesListeners.add;
23502 delete _this2.edgesListeners.update;
23503 delete _this2.edgesListeners.remove;
23504 delete _this2.edgesListeners;
23505 });
23506 }
23507 /**
23508 *
23509 * @param {object} options
23510 */
23511
23512 }, {
23513 key: "setOptions",
23514 value: function setOptions(options) {
23515 if (options !== undefined) {
23516 // use the parser from the Edge class to fill in all shorthand notations
23517 Edge.parseOptions(this.options, options, true, this.defaultOptions, true); // update smooth settings in all edges
23518
23519 var dataChanged = false;
23520
23521 if (options.smooth !== undefined) {
23522 for (var edgeId in this.body.edges) {
23523 if (Object.prototype.hasOwnProperty.call(this.body.edges, edgeId)) {
23524 dataChanged = this.body.edges[edgeId].updateEdgeType() || dataChanged;
23525 }
23526 }
23527 } // update fonts in all edges
23528
23529
23530 if (options.font !== undefined) {
23531 for (var _edgeId in this.body.edges) {
23532 if (Object.prototype.hasOwnProperty.call(this.body.edges, _edgeId)) {
23533 this.body.edges[_edgeId].updateLabelModule();
23534 }
23535 }
23536 } // update the state of the variables if needed
23537
23538
23539 if (options.hidden !== undefined || options.physics !== undefined || dataChanged === true) {
23540 this.body.emitter.emit("_dataChanged");
23541 }
23542 }
23543 }
23544 /**
23545 * Load edges by reading the data table
23546 *
23547 * @param {Array | DataSet | DataView} edges The data containing the edges.
23548 * @param {boolean} [doNotEmit=false] - Suppress data changed event.
23549 * @private
23550 */
23551
23552 }, {
23553 key: "setData",
23554 value: function setData(edges) {
23555 var _this3 = this;
23556
23557 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
23558 var oldEdgesData = this.body.data.edges;
23559
23560 if (esnext.isDataViewLike("id", edges)) {
23561 this.body.data.edges = edges;
23562 } else if (isArray$1(edges)) {
23563 this.body.data.edges = new esnext.DataSet();
23564 this.body.data.edges.add(edges);
23565 } else if (!edges) {
23566 this.body.data.edges = new esnext.DataSet();
23567 } else {
23568 throw new TypeError("Array or DataSet expected");
23569 } // TODO: is this null or undefined or false?
23570
23571
23572 if (oldEdgesData) {
23573 // unsubscribe from old dataset
23574 forEach$1(this.edgesListeners, function (callback, event) {
23575 oldEdgesData.off(event, callback);
23576 });
23577 } // remove drawn edges
23578
23579
23580 this.body.edges = {}; // TODO: is this null or undefined or false?
23581
23582 if (this.body.data.edges) {
23583 // subscribe to new dataset
23584 forEach$1(this.edgesListeners, function (callback, event) {
23585 _this3.body.data.edges.on(event, callback);
23586 }); // draw all new nodes
23587
23588 var ids = this.body.data.edges.getIds();
23589 this.add(ids, true);
23590 }
23591
23592 this.body.emitter.emit("_adjustEdgesForHierarchicalLayout");
23593
23594 if (doNotEmit === false) {
23595 this.body.emitter.emit("_dataChanged");
23596 }
23597 }
23598 /**
23599 * Add edges
23600 *
23601 * @param {number[] | string[]} ids
23602 * @param {boolean} [doNotEmit=false]
23603 * @private
23604 */
23605
23606 }, {
23607 key: "add",
23608 value: function add(ids) {
23609 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
23610 var edges = this.body.edges;
23611 var edgesData = this.body.data.edges;
23612
23613 for (var i = 0; i < ids.length; i++) {
23614 var id = ids[i];
23615 var oldEdge = edges[id];
23616
23617 if (oldEdge) {
23618 oldEdge.disconnect();
23619 }
23620
23621 var data = edgesData.get(id, {
23622 showInternalIds: true
23623 });
23624 edges[id] = this.create(data);
23625 }
23626
23627 this.body.emitter.emit("_adjustEdgesForHierarchicalLayout");
23628
23629 if (doNotEmit === false) {
23630 this.body.emitter.emit("_dataChanged");
23631 }
23632 }
23633 /**
23634 * Update existing edges, or create them when not yet existing
23635 *
23636 * @param {number[] | string[]} ids
23637 * @private
23638 */
23639
23640 }, {
23641 key: "update",
23642 value: function update(ids) {
23643 var edges = this.body.edges;
23644 var edgesData = this.body.data.edges;
23645 var dataChanged = false;
23646
23647 for (var i = 0; i < ids.length; i++) {
23648 var id = ids[i];
23649 var data = edgesData.get(id);
23650 var edge = edges[id];
23651
23652 if (edge !== undefined) {
23653 // update edge
23654 edge.disconnect();
23655 dataChanged = edge.setOptions(data) || dataChanged; // if a support node is added, data can be changed.
23656
23657 edge.connect();
23658 } else {
23659 // create edge
23660 this.body.edges[id] = this.create(data);
23661 dataChanged = true;
23662 }
23663 }
23664
23665 if (dataChanged === true) {
23666 this.body.emitter.emit("_adjustEdgesForHierarchicalLayout");
23667 this.body.emitter.emit("_dataChanged");
23668 } else {
23669 this.body.emitter.emit("_dataUpdated");
23670 }
23671 }
23672 /**
23673 * Remove existing edges. Non existing ids will be ignored
23674 *
23675 * @param {number[] | string[]} ids
23676 * @param {boolean} [emit=true]
23677 * @private
23678 */
23679
23680 }, {
23681 key: "remove",
23682 value: function remove(ids) {
23683 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
23684 if (ids.length === 0) return; // early out
23685
23686 var edges = this.body.edges;
23687 forEach$1(ids, function (id) {
23688 var edge = edges[id];
23689
23690 if (edge !== undefined) {
23691 edge.remove();
23692 }
23693 });
23694
23695 if (emit) {
23696 this.body.emitter.emit("_dataChanged");
23697 }
23698 }
23699 /**
23700 * Refreshes Edge Handler
23701 */
23702
23703 }, {
23704 key: "refresh",
23705 value: function refresh() {
23706 var _this4 = this;
23707
23708 forEach$1(this.body.edges, function (edge, edgeId) {
23709 var data = _this4.body.data.edges.get(edgeId);
23710
23711 if (data !== undefined) {
23712 edge.setOptions(data);
23713 }
23714 });
23715 }
23716 /**
23717 *
23718 * @param {object} properties
23719 * @returns {Edge}
23720 */
23721
23722 }, {
23723 key: "create",
23724 value: function create(properties) {
23725 return new Edge(properties, this.body, this.images, this.options, this.defaultOptions);
23726 }
23727 /**
23728 * Reconnect all edges
23729 *
23730 * @private
23731 */
23732
23733 }, {
23734 key: "reconnectEdges",
23735 value: function reconnectEdges() {
23736 var id;
23737 var nodes = this.body.nodes;
23738 var edges = this.body.edges;
23739
23740 for (id in nodes) {
23741 if (Object.prototype.hasOwnProperty.call(nodes, id)) {
23742 nodes[id].edges = [];
23743 }
23744 }
23745
23746 for (id in edges) {
23747 if (Object.prototype.hasOwnProperty.call(edges, id)) {
23748 var edge = edges[id];
23749 edge.from = null;
23750 edge.to = null;
23751 edge.connect();
23752 }
23753 }
23754 }
23755 /**
23756 *
23757 * @param {Edge.id} edgeId
23758 * @returns {Array}
23759 */
23760
23761 }, {
23762 key: "getConnectedNodes",
23763 value: function getConnectedNodes(edgeId) {
23764 var nodeList = [];
23765
23766 if (this.body.edges[edgeId] !== undefined) {
23767 var edge = this.body.edges[edgeId];
23768
23769 if (edge.fromId !== undefined) {
23770 nodeList.push(edge.fromId);
23771 }
23772
23773 if (edge.toId !== undefined) {
23774 nodeList.push(edge.toId);
23775 }
23776 }
23777
23778 return nodeList;
23779 }
23780 /**
23781 * There is no direct relation between the nodes and the edges DataSet,
23782 * so the right place to do call this is in the handler for event `_dataUpdated`.
23783 */
23784
23785 }, {
23786 key: "_updateState",
23787 value: function _updateState() {
23788 this._addMissingEdges();
23789
23790 this._removeInvalidEdges();
23791 }
23792 /**
23793 * Scan for missing nodes and remove corresponding edges, if any.
23794 *
23795 * @private
23796 */
23797
23798 }, {
23799 key: "_removeInvalidEdges",
23800 value: function _removeInvalidEdges() {
23801 var _this5 = this;
23802
23803 var edgesToDelete = [];
23804 forEach$1(this.body.edges, function (edge, id) {
23805 var toNode = _this5.body.nodes[edge.toId];
23806 var fromNode = _this5.body.nodes[edge.fromId]; // Skip clustering edges here, let the Clustering module handle those
23807
23808 if (toNode !== undefined && toNode.isCluster === true || fromNode !== undefined && fromNode.isCluster === true) {
23809 return;
23810 }
23811
23812 if (toNode === undefined || fromNode === undefined) {
23813 edgesToDelete.push(id);
23814 }
23815 });
23816 this.remove(edgesToDelete, false);
23817 }
23818 /**
23819 * add all edges from dataset that are not in the cached state
23820 *
23821 * @private
23822 */
23823
23824 }, {
23825 key: "_addMissingEdges",
23826 value: function _addMissingEdges() {
23827 var edgesData = this.body.data.edges;
23828
23829 if (edgesData === undefined || edgesData === null) {
23830 return; // No edges DataSet yet; can happen on startup
23831 }
23832
23833 var edges = this.body.edges;
23834 var addIds = [];
23835
23836 forEach$2(edgesData).call(edgesData, function (edgeData, edgeId) {
23837 var edge = edges[edgeId];
23838
23839 if (edge === undefined) {
23840 addIds.push(edgeId);
23841 }
23842 });
23843
23844 this.add(addIds, true);
23845 }
23846 }]);
23847
23848 return EdgesHandler;
23849 }();
23850
23851 /**
23852 * Barnes Hut Solver
23853 */
23854
23855 var BarnesHutSolver = /*#__PURE__*/function () {
23856 /**
23857 * @param {object} body
23858 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
23859 * @param {object} options
23860 */
23861 function BarnesHutSolver(body, physicsBody, options) {
23862 _classCallCheck(this, BarnesHutSolver);
23863
23864 this.body = body;
23865 this.physicsBody = physicsBody;
23866 this.barnesHutTree;
23867 this.setOptions(options);
23868 this._rng = Alea("BARNES HUT SOLVER"); // debug: show grid
23869 // this.body.emitter.on("afterDrawing", (ctx) => {this._debug(ctx,'#ff0000')})
23870 }
23871 /**
23872 *
23873 * @param {object} options
23874 */
23875
23876
23877 _createClass(BarnesHutSolver, [{
23878 key: "setOptions",
23879 value: function setOptions(options) {
23880 this.options = options;
23881 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
23882
23883 this.overlapAvoidanceFactor = 1 - Math.max(0, Math.min(1, this.options.avoidOverlap));
23884 }
23885 /**
23886 * This function calculates the forces the nodes apply on each other based on a gravitational model.
23887 * The Barnes Hut method is used to speed up this N-body simulation.
23888 *
23889 * @private
23890 */
23891
23892 }, {
23893 key: "solve",
23894 value: function solve() {
23895 if (this.options.gravitationalConstant !== 0 && this.physicsBody.physicsNodeIndices.length > 0) {
23896 var node;
23897 var nodes = this.body.nodes;
23898 var nodeIndices = this.physicsBody.physicsNodeIndices;
23899 var nodeCount = nodeIndices.length; // create the tree
23900
23901 var barnesHutTree = this._formBarnesHutTree(nodes, nodeIndices); // for debugging
23902
23903
23904 this.barnesHutTree = barnesHutTree; // place the nodes one by one recursively
23905
23906 for (var i = 0; i < nodeCount; i++) {
23907 node = nodes[nodeIndices[i]];
23908
23909 if (node.options.mass > 0) {
23910 // starting with root is irrelevant, it never passes the BarnesHutSolver condition
23911 this._getForceContributions(barnesHutTree.root, node);
23912 }
23913 }
23914 }
23915 }
23916 /**
23917 * @param {object} parentBranch
23918 * @param {Node} node
23919 * @private
23920 */
23921
23922 }, {
23923 key: "_getForceContributions",
23924 value: function _getForceContributions(parentBranch, node) {
23925 this._getForceContribution(parentBranch.children.NW, node);
23926
23927 this._getForceContribution(parentBranch.children.NE, node);
23928
23929 this._getForceContribution(parentBranch.children.SW, node);
23930
23931 this._getForceContribution(parentBranch.children.SE, node);
23932 }
23933 /**
23934 * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass.
23935 * If a region contains a single node, we check if it is not itself, then we apply the force.
23936 *
23937 * @param {object} parentBranch
23938 * @param {Node} node
23939 * @private
23940 */
23941
23942 }, {
23943 key: "_getForceContribution",
23944 value: function _getForceContribution(parentBranch, node) {
23945 // we get no force contribution from an empty region
23946 if (parentBranch.childrenCount > 0) {
23947 // get the distance from the center of mass to the node.
23948 var dx = parentBranch.centerOfMass.x - node.x;
23949 var dy = parentBranch.centerOfMass.y - node.y;
23950 var distance = Math.sqrt(dx * dx + dy * dy); // BarnesHutSolver condition
23951 // original condition : s/d < theta = passed === d/s > 1/theta = passed
23952 // calcSize = 1/s --> d * 1/s > 1/theta = passed
23953
23954 if (distance * parentBranch.calcSize > this.thetaInversed) {
23955 this._calculateForces(distance, dx, dy, node, parentBranch);
23956 } else {
23957 // Did not pass the condition, go into children if available
23958 if (parentBranch.childrenCount === 4) {
23959 this._getForceContributions(parentBranch, node);
23960 } else {
23961 // parentBranch must have only one node, if it was empty we wouldnt be here
23962 if (parentBranch.children.data.id != node.id) {
23963 // if it is not self
23964 this._calculateForces(distance, dx, dy, node, parentBranch);
23965 }
23966 }
23967 }
23968 }
23969 }
23970 /**
23971 * Calculate the forces based on the distance.
23972 *
23973 * @param {number} distance
23974 * @param {number} dx
23975 * @param {number} dy
23976 * @param {Node} node
23977 * @param {object} parentBranch
23978 * @private
23979 */
23980
23981 }, {
23982 key: "_calculateForces",
23983 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
23984 if (distance === 0) {
23985 distance = 0.1;
23986 dx = distance;
23987 }
23988
23989 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
23990 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
23991 } // the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
23992 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
23993
23994
23995 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass / Math.pow(distance, 3);
23996 var fx = dx * gravityForce;
23997 var fy = dy * gravityForce;
23998 this.physicsBody.forces[node.id].x += fx;
23999 this.physicsBody.forces[node.id].y += fy;
24000 }
24001 /**
24002 * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes.
24003 *
24004 * @param {Array.<Node>} nodes
24005 * @param {Array.<number>} nodeIndices
24006 * @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
24007 * @private
24008 */
24009
24010 }, {
24011 key: "_formBarnesHutTree",
24012 value: function _formBarnesHutTree(nodes, nodeIndices) {
24013 var node;
24014 var nodeCount = nodeIndices.length;
24015 var minX = nodes[nodeIndices[0]].x;
24016 var minY = nodes[nodeIndices[0]].y;
24017 var maxX = nodes[nodeIndices[0]].x;
24018 var maxY = nodes[nodeIndices[0]].y; // get the range of the nodes
24019
24020 for (var i = 1; i < nodeCount; i++) {
24021 var _node = nodes[nodeIndices[i]];
24022 var x = _node.x;
24023 var y = _node.y;
24024
24025 if (_node.options.mass > 0) {
24026 if (x < minX) {
24027 minX = x;
24028 }
24029
24030 if (x > maxX) {
24031 maxX = x;
24032 }
24033
24034 if (y < minY) {
24035 minY = y;
24036 }
24037
24038 if (y > maxY) {
24039 maxY = y;
24040 }
24041 }
24042 } // make the range a square
24043
24044
24045 var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
24046
24047 if (sizeDiff > 0) {
24048 minY -= 0.5 * sizeDiff;
24049 maxY += 0.5 * sizeDiff;
24050 } // xSize > ySize
24051 else {
24052 minX += 0.5 * sizeDiff;
24053 maxX -= 0.5 * sizeDiff;
24054 } // xSize < ySize
24055
24056
24057 var minimumTreeSize = 1e-5;
24058 var rootSize = Math.max(minimumTreeSize, Math.abs(maxX - minX));
24059 var halfRootSize = 0.5 * rootSize;
24060 var centerX = 0.5 * (minX + maxX),
24061 centerY = 0.5 * (minY + maxY); // construct the barnesHutTree
24062
24063 var barnesHutTree = {
24064 root: {
24065 centerOfMass: {
24066 x: 0,
24067 y: 0
24068 },
24069 mass: 0,
24070 range: {
24071 minX: centerX - halfRootSize,
24072 maxX: centerX + halfRootSize,
24073 minY: centerY - halfRootSize,
24074 maxY: centerY + halfRootSize
24075 },
24076 size: rootSize,
24077 calcSize: 1 / rootSize,
24078 children: {
24079 data: null
24080 },
24081 maxWidth: 0,
24082 level: 0,
24083 childrenCount: 4
24084 }
24085 };
24086
24087 this._splitBranch(barnesHutTree.root); // place the nodes one by one recursively
24088
24089
24090 for (var _i = 0; _i < nodeCount; _i++) {
24091 node = nodes[nodeIndices[_i]];
24092
24093 if (node.options.mass > 0) {
24094 this._placeInTree(barnesHutTree.root, node);
24095 }
24096 } // make global
24097
24098
24099 return barnesHutTree;
24100 }
24101 /**
24102 * this updates the mass of a branch. this is increased by adding a node.
24103 *
24104 * @param {object} parentBranch
24105 * @param {Node} node
24106 * @private
24107 */
24108
24109 }, {
24110 key: "_updateBranchMass",
24111 value: function _updateBranchMass(parentBranch, node) {
24112 var centerOfMass = parentBranch.centerOfMass;
24113 var totalMass = parentBranch.mass + node.options.mass;
24114 var totalMassInv = 1 / totalMass;
24115 centerOfMass.x = centerOfMass.x * parentBranch.mass + node.x * node.options.mass;
24116 centerOfMass.x *= totalMassInv;
24117 centerOfMass.y = centerOfMass.y * parentBranch.mass + node.y * node.options.mass;
24118 centerOfMass.y *= totalMassInv;
24119 parentBranch.mass = totalMass;
24120 var biggestSize = Math.max(Math.max(node.height, node.radius), node.width);
24121 parentBranch.maxWidth = parentBranch.maxWidth < biggestSize ? biggestSize : parentBranch.maxWidth;
24122 }
24123 /**
24124 * determine in which branch the node will be placed.
24125 *
24126 * @param {object} parentBranch
24127 * @param {Node} node
24128 * @param {boolean} skipMassUpdate
24129 * @private
24130 */
24131
24132 }, {
24133 key: "_placeInTree",
24134 value: function _placeInTree(parentBranch, node, skipMassUpdate) {
24135 if (skipMassUpdate != true || skipMassUpdate === undefined) {
24136 // update the mass of the branch.
24137 this._updateBranchMass(parentBranch, node);
24138 }
24139
24140 var range = parentBranch.children.NW.range;
24141 var region;
24142
24143 if (range.maxX > node.x) {
24144 // in NW or SW
24145 if (range.maxY > node.y) {
24146 region = "NW";
24147 } else {
24148 region = "SW";
24149 }
24150 } else {
24151 // in NE or SE
24152 if (range.maxY > node.y) {
24153 region = "NE";
24154 } else {
24155 region = "SE";
24156 }
24157 }
24158
24159 this._placeInRegion(parentBranch, node, region);
24160 }
24161 /**
24162 * actually place the node in a region (or branch)
24163 *
24164 * @param {object} parentBranch
24165 * @param {Node} node
24166 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
24167 * @private
24168 */
24169
24170 }, {
24171 key: "_placeInRegion",
24172 value: function _placeInRegion(parentBranch, node, region) {
24173 var children = parentBranch.children[region];
24174
24175 switch (children.childrenCount) {
24176 case 0:
24177 // place node here
24178 children.children.data = node;
24179 children.childrenCount = 1;
24180
24181 this._updateBranchMass(children, node);
24182
24183 break;
24184
24185 case 1:
24186 // convert into children
24187 // if there are two nodes exactly overlapping (on init, on opening of cluster etc.)
24188 // we move one node a little bit and we do not put it in the tree.
24189 if (children.children.data.x === node.x && children.children.data.y === node.y) {
24190 node.x += this._rng();
24191 node.y += this._rng();
24192 } else {
24193 this._splitBranch(children);
24194
24195 this._placeInTree(children, node);
24196 }
24197
24198 break;
24199
24200 case 4:
24201 // place in branch
24202 this._placeInTree(children, node);
24203
24204 break;
24205 }
24206 }
24207 /**
24208 * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch
24209 * after the split is complete.
24210 *
24211 * @param {object} parentBranch
24212 * @private
24213 */
24214
24215 }, {
24216 key: "_splitBranch",
24217 value: function _splitBranch(parentBranch) {
24218 // if the branch is shaded with a node, replace the node in the new subset.
24219 var containedNode = null;
24220
24221 if (parentBranch.childrenCount === 1) {
24222 containedNode = parentBranch.children.data;
24223 parentBranch.mass = 0;
24224 parentBranch.centerOfMass.x = 0;
24225 parentBranch.centerOfMass.y = 0;
24226 }
24227
24228 parentBranch.childrenCount = 4;
24229 parentBranch.children.data = null;
24230
24231 this._insertRegion(parentBranch, "NW");
24232
24233 this._insertRegion(parentBranch, "NE");
24234
24235 this._insertRegion(parentBranch, "SW");
24236
24237 this._insertRegion(parentBranch, "SE");
24238
24239 if (containedNode != null) {
24240 this._placeInTree(parentBranch, containedNode);
24241 }
24242 }
24243 /**
24244 * This function subdivides the region into four new segments.
24245 * Specifically, this inserts a single new segment.
24246 * It fills the children section of the parentBranch
24247 *
24248 * @param {object} parentBranch
24249 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
24250 * @private
24251 */
24252
24253 }, {
24254 key: "_insertRegion",
24255 value: function _insertRegion(parentBranch, region) {
24256 var minX, maxX, minY, maxY;
24257 var childSize = 0.5 * parentBranch.size;
24258
24259 switch (region) {
24260 case "NW":
24261 minX = parentBranch.range.minX;
24262 maxX = parentBranch.range.minX + childSize;
24263 minY = parentBranch.range.minY;
24264 maxY = parentBranch.range.minY + childSize;
24265 break;
24266
24267 case "NE":
24268 minX = parentBranch.range.minX + childSize;
24269 maxX = parentBranch.range.maxX;
24270 minY = parentBranch.range.minY;
24271 maxY = parentBranch.range.minY + childSize;
24272 break;
24273
24274 case "SW":
24275 minX = parentBranch.range.minX;
24276 maxX = parentBranch.range.minX + childSize;
24277 minY = parentBranch.range.minY + childSize;
24278 maxY = parentBranch.range.maxY;
24279 break;
24280
24281 case "SE":
24282 minX = parentBranch.range.minX + childSize;
24283 maxX = parentBranch.range.maxX;
24284 minY = parentBranch.range.minY + childSize;
24285 maxY = parentBranch.range.maxY;
24286 break;
24287 }
24288
24289 parentBranch.children[region] = {
24290 centerOfMass: {
24291 x: 0,
24292 y: 0
24293 },
24294 mass: 0,
24295 range: {
24296 minX: minX,
24297 maxX: maxX,
24298 minY: minY,
24299 maxY: maxY
24300 },
24301 size: 0.5 * parentBranch.size,
24302 calcSize: 2 * parentBranch.calcSize,
24303 children: {
24304 data: null
24305 },
24306 maxWidth: 0,
24307 level: parentBranch.level + 1,
24308 childrenCount: 0
24309 };
24310 } //--------------------------- DEBUGGING BELOW ---------------------------//
24311
24312 /**
24313 * This function is for debugging purposed, it draws the tree.
24314 *
24315 * @param {CanvasRenderingContext2D} ctx
24316 * @param {string} color
24317 * @private
24318 */
24319
24320 }, {
24321 key: "_debug",
24322 value: function _debug(ctx, color) {
24323 if (this.barnesHutTree !== undefined) {
24324 ctx.lineWidth = 1;
24325
24326 this._drawBranch(this.barnesHutTree.root, ctx, color);
24327 }
24328 }
24329 /**
24330 * This function is for debugging purposes. It draws the branches recursively.
24331 *
24332 * @param {object} branch
24333 * @param {CanvasRenderingContext2D} ctx
24334 * @param {string} color
24335 * @private
24336 */
24337
24338 }, {
24339 key: "_drawBranch",
24340 value: function _drawBranch(branch, ctx, color) {
24341 if (color === undefined) {
24342 color = "#FF0000";
24343 }
24344
24345 if (branch.childrenCount === 4) {
24346 this._drawBranch(branch.children.NW, ctx);
24347
24348 this._drawBranch(branch.children.NE, ctx);
24349
24350 this._drawBranch(branch.children.SE, ctx);
24351
24352 this._drawBranch(branch.children.SW, ctx);
24353 }
24354
24355 ctx.strokeStyle = color;
24356 ctx.beginPath();
24357 ctx.moveTo(branch.range.minX, branch.range.minY);
24358 ctx.lineTo(branch.range.maxX, branch.range.minY);
24359 ctx.stroke();
24360 ctx.beginPath();
24361 ctx.moveTo(branch.range.maxX, branch.range.minY);
24362 ctx.lineTo(branch.range.maxX, branch.range.maxY);
24363 ctx.stroke();
24364 ctx.beginPath();
24365 ctx.moveTo(branch.range.maxX, branch.range.maxY);
24366 ctx.lineTo(branch.range.minX, branch.range.maxY);
24367 ctx.stroke();
24368 ctx.beginPath();
24369 ctx.moveTo(branch.range.minX, branch.range.maxY);
24370 ctx.lineTo(branch.range.minX, branch.range.minY);
24371 ctx.stroke();
24372 /*
24373 if (branch.mass > 0) {
24374 ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass);
24375 ctx.stroke();
24376 }
24377 */
24378 }
24379 }]);
24380
24381 return BarnesHutSolver;
24382 }();
24383
24384 /**
24385 * Repulsion Solver
24386 */
24387
24388 var RepulsionSolver = /*#__PURE__*/function () {
24389 /**
24390 * @param {object} body
24391 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
24392 * @param {object} options
24393 */
24394 function RepulsionSolver(body, physicsBody, options) {
24395 _classCallCheck(this, RepulsionSolver);
24396
24397 this._rng = Alea("REPULSION SOLVER");
24398 this.body = body;
24399 this.physicsBody = physicsBody;
24400 this.setOptions(options);
24401 }
24402 /**
24403 *
24404 * @param {object} options
24405 */
24406
24407
24408 _createClass(RepulsionSolver, [{
24409 key: "setOptions",
24410 value: function setOptions(options) {
24411 this.options = options;
24412 }
24413 /**
24414 * Calculate the forces the nodes apply on each other based on a repulsion field.
24415 * This field is linearly approximated.
24416 *
24417 * @private
24418 */
24419
24420 }, {
24421 key: "solve",
24422 value: function solve() {
24423 var dx, dy, distance, fx, fy, repulsingForce, node1, node2;
24424 var nodes = this.body.nodes;
24425 var nodeIndices = this.physicsBody.physicsNodeIndices;
24426 var forces = this.physicsBody.forces; // repulsing forces between nodes
24427
24428 var nodeDistance = this.options.nodeDistance; // approximation constants
24429
24430 var a = -2 / 3 / nodeDistance;
24431 var b = 4 / 3; // we loop from i over all but the last entree in the array
24432 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
24433
24434 for (var i = 0; i < nodeIndices.length - 1; i++) {
24435 node1 = nodes[nodeIndices[i]];
24436
24437 for (var j = i + 1; j < nodeIndices.length; j++) {
24438 node2 = nodes[nodeIndices[j]];
24439 dx = node2.x - node1.x;
24440 dy = node2.y - node1.y;
24441 distance = Math.sqrt(dx * dx + dy * dy); // same condition as BarnesHutSolver, making sure nodes are never 100% overlapping.
24442
24443 if (distance === 0) {
24444 distance = 0.1 * this._rng();
24445 dx = distance;
24446 }
24447
24448 if (distance < 2 * nodeDistance) {
24449 if (distance < 0.5 * nodeDistance) {
24450 repulsingForce = 1.0;
24451 } else {
24452 repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / nodeDistance - 1) * steepness))
24453 }
24454
24455 repulsingForce = repulsingForce / distance;
24456 fx = dx * repulsingForce;
24457 fy = dy * repulsingForce;
24458 forces[node1.id].x -= fx;
24459 forces[node1.id].y -= fy;
24460 forces[node2.id].x += fx;
24461 forces[node2.id].y += fy;
24462 }
24463 }
24464 }
24465 }
24466 }]);
24467
24468 return RepulsionSolver;
24469 }();
24470
24471 /**
24472 * Hierarchical Repulsion Solver
24473 */
24474 var HierarchicalRepulsionSolver = /*#__PURE__*/function () {
24475 /**
24476 * @param {object} body
24477 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
24478 * @param {object} options
24479 */
24480 function HierarchicalRepulsionSolver(body, physicsBody, options) {
24481 _classCallCheck(this, HierarchicalRepulsionSolver);
24482
24483 this.body = body;
24484 this.physicsBody = physicsBody;
24485 this.setOptions(options);
24486 }
24487 /**
24488 *
24489 * @param {object} options
24490 */
24491
24492
24493 _createClass(HierarchicalRepulsionSolver, [{
24494 key: "setOptions",
24495 value: function setOptions(options) {
24496 this.options = options;
24497 this.overlapAvoidanceFactor = Math.max(0, Math.min(1, this.options.avoidOverlap || 0));
24498 }
24499 /**
24500 * Calculate the forces the nodes apply on each other based on a repulsion field.
24501 * This field is linearly approximated.
24502 *
24503 * @private
24504 */
24505
24506 }, {
24507 key: "solve",
24508 value: function solve() {
24509 var nodes = this.body.nodes;
24510 var nodeIndices = this.physicsBody.physicsNodeIndices;
24511 var forces = this.physicsBody.forces; // repulsing forces between nodes
24512
24513 var nodeDistance = this.options.nodeDistance; // we loop from i over all but the last entree in the array
24514 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
24515
24516 for (var i = 0; i < nodeIndices.length - 1; i++) {
24517 var node1 = nodes[nodeIndices[i]];
24518
24519 for (var j = i + 1; j < nodeIndices.length; j++) {
24520 var node2 = nodes[nodeIndices[j]]; // nodes only affect nodes on their level
24521
24522 if (node1.level === node2.level) {
24523 var theseNodesDistance = nodeDistance + this.overlapAvoidanceFactor * ((node1.shape.radius || 0) / 2 + (node2.shape.radius || 0) / 2);
24524 var dx = node2.x - node1.x;
24525 var dy = node2.y - node1.y;
24526 var distance = Math.sqrt(dx * dx + dy * dy);
24527 var steepness = 0.05;
24528 var repulsingForce = void 0;
24529
24530 if (distance < theseNodesDistance) {
24531 repulsingForce = -Math.pow(steepness * distance, 2) + Math.pow(steepness * theseNodesDistance, 2);
24532 } else {
24533 repulsingForce = 0;
24534 } // normalize force with
24535
24536
24537 if (distance !== 0) {
24538 repulsingForce = repulsingForce / distance;
24539 }
24540
24541 var fx = dx * repulsingForce;
24542 var fy = dy * repulsingForce;
24543 forces[node1.id].x -= fx;
24544 forces[node1.id].y -= fy;
24545 forces[node2.id].x += fx;
24546 forces[node2.id].y += fy;
24547 }
24548 }
24549 }
24550 }
24551 }]);
24552
24553 return HierarchicalRepulsionSolver;
24554 }();
24555
24556 /**
24557 * Spring Solver
24558 */
24559 var SpringSolver = /*#__PURE__*/function () {
24560 /**
24561 * @param {object} body
24562 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
24563 * @param {object} options
24564 */
24565 function SpringSolver(body, physicsBody, options) {
24566 _classCallCheck(this, SpringSolver);
24567
24568 this.body = body;
24569 this.physicsBody = physicsBody;
24570 this.setOptions(options);
24571 }
24572 /**
24573 *
24574 * @param {object} options
24575 */
24576
24577
24578 _createClass(SpringSolver, [{
24579 key: "setOptions",
24580 value: function setOptions(options) {
24581 this.options = options;
24582 }
24583 /**
24584 * This function calculates the springforces on the nodes, accounting for the support nodes.
24585 *
24586 * @private
24587 */
24588
24589 }, {
24590 key: "solve",
24591 value: function solve() {
24592 var edgeLength, edge;
24593 var edgeIndices = this.physicsBody.physicsEdgeIndices;
24594 var edges = this.body.edges;
24595 var node1, node2, node3; // forces caused by the edges, modelled as springs
24596
24597 for (var i = 0; i < edgeIndices.length; i++) {
24598 edge = edges[edgeIndices[i]];
24599
24600 if (edge.connected === true && edge.toId !== edge.fromId) {
24601 // only calculate forces if nodes are in the same sector
24602 if (this.body.nodes[edge.toId] !== undefined && this.body.nodes[edge.fromId] !== undefined) {
24603 if (edge.edgeType.via !== undefined) {
24604 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
24605 node1 = edge.to;
24606 node2 = edge.edgeType.via;
24607 node3 = edge.from;
24608
24609 this._calculateSpringForce(node1, node2, 0.5 * edgeLength);
24610
24611 this._calculateSpringForce(node2, node3, 0.5 * edgeLength);
24612 } else {
24613 // the * 1.5 is here so the edge looks as large as a smooth edge. It does not initially because the smooth edges use
24614 // the support nodes which exert a repulsive force on the to and from nodes, making the edge appear larger.
24615 edgeLength = edge.options.length === undefined ? this.options.springLength * 1.5 : edge.options.length;
24616
24617 this._calculateSpringForce(edge.from, edge.to, edgeLength);
24618 }
24619 }
24620 }
24621 }
24622 }
24623 /**
24624 * This is the code actually performing the calculation for the function above.
24625 *
24626 * @param {Node} node1
24627 * @param {Node} node2
24628 * @param {number} edgeLength
24629 * @private
24630 */
24631
24632 }, {
24633 key: "_calculateSpringForce",
24634 value: function _calculateSpringForce(node1, node2, edgeLength) {
24635 var dx = node1.x - node2.x;
24636 var dy = node1.y - node2.y;
24637 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.
24638
24639 var springForce = this.options.springConstant * (edgeLength - distance) / distance;
24640 var fx = dx * springForce;
24641 var fy = dy * springForce; // handle the case where one node is not part of the physcis
24642
24643 if (this.physicsBody.forces[node1.id] !== undefined) {
24644 this.physicsBody.forces[node1.id].x += fx;
24645 this.physicsBody.forces[node1.id].y += fy;
24646 }
24647
24648 if (this.physicsBody.forces[node2.id] !== undefined) {
24649 this.physicsBody.forces[node2.id].x -= fx;
24650 this.physicsBody.forces[node2.id].y -= fy;
24651 }
24652 }
24653 }]);
24654
24655 return SpringSolver;
24656 }();
24657
24658 /**
24659 * Hierarchical Spring Solver
24660 */
24661 var HierarchicalSpringSolver = /*#__PURE__*/function () {
24662 /**
24663 * @param {object} body
24664 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
24665 * @param {object} options
24666 */
24667 function HierarchicalSpringSolver(body, physicsBody, options) {
24668 _classCallCheck(this, HierarchicalSpringSolver);
24669
24670 this.body = body;
24671 this.physicsBody = physicsBody;
24672 this.setOptions(options);
24673 }
24674 /**
24675 *
24676 * @param {object} options
24677 */
24678
24679
24680 _createClass(HierarchicalSpringSolver, [{
24681 key: "setOptions",
24682 value: function setOptions(options) {
24683 this.options = options;
24684 }
24685 /**
24686 * This function calculates the springforces on the nodes, accounting for the support nodes.
24687 *
24688 * @private
24689 */
24690
24691 }, {
24692 key: "solve",
24693 value: function solve() {
24694 var edgeLength, edge;
24695 var dx, dy, fx, fy, springForce, distance;
24696 var edges = this.body.edges;
24697 var factor = 0.5;
24698 var edgeIndices = this.physicsBody.physicsEdgeIndices;
24699 var nodeIndices = this.physicsBody.physicsNodeIndices;
24700 var forces = this.physicsBody.forces; // initialize the spring force counters
24701
24702 for (var i = 0; i < nodeIndices.length; i++) {
24703 var nodeId = nodeIndices[i];
24704 forces[nodeId].springFx = 0;
24705 forces[nodeId].springFy = 0;
24706 } // forces caused by the edges, modelled as springs
24707
24708
24709 for (var _i = 0; _i < edgeIndices.length; _i++) {
24710 edge = edges[edgeIndices[_i]];
24711
24712 if (edge.connected === true) {
24713 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
24714 dx = edge.from.x - edge.to.x;
24715 dy = edge.from.y - edge.to.y;
24716 distance = Math.sqrt(dx * dx + dy * dy);
24717 distance = distance === 0 ? 0.01 : distance; // the 1/distance is so the fx and fy can be calculated without sine or cosine.
24718
24719 springForce = this.options.springConstant * (edgeLength - distance) / distance;
24720 fx = dx * springForce;
24721 fy = dy * springForce;
24722
24723 if (edge.to.level != edge.from.level) {
24724 if (forces[edge.toId] !== undefined) {
24725 forces[edge.toId].springFx -= fx;
24726 forces[edge.toId].springFy -= fy;
24727 }
24728
24729 if (forces[edge.fromId] !== undefined) {
24730 forces[edge.fromId].springFx += fx;
24731 forces[edge.fromId].springFy += fy;
24732 }
24733 } else {
24734 if (forces[edge.toId] !== undefined) {
24735 forces[edge.toId].x -= factor * fx;
24736 forces[edge.toId].y -= factor * fy;
24737 }
24738
24739 if (forces[edge.fromId] !== undefined) {
24740 forces[edge.fromId].x += factor * fx;
24741 forces[edge.fromId].y += factor * fy;
24742 }
24743 }
24744 }
24745 } // normalize spring forces
24746
24747
24748 springForce = 1;
24749 var springFx, springFy;
24750
24751 for (var _i2 = 0; _i2 < nodeIndices.length; _i2++) {
24752 var _nodeId = nodeIndices[_i2];
24753 springFx = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFx));
24754 springFy = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFy));
24755 forces[_nodeId].x += springFx;
24756 forces[_nodeId].y += springFy;
24757 } // retain energy balance
24758
24759
24760 var totalFx = 0;
24761 var totalFy = 0;
24762
24763 for (var _i3 = 0; _i3 < nodeIndices.length; _i3++) {
24764 var _nodeId2 = nodeIndices[_i3];
24765 totalFx += forces[_nodeId2].x;
24766 totalFy += forces[_nodeId2].y;
24767 }
24768
24769 var correctionFx = totalFx / nodeIndices.length;
24770 var correctionFy = totalFy / nodeIndices.length;
24771
24772 for (var _i4 = 0; _i4 < nodeIndices.length; _i4++) {
24773 var _nodeId3 = nodeIndices[_i4];
24774 forces[_nodeId3].x -= correctionFx;
24775 forces[_nodeId3].y -= correctionFy;
24776 }
24777 }
24778 }]);
24779
24780 return HierarchicalSpringSolver;
24781 }();
24782
24783 /**
24784 * Central Gravity Solver
24785 */
24786 var CentralGravitySolver = /*#__PURE__*/function () {
24787 /**
24788 * @param {object} body
24789 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
24790 * @param {object} options
24791 */
24792 function CentralGravitySolver(body, physicsBody, options) {
24793 _classCallCheck(this, CentralGravitySolver);
24794
24795 this.body = body;
24796 this.physicsBody = physicsBody;
24797 this.setOptions(options);
24798 }
24799 /**
24800 *
24801 * @param {object} options
24802 */
24803
24804
24805 _createClass(CentralGravitySolver, [{
24806 key: "setOptions",
24807 value: function setOptions(options) {
24808 this.options = options;
24809 }
24810 /**
24811 * Calculates forces for each node
24812 */
24813
24814 }, {
24815 key: "solve",
24816 value: function solve() {
24817 var dx, dy, distance, node;
24818 var nodes = this.body.nodes;
24819 var nodeIndices = this.physicsBody.physicsNodeIndices;
24820 var forces = this.physicsBody.forces;
24821
24822 for (var i = 0; i < nodeIndices.length; i++) {
24823 var nodeId = nodeIndices[i];
24824 node = nodes[nodeId];
24825 dx = -node.x;
24826 dy = -node.y;
24827 distance = Math.sqrt(dx * dx + dy * dy);
24828
24829 this._calculateForces(distance, dx, dy, forces, node);
24830 }
24831 }
24832 /**
24833 * Calculate the forces based on the distance.
24834 *
24835 * @param {number} distance
24836 * @param {number} dx
24837 * @param {number} dy
24838 * @param {object<Node.id, vis.Node>} forces
24839 * @param {Node} node
24840 * @private
24841 */
24842
24843 }, {
24844 key: "_calculateForces",
24845 value: function _calculateForces(distance, dx, dy, forces, node) {
24846 var gravityForce = distance === 0 ? 0 : this.options.centralGravity / distance;
24847 forces[node.id].x = dx * gravityForce;
24848 forces[node.id].y = dy * gravityForce;
24849 }
24850 }]);
24851
24852 return CentralGravitySolver;
24853 }();
24854
24855 function _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); }; }
24856
24857 function _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; } }
24858 /**
24859 * @augments BarnesHutSolver
24860 */
24861
24862 var ForceAtlas2BasedRepulsionSolver = /*#__PURE__*/function (_BarnesHutSolver) {
24863 _inherits(ForceAtlas2BasedRepulsionSolver, _BarnesHutSolver);
24864
24865 var _super = _createSuper$3(ForceAtlas2BasedRepulsionSolver);
24866
24867 /**
24868 * @param {object} body
24869 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
24870 * @param {object} options
24871 */
24872 function ForceAtlas2BasedRepulsionSolver(body, physicsBody, options) {
24873 var _this;
24874
24875 _classCallCheck(this, ForceAtlas2BasedRepulsionSolver);
24876
24877 _this = _super.call(this, body, physicsBody, options);
24878 _this._rng = Alea("FORCE ATLAS 2 BASED REPULSION SOLVER");
24879 return _this;
24880 }
24881 /**
24882 * Calculate the forces based on the distance.
24883 *
24884 * @param {number} distance
24885 * @param {number} dx
24886 * @param {number} dy
24887 * @param {Node} node
24888 * @param {object} parentBranch
24889 * @private
24890 */
24891
24892
24893 _createClass(ForceAtlas2BasedRepulsionSolver, [{
24894 key: "_calculateForces",
24895 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
24896 if (distance === 0) {
24897 distance = 0.1 * this._rng();
24898 dx = distance;
24899 }
24900
24901 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
24902 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
24903 }
24904
24905 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
24906 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
24907
24908 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass * degree / Math.pow(distance, 2);
24909 var fx = dx * gravityForce;
24910 var fy = dy * gravityForce;
24911 this.physicsBody.forces[node.id].x += fx;
24912 this.physicsBody.forces[node.id].y += fy;
24913 }
24914 }]);
24915
24916 return ForceAtlas2BasedRepulsionSolver;
24917 }(BarnesHutSolver);
24918
24919 function _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); }; }
24920
24921 function _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; } }
24922 /**
24923 * @augments CentralGravitySolver
24924 */
24925
24926 var ForceAtlas2BasedCentralGravitySolver = /*#__PURE__*/function (_CentralGravitySolver) {
24927 _inherits(ForceAtlas2BasedCentralGravitySolver, _CentralGravitySolver);
24928
24929 var _super = _createSuper$2(ForceAtlas2BasedCentralGravitySolver);
24930
24931 /**
24932 * @param {object} body
24933 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
24934 * @param {object} options
24935 */
24936 function ForceAtlas2BasedCentralGravitySolver(body, physicsBody, options) {
24937 _classCallCheck(this, ForceAtlas2BasedCentralGravitySolver);
24938
24939 return _super.call(this, body, physicsBody, options);
24940 }
24941 /**
24942 * Calculate the forces based on the distance.
24943 *
24944 * @param {number} distance
24945 * @param {number} dx
24946 * @param {number} dy
24947 * @param {object<Node.id, Node>} forces
24948 * @param {Node} node
24949 * @private
24950 */
24951
24952
24953 _createClass(ForceAtlas2BasedCentralGravitySolver, [{
24954 key: "_calculateForces",
24955 value: function _calculateForces(distance, dx, dy, forces, node) {
24956 if (distance > 0) {
24957 var degree = node.edges.length + 1;
24958 var gravityForce = this.options.centralGravity * degree * node.options.mass;
24959 forces[node.id].x = dx * gravityForce;
24960 forces[node.id].y = dy * gravityForce;
24961 }
24962 }
24963 }]);
24964
24965 return ForceAtlas2BasedCentralGravitySolver;
24966 }(CentralGravitySolver);
24967
24968 /**
24969 * The physics engine
24970 */
24971
24972 var PhysicsEngine = /*#__PURE__*/function () {
24973 /**
24974 * @param {object} body
24975 */
24976 function PhysicsEngine(body) {
24977 _classCallCheck(this, PhysicsEngine);
24978
24979 this.body = body;
24980 this.physicsBody = {
24981 physicsNodeIndices: [],
24982 physicsEdgeIndices: [],
24983 forces: {},
24984 velocities: {}
24985 };
24986 this.physicsEnabled = true;
24987 this.simulationInterval = 1000 / 60;
24988 this.requiresTimeout = true;
24989 this.previousStates = {};
24990 this.referenceState = {};
24991 this.freezeCache = {};
24992 this.renderTimer = undefined; // parameters for the adaptive timestep
24993
24994 this.adaptiveTimestep = false;
24995 this.adaptiveTimestepEnabled = false;
24996 this.adaptiveCounter = 0;
24997 this.adaptiveInterval = 3;
24998 this.stabilized = false;
24999 this.startedStabilization = false;
25000 this.stabilizationIterations = 0;
25001 this.ready = false; // will be set to true if the stabilize
25002 // default options
25003
25004 this.options = {};
25005 this.defaultOptions = {
25006 enabled: true,
25007 barnesHut: {
25008 theta: 0.5,
25009 gravitationalConstant: -2000,
25010 centralGravity: 0.3,
25011 springLength: 95,
25012 springConstant: 0.04,
25013 damping: 0.09,
25014 avoidOverlap: 0
25015 },
25016 forceAtlas2Based: {
25017 theta: 0.5,
25018 gravitationalConstant: -50,
25019 centralGravity: 0.01,
25020 springConstant: 0.08,
25021 springLength: 100,
25022 damping: 0.4,
25023 avoidOverlap: 0
25024 },
25025 repulsion: {
25026 centralGravity: 0.2,
25027 springLength: 200,
25028 springConstant: 0.05,
25029 nodeDistance: 100,
25030 damping: 0.09,
25031 avoidOverlap: 0
25032 },
25033 hierarchicalRepulsion: {
25034 centralGravity: 0.0,
25035 springLength: 100,
25036 springConstant: 0.01,
25037 nodeDistance: 120,
25038 damping: 0.09
25039 },
25040 maxVelocity: 50,
25041 minVelocity: 0.75,
25042 // px/s
25043 solver: "barnesHut",
25044 stabilization: {
25045 enabled: true,
25046 iterations: 1000,
25047 // maximum number of iteration to stabilize
25048 updateInterval: 50,
25049 onlyDynamicEdges: false,
25050 fit: true
25051 },
25052 timestep: 0.5,
25053 adaptiveTimestep: true,
25054 wind: {
25055 x: 0,
25056 y: 0
25057 }
25058 };
25059
25060 assign$2(this.options, this.defaultOptions);
25061
25062 this.timestep = 0.5;
25063 this.layoutFailed = false;
25064 this.bindEventListeners();
25065 }
25066 /**
25067 * Binds event listeners
25068 */
25069
25070
25071 _createClass(PhysicsEngine, [{
25072 key: "bindEventListeners",
25073 value: function bindEventListeners() {
25074 var _this = this;
25075
25076 this.body.emitter.on("initPhysics", function () {
25077 _this.initPhysics();
25078 });
25079 this.body.emitter.on("_layoutFailed", function () {
25080 _this.layoutFailed = true;
25081 });
25082 this.body.emitter.on("resetPhysics", function () {
25083 _this.stopSimulation();
25084
25085 _this.ready = false;
25086 });
25087 this.body.emitter.on("disablePhysics", function () {
25088 _this.physicsEnabled = false;
25089
25090 _this.stopSimulation();
25091 });
25092 this.body.emitter.on("restorePhysics", function () {
25093 _this.setOptions(_this.options);
25094
25095 if (_this.ready === true) {
25096 _this.startSimulation();
25097 }
25098 });
25099 this.body.emitter.on("startSimulation", function () {
25100 if (_this.ready === true) {
25101 _this.startSimulation();
25102 }
25103 });
25104 this.body.emitter.on("stopSimulation", function () {
25105 _this.stopSimulation();
25106 });
25107 this.body.emitter.on("destroy", function () {
25108 _this.stopSimulation(false);
25109
25110 _this.body.emitter.off();
25111 });
25112 this.body.emitter.on("_dataChanged", function () {
25113 // Nodes and/or edges have been added or removed, update shortcut lists.
25114 _this.updatePhysicsData();
25115 }); // debug: show forces
25116 // this.body.emitter.on("afterDrawing", (ctx) => {this._drawForces(ctx);});
25117 }
25118 /**
25119 * set the physics options
25120 *
25121 * @param {object} options
25122 */
25123
25124 }, {
25125 key: "setOptions",
25126 value: function setOptions(options) {
25127 if (options !== undefined) {
25128 if (options === false) {
25129 this.options.enabled = false;
25130 this.physicsEnabled = false;
25131 this.stopSimulation();
25132 } else if (options === true) {
25133 this.options.enabled = true;
25134 this.physicsEnabled = true;
25135 this.startSimulation();
25136 } else {
25137 this.physicsEnabled = true;
25138 selectiveNotDeepExtend(["stabilization"], this.options, options);
25139 mergeOptions(this.options, options, "stabilization");
25140
25141 if (options.enabled === undefined) {
25142 this.options.enabled = true;
25143 }
25144
25145 if (this.options.enabled === false) {
25146 this.physicsEnabled = false;
25147 this.stopSimulation();
25148 }
25149
25150 var wind = this.options.wind;
25151
25152 if (wind) {
25153 if (typeof wind.x !== "number" || isNan(wind.x)) {
25154 wind.x = 0;
25155 }
25156
25157 if (typeof wind.y !== "number" || isNan(wind.y)) {
25158 wind.y = 0;
25159 }
25160 } // set the timestep
25161
25162
25163 this.timestep = this.options.timestep;
25164 }
25165 }
25166
25167 this.init();
25168 }
25169 /**
25170 * configure the engine.
25171 */
25172
25173 }, {
25174 key: "init",
25175 value: function init() {
25176 var options;
25177
25178 if (this.options.solver === "forceAtlas2Based") {
25179 options = this.options.forceAtlas2Based;
25180 this.nodesSolver = new ForceAtlas2BasedRepulsionSolver(this.body, this.physicsBody, options);
25181 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
25182 this.gravitySolver = new ForceAtlas2BasedCentralGravitySolver(this.body, this.physicsBody, options);
25183 } else if (this.options.solver === "repulsion") {
25184 options = this.options.repulsion;
25185 this.nodesSolver = new RepulsionSolver(this.body, this.physicsBody, options);
25186 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
25187 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
25188 } else if (this.options.solver === "hierarchicalRepulsion") {
25189 options = this.options.hierarchicalRepulsion;
25190 this.nodesSolver = new HierarchicalRepulsionSolver(this.body, this.physicsBody, options);
25191 this.edgesSolver = new HierarchicalSpringSolver(this.body, this.physicsBody, options);
25192 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
25193 } else {
25194 // barnesHut
25195 options = this.options.barnesHut;
25196 this.nodesSolver = new BarnesHutSolver(this.body, this.physicsBody, options);
25197 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
25198 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
25199 }
25200
25201 this.modelOptions = options;
25202 }
25203 /**
25204 * initialize the engine
25205 */
25206
25207 }, {
25208 key: "initPhysics",
25209 value: function initPhysics() {
25210 if (this.physicsEnabled === true && this.options.enabled === true) {
25211 if (this.options.stabilization.enabled === true) {
25212 this.stabilize();
25213 } else {
25214 this.stabilized = false;
25215 this.ready = true;
25216 this.body.emitter.emit("fit", {}, this.layoutFailed); // if the layout failed, we use the approximation for the zoom
25217
25218 this.startSimulation();
25219 }
25220 } else {
25221 this.ready = true;
25222 this.body.emitter.emit("fit");
25223 }
25224 }
25225 /**
25226 * Start the simulation
25227 */
25228
25229 }, {
25230 key: "startSimulation",
25231 value: function startSimulation() {
25232 if (this.physicsEnabled === true && this.options.enabled === true) {
25233 this.stabilized = false; // when visible, adaptivity is disabled.
25234
25235 this.adaptiveTimestep = false; // this sets the width of all nodes initially which could be required for the avoidOverlap
25236
25237 this.body.emitter.emit("_resizeNodes");
25238
25239 if (this.viewFunction === undefined) {
25240 var _context;
25241
25242 this.viewFunction = bind$5(_context = this.simulationStep).call(_context, this);
25243 this.body.emitter.on("initRedraw", this.viewFunction);
25244 this.body.emitter.emit("_startRendering");
25245 }
25246 } else {
25247 this.body.emitter.emit("_redraw");
25248 }
25249 }
25250 /**
25251 * Stop the simulation, force stabilization.
25252 *
25253 * @param {boolean} [emit=true]
25254 */
25255
25256 }, {
25257 key: "stopSimulation",
25258 value: function stopSimulation() {
25259 var emit = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
25260 this.stabilized = true;
25261
25262 if (emit === true) {
25263 this._emitStabilized();
25264 }
25265
25266 if (this.viewFunction !== undefined) {
25267 this.body.emitter.off("initRedraw", this.viewFunction);
25268 this.viewFunction = undefined;
25269
25270 if (emit === true) {
25271 this.body.emitter.emit("_stopRendering");
25272 }
25273 }
25274 }
25275 /**
25276 * The viewFunction inserts this step into each render loop. It calls the physics tick and handles the cleanup at stabilized.
25277 *
25278 */
25279
25280 }, {
25281 key: "simulationStep",
25282 value: function simulationStep() {
25283 // check if the physics have settled
25284 var startTime = now$1();
25285
25286 this.physicsTick();
25287 var physicsTime = now$1() - startTime; // run double speed if it is a little graph
25288
25289 if ((physicsTime < 0.4 * this.simulationInterval || this.runDoubleSpeed === true) && this.stabilized === false) {
25290 this.physicsTick(); // this makes sure there is no jitter. The decision is taken once to run it at double speed.
25291
25292 this.runDoubleSpeed = true;
25293 }
25294
25295 if (this.stabilized === true) {
25296 this.stopSimulation();
25297 }
25298 }
25299 /**
25300 * trigger the stabilized event.
25301 *
25302 * @param {number} [amountOfIterations=this.stabilizationIterations]
25303 * @private
25304 */
25305
25306 }, {
25307 key: "_emitStabilized",
25308 value: function _emitStabilized() {
25309 var _this2 = this;
25310
25311 var amountOfIterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.stabilizationIterations;
25312
25313 if (this.stabilizationIterations > 1 || this.startedStabilization === true) {
25314 setTimeout$1(function () {
25315 _this2.body.emitter.emit("stabilized", {
25316 iterations: amountOfIterations
25317 });
25318
25319 _this2.startedStabilization = false;
25320 _this2.stabilizationIterations = 0;
25321 }, 0);
25322 }
25323 }
25324 /**
25325 * Calculate the forces for one physics iteration and move the nodes.
25326 *
25327 * @private
25328 */
25329
25330 }, {
25331 key: "physicsStep",
25332 value: function physicsStep() {
25333 this.gravitySolver.solve();
25334 this.nodesSolver.solve();
25335 this.edgesSolver.solve();
25336 this.moveNodes();
25337 }
25338 /**
25339 * Make dynamic adjustments to the timestep, based on current state.
25340 *
25341 * Helper function for physicsTick().
25342 *
25343 * @private
25344 */
25345
25346 }, {
25347 key: "adjustTimeStep",
25348 value: function adjustTimeStep() {
25349 var factor = 1.2; // Factor for increasing the timestep on success.
25350 // we compare the two steps. if it is acceptable we double the step.
25351
25352 if (this._evaluateStepQuality() === true) {
25353 this.timestep = factor * this.timestep;
25354 } else {
25355 // if not, we decrease the step to a minimum of the options timestep.
25356 // if the decreased timestep is smaller than the options step, we do not reset the counter
25357 // we assume that the options timestep is stable enough.
25358 if (this.timestep / factor < this.options.timestep) {
25359 this.timestep = this.options.timestep;
25360 } else {
25361 // if the timestep was larger than 2 times the option one we check the adaptivity again to ensure
25362 // that large instabilities do not form.
25363 this.adaptiveCounter = -1; // check again next iteration
25364
25365 this.timestep = Math.max(this.options.timestep, this.timestep / factor);
25366 }
25367 }
25368 }
25369 /**
25370 * A single simulation step (or 'tick') in the physics simulation
25371 *
25372 * @private
25373 */
25374
25375 }, {
25376 key: "physicsTick",
25377 value: function physicsTick() {
25378 this._startStabilizing(); // this ensures that there is no start event when the network is already stable.
25379
25380
25381 if (this.stabilized === true) return; // adaptivity means the timestep adapts to the situation, only applicable for stabilization
25382
25383 if (this.adaptiveTimestep === true && this.adaptiveTimestepEnabled === true) {
25384 // timestep remains stable for "interval" iterations.
25385 var doAdaptive = this.adaptiveCounter % this.adaptiveInterval === 0;
25386
25387 if (doAdaptive) {
25388 // first the big step and revert.
25389 this.timestep = 2 * this.timestep;
25390 this.physicsStep();
25391 this.revert(); // saves the reference state
25392 // now the normal step. Since this is the last step, it is the more stable one and we will take this.
25393
25394 this.timestep = 0.5 * this.timestep; // since it's half the step, we do it twice.
25395
25396 this.physicsStep();
25397 this.physicsStep();
25398 this.adjustTimeStep();
25399 } else {
25400 this.physicsStep(); // normal step, keeping timestep constant
25401 }
25402
25403 this.adaptiveCounter += 1;
25404 } else {
25405 // case for the static timestep, we reset it to the one in options and take a normal step.
25406 this.timestep = this.options.timestep;
25407 this.physicsStep();
25408 }
25409
25410 if (this.stabilized === true) this.revert();
25411 this.stabilizationIterations++;
25412 }
25413 /**
25414 * 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.
25415 *
25416 * @private
25417 */
25418
25419 }, {
25420 key: "updatePhysicsData",
25421 value: function updatePhysicsData() {
25422 this.physicsBody.forces = {};
25423 this.physicsBody.physicsNodeIndices = [];
25424 this.physicsBody.physicsEdgeIndices = [];
25425 var nodes = this.body.nodes;
25426 var edges = this.body.edges; // get node indices for physics
25427
25428 for (var nodeId in nodes) {
25429 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
25430 if (nodes[nodeId].options.physics === true) {
25431 this.physicsBody.physicsNodeIndices.push(nodes[nodeId].id);
25432 }
25433 }
25434 } // get edge indices for physics
25435
25436
25437 for (var edgeId in edges) {
25438 if (Object.prototype.hasOwnProperty.call(edges, edgeId)) {
25439 if (edges[edgeId].options.physics === true) {
25440 this.physicsBody.physicsEdgeIndices.push(edges[edgeId].id);
25441 }
25442 }
25443 } // get the velocity and the forces vector
25444
25445
25446 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
25447 var _nodeId = this.physicsBody.physicsNodeIndices[i];
25448 this.physicsBody.forces[_nodeId] = {
25449 x: 0,
25450 y: 0
25451 }; // forces can be reset because they are recalculated. Velocities have to persist.
25452
25453 if (this.physicsBody.velocities[_nodeId] === undefined) {
25454 this.physicsBody.velocities[_nodeId] = {
25455 x: 0,
25456 y: 0
25457 };
25458 }
25459 } // clean deleted nodes from the velocity vector
25460
25461
25462 for (var _nodeId2 in this.physicsBody.velocities) {
25463 if (nodes[_nodeId2] === undefined) {
25464 delete this.physicsBody.velocities[_nodeId2];
25465 }
25466 }
25467 }
25468 /**
25469 * Revert the simulation one step. This is done so after stabilization, every new start of the simulation will also say stabilized.
25470 */
25471
25472 }, {
25473 key: "revert",
25474 value: function revert() {
25475 var nodeIds = keys(this.previousStates);
25476
25477 var nodes = this.body.nodes;
25478 var velocities = this.physicsBody.velocities;
25479 this.referenceState = {};
25480
25481 for (var i = 0; i < nodeIds.length; i++) {
25482 var nodeId = nodeIds[i];
25483
25484 if (nodes[nodeId] !== undefined) {
25485 if (nodes[nodeId].options.physics === true) {
25486 this.referenceState[nodeId] = {
25487 positions: {
25488 x: nodes[nodeId].x,
25489 y: nodes[nodeId].y
25490 }
25491 };
25492 velocities[nodeId].x = this.previousStates[nodeId].vx;
25493 velocities[nodeId].y = this.previousStates[nodeId].vy;
25494 nodes[nodeId].x = this.previousStates[nodeId].x;
25495 nodes[nodeId].y = this.previousStates[nodeId].y;
25496 }
25497 } else {
25498 delete this.previousStates[nodeId];
25499 }
25500 }
25501 }
25502 /**
25503 * This compares the reference state to the current state
25504 *
25505 * @returns {boolean}
25506 * @private
25507 */
25508
25509 }, {
25510 key: "_evaluateStepQuality",
25511 value: function _evaluateStepQuality() {
25512 var dx, dy, dpos;
25513 var nodes = this.body.nodes;
25514 var reference = this.referenceState;
25515 var posThreshold = 0.3;
25516
25517 for (var nodeId in this.referenceState) {
25518 if (Object.prototype.hasOwnProperty.call(this.referenceState, nodeId) && nodes[nodeId] !== undefined) {
25519 dx = nodes[nodeId].x - reference[nodeId].positions.x;
25520 dy = nodes[nodeId].y - reference[nodeId].positions.y;
25521 dpos = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
25522
25523 if (dpos > posThreshold) {
25524 return false;
25525 }
25526 }
25527 }
25528
25529 return true;
25530 }
25531 /**
25532 * move the nodes one timestep and check if they are stabilized
25533 */
25534
25535 }, {
25536 key: "moveNodes",
25537 value: function moveNodes() {
25538 var nodeIndices = this.physicsBody.physicsNodeIndices;
25539 var maxNodeVelocity = 0;
25540 var averageNodeVelocity = 0; // the velocity threshold (energy in the system) for the adaptivity toggle
25541
25542 var velocityAdaptiveThreshold = 5;
25543
25544 for (var i = 0; i < nodeIndices.length; i++) {
25545 var nodeId = nodeIndices[i];
25546
25547 var nodeVelocity = this._performStep(nodeId); // stabilized is true if stabilized is true and velocity is smaller than vmin --> all nodes must be stabilized
25548
25549
25550 maxNodeVelocity = Math.max(maxNodeVelocity, nodeVelocity);
25551 averageNodeVelocity += nodeVelocity;
25552 } // evaluating the stabilized and adaptiveTimestepEnabled conditions
25553
25554
25555 this.adaptiveTimestepEnabled = averageNodeVelocity / nodeIndices.length < velocityAdaptiveThreshold;
25556 this.stabilized = maxNodeVelocity < this.options.minVelocity;
25557 }
25558 /**
25559 * Calculate new velocity for a coordinate direction
25560 *
25561 * @param {number} v velocity for current coordinate
25562 * @param {number} f regular force for current coordinate
25563 * @param {number} m mass of current node
25564 * @returns {number} new velocity for current coordinate
25565 * @private
25566 */
25567
25568 }, {
25569 key: "calculateComponentVelocity",
25570 value: function calculateComponentVelocity(v, f, m) {
25571 var df = this.modelOptions.damping * v; // damping force
25572
25573 var a = (f - df) / m; // acceleration
25574
25575 v += a * this.timestep; // Put a limit on the velocities if it is really high
25576
25577 var maxV = this.options.maxVelocity || 1e9;
25578
25579 if (Math.abs(v) > maxV) {
25580 v = v > 0 ? maxV : -maxV;
25581 }
25582
25583 return v;
25584 }
25585 /**
25586 * Perform the actual step
25587 *
25588 * @param {Node.id} nodeId
25589 * @returns {number} the new velocity of given node
25590 * @private
25591 */
25592
25593 }, {
25594 key: "_performStep",
25595 value: function _performStep(nodeId) {
25596 var node = this.body.nodes[nodeId];
25597 var force = this.physicsBody.forces[nodeId];
25598
25599 if (this.options.wind) {
25600 force.x += this.options.wind.x;
25601 force.y += this.options.wind.y;
25602 }
25603
25604 var velocity = this.physicsBody.velocities[nodeId]; // store the state so we can revert
25605
25606 this.previousStates[nodeId] = {
25607 x: node.x,
25608 y: node.y,
25609 vx: velocity.x,
25610 vy: velocity.y
25611 };
25612
25613 if (node.options.fixed.x === false) {
25614 velocity.x = this.calculateComponentVelocity(velocity.x, force.x, node.options.mass);
25615 node.x += velocity.x * this.timestep;
25616 } else {
25617 force.x = 0;
25618 velocity.x = 0;
25619 }
25620
25621 if (node.options.fixed.y === false) {
25622 velocity.y = this.calculateComponentVelocity(velocity.y, force.y, node.options.mass);
25623 node.y += velocity.y * this.timestep;
25624 } else {
25625 force.y = 0;
25626 velocity.y = 0;
25627 }
25628
25629 var totalVelocity = Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(velocity.y, 2));
25630 return totalVelocity;
25631 }
25632 /**
25633 * When initializing and stabilizing, we can freeze nodes with a predefined position.
25634 * This greatly speeds up stabilization because only the supportnodes for the smoothCurves have to settle.
25635 *
25636 * @private
25637 */
25638
25639 }, {
25640 key: "_freezeNodes",
25641 value: function _freezeNodes() {
25642 var nodes = this.body.nodes;
25643
25644 for (var id in nodes) {
25645 if (Object.prototype.hasOwnProperty.call(nodes, id)) {
25646 if (nodes[id].x && nodes[id].y) {
25647 var fixed = nodes[id].options.fixed;
25648 this.freezeCache[id] = {
25649 x: fixed.x,
25650 y: fixed.y
25651 };
25652 fixed.x = true;
25653 fixed.y = true;
25654 }
25655 }
25656 }
25657 }
25658 /**
25659 * Unfreezes the nodes that have been frozen by _freezeDefinedNodes.
25660 *
25661 * @private
25662 */
25663
25664 }, {
25665 key: "_restoreFrozenNodes",
25666 value: function _restoreFrozenNodes() {
25667 var nodes = this.body.nodes;
25668
25669 for (var id in nodes) {
25670 if (Object.prototype.hasOwnProperty.call(nodes, id)) {
25671 if (this.freezeCache[id] !== undefined) {
25672 nodes[id].options.fixed.x = this.freezeCache[id].x;
25673 nodes[id].options.fixed.y = this.freezeCache[id].y;
25674 }
25675 }
25676 }
25677
25678 this.freezeCache = {};
25679 }
25680 /**
25681 * Find a stable position for all nodes
25682 *
25683 * @param {number} [iterations=this.options.stabilization.iterations]
25684 */
25685
25686 }, {
25687 key: "stabilize",
25688 value: function stabilize() {
25689 var _this3 = this;
25690
25691 var iterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.stabilization.iterations;
25692
25693 if (typeof iterations !== "number") {
25694 iterations = this.options.stabilization.iterations;
25695 console.error("The stabilize method needs a numeric amount of iterations. Switching to default: ", iterations);
25696 }
25697
25698 if (this.physicsBody.physicsNodeIndices.length === 0) {
25699 this.ready = true;
25700 return;
25701 } // enable adaptive timesteps
25702
25703
25704 this.adaptiveTimestep = this.options.adaptiveTimestep; // this sets the width of all nodes initially which could be required for the avoidOverlap
25705
25706 this.body.emitter.emit("_resizeNodes");
25707 this.stopSimulation(); // stop the render loop
25708
25709 this.stabilized = false; // block redraw requests
25710
25711 this.body.emitter.emit("_blockRedraw");
25712 this.targetIterations = iterations; // start the stabilization
25713
25714 if (this.options.stabilization.onlyDynamicEdges === true) {
25715 this._freezeNodes();
25716 }
25717
25718 this.stabilizationIterations = 0;
25719
25720 setTimeout$1(function () {
25721 return _this3._stabilizationBatch();
25722 }, 0);
25723 }
25724 /**
25725 * If not already stabilizing, start it and emit a start event.
25726 *
25727 * @returns {boolean} true if stabilization started with this call
25728 * @private
25729 */
25730
25731 }, {
25732 key: "_startStabilizing",
25733 value: function _startStabilizing() {
25734 if (this.startedStabilization === true) return false;
25735 this.body.emitter.emit("startStabilizing");
25736 this.startedStabilization = true;
25737 return true;
25738 }
25739 /**
25740 * One batch of stabilization
25741 *
25742 * @private
25743 */
25744
25745 }, {
25746 key: "_stabilizationBatch",
25747 value: function _stabilizationBatch() {
25748 var _this4 = this;
25749
25750 var running = function running() {
25751 return _this4.stabilized === false && _this4.stabilizationIterations < _this4.targetIterations;
25752 };
25753
25754 var sendProgress = function sendProgress() {
25755 _this4.body.emitter.emit("stabilizationProgress", {
25756 iterations: _this4.stabilizationIterations,
25757 total: _this4.targetIterations
25758 });
25759 };
25760
25761 if (this._startStabilizing()) {
25762 sendProgress(); // Ensure that there is at least one start event.
25763 }
25764
25765 var count = 0;
25766
25767 while (running() && count < this.options.stabilization.updateInterval) {
25768 this.physicsTick();
25769 count++;
25770 }
25771
25772 sendProgress();
25773
25774 if (running()) {
25775 var _context2;
25776
25777 setTimeout$1(bind$5(_context2 = this._stabilizationBatch).call(_context2, this), 0);
25778 } else {
25779 this._finalizeStabilization();
25780 }
25781 }
25782 /**
25783 * Wrap up the stabilization, fit and emit the events.
25784 *
25785 * @private
25786 */
25787
25788 }, {
25789 key: "_finalizeStabilization",
25790 value: function _finalizeStabilization() {
25791 this.body.emitter.emit("_allowRedraw");
25792
25793 if (this.options.stabilization.fit === true) {
25794 this.body.emitter.emit("fit");
25795 }
25796
25797 if (this.options.stabilization.onlyDynamicEdges === true) {
25798 this._restoreFrozenNodes();
25799 }
25800
25801 this.body.emitter.emit("stabilizationIterationsDone");
25802 this.body.emitter.emit("_requestRedraw");
25803
25804 if (this.stabilized === true) {
25805 this._emitStabilized();
25806 } else {
25807 this.startSimulation();
25808 }
25809
25810 this.ready = true;
25811 } //--------------------------- DEBUGGING BELOW ---------------------------//
25812
25813 /**
25814 * Debug function that display arrows for the forces currently active in the network.
25815 *
25816 * Use this when debugging only.
25817 *
25818 * @param {CanvasRenderingContext2D} ctx
25819 * @private
25820 */
25821
25822 }, {
25823 key: "_drawForces",
25824 value: function _drawForces(ctx) {
25825 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
25826 var index = this.physicsBody.physicsNodeIndices[i];
25827 var node = this.body.nodes[index];
25828 var force = this.physicsBody.forces[index];
25829 var factor = 20;
25830 var colorFactor = 0.03;
25831 var forceSize = Math.sqrt(Math.pow(force.x, 2) + Math.pow(force.x, 2));
25832 var size = Math.min(Math.max(5, forceSize), 15);
25833 var arrowSize = 3 * size;
25834 var color = HSVToHex((180 - Math.min(1, Math.max(0, colorFactor * forceSize)) * 180) / 360, 1, 1);
25835 var point = {
25836 x: node.x + factor * force.x,
25837 y: node.y + factor * force.y
25838 };
25839 ctx.lineWidth = size;
25840 ctx.strokeStyle = color;
25841 ctx.beginPath();
25842 ctx.moveTo(node.x, node.y);
25843 ctx.lineTo(point.x, point.y);
25844 ctx.stroke();
25845 var angle = Math.atan2(force.y, force.x);
25846 ctx.fillStyle = color;
25847 EndPoints.draw(ctx, {
25848 type: "arrow",
25849 point: point,
25850 angle: angle,
25851 length: arrowSize
25852 });
25853
25854 fill(ctx).call(ctx);
25855 }
25856 }
25857 }]);
25858
25859 return PhysicsEngine;
25860 }();
25861
25862 // Unique ID creation requires a high quality random # generator. In the browser we therefore
25863 // require the crypto API and do not support built-in fallback to lower quality random number
25864 // generators (like Math.random()).
25865 var getRandomValues;
25866 var rnds8 = new Uint8Array(16);
25867 function rng() {
25868 // lazy load so that environments that need to polyfill have a chance to do so
25869 if (!getRandomValues) {
25870 // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also,
25871 // find the complete implementation of crypto (msCrypto) on IE11.
25872 getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);
25873
25874 if (!getRandomValues) {
25875 throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
25876 }
25877 }
25878
25879 return getRandomValues(rnds8);
25880 }
25881
25882 var 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;
25883
25884 function validate(uuid) {
25885 return typeof uuid === 'string' && REGEX.test(uuid);
25886 }
25887
25888 /**
25889 * Convert array of 16 byte values to UUID string format of the form:
25890 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
25891 */
25892
25893 var byteToHex = [];
25894
25895 for (var i = 0; i < 256; ++i) {
25896 byteToHex.push((i + 0x100).toString(16).substr(1));
25897 }
25898
25899 function stringify(arr) {
25900 var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; // Note: Be careful editing this code! It's been tuned for performance
25901 // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
25902
25903 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
25904 // of the following:
25905 // - One or more input array values don't map to a hex octet (leading to
25906 // "undefined" in the uuid)
25907 // - Invalid input values for the RFC `version` or `variant` fields
25908
25909 if (!validate(uuid)) {
25910 throw TypeError('Stringified UUID is invalid');
25911 }
25912
25913 return uuid;
25914 }
25915
25916 function v4(options, buf, offset) {
25917 options = options || {};
25918 var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
25919
25920 rnds[6] = rnds[6] & 0x0f | 0x40;
25921 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
25922
25923 if (buf) {
25924 offset = offset || 0;
25925
25926 for (var i = 0; i < 16; ++i) {
25927 buf[offset + i] = rnds[i];
25928 }
25929
25930 return buf;
25931 }
25932
25933 return stringify(rnds);
25934 }
25935
25936 /**
25937 * Utility Class
25938 */
25939
25940 var NetworkUtil = /*#__PURE__*/function () {
25941 /**
25942 * @ignore
25943 */
25944 function NetworkUtil() {
25945 _classCallCheck(this, NetworkUtil);
25946 }
25947 /**
25948 * Find the center position of the network considering the bounding boxes
25949 *
25950 * @param {Array.<Node>} allNodes
25951 * @param {Array.<Node>} [specificNodes=[]]
25952 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
25953 * @static
25954 */
25955
25956
25957 _createClass(NetworkUtil, null, [{
25958 key: "getRange",
25959 value: function getRange(allNodes) {
25960 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
25961 var minY = 1e9,
25962 maxY = -1e9,
25963 minX = 1e9,
25964 maxX = -1e9,
25965 node;
25966
25967 if (specificNodes.length > 0) {
25968 for (var i = 0; i < specificNodes.length; i++) {
25969 node = allNodes[specificNodes[i]];
25970
25971 if (minX > node.shape.boundingBox.left) {
25972 minX = node.shape.boundingBox.left;
25973 }
25974
25975 if (maxX < node.shape.boundingBox.right) {
25976 maxX = node.shape.boundingBox.right;
25977 }
25978
25979 if (minY > node.shape.boundingBox.top) {
25980 minY = node.shape.boundingBox.top;
25981 } // top is negative, bottom is positive
25982
25983
25984 if (maxY < node.shape.boundingBox.bottom) {
25985 maxY = node.shape.boundingBox.bottom;
25986 } // top is negative, bottom is positive
25987
25988 }
25989 }
25990
25991 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
25992 minY = 0, maxY = 0, minX = 0, maxX = 0;
25993 }
25994
25995 return {
25996 minX: minX,
25997 maxX: maxX,
25998 minY: minY,
25999 maxY: maxY
26000 };
26001 }
26002 /**
26003 * Find the center position of the network
26004 *
26005 * @param {Array.<Node>} allNodes
26006 * @param {Array.<Node>} [specificNodes=[]]
26007 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
26008 * @static
26009 */
26010
26011 }, {
26012 key: "getRangeCore",
26013 value: function getRangeCore(allNodes) {
26014 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
26015 var minY = 1e9,
26016 maxY = -1e9,
26017 minX = 1e9,
26018 maxX = -1e9,
26019 node;
26020
26021 if (specificNodes.length > 0) {
26022 for (var i = 0; i < specificNodes.length; i++) {
26023 node = allNodes[specificNodes[i]];
26024
26025 if (minX > node.x) {
26026 minX = node.x;
26027 }
26028
26029 if (maxX < node.x) {
26030 maxX = node.x;
26031 }
26032
26033 if (minY > node.y) {
26034 minY = node.y;
26035 } // top is negative, bottom is positive
26036
26037
26038 if (maxY < node.y) {
26039 maxY = node.y;
26040 } // top is negative, bottom is positive
26041
26042 }
26043 }
26044
26045 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
26046 minY = 0, maxY = 0, minX = 0, maxX = 0;
26047 }
26048
26049 return {
26050 minX: minX,
26051 maxX: maxX,
26052 minY: minY,
26053 maxY: maxY
26054 };
26055 }
26056 /**
26057 * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY};
26058 * @returns {{x: number, y: number}}
26059 * @static
26060 */
26061
26062 }, {
26063 key: "findCenter",
26064 value: function findCenter(range) {
26065 return {
26066 x: 0.5 * (range.maxX + range.minX),
26067 y: 0.5 * (range.maxY + range.minY)
26068 };
26069 }
26070 /**
26071 * 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.
26072 *
26073 * @param {vis.Item} item
26074 * @param {'node'|undefined} type
26075 * @returns {{}}
26076 * @static
26077 */
26078
26079 }, {
26080 key: "cloneOptions",
26081 value: function cloneOptions(item, type) {
26082 var clonedOptions = {};
26083
26084 if (type === undefined || type === "node") {
26085 deepExtend(clonedOptions, item.options, true);
26086 clonedOptions.x = item.x;
26087 clonedOptions.y = item.y;
26088 clonedOptions.amountOfConnections = item.edges.length;
26089 } else {
26090 deepExtend(clonedOptions, item.options, true);
26091 }
26092
26093 return clonedOptions;
26094 }
26095 }]);
26096
26097 return NetworkUtil;
26098 }();
26099
26100 function _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); }; }
26101
26102 function _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; } }
26103 /**
26104 * A Cluster is a special Node that allows a group of Nodes positioned closely together
26105 * to be represented by a single Cluster Node.
26106 *
26107 * @augments Node
26108 */
26109
26110 var Cluster = /*#__PURE__*/function (_Node) {
26111 _inherits(Cluster, _Node);
26112
26113 var _super = _createSuper$1(Cluster);
26114
26115 /**
26116 * @param {object} options
26117 * @param {object} body
26118 * @param {Array.<HTMLImageElement>}imagelist
26119 * @param {Array} grouplist
26120 * @param {object} globalOptions
26121 * @param {object} defaultOptions Global default options for nodes
26122 */
26123 function Cluster(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
26124 var _this;
26125
26126 _classCallCheck(this, Cluster);
26127
26128 _this = _super.call(this, options, body, imagelist, grouplist, globalOptions, defaultOptions);
26129 _this.isCluster = true;
26130 _this.containedNodes = {};
26131 _this.containedEdges = {};
26132 return _this;
26133 }
26134 /**
26135 * Transfer child cluster data to current and disconnect the child cluster.
26136 *
26137 * Please consult the header comment in 'Clustering.js' for the fields set here.
26138 *
26139 * @param {string|number} childClusterId id of child cluster to open
26140 */
26141
26142
26143 _createClass(Cluster, [{
26144 key: "_openChildCluster",
26145 value: function _openChildCluster(childClusterId) {
26146 var _this2 = this;
26147
26148 var childCluster = this.body.nodes[childClusterId];
26149
26150 if (this.containedNodes[childClusterId] === undefined) {
26151 throw new Error("node with id: " + childClusterId + " not in current cluster");
26152 }
26153
26154 if (!childCluster.isCluster) {
26155 throw new Error("node with id: " + childClusterId + " is not a cluster");
26156 } // Disconnect child cluster from current cluster
26157
26158
26159 delete this.containedNodes[childClusterId];
26160 forEach$1(childCluster.edges, function (edge) {
26161 delete _this2.containedEdges[edge.id];
26162 }); // Transfer nodes and edges
26163
26164 forEach$1(childCluster.containedNodes, function (node, nodeId) {
26165 _this2.containedNodes[nodeId] = node;
26166 });
26167 childCluster.containedNodes = {};
26168 forEach$1(childCluster.containedEdges, function (edge, edgeId) {
26169 _this2.containedEdges[edgeId] = edge;
26170 });
26171 childCluster.containedEdges = {}; // Transfer edges within cluster edges which are clustered
26172
26173 forEach$1(childCluster.edges, function (clusterEdge) {
26174 forEach$1(_this2.edges, function (parentClusterEdge) {
26175 var _context, _context2;
26176
26177 // Assumption: a clustered edge can only be present in a single clustering edge
26178 // Not tested here
26179 var index = indexOf(_context = parentClusterEdge.clusteringEdgeReplacingIds).call(_context, clusterEdge.id);
26180
26181 if (index === -1) return;
26182 forEach$1(clusterEdge.clusteringEdgeReplacingIds, function (srcId) {
26183 parentClusterEdge.clusteringEdgeReplacingIds.push(srcId); // Maintain correct bookkeeping for transferred edge
26184
26185 _this2.body.edges[srcId].edgeReplacedById = parentClusterEdge.id;
26186 }); // Remove cluster edge from parent cluster edge
26187
26188 splice(_context2 = parentClusterEdge.clusteringEdgeReplacingIds).call(_context2, index, 1);
26189 });
26190 });
26191 childCluster.edges = [];
26192 }
26193 }]);
26194
26195 return Cluster;
26196 }(Node);
26197
26198 /**
26199 * The clustering engine
26200 */
26201
26202 var ClusterEngine = /*#__PURE__*/function () {
26203 /**
26204 * @param {object} body
26205 */
26206 function ClusterEngine(body) {
26207 var _this = this;
26208
26209 _classCallCheck(this, ClusterEngine);
26210
26211 this.body = body;
26212 this.clusteredNodes = {}; // key: node id, value: { clusterId: <id of cluster>, node: <node instance>}
26213
26214 this.clusteredEdges = {}; // key: edge id, value: restore information for given edge
26215
26216 this.options = {};
26217 this.defaultOptions = {};
26218
26219 assign$2(this.options, this.defaultOptions);
26220
26221 this.body.emitter.on("_resetData", function () {
26222 _this.clusteredNodes = {};
26223 _this.clusteredEdges = {};
26224 });
26225 }
26226 /**
26227 *
26228 * @param {number} hubsize
26229 * @param {object} options
26230 */
26231
26232
26233 _createClass(ClusterEngine, [{
26234 key: "clusterByHubsize",
26235 value: function clusterByHubsize(hubsize, options) {
26236 if (hubsize === undefined) {
26237 hubsize = this._getHubSize();
26238 } else if (_typeof(hubsize) === "object") {
26239 options = this._checkOptions(hubsize);
26240 hubsize = this._getHubSize();
26241 }
26242
26243 var nodesToCluster = [];
26244
26245 for (var i = 0; i < this.body.nodeIndices.length; i++) {
26246 var node = this.body.nodes[this.body.nodeIndices[i]];
26247
26248 if (node.edges.length >= hubsize) {
26249 nodesToCluster.push(node.id);
26250 }
26251 }
26252
26253 for (var _i = 0; _i < nodesToCluster.length; _i++) {
26254 this.clusterByConnection(nodesToCluster[_i], options, true);
26255 }
26256
26257 this.body.emitter.emit("_dataChanged");
26258 }
26259 /**
26260 * loop over all nodes, check if they adhere to the condition and cluster if needed.
26261 *
26262 * @param {object} options
26263 * @param {boolean} [refreshData=true]
26264 */
26265
26266 }, {
26267 key: "cluster",
26268 value: function cluster() {
26269 var _this2 = this;
26270
26271 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
26272 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
26273
26274 if (options.joinCondition === undefined) {
26275 throw new Error("Cannot call clusterByNodeData without a joinCondition function in the options.");
26276 } // check if the options object is fine, append if needed
26277
26278
26279 options = this._checkOptions(options);
26280 var childNodesObj = {};
26281 var childEdgesObj = {}; // collect the nodes that will be in the cluster
26282
26283 forEach$1(this.body.nodes, function (node, nodeId) {
26284 if (node.options && options.joinCondition(node.options) === true) {
26285 childNodesObj[nodeId] = node; // collect the edges that will be in the cluster
26286
26287 forEach$1(node.edges, function (edge) {
26288 if (_this2.clusteredEdges[edge.id] === undefined) {
26289 childEdgesObj[edge.id] = edge;
26290 }
26291 });
26292 }
26293 });
26294
26295 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
26296 }
26297 /**
26298 * Cluster all nodes in the network that have only X edges
26299 *
26300 * @param {number} edgeCount
26301 * @param {object} options
26302 * @param {boolean} [refreshData=true]
26303 */
26304
26305 }, {
26306 key: "clusterByEdgeCount",
26307 value: function clusterByEdgeCount(edgeCount, options) {
26308 var _this3 = this;
26309
26310 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
26311 options = this._checkOptions(options);
26312 var clusters = [];
26313 var usedNodes = {};
26314 var edge, edges, relevantEdgeCount; // collect the nodes that will be in the cluster
26315
26316 var _loop = function _loop(i) {
26317 var childNodesObj = {};
26318 var childEdgesObj = {};
26319 var nodeId = _this3.body.nodeIndices[i];
26320 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.
26321
26322 if (usedNodes[nodeId] === undefined) {
26323 relevantEdgeCount = 0;
26324 edges = [];
26325
26326 for (var j = 0; j < node.edges.length; j++) {
26327 edge = node.edges[j];
26328
26329 if (_this3.clusteredEdges[edge.id] === undefined) {
26330 if (edge.toId !== edge.fromId) {
26331 relevantEdgeCount++;
26332 }
26333
26334 edges.push(edge);
26335 }
26336 } // this node qualifies, we collect its neighbours to start the clustering process.
26337
26338
26339 if (relevantEdgeCount === edgeCount) {
26340 var checkJoinCondition = function checkJoinCondition(node) {
26341 if (options.joinCondition === undefined || options.joinCondition === null) {
26342 return true;
26343 }
26344
26345 var clonedOptions = NetworkUtil.cloneOptions(node);
26346 return options.joinCondition(clonedOptions);
26347 };
26348
26349 var gatheringSuccessful = true;
26350
26351 for (var _j = 0; _j < edges.length; _j++) {
26352 edge = edges[_j];
26353
26354 var childNodeId = _this3._getConnectedId(edge, nodeId); // add the nodes to the list by the join condition.
26355
26356
26357 if (checkJoinCondition(node)) {
26358 childEdgesObj[edge.id] = edge;
26359 childNodesObj[nodeId] = node;
26360 childNodesObj[childNodeId] = _this3.body.nodes[childNodeId];
26361 usedNodes[nodeId] = true;
26362 } else {
26363 // this node does not qualify after all.
26364 gatheringSuccessful = false;
26365 break;
26366 }
26367 } // add to the cluster queue
26368
26369
26370 if (keys(childNodesObj).length > 0 && keys(childEdgesObj).length > 0 && gatheringSuccessful === true) {
26371 /**
26372 * Search for cluster data that contains any of the node id's
26373 *
26374 * @returns {boolean} true if no joinCondition, otherwise return value of joinCondition
26375 */
26376 var findClusterData = function findClusterData() {
26377 for (var n = 0; n < clusters.length; ++n) {
26378 // Search for a cluster containing any of the node id's
26379 for (var m in childNodesObj) {
26380 if (clusters[n].nodes[m] !== undefined) {
26381 return clusters[n];
26382 }
26383 }
26384 }
26385
26386 return undefined;
26387 }; // If any of the found nodes is part of a cluster found in this method,
26388 // add the current values to that cluster
26389
26390
26391 var foundCluster = findClusterData();
26392
26393 if (foundCluster !== undefined) {
26394 // Add nodes to found cluster if not present
26395 for (var m in childNodesObj) {
26396 if (foundCluster.nodes[m] === undefined) {
26397 foundCluster.nodes[m] = childNodesObj[m];
26398 }
26399 } // Add edges to found cluster, if not present
26400
26401
26402 for (var _m in childEdgesObj) {
26403 if (foundCluster.edges[_m] === undefined) {
26404 foundCluster.edges[_m] = childEdgesObj[_m];
26405 }
26406 }
26407 } else {
26408 // Create a new cluster group
26409 clusters.push({
26410 nodes: childNodesObj,
26411 edges: childEdgesObj
26412 });
26413 }
26414 }
26415 }
26416 }
26417 };
26418
26419 for (var i = 0; i < this.body.nodeIndices.length; i++) {
26420 _loop(i);
26421 }
26422
26423 for (var _i2 = 0; _i2 < clusters.length; _i2++) {
26424 this._cluster(clusters[_i2].nodes, clusters[_i2].edges, options, false);
26425 }
26426
26427 if (refreshData === true) {
26428 this.body.emitter.emit("_dataChanged");
26429 }
26430 }
26431 /**
26432 * Cluster all nodes in the network that have only 1 edge
26433 *
26434 * @param {object} options
26435 * @param {boolean} [refreshData=true]
26436 */
26437
26438 }, {
26439 key: "clusterOutliers",
26440 value: function clusterOutliers(options) {
26441 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
26442 this.clusterByEdgeCount(1, options, refreshData);
26443 }
26444 /**
26445 * Cluster all nodes in the network that have only 2 edge
26446 *
26447 * @param {object} options
26448 * @param {boolean} [refreshData=true]
26449 */
26450
26451 }, {
26452 key: "clusterBridges",
26453 value: function clusterBridges(options) {
26454 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
26455 this.clusterByEdgeCount(2, options, refreshData);
26456 }
26457 /**
26458 * suck all connected nodes of a node into the node.
26459 *
26460 * @param {Node.id} nodeId
26461 * @param {object} options
26462 * @param {boolean} [refreshData=true]
26463 */
26464
26465 }, {
26466 key: "clusterByConnection",
26467 value: function clusterByConnection(nodeId, options) {
26468 var _context;
26469
26470 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
26471
26472 // kill conditions
26473 if (nodeId === undefined) {
26474 throw new Error("No nodeId supplied to clusterByConnection!");
26475 }
26476
26477 if (this.body.nodes[nodeId] === undefined) {
26478 throw new Error("The nodeId given to clusterByConnection does not exist!");
26479 }
26480
26481 var node = this.body.nodes[nodeId];
26482 options = this._checkOptions(options, node);
26483
26484 if (options.clusterNodeProperties.x === undefined) {
26485 options.clusterNodeProperties.x = node.x;
26486 }
26487
26488 if (options.clusterNodeProperties.y === undefined) {
26489 options.clusterNodeProperties.y = node.y;
26490 }
26491
26492 if (options.clusterNodeProperties.fixed === undefined) {
26493 options.clusterNodeProperties.fixed = {};
26494 options.clusterNodeProperties.fixed.x = node.options.fixed.x;
26495 options.clusterNodeProperties.fixed.y = node.options.fixed.y;
26496 }
26497
26498 var childNodesObj = {};
26499 var childEdgesObj = {};
26500 var parentNodeId = node.id;
26501 var parentClonedOptions = NetworkUtil.cloneOptions(node);
26502 childNodesObj[parentNodeId] = node; // collect the nodes that will be in the cluster
26503
26504 for (var i = 0; i < node.edges.length; i++) {
26505 var edge = node.edges[i];
26506
26507 if (this.clusteredEdges[edge.id] === undefined) {
26508 var childNodeId = this._getConnectedId(edge, parentNodeId); // if the child node is not in a cluster
26509
26510
26511 if (this.clusteredNodes[childNodeId] === undefined) {
26512 if (childNodeId !== parentNodeId) {
26513 if (options.joinCondition === undefined) {
26514 childEdgesObj[edge.id] = edge;
26515 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
26516 } else {
26517 // clone the options and insert some additional parameters that could be interesting.
26518 var childClonedOptions = NetworkUtil.cloneOptions(this.body.nodes[childNodeId]);
26519
26520 if (options.joinCondition(parentClonedOptions, childClonedOptions) === true) {
26521 childEdgesObj[edge.id] = edge;
26522 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
26523 }
26524 }
26525 } else {
26526 // swallow the edge if it is self-referencing.
26527 childEdgesObj[edge.id] = edge;
26528 }
26529 }
26530 }
26531 }
26532
26533 var childNodeIDs = map$3(_context = keys(childNodesObj)).call(_context, function (childNode) {
26534 return childNodesObj[childNode].id;
26535 });
26536
26537 for (var childNodeKey in childNodesObj) {
26538 if (!Object.prototype.hasOwnProperty.call(childNodesObj, childNodeKey)) continue;
26539 var childNode = childNodesObj[childNodeKey];
26540
26541 for (var y = 0; y < childNode.edges.length; y++) {
26542 var childEdge = childNode.edges[y];
26543
26544 if (indexOf(childNodeIDs).call(childNodeIDs, this._getConnectedId(childEdge, childNode.id)) > -1) {
26545 childEdgesObj[childEdge.id] = childEdge;
26546 }
26547 }
26548 }
26549
26550 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
26551 }
26552 /**
26553 * This function creates the edges that will be attached to the cluster
26554 * It looks for edges that are connected to the nodes from the "outside' of the cluster.
26555 *
26556 * @param {{Node.id: vis.Node}} childNodesObj
26557 * @param {{vis.Edge.id: vis.Edge}} childEdgesObj
26558 * @param {object} clusterNodeProperties
26559 * @param {object} clusterEdgeProperties
26560 * @private
26561 */
26562
26563 }, {
26564 key: "_createClusterEdges",
26565 value: function _createClusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, clusterEdgeProperties) {
26566 var edge, childNodeId, childNode, toId, fromId, otherNodeId; // loop over all child nodes and their edges to find edges going out of the cluster
26567 // these edges will be replaced by clusterEdges.
26568
26569 var childKeys = keys(childNodesObj);
26570
26571 var createEdges = [];
26572
26573 for (var i = 0; i < childKeys.length; i++) {
26574 childNodeId = childKeys[i];
26575 childNode = childNodesObj[childNodeId]; // construct new edges from the cluster to others
26576
26577 for (var j = 0; j < childNode.edges.length; j++) {
26578 edge = childNode.edges[j]; // we only handle edges that are visible to the system, not the disabled ones from the clustering process.
26579
26580 if (this.clusteredEdges[edge.id] === undefined) {
26581 // self-referencing edges will be added to the "hidden" list
26582 if (edge.toId == edge.fromId) {
26583 childEdgesObj[edge.id] = edge;
26584 } else {
26585 // set up the from and to.
26586 if (edge.toId == childNodeId) {
26587 // this is a double equals because ints and strings can be interchanged here.
26588 toId = clusterNodeProperties.id;
26589 fromId = edge.fromId;
26590 otherNodeId = fromId;
26591 } else {
26592 toId = edge.toId;
26593 fromId = clusterNodeProperties.id;
26594 otherNodeId = toId;
26595 }
26596 } // Only edges from the cluster outwards are being replaced.
26597
26598
26599 if (childNodesObj[otherNodeId] === undefined) {
26600 createEdges.push({
26601 edge: edge,
26602 fromId: fromId,
26603 toId: toId
26604 });
26605 }
26606 }
26607 }
26608 } //
26609 // Here we actually create the replacement edges.
26610 //
26611 // We could not do this in the loop above as the creation process
26612 // would add an edge to the edges array we are iterating over.
26613 //
26614 // NOTE: a clustered edge can have multiple base edges!
26615 //
26616
26617
26618 var newEdges = [];
26619 /**
26620 * Find a cluster edge which matches the given created edge.
26621 *
26622 * @param {vis.Edge} createdEdge
26623 * @returns {vis.Edge}
26624 */
26625
26626 var getNewEdge = function getNewEdge(createdEdge) {
26627 for (var _j2 = 0; _j2 < newEdges.length; _j2++) {
26628 var newEdge = newEdges[_j2]; // We replace both to and from edges with a single cluster edge
26629
26630 var matchToDirection = createdEdge.fromId === newEdge.fromId && createdEdge.toId === newEdge.toId;
26631 var matchFromDirection = createdEdge.fromId === newEdge.toId && createdEdge.toId === newEdge.fromId;
26632
26633 if (matchToDirection || matchFromDirection) {
26634 return newEdge;
26635 }
26636 }
26637
26638 return null;
26639 };
26640
26641 for (var _j3 = 0; _j3 < createEdges.length; _j3++) {
26642 var createdEdge = createEdges[_j3];
26643 var _edge = createdEdge.edge;
26644 var newEdge = getNewEdge(createdEdge);
26645
26646 if (newEdge === null) {
26647 // Create a clustered edge for this connection
26648 newEdge = this._createClusteredEdge(createdEdge.fromId, createdEdge.toId, _edge, clusterEdgeProperties);
26649 newEdges.push(newEdge);
26650 } else {
26651 newEdge.clusteringEdgeReplacingIds.push(_edge.id);
26652 } // also reference the new edge in the old edge
26653
26654
26655 this.body.edges[_edge.id].edgeReplacedById = newEdge.id; // hide the replaced edge
26656
26657 this._backupEdgeOptions(_edge);
26658
26659 _edge.setOptions({
26660 physics: false
26661 });
26662 }
26663 }
26664 /**
26665 * This function checks the options that can be supplied to the different cluster functions
26666 * for certain fields and inserts defaults if needed
26667 *
26668 * @param {object} options
26669 * @returns {*}
26670 * @private
26671 */
26672
26673 }, {
26674 key: "_checkOptions",
26675 value: function _checkOptions() {
26676 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
26677
26678 if (options.clusterEdgeProperties === undefined) {
26679 options.clusterEdgeProperties = {};
26680 }
26681
26682 if (options.clusterNodeProperties === undefined) {
26683 options.clusterNodeProperties = {};
26684 }
26685
26686 return options;
26687 }
26688 /**
26689 *
26690 * @param {object} childNodesObj | object with node objects, id as keys, same as childNodes except it also contains a source node
26691 * @param {object} childEdgesObj | object with edge objects, id as keys
26692 * @param {Array} options | object with {clusterNodeProperties, clusterEdgeProperties, processProperties}
26693 * @param {boolean} refreshData | when true, do not wrap up
26694 * @private
26695 */
26696
26697 }, {
26698 key: "_cluster",
26699 value: function _cluster(childNodesObj, childEdgesObj, options) {
26700 var refreshData = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
26701 // Remove nodes which are already clustered
26702 var tmpNodesToRemove = [];
26703
26704 for (var nodeId in childNodesObj) {
26705 if (Object.prototype.hasOwnProperty.call(childNodesObj, nodeId)) {
26706 if (this.clusteredNodes[nodeId] !== undefined) {
26707 tmpNodesToRemove.push(nodeId);
26708 }
26709 }
26710 }
26711
26712 for (var n = 0; n < tmpNodesToRemove.length; ++n) {
26713 delete childNodesObj[tmpNodesToRemove[n]];
26714 } // kill condition: no nodes don't bother
26715
26716
26717 if (keys(childNodesObj).length == 0) {
26718 return;
26719 } // allow clusters of 1 if options allow
26720
26721
26722 if (keys(childNodesObj).length == 1 && options.clusterNodeProperties.allowSingleNodeCluster != true) {
26723 return;
26724 }
26725
26726 var clusterNodeProperties = deepExtend({}, options.clusterNodeProperties); // construct the clusterNodeProperties
26727
26728 if (options.processProperties !== undefined) {
26729 // get the childNode options
26730 var childNodesOptions = [];
26731
26732 for (var _nodeId in childNodesObj) {
26733 if (Object.prototype.hasOwnProperty.call(childNodesObj, _nodeId)) {
26734 var clonedOptions = NetworkUtil.cloneOptions(childNodesObj[_nodeId]);
26735 childNodesOptions.push(clonedOptions);
26736 }
26737 } // get cluster properties based on childNodes
26738
26739
26740 var childEdgesOptions = [];
26741
26742 for (var edgeId in childEdgesObj) {
26743 if (Object.prototype.hasOwnProperty.call(childEdgesObj, edgeId)) {
26744 // these cluster edges will be removed on creation of the cluster.
26745 if (edgeId.substr(0, 12) !== "clusterEdge:") {
26746 var _clonedOptions = NetworkUtil.cloneOptions(childEdgesObj[edgeId], "edge");
26747
26748 childEdgesOptions.push(_clonedOptions);
26749 }
26750 }
26751 }
26752
26753 clusterNodeProperties = options.processProperties(clusterNodeProperties, childNodesOptions, childEdgesOptions);
26754
26755 if (!clusterNodeProperties) {
26756 throw new Error("The processProperties function does not return properties!");
26757 }
26758 } // check if we have an unique id;
26759
26760
26761 if (clusterNodeProperties.id === undefined) {
26762 clusterNodeProperties.id = "cluster:" + v4();
26763 }
26764
26765 var clusterId = clusterNodeProperties.id;
26766
26767 if (clusterNodeProperties.label === undefined) {
26768 clusterNodeProperties.label = "cluster";
26769 } // give the clusterNode a position if it does not have one.
26770
26771
26772 var pos = undefined;
26773
26774 if (clusterNodeProperties.x === undefined) {
26775 pos = this._getClusterPosition(childNodesObj);
26776 clusterNodeProperties.x = pos.x;
26777 }
26778
26779 if (clusterNodeProperties.y === undefined) {
26780 if (pos === undefined) {
26781 pos = this._getClusterPosition(childNodesObj);
26782 }
26783
26784 clusterNodeProperties.y = pos.y;
26785 } // force the ID to remain the same
26786
26787
26788 clusterNodeProperties.id = clusterId; // create the cluster Node
26789 // Note that allowSingleNodeCluster, if present, is stored in the options as well
26790
26791 var clusterNode = this.body.functions.createNode(clusterNodeProperties, Cluster);
26792 clusterNode.containedNodes = childNodesObj;
26793 clusterNode.containedEdges = childEdgesObj; // cache a copy from the cluster edge properties if we have to reconnect others later on
26794
26795 clusterNode.clusterEdgeProperties = options.clusterEdgeProperties; // finally put the cluster node into global
26796
26797 this.body.nodes[clusterNodeProperties.id] = clusterNode;
26798
26799 this._clusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, options.clusterEdgeProperties); // set ID to undefined so no duplicates arise
26800
26801
26802 clusterNodeProperties.id = undefined; // wrap up
26803
26804 if (refreshData === true) {
26805 this.body.emitter.emit("_dataChanged");
26806 }
26807 }
26808 /**
26809 *
26810 * @param {Edge} edge
26811 * @private
26812 */
26813
26814 }, {
26815 key: "_backupEdgeOptions",
26816 value: function _backupEdgeOptions(edge) {
26817 if (this.clusteredEdges[edge.id] === undefined) {
26818 this.clusteredEdges[edge.id] = {
26819 physics: edge.options.physics
26820 };
26821 }
26822 }
26823 /**
26824 *
26825 * @param {Edge} edge
26826 * @private
26827 */
26828
26829 }, {
26830 key: "_restoreEdge",
26831 value: function _restoreEdge(edge) {
26832 var originalOptions = this.clusteredEdges[edge.id];
26833
26834 if (originalOptions !== undefined) {
26835 edge.setOptions({
26836 physics: originalOptions.physics
26837 });
26838 delete this.clusteredEdges[edge.id];
26839 }
26840 }
26841 /**
26842 * Check if a node is a cluster.
26843 *
26844 * @param {Node.id} nodeId
26845 * @returns {*}
26846 */
26847
26848 }, {
26849 key: "isCluster",
26850 value: function isCluster(nodeId) {
26851 if (this.body.nodes[nodeId] !== undefined) {
26852 return this.body.nodes[nodeId].isCluster === true;
26853 } else {
26854 console.error("Node does not exist.");
26855 return false;
26856 }
26857 }
26858 /**
26859 * get the position of the cluster node based on what's inside
26860 *
26861 * @param {object} childNodesObj | object with node objects, id as keys
26862 * @returns {{x: number, y: number}}
26863 * @private
26864 */
26865
26866 }, {
26867 key: "_getClusterPosition",
26868 value: function _getClusterPosition(childNodesObj) {
26869 var childKeys = keys(childNodesObj);
26870
26871 var minX = childNodesObj[childKeys[0]].x;
26872 var maxX = childNodesObj[childKeys[0]].x;
26873 var minY = childNodesObj[childKeys[0]].y;
26874 var maxY = childNodesObj[childKeys[0]].y;
26875 var node;
26876
26877 for (var i = 1; i < childKeys.length; i++) {
26878 node = childNodesObj[childKeys[i]];
26879 minX = node.x < minX ? node.x : minX;
26880 maxX = node.x > maxX ? node.x : maxX;
26881 minY = node.y < minY ? node.y : minY;
26882 maxY = node.y > maxY ? node.y : maxY;
26883 }
26884
26885 return {
26886 x: 0.5 * (minX + maxX),
26887 y: 0.5 * (minY + maxY)
26888 };
26889 }
26890 /**
26891 * Open a cluster by calling this function.
26892 *
26893 * @param {vis.Edge.id} clusterNodeId | the ID of the cluster node
26894 * @param {object} options
26895 * @param {boolean} refreshData | wrap up afterwards if not true
26896 */
26897
26898 }, {
26899 key: "openCluster",
26900 value: function openCluster(clusterNodeId, options) {
26901 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
26902
26903 // kill conditions
26904 if (clusterNodeId === undefined) {
26905 throw new Error("No clusterNodeId supplied to openCluster.");
26906 }
26907
26908 var clusterNode = this.body.nodes[clusterNodeId];
26909
26910 if (clusterNode === undefined) {
26911 throw new Error("The clusterNodeId supplied to openCluster does not exist.");
26912 }
26913
26914 if (clusterNode.isCluster !== true || clusterNode.containedNodes === undefined || clusterNode.containedEdges === undefined) {
26915 throw new Error("The node:" + clusterNodeId + " is not a valid cluster.");
26916 } // Check if current cluster is clustered itself
26917
26918
26919 var stack = this.findNode(clusterNodeId);
26920 var parentIndex = indexOf(stack).call(stack, clusterNodeId) - 1;
26921
26922 if (parentIndex >= 0) {
26923 // Current cluster is clustered; transfer contained nodes and edges to parent
26924 var parentClusterNodeId = stack[parentIndex];
26925 var parentClusterNode = this.body.nodes[parentClusterNodeId]; // clustering.clusteredNodes and clustering.clusteredEdges remain unchanged
26926
26927 parentClusterNode._openChildCluster(clusterNodeId); // All components of child cluster node have been transferred. It can die now.
26928
26929
26930 delete this.body.nodes[clusterNodeId];
26931
26932 if (refreshData === true) {
26933 this.body.emitter.emit("_dataChanged");
26934 }
26935
26936 return;
26937 } // main body
26938
26939
26940 var containedNodes = clusterNode.containedNodes;
26941 var containedEdges = clusterNode.containedEdges; // allow the user to position the nodes after release.
26942
26943 if (options !== undefined && options.releaseFunction !== undefined && typeof options.releaseFunction === "function") {
26944 var positions = {};
26945 var clusterPosition = {
26946 x: clusterNode.x,
26947 y: clusterNode.y
26948 };
26949
26950 for (var nodeId in containedNodes) {
26951 if (Object.prototype.hasOwnProperty.call(containedNodes, nodeId)) {
26952 var containedNode = this.body.nodes[nodeId];
26953 positions[nodeId] = {
26954 x: containedNode.x,
26955 y: containedNode.y
26956 };
26957 }
26958 }
26959
26960 var newPositions = options.releaseFunction(clusterPosition, positions);
26961
26962 for (var _nodeId2 in containedNodes) {
26963 if (Object.prototype.hasOwnProperty.call(containedNodes, _nodeId2)) {
26964 var _containedNode = this.body.nodes[_nodeId2];
26965
26966 if (newPositions[_nodeId2] !== undefined) {
26967 _containedNode.x = newPositions[_nodeId2].x === undefined ? clusterNode.x : newPositions[_nodeId2].x;
26968 _containedNode.y = newPositions[_nodeId2].y === undefined ? clusterNode.y : newPositions[_nodeId2].y;
26969 }
26970 }
26971 }
26972 } else {
26973 // copy the position from the cluster
26974 forEach$1(containedNodes, function (containedNode) {
26975 // inherit position
26976 if (containedNode.options.fixed.x === false) {
26977 containedNode.x = clusterNode.x;
26978 }
26979
26980 if (containedNode.options.fixed.y === false) {
26981 containedNode.y = clusterNode.y;
26982 }
26983 });
26984 } // release nodes
26985
26986
26987 for (var _nodeId3 in containedNodes) {
26988 if (Object.prototype.hasOwnProperty.call(containedNodes, _nodeId3)) {
26989 var _containedNode2 = this.body.nodes[_nodeId3]; // inherit speed
26990
26991 _containedNode2.vx = clusterNode.vx;
26992 _containedNode2.vy = clusterNode.vy;
26993
26994 _containedNode2.setOptions({
26995 physics: true
26996 });
26997
26998 delete this.clusteredNodes[_nodeId3];
26999 }
27000 } // copy the clusterNode edges because we cannot iterate over an object that we add or remove from.
27001
27002
27003 var edgesToBeDeleted = [];
27004
27005 for (var i = 0; i < clusterNode.edges.length; i++) {
27006 edgesToBeDeleted.push(clusterNode.edges[i]);
27007 } // actually handling the deleting.
27008
27009
27010 for (var _i3 = 0; _i3 < edgesToBeDeleted.length; _i3++) {
27011 var edge = edgesToBeDeleted[_i3];
27012
27013 var otherNodeId = this._getConnectedId(edge, clusterNodeId);
27014
27015 var otherNode = this.clusteredNodes[otherNodeId];
27016
27017 for (var j = 0; j < edge.clusteringEdgeReplacingIds.length; j++) {
27018 var transferId = edge.clusteringEdgeReplacingIds[j];
27019 var transferEdge = this.body.edges[transferId];
27020 if (transferEdge === undefined) continue; // if the other node is in another cluster, we transfer ownership of this edge to the other cluster
27021
27022 if (otherNode !== undefined) {
27023 // transfer ownership:
27024 var otherCluster = this.body.nodes[otherNode.clusterId];
27025 otherCluster.containedEdges[transferEdge.id] = transferEdge; // delete local reference
27026
27027 delete containedEdges[transferEdge.id]; // get to and from
27028
27029 var fromId = transferEdge.fromId;
27030 var toId = transferEdge.toId;
27031
27032 if (transferEdge.toId == otherNodeId) {
27033 toId = otherNode.clusterId;
27034 } else {
27035 fromId = otherNode.clusterId;
27036 } // create new cluster edge from the otherCluster
27037
27038
27039 this._createClusteredEdge(fromId, toId, transferEdge, otherCluster.clusterEdgeProperties, {
27040 hidden: false,
27041 physics: true
27042 });
27043 } else {
27044 this._restoreEdge(transferEdge);
27045 }
27046 }
27047
27048 edge.remove();
27049 } // handle the releasing of the edges
27050
27051
27052 for (var edgeId in containedEdges) {
27053 if (Object.prototype.hasOwnProperty.call(containedEdges, edgeId)) {
27054 this._restoreEdge(containedEdges[edgeId]);
27055 }
27056 } // remove clusterNode
27057
27058
27059 delete this.body.nodes[clusterNodeId];
27060
27061 if (refreshData === true) {
27062 this.body.emitter.emit("_dataChanged");
27063 }
27064 }
27065 /**
27066 *
27067 * @param {Cluster.id} clusterId
27068 * @returns {Array.<Node.id>}
27069 */
27070
27071 }, {
27072 key: "getNodesInCluster",
27073 value: function getNodesInCluster(clusterId) {
27074 var nodesArray = [];
27075
27076 if (this.isCluster(clusterId) === true) {
27077 var containedNodes = this.body.nodes[clusterId].containedNodes;
27078
27079 for (var nodeId in containedNodes) {
27080 if (Object.prototype.hasOwnProperty.call(containedNodes, nodeId)) {
27081 nodesArray.push(this.body.nodes[nodeId].id);
27082 }
27083 }
27084 }
27085
27086 return nodesArray;
27087 }
27088 /**
27089 * Get the stack clusterId's that a certain node resides in. cluster A -> cluster B -> cluster C -> node
27090 *
27091 * If a node can't be found in the chain, return an empty array.
27092 *
27093 * @param {string|number} nodeId
27094 * @returns {Array}
27095 */
27096
27097 }, {
27098 key: "findNode",
27099 value: function findNode(nodeId) {
27100 var stack = [];
27101 var max = 100;
27102 var counter = 0;
27103 var node;
27104
27105 while (this.clusteredNodes[nodeId] !== undefined && counter < max) {
27106 node = this.body.nodes[nodeId];
27107 if (node === undefined) return [];
27108 stack.push(node.id);
27109 nodeId = this.clusteredNodes[nodeId].clusterId;
27110 counter++;
27111 }
27112
27113 node = this.body.nodes[nodeId];
27114 if (node === undefined) return [];
27115 stack.push(node.id);
27116
27117 reverse(stack).call(stack);
27118
27119 return stack;
27120 }
27121 /**
27122 * Using a clustered nodeId, update with the new options
27123 *
27124 * @param {Node.id} clusteredNodeId
27125 * @param {object} newOptions
27126 */
27127
27128 }, {
27129 key: "updateClusteredNode",
27130 value: function updateClusteredNode(clusteredNodeId, newOptions) {
27131 if (clusteredNodeId === undefined) {
27132 throw new Error("No clusteredNodeId supplied to updateClusteredNode.");
27133 }
27134
27135 if (newOptions === undefined) {
27136 throw new Error("No newOptions supplied to updateClusteredNode.");
27137 }
27138
27139 if (this.body.nodes[clusteredNodeId] === undefined) {
27140 throw new Error("The clusteredNodeId supplied to updateClusteredNode does not exist.");
27141 }
27142
27143 this.body.nodes[clusteredNodeId].setOptions(newOptions);
27144 this.body.emitter.emit("_dataChanged");
27145 }
27146 /**
27147 * Using a base edgeId, update all related clustered edges with the new options
27148 *
27149 * @param {vis.Edge.id} startEdgeId
27150 * @param {object} newOptions
27151 */
27152
27153 }, {
27154 key: "updateEdge",
27155 value: function updateEdge(startEdgeId, newOptions) {
27156 if (startEdgeId === undefined) {
27157 throw new Error("No startEdgeId supplied to updateEdge.");
27158 }
27159
27160 if (newOptions === undefined) {
27161 throw new Error("No newOptions supplied to updateEdge.");
27162 }
27163
27164 if (this.body.edges[startEdgeId] === undefined) {
27165 throw new Error("The startEdgeId supplied to updateEdge does not exist.");
27166 }
27167
27168 var allEdgeIds = this.getClusteredEdges(startEdgeId);
27169
27170 for (var i = 0; i < allEdgeIds.length; i++) {
27171 var edge = this.body.edges[allEdgeIds[i]];
27172 edge.setOptions(newOptions);
27173 }
27174
27175 this.body.emitter.emit("_dataChanged");
27176 }
27177 /**
27178 * 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)
27179 *
27180 * @param {vis.Edge.id} edgeId
27181 * @returns {Array.<vis.Edge.id>}
27182 */
27183
27184 }, {
27185 key: "getClusteredEdges",
27186 value: function getClusteredEdges(edgeId) {
27187 var stack = [];
27188 var max = 100;
27189 var counter = 0;
27190
27191 while (edgeId !== undefined && this.body.edges[edgeId] !== undefined && counter < max) {
27192 stack.push(this.body.edges[edgeId].id);
27193 edgeId = this.body.edges[edgeId].edgeReplacedById;
27194 counter++;
27195 }
27196
27197 reverse(stack).call(stack);
27198
27199 return stack;
27200 }
27201 /**
27202 * Get the base edge id of clusterEdgeId. cluster edge (clusteredEdgeId) -> cluster edge B -> cluster edge C -> base edge
27203 *
27204 * @param {vis.Edge.id} clusteredEdgeId
27205 * @returns {vis.Edge.id} baseEdgeId
27206 *
27207 * TODO: deprecate in 5.0.0. Method getBaseEdges() is the correct one to use.
27208 */
27209
27210 }, {
27211 key: "getBaseEdge",
27212 value: function getBaseEdge(clusteredEdgeId) {
27213 // Just kludge this by returning the first base edge id found
27214 return this.getBaseEdges(clusteredEdgeId)[0];
27215 }
27216 /**
27217 * Get all regular edges for this clustered edge id.
27218 *
27219 * @param {vis.Edge.id} clusteredEdgeId
27220 * @returns {Array.<vis.Edge.id>} all baseEdgeId's under this clustered edge
27221 */
27222
27223 }, {
27224 key: "getBaseEdges",
27225 value: function getBaseEdges(clusteredEdgeId) {
27226 var IdsToHandle = [clusteredEdgeId];
27227 var doneIds = [];
27228 var foundIds = [];
27229 var max = 100;
27230 var counter = 0;
27231
27232 while (IdsToHandle.length > 0 && counter < max) {
27233 var nextId = IdsToHandle.pop();
27234 if (nextId === undefined) continue; // Paranoia here and onwards
27235
27236 var nextEdge = this.body.edges[nextId];
27237 if (nextEdge === undefined) continue;
27238 counter++;
27239 var replacingIds = nextEdge.clusteringEdgeReplacingIds;
27240
27241 if (replacingIds === undefined) {
27242 // nextId is a base id
27243 foundIds.push(nextId);
27244 } else {
27245 // Another cluster edge, unravel this one as well
27246 for (var i = 0; i < replacingIds.length; ++i) {
27247 var replacingId = replacingIds[i]; // Don't add if already handled
27248 // TODO: never triggers; find a test-case which does
27249
27250 if (indexOf(IdsToHandle).call(IdsToHandle, replacingIds) !== -1 || indexOf(doneIds).call(doneIds, replacingIds) !== -1) {
27251 continue;
27252 }
27253
27254 IdsToHandle.push(replacingId);
27255 }
27256 }
27257
27258 doneIds.push(nextId);
27259 }
27260
27261 return foundIds;
27262 }
27263 /**
27264 * Get the Id the node is connected to
27265 *
27266 * @param {vis.Edge} edge
27267 * @param {Node.id} nodeId
27268 * @returns {*}
27269 * @private
27270 */
27271
27272 }, {
27273 key: "_getConnectedId",
27274 value: function _getConnectedId(edge, nodeId) {
27275 if (edge.toId != nodeId) {
27276 return edge.toId;
27277 } else if (edge.fromId != nodeId) {
27278 return edge.fromId;
27279 } else {
27280 return edge.fromId;
27281 }
27282 }
27283 /**
27284 * We determine how many connections denote an important hub.
27285 * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%)
27286 *
27287 * @returns {number}
27288 * @private
27289 */
27290
27291 }, {
27292 key: "_getHubSize",
27293 value: function _getHubSize() {
27294 var average = 0;
27295 var averageSquared = 0;
27296 var hubCounter = 0;
27297 var largestHub = 0;
27298
27299 for (var i = 0; i < this.body.nodeIndices.length; i++) {
27300 var node = this.body.nodes[this.body.nodeIndices[i]];
27301
27302 if (node.edges.length > largestHub) {
27303 largestHub = node.edges.length;
27304 }
27305
27306 average += node.edges.length;
27307 averageSquared += Math.pow(node.edges.length, 2);
27308 hubCounter += 1;
27309 }
27310
27311 average = average / hubCounter;
27312 averageSquared = averageSquared / hubCounter;
27313 var variance = averageSquared - Math.pow(average, 2);
27314 var standardDeviation = Math.sqrt(variance);
27315 var hubThreshold = Math.floor(average + 2 * standardDeviation); // always have at least one to cluster
27316
27317 if (hubThreshold > largestHub) {
27318 hubThreshold = largestHub;
27319 }
27320
27321 return hubThreshold;
27322 }
27323 /**
27324 * Create an edge for the cluster representation.
27325 *
27326 * @param {Node.id} fromId
27327 * @param {Node.id} toId
27328 * @param {vis.Edge} baseEdge
27329 * @param {object} clusterEdgeProperties
27330 * @param {object} extraOptions
27331 * @returns {Edge} newly created clustered edge
27332 * @private
27333 */
27334
27335 }, {
27336 key: "_createClusteredEdge",
27337 value: function _createClusteredEdge(fromId, toId, baseEdge, clusterEdgeProperties, extraOptions) {
27338 // copy the options of the edge we will replace
27339 var clonedOptions = NetworkUtil.cloneOptions(baseEdge, "edge"); // make sure the properties of clusterEdges are superimposed on it
27340
27341 deepExtend(clonedOptions, clusterEdgeProperties); // set up the edge
27342
27343 clonedOptions.from = fromId;
27344 clonedOptions.to = toId;
27345 clonedOptions.id = "clusterEdge:" + v4(); // apply the edge specific options to it if specified
27346
27347 if (extraOptions !== undefined) {
27348 deepExtend(clonedOptions, extraOptions);
27349 }
27350
27351 var newEdge = this.body.functions.createEdge(clonedOptions);
27352 newEdge.clusteringEdgeReplacingIds = [baseEdge.id];
27353 newEdge.connect(); // Register the new edge
27354
27355 this.body.edges[newEdge.id] = newEdge;
27356 return newEdge;
27357 }
27358 /**
27359 * Add the passed child nodes and edges to the given cluster node.
27360 *
27361 * @param {object | Node} childNodes hash of nodes or single node to add in cluster
27362 * @param {object | Edge} childEdges hash of edges or single edge to take into account when clustering
27363 * @param {Node} clusterNode cluster node to add nodes and edges to
27364 * @param {object} [clusterEdgeProperties]
27365 * @private
27366 */
27367
27368 }, {
27369 key: "_clusterEdges",
27370 value: function _clusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties) {
27371 if (childEdges instanceof Edge) {
27372 var edge = childEdges;
27373 var obj = {};
27374 obj[edge.id] = edge;
27375 childEdges = obj;
27376 }
27377
27378 if (childNodes instanceof Node) {
27379 var node = childNodes;
27380 var _obj = {};
27381 _obj[node.id] = node;
27382 childNodes = _obj;
27383 }
27384
27385 if (clusterNode === undefined || clusterNode === null) {
27386 throw new Error("_clusterEdges: parameter clusterNode required");
27387 }
27388
27389 if (clusterEdgeProperties === undefined) {
27390 // Take the required properties from the cluster node
27391 clusterEdgeProperties = clusterNode.clusterEdgeProperties;
27392 } // create the new edges that will connect to the cluster.
27393 // All self-referencing edges will be added to childEdges here.
27394
27395
27396 this._createClusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties); // disable the childEdges
27397
27398
27399 for (var edgeId in childEdges) {
27400 if (Object.prototype.hasOwnProperty.call(childEdges, edgeId)) {
27401 if (this.body.edges[edgeId] !== undefined) {
27402 var _edge2 = this.body.edges[edgeId]; // cache the options before changing
27403
27404 this._backupEdgeOptions(_edge2); // disable physics and hide the edge
27405
27406
27407 _edge2.setOptions({
27408 physics: false
27409 });
27410 }
27411 }
27412 } // disable the childNodes
27413
27414
27415 for (var nodeId in childNodes) {
27416 if (Object.prototype.hasOwnProperty.call(childNodes, nodeId)) {
27417 this.clusteredNodes[nodeId] = {
27418 clusterId: clusterNode.id,
27419 node: this.body.nodes[nodeId]
27420 };
27421 this.body.nodes[nodeId].setOptions({
27422 physics: false
27423 });
27424 }
27425 }
27426 }
27427 /**
27428 * Determine in which cluster given nodeId resides.
27429 *
27430 * If not in cluster, return undefined.
27431 *
27432 * NOTE: If you know a cleaner way to do this, please enlighten me (wimrijnders).
27433 *
27434 * @param {Node.id} nodeId
27435 * @returns {Node|undefined} Node instance for cluster, if present
27436 * @private
27437 */
27438
27439 }, {
27440 key: "_getClusterNodeForNode",
27441 value: function _getClusterNodeForNode(nodeId) {
27442 if (nodeId === undefined) return undefined;
27443 var clusteredNode = this.clusteredNodes[nodeId]; // NOTE: If no cluster info found, it should actually be an error
27444
27445 if (clusteredNode === undefined) return undefined;
27446 var clusterId = clusteredNode.clusterId;
27447 if (clusterId === undefined) return undefined;
27448 return this.body.nodes[clusterId];
27449 }
27450 /**
27451 * Internal helper function for conditionally removing items in array
27452 *
27453 * Done like this because Array.filter() is not fully supported by all IE's.
27454 *
27455 * @param {Array} arr
27456 * @param {Function} callback
27457 * @returns {Array}
27458 * @private
27459 */
27460
27461 }, {
27462 key: "_filter",
27463 value: function _filter(arr, callback) {
27464 var ret = [];
27465 forEach$1(arr, function (item) {
27466 if (callback(item)) {
27467 ret.push(item);
27468 }
27469 });
27470 return ret;
27471 }
27472 /**
27473 * Scan all edges for changes in clustering and adjust this if necessary.
27474 *
27475 * Call this (internally) after there has been a change in node or edge data.
27476 *
27477 * Pre: States of this.body.nodes and this.body.edges consistent
27478 * Pre: this.clusteredNodes and this.clusteredEdge consistent with containedNodes and containedEdges
27479 * of cluster nodes.
27480 */
27481
27482 }, {
27483 key: "_updateState",
27484 value: function _updateState() {
27485 var _this4 = this;
27486
27487 var nodeId;
27488 var deletedNodeIds = [];
27489 var deletedEdgeIds = {};
27490 /**
27491 * Utility function to iterate over clustering nodes only
27492 *
27493 * @param {Function} callback function to call for each cluster node
27494 */
27495
27496 var eachClusterNode = function eachClusterNode(callback) {
27497 forEach$1(_this4.body.nodes, function (node) {
27498 if (node.isCluster === true) {
27499 callback(node);
27500 }
27501 });
27502 }; //
27503 // Remove deleted regular nodes from clustering
27504 //
27505 // Determine the deleted nodes
27506
27507
27508 for (nodeId in this.clusteredNodes) {
27509 if (!Object.prototype.hasOwnProperty.call(this.clusteredNodes, nodeId)) continue;
27510 var node = this.body.nodes[nodeId];
27511
27512 if (node === undefined) {
27513 deletedNodeIds.push(nodeId);
27514 }
27515 } // Remove nodes from cluster nodes
27516
27517
27518 eachClusterNode(function (clusterNode) {
27519 for (var n = 0; n < deletedNodeIds.length; n++) {
27520 delete clusterNode.containedNodes[deletedNodeIds[n]];
27521 }
27522 }); // Remove nodes from cluster list
27523
27524 for (var n = 0; n < deletedNodeIds.length; n++) {
27525 delete this.clusteredNodes[deletedNodeIds[n]];
27526 } //
27527 // Remove deleted edges from clustering
27528 //
27529 // Add the deleted clustered edges to the list
27530
27531
27532 forEach$1(this.clusteredEdges, function (edgeId) {
27533 var edge = _this4.body.edges[edgeId];
27534
27535 if (edge === undefined || !edge.endPointsValid()) {
27536 deletedEdgeIds[edgeId] = edgeId;
27537 }
27538 }); // Cluster nodes can also contain edges which are not clustered,
27539 // i.e. nodes 1-2 within cluster with an edge in between.
27540 // So the cluster nodes also need to be scanned for invalid edges
27541
27542 eachClusterNode(function (clusterNode) {
27543 forEach$1(clusterNode.containedEdges, function (edge, edgeId) {
27544 if (!edge.endPointsValid() && !deletedEdgeIds[edgeId]) {
27545 deletedEdgeIds[edgeId] = edgeId;
27546 }
27547 });
27548 }); // Also scan for cluster edges which need to be removed in the active list.
27549 // Regular edges have been removed beforehand, so this only picks up the cluster edges.
27550
27551 forEach$1(this.body.edges, function (edge, edgeId) {
27552 // Explicitly scan the contained edges for validity
27553 var isValid = true;
27554 var replacedIds = edge.clusteringEdgeReplacingIds;
27555
27556 if (replacedIds !== undefined) {
27557 var numValid = 0;
27558 forEach$1(replacedIds, function (containedEdgeId) {
27559 var containedEdge = _this4.body.edges[containedEdgeId];
27560
27561 if (containedEdge !== undefined && containedEdge.endPointsValid()) {
27562 numValid += 1;
27563 }
27564 });
27565 isValid = numValid > 0;
27566 }
27567
27568 if (!edge.endPointsValid() || !isValid) {
27569 deletedEdgeIds[edgeId] = edgeId;
27570 }
27571 }); // Remove edges from cluster nodes
27572
27573 eachClusterNode(function (clusterNode) {
27574 forEach$1(deletedEdgeIds, function (deletedEdgeId) {
27575 delete clusterNode.containedEdges[deletedEdgeId];
27576 forEach$1(clusterNode.edges, function (edge, m) {
27577 if (edge.id === deletedEdgeId) {
27578 clusterNode.edges[m] = null; // Don't want to directly delete here, because in the loop
27579
27580 return;
27581 }
27582
27583 edge.clusteringEdgeReplacingIds = _this4._filter(edge.clusteringEdgeReplacingIds, function (id) {
27584 return !deletedEdgeIds[id];
27585 });
27586 }); // Clean up the nulls
27587
27588 clusterNode.edges = _this4._filter(clusterNode.edges, function (item) {
27589 return item !== null;
27590 });
27591 });
27592 }); // Remove from cluster list
27593
27594 forEach$1(deletedEdgeIds, function (edgeId) {
27595 delete _this4.clusteredEdges[edgeId];
27596 }); // Remove cluster edges from active list (this.body.edges).
27597 // deletedEdgeIds still contains id of regular edges, but these should all
27598 // be gone when you reach here.
27599
27600 forEach$1(deletedEdgeIds, function (edgeId) {
27601 delete _this4.body.edges[edgeId];
27602 }); //
27603 // Check changed cluster state of edges
27604 //
27605 // Iterating over keys here, because edges may be removed in the loop
27606
27607 var ids = keys(this.body.edges);
27608
27609 forEach$1(ids, function (edgeId) {
27610 var edge = _this4.body.edges[edgeId];
27611
27612 var shouldBeClustered = _this4._isClusteredNode(edge.fromId) || _this4._isClusteredNode(edge.toId);
27613
27614 if (shouldBeClustered === _this4._isClusteredEdge(edge.id)) {
27615 return; // all is well
27616 }
27617
27618 if (shouldBeClustered) {
27619 // add edge to clustering
27620 var clusterFrom = _this4._getClusterNodeForNode(edge.fromId);
27621
27622 if (clusterFrom !== undefined) {
27623 _this4._clusterEdges(_this4.body.nodes[edge.fromId], edge, clusterFrom);
27624 }
27625
27626 var clusterTo = _this4._getClusterNodeForNode(edge.toId);
27627
27628 if (clusterTo !== undefined) {
27629 _this4._clusterEdges(_this4.body.nodes[edge.toId], edge, clusterTo);
27630 } // TODO: check that it works for both edges clustered
27631 // (This might be paranoia)
27632
27633 } else {
27634 delete _this4._clusterEdges[edgeId];
27635
27636 _this4._restoreEdge(edge); // This should not be happening, the state should
27637 // be properly updated at this point.
27638 //
27639 // If it *is* reached during normal operation, then we have to implement
27640 // undo clustering for this edge here.
27641 // throw new Error('remove edge from clustering not implemented!')
27642
27643 }
27644 }); // Clusters may be nested to any level. Keep on opening until nothing to open
27645
27646 var changed = false;
27647 var continueLoop = true;
27648
27649 var _loop2 = function _loop2() {
27650 var clustersToOpen = []; // Determine the id's of clusters that need opening
27651
27652 eachClusterNode(function (clusterNode) {
27653 var numNodes = keys(clusterNode.containedNodes).length;
27654
27655 var allowSingle = clusterNode.options.allowSingleNodeCluster === true;
27656
27657 if (allowSingle && numNodes < 1 || !allowSingle && numNodes < 2) {
27658 clustersToOpen.push(clusterNode.id);
27659 }
27660 }); // Open them
27661
27662 for (var _n = 0; _n < clustersToOpen.length; ++_n) {
27663 _this4.openCluster(clustersToOpen[_n], {}, false
27664 /* Don't refresh, we're in an refresh/update already */
27665 );
27666 }
27667
27668 continueLoop = clustersToOpen.length > 0;
27669 changed = changed || continueLoop;
27670 };
27671
27672 while (continueLoop) {
27673 _loop2();
27674 }
27675
27676 if (changed) {
27677 this._updateState(); // Redo this method (recursion possible! should be safe)
27678
27679 }
27680 }
27681 /**
27682 * Determine if node with given id is part of a cluster.
27683 *
27684 * @param {Node.id} nodeId
27685 * @returns {boolean} true if part of a cluster.
27686 */
27687
27688 }, {
27689 key: "_isClusteredNode",
27690 value: function _isClusteredNode(nodeId) {
27691 return this.clusteredNodes[nodeId] !== undefined;
27692 }
27693 /**
27694 * Determine if edge with given id is not visible due to clustering.
27695 *
27696 * An edge is considered clustered if:
27697 * - it is directly replaced by a clustering edge
27698 * - any of its connecting nodes is in a cluster
27699 *
27700 * @param {vis.Edge.id} edgeId
27701 * @returns {boolean} true if part of a cluster.
27702 */
27703
27704 }, {
27705 key: "_isClusteredEdge",
27706 value: function _isClusteredEdge(edgeId) {
27707 return this.clusteredEdges[edgeId] !== undefined;
27708 }
27709 }]);
27710
27711 return ClusterEngine;
27712 }();
27713
27714 function _createForOfIteratorHelper$5(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$1(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; } } }; }
27715
27716 function _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$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$5(o, minLen); }
27717
27718 function _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; }
27719 /**
27720 * Initializes window.requestAnimationFrame() to a usable form.
27721 *
27722 * Specifically, set up this method for the case of running on node.js with jsdom enabled.
27723 *
27724 * NOTES:
27725 *
27726 * * On node.js, when calling this directly outside of this class, `window` is not defined.
27727 * This happens even if jsdom is used.
27728 * * For node.js + jsdom, `window` is available at the moment the constructor is called.
27729 * For this reason, the called is placed within the constructor.
27730 * * Even then, `window.requestAnimationFrame()` is not defined, so it still needs to be added.
27731 * * During unit testing, it happens that the window object is reset during execution, causing
27732 * a runtime error due to missing `requestAnimationFrame()`. This needs to be compensated for,
27733 * see `_requestNextFrame()`.
27734 * * Since this is a global object, it may affect other modules besides `Network`. With normal
27735 * usage, this does not cause any problems. During unit testing, errors may occur. These have
27736 * been compensated for, see comment block in _requestNextFrame().
27737 *
27738 * @private
27739 */
27740
27741 function _initRequestAnimationFrame() {
27742 var func;
27743
27744 if (window !== undefined) {
27745 func = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
27746 }
27747
27748 if (func === undefined) {
27749 // window or method not present, setting mock requestAnimationFrame
27750 window.requestAnimationFrame = function (callback) {
27751 //console.log("Called mock requestAnimationFrame");
27752 callback();
27753 };
27754 } else {
27755 window.requestAnimationFrame = func;
27756 }
27757 }
27758 /**
27759 * The canvas renderer
27760 */
27761
27762
27763 var CanvasRenderer = /*#__PURE__*/function () {
27764 /**
27765 * @param {object} body
27766 * @param {Canvas} canvas
27767 */
27768 function CanvasRenderer(body, canvas) {
27769 _classCallCheck(this, CanvasRenderer);
27770
27771 _initRequestAnimationFrame();
27772
27773 this.body = body;
27774 this.canvas = canvas;
27775 this.redrawRequested = false;
27776 this.renderTimer = undefined;
27777 this.requiresTimeout = true;
27778 this.renderingActive = false;
27779 this.renderRequests = 0;
27780 this.allowRedraw = true;
27781 this.dragging = false;
27782 this.zooming = false;
27783 this.options = {};
27784 this.defaultOptions = {
27785 hideEdgesOnDrag: false,
27786 hideEdgesOnZoom: false,
27787 hideNodesOnDrag: false
27788 };
27789
27790 assign$2(this.options, this.defaultOptions);
27791
27792 this._determineBrowserMethod();
27793
27794 this.bindEventListeners();
27795 }
27796 /**
27797 * Binds event listeners
27798 */
27799
27800
27801 _createClass(CanvasRenderer, [{
27802 key: "bindEventListeners",
27803 value: function bindEventListeners() {
27804 var _this = this,
27805 _context2;
27806
27807 this.body.emitter.on("dragStart", function () {
27808 _this.dragging = true;
27809 });
27810 this.body.emitter.on("dragEnd", function () {
27811 _this.dragging = false;
27812 });
27813 this.body.emitter.on("zoom", function () {
27814 _this.zooming = true;
27815 window.clearTimeout(_this.zoomTimeoutId);
27816 _this.zoomTimeoutId = setTimeout$1(function () {
27817 var _context;
27818
27819 _this.zooming = false;
27820
27821 bind$5(_context = _this._requestRedraw).call(_context, _this)();
27822 }, 250);
27823 });
27824 this.body.emitter.on("_resizeNodes", function () {
27825 _this._resizeNodes();
27826 });
27827 this.body.emitter.on("_redraw", function () {
27828 if (_this.renderingActive === false) {
27829 _this._redraw();
27830 }
27831 });
27832 this.body.emitter.on("_blockRedraw", function () {
27833 _this.allowRedraw = false;
27834 });
27835 this.body.emitter.on("_allowRedraw", function () {
27836 _this.allowRedraw = true;
27837 _this.redrawRequested = false;
27838 });
27839 this.body.emitter.on("_requestRedraw", bind$5(_context2 = this._requestRedraw).call(_context2, this));
27840 this.body.emitter.on("_startRendering", function () {
27841 _this.renderRequests += 1;
27842 _this.renderingActive = true;
27843
27844 _this._startRendering();
27845 });
27846 this.body.emitter.on("_stopRendering", function () {
27847 _this.renderRequests -= 1;
27848 _this.renderingActive = _this.renderRequests > 0;
27849 _this.renderTimer = undefined;
27850 });
27851 this.body.emitter.on("destroy", function () {
27852 _this.renderRequests = 0;
27853 _this.allowRedraw = false;
27854 _this.renderingActive = false;
27855
27856 if (_this.requiresTimeout === true) {
27857 clearTimeout(_this.renderTimer);
27858 } else {
27859 window.cancelAnimationFrame(_this.renderTimer);
27860 }
27861
27862 _this.body.emitter.off();
27863 });
27864 }
27865 /**
27866 *
27867 * @param {object} options
27868 */
27869
27870 }, {
27871 key: "setOptions",
27872 value: function setOptions(options) {
27873 if (options !== undefined) {
27874 var fields = ["hideEdgesOnDrag", "hideEdgesOnZoom", "hideNodesOnDrag"];
27875 selectiveDeepExtend(fields, this.options, options);
27876 }
27877 }
27878 /**
27879 * Prepare the drawing of the next frame.
27880 *
27881 * Calls the callback when the next frame can or will be drawn.
27882 *
27883 * @param {Function} callback
27884 * @param {number} delay - timeout case only, wait this number of milliseconds
27885 * @returns {Function | undefined}
27886 * @private
27887 */
27888
27889 }, {
27890 key: "_requestNextFrame",
27891 value: function _requestNextFrame(callback, delay) {
27892 // During unit testing, it happens that the mock window object is reset while
27893 // the next frame is still pending. Then, either 'window' is not present, or
27894 // 'requestAnimationFrame()' is not present because it is not defined on the
27895 // mock window object.
27896 //
27897 // As a consequence, unrelated unit tests may appear to fail, even if the problem
27898 // described happens in the current unit test.
27899 //
27900 // This is not something that will happen in normal operation, but we still need
27901 // to take it into account.
27902 //
27903 if (typeof window === "undefined") return; // Doing `if (window === undefined)` does not work here!
27904
27905 var timer;
27906 var myWindow = window; // Grab a reference to reduce the possibility that 'window' is reset
27907 // while running this method.
27908
27909 if (this.requiresTimeout === true) {
27910 // wait given number of milliseconds and perform the animation step function
27911 timer = setTimeout$1(callback, delay);
27912 } else {
27913 if (myWindow.requestAnimationFrame) {
27914 timer = myWindow.requestAnimationFrame(callback);
27915 }
27916 }
27917
27918 return timer;
27919 }
27920 /**
27921 *
27922 * @private
27923 */
27924
27925 }, {
27926 key: "_startRendering",
27927 value: function _startRendering() {
27928 if (this.renderingActive === true) {
27929 if (this.renderTimer === undefined) {
27930 var _context3;
27931
27932 this.renderTimer = this._requestNextFrame(bind$5(_context3 = this._renderStep).call(_context3, this), this.simulationInterval);
27933 }
27934 }
27935 }
27936 /**
27937 *
27938 * @private
27939 */
27940
27941 }, {
27942 key: "_renderStep",
27943 value: function _renderStep() {
27944 if (this.renderingActive === true) {
27945 // reset the renderTimer so a new scheduled animation step can be set
27946 this.renderTimer = undefined;
27947
27948 if (this.requiresTimeout === true) {
27949 // this schedules a new simulation step
27950 this._startRendering();
27951 }
27952
27953 this._redraw();
27954
27955 if (this.requiresTimeout === false) {
27956 // this schedules a new simulation step
27957 this._startRendering();
27958 }
27959 }
27960 }
27961 /**
27962 * Redraw the network with the current data
27963 * chart will be resized too.
27964 */
27965
27966 }, {
27967 key: "redraw",
27968 value: function redraw() {
27969 this.body.emitter.emit("setSize");
27970
27971 this._redraw();
27972 }
27973 /**
27974 * Redraw the network with the current data
27975 *
27976 * @private
27977 */
27978
27979 }, {
27980 key: "_requestRedraw",
27981 value: function _requestRedraw() {
27982 var _this2 = this;
27983
27984 if (this.redrawRequested !== true && this.renderingActive === false && this.allowRedraw === true) {
27985 this.redrawRequested = true;
27986
27987 this._requestNextFrame(function () {
27988 _this2._redraw(false);
27989 }, 0);
27990 }
27991 }
27992 /**
27993 * Redraw the network with the current data
27994 *
27995 * @param {boolean} [hidden=false] | Used to get the first estimate of the node sizes.
27996 * Only the nodes are drawn after which they are quickly drawn over.
27997 * @private
27998 */
27999
28000 }, {
28001 key: "_redraw",
28002 value: function _redraw() {
28003 var hidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
28004
28005 if (this.allowRedraw === true) {
28006 this.body.emitter.emit("initRedraw");
28007 this.redrawRequested = false;
28008 var drawLater = {
28009 drawExternalLabels: null
28010 }; // when the container div was hidden, this fixes it back up!
28011
28012 if (this.canvas.frame.canvas.width === 0 || this.canvas.frame.canvas.height === 0) {
28013 this.canvas.setSize();
28014 }
28015
28016 this.canvas.setTransform();
28017 var ctx = this.canvas.getContext(); // clear the canvas
28018
28019 var w = this.canvas.frame.canvas.clientWidth;
28020 var h = this.canvas.frame.canvas.clientHeight;
28021 ctx.clearRect(0, 0, w, h); // if the div is hidden, we stop the redraw here for performance.
28022
28023 if (this.canvas.frame.clientWidth === 0) {
28024 return;
28025 } // set scaling and translation
28026
28027
28028 ctx.save();
28029 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
28030 ctx.scale(this.body.view.scale, this.body.view.scale);
28031 ctx.beginPath();
28032 this.body.emitter.emit("beforeDrawing", ctx);
28033 ctx.closePath();
28034
28035 if (hidden === false) {
28036 if ((this.dragging === false || this.dragging === true && this.options.hideEdgesOnDrag === false) && (this.zooming === false || this.zooming === true && this.options.hideEdgesOnZoom === false)) {
28037 this._drawEdges(ctx);
28038 }
28039 }
28040
28041 if (this.dragging === false || this.dragging === true && this.options.hideNodesOnDrag === false) {
28042 var _this$_drawNodes = this._drawNodes(ctx, hidden),
28043 drawExternalLabels = _this$_drawNodes.drawExternalLabels;
28044
28045 drawLater.drawExternalLabels = drawExternalLabels;
28046 } // draw the arrows last so they will be at the top
28047
28048
28049 if (hidden === false) {
28050 if ((this.dragging === false || this.dragging === true && this.options.hideEdgesOnDrag === false) && (this.zooming === false || this.zooming === true && this.options.hideEdgesOnZoom === false)) {
28051 this._drawArrows(ctx);
28052 }
28053 }
28054
28055 if (drawLater.drawExternalLabels != null) {
28056 drawLater.drawExternalLabels();
28057 }
28058
28059 if (hidden === false) {
28060 this._drawSelectionBox(ctx);
28061 }
28062
28063 ctx.beginPath();
28064 this.body.emitter.emit("afterDrawing", ctx);
28065 ctx.closePath(); // restore original scaling and translation
28066
28067 ctx.restore();
28068
28069 if (hidden === true) {
28070 ctx.clearRect(0, 0, w, h);
28071 }
28072 }
28073 }
28074 /**
28075 * Redraw all nodes
28076 *
28077 * @param {CanvasRenderingContext2D} ctx
28078 * @param {boolean} [alwaysShow]
28079 * @private
28080 */
28081
28082 }, {
28083 key: "_resizeNodes",
28084 value: function _resizeNodes() {
28085 this.canvas.setTransform();
28086 var ctx = this.canvas.getContext();
28087 ctx.save();
28088 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
28089 ctx.scale(this.body.view.scale, this.body.view.scale);
28090 var nodes = this.body.nodes;
28091 var node; // resize all nodes
28092
28093 for (var nodeId in nodes) {
28094 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
28095 node = nodes[nodeId];
28096 node.resize(ctx);
28097 node.updateBoundingBox(ctx, node.selected);
28098 }
28099 } // restore original scaling and translation
28100
28101
28102 ctx.restore();
28103 }
28104 /**
28105 * Redraw all nodes
28106 *
28107 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
28108 * @param {boolean} [alwaysShow]
28109 * @private
28110 *
28111 * @returns {object} Callbacks to draw later on higher layers.
28112 */
28113
28114 }, {
28115 key: "_drawNodes",
28116 value: function _drawNodes(ctx) {
28117 var alwaysShow = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
28118 var nodes = this.body.nodes;
28119 var nodeIndices = this.body.nodeIndices;
28120 var node;
28121 var selected = [];
28122 var hovered = [];
28123 var margin = 20;
28124 var topLeft = this.canvas.DOMtoCanvas({
28125 x: -margin,
28126 y: -margin
28127 });
28128 var bottomRight = this.canvas.DOMtoCanvas({
28129 x: this.canvas.frame.canvas.clientWidth + margin,
28130 y: this.canvas.frame.canvas.clientHeight + margin
28131 });
28132 var viewableArea = {
28133 top: topLeft.y,
28134 left: topLeft.x,
28135 bottom: bottomRight.y,
28136 right: bottomRight.x
28137 };
28138 var _drawExternalLabels = []; // draw unselected nodes;
28139
28140 for (var _i = 0; _i < nodeIndices.length; _i++) {
28141 node = nodes[nodeIndices[_i]]; // set selected and hovered nodes aside
28142
28143 if (node.hover) {
28144 hovered.push(nodeIndices[_i]);
28145 } else if (node.isSelected()) {
28146 selected.push(nodeIndices[_i]);
28147 } else {
28148 if (alwaysShow === true) {
28149 var drawLater = node.draw(ctx);
28150
28151 if (drawLater.drawExternalLabel != null) {
28152 _drawExternalLabels.push(drawLater.drawExternalLabel);
28153 }
28154 } else if (node.isBoundingBoxOverlappingWith(viewableArea) === true) {
28155 var _drawLater = node.draw(ctx);
28156
28157 if (_drawLater.drawExternalLabel != null) {
28158 _drawExternalLabels.push(_drawLater.drawExternalLabel);
28159 }
28160 } else {
28161 node.updateBoundingBox(ctx, node.selected);
28162 }
28163 }
28164 }
28165
28166 var i;
28167 var selectedLength = selected.length;
28168 var hoveredLength = hovered.length; // draw the selected nodes on top
28169
28170 for (i = 0; i < selectedLength; i++) {
28171 node = nodes[selected[i]];
28172
28173 var _drawLater2 = node.draw(ctx);
28174
28175 if (_drawLater2.drawExternalLabel != null) {
28176 _drawExternalLabels.push(_drawLater2.drawExternalLabel);
28177 }
28178 } // draw hovered nodes above everything else: fixes https://github.com/visjs/vis-network/issues/226
28179
28180
28181 for (i = 0; i < hoveredLength; i++) {
28182 node = nodes[hovered[i]];
28183
28184 var _drawLater3 = node.draw(ctx);
28185
28186 if (_drawLater3.drawExternalLabel != null) {
28187 _drawExternalLabels.push(_drawLater3.drawExternalLabel);
28188 }
28189 }
28190
28191 return {
28192 drawExternalLabels: function drawExternalLabels() {
28193 var _iterator = _createForOfIteratorHelper$5(_drawExternalLabels),
28194 _step;
28195
28196 try {
28197 for (_iterator.s(); !(_step = _iterator.n()).done;) {
28198 var draw = _step.value;
28199 draw();
28200 }
28201 } catch (err) {
28202 _iterator.e(err);
28203 } finally {
28204 _iterator.f();
28205 }
28206 }
28207 };
28208 }
28209 /**
28210 * Redraw all edges
28211 *
28212 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
28213 * @private
28214 */
28215
28216 }, {
28217 key: "_drawEdges",
28218 value: function _drawEdges(ctx) {
28219 var edges = this.body.edges;
28220 var edgeIndices = this.body.edgeIndices;
28221
28222 for (var i = 0; i < edgeIndices.length; i++) {
28223 var edge = edges[edgeIndices[i]];
28224
28225 if (edge.connected === true) {
28226 edge.draw(ctx);
28227 }
28228 }
28229 }
28230 /**
28231 * Redraw all arrows
28232 *
28233 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
28234 * @private
28235 */
28236
28237 }, {
28238 key: "_drawArrows",
28239 value: function _drawArrows(ctx) {
28240 var edges = this.body.edges;
28241 var edgeIndices = this.body.edgeIndices;
28242
28243 for (var i = 0; i < edgeIndices.length; i++) {
28244 var edge = edges[edgeIndices[i]];
28245
28246 if (edge.connected === true) {
28247 edge.drawArrows(ctx);
28248 }
28249 }
28250 }
28251 /**
28252 * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because
28253 * some implementations (safari and IE9) did not support requestAnimationFrame
28254 *
28255 * @private
28256 */
28257
28258 }, {
28259 key: "_determineBrowserMethod",
28260 value: function _determineBrowserMethod() {
28261 if (typeof window !== "undefined") {
28262 var browserType = navigator.userAgent.toLowerCase();
28263 this.requiresTimeout = false;
28264
28265 if (indexOf(browserType).call(browserType, "msie 9.0") != -1) {
28266 // IE 9
28267 this.requiresTimeout = true;
28268 } else if (indexOf(browserType).call(browserType, "safari") != -1) {
28269 // safari
28270 if (indexOf(browserType).call(browserType, "chrome") <= -1) {
28271 this.requiresTimeout = true;
28272 }
28273 }
28274 } else {
28275 this.requiresTimeout = true;
28276 }
28277 }
28278 /**
28279 * Redraw selection box
28280 *
28281 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
28282 * @private
28283 */
28284
28285 }, {
28286 key: "_drawSelectionBox",
28287 value: function _drawSelectionBox(ctx) {
28288 if (this.body.selectionBox.show) {
28289 ctx.beginPath();
28290 var width = this.body.selectionBox.position.end.x - this.body.selectionBox.position.start.x;
28291 var height = this.body.selectionBox.position.end.y - this.body.selectionBox.position.start.y;
28292 ctx.rect(this.body.selectionBox.position.start.x, this.body.selectionBox.position.start.y, width, height);
28293 ctx.fillStyle = "rgba(151, 194, 252, 0.2)";
28294 ctx.fillRect(this.body.selectionBox.position.start.x, this.body.selectionBox.position.start.y, width, height);
28295 ctx.strokeStyle = "rgba(151, 194, 252, 1)";
28296 ctx.stroke();
28297 } else {
28298 ctx.closePath();
28299 }
28300 }
28301 }]);
28302
28303 return CanvasRenderer;
28304 }();
28305
28306 var path$2 = path$x;
28307 var setInterval$1 = path$2.setInterval;
28308
28309 var setInterval = setInterval$1;
28310
28311 /**
28312 * Register a touch event, taking place before a gesture
28313 *
28314 * @param {Hammer} hammer A hammer instance
28315 * @param {Function} callback Callback, called as callback(event)
28316 */
28317 function onTouch(hammer, callback) {
28318 callback.inputHandler = function (event) {
28319 if (event.isFirst) {
28320 callback(event);
28321 }
28322 };
28323
28324 hammer.on("hammer.input", callback.inputHandler);
28325 }
28326 /**
28327 * Register a release event, taking place after a gesture
28328 *
28329 * @param {Hammer} hammer A hammer instance
28330 * @param {Function} callback Callback, called as callback(event)
28331 * @returns {*}
28332 */
28333
28334 function onRelease(hammer, callback) {
28335 callback.inputHandler = function (event) {
28336 if (event.isFinal) {
28337 callback(event);
28338 }
28339 };
28340
28341 return hammer.on("hammer.input", callback.inputHandler);
28342 }
28343
28344 /**
28345 * Create the main frame for the Network.
28346 * This function is executed once when a Network object is created. The frame
28347 * contains a canvas, and this canvas contains all objects like the axis and
28348 * nodes.
28349 */
28350
28351 var Canvas = /*#__PURE__*/function () {
28352 /**
28353 * @param {object} body
28354 */
28355 function Canvas(body) {
28356 _classCallCheck(this, Canvas);
28357
28358 this.body = body;
28359 this.pixelRatio = 1;
28360 this.cameraState = {};
28361 this.initialized = false;
28362 this.canvasViewCenter = {};
28363 this._cleanupCallbacks = [];
28364 this.options = {};
28365 this.defaultOptions = {
28366 autoResize: true,
28367 height: "100%",
28368 width: "100%"
28369 };
28370
28371 assign$2(this.options, this.defaultOptions);
28372
28373 this.bindEventListeners();
28374 }
28375 /**
28376 * Binds event listeners
28377 */
28378
28379
28380 _createClass(Canvas, [{
28381 key: "bindEventListeners",
28382 value: function bindEventListeners() {
28383 var _this = this,
28384 _context;
28385
28386 // bind the events
28387 this.body.emitter.once("resize", function (obj) {
28388 if (obj.width !== 0) {
28389 _this.body.view.translation.x = obj.width * 0.5;
28390 }
28391
28392 if (obj.height !== 0) {
28393 _this.body.view.translation.y = obj.height * 0.5;
28394 }
28395 });
28396 this.body.emitter.on("setSize", bind$5(_context = this.setSize).call(_context, this));
28397 this.body.emitter.on("destroy", function () {
28398 _this.hammerFrame.destroy();
28399
28400 _this.hammer.destroy();
28401
28402 _this._cleanUp();
28403 });
28404 }
28405 /**
28406 * @param {object} options
28407 */
28408
28409 }, {
28410 key: "setOptions",
28411 value: function setOptions(options) {
28412 var _this2 = this;
28413
28414 if (options !== undefined) {
28415 var fields = ["width", "height", "autoResize"];
28416 selectiveDeepExtend(fields, this.options, options);
28417 } // Automatically adapt to changing size of the container element.
28418
28419
28420 this._cleanUp();
28421
28422 if (this.options.autoResize === true) {
28423 var _context2;
28424
28425 if (window.ResizeObserver) {
28426 // decent browsers, immediate reactions
28427 var observer = new ResizeObserver(function () {
28428 var changed = _this2.setSize();
28429
28430 if (changed === true) {
28431 _this2.body.emitter.emit("_requestRedraw");
28432 }
28433 });
28434 var frame = this.frame;
28435 observer.observe(frame);
28436
28437 this._cleanupCallbacks.push(function () {
28438 observer.unobserve(frame);
28439 });
28440 } else {
28441 // IE11, continous polling
28442 var resizeTimer = setInterval(function () {
28443 var changed = _this2.setSize();
28444
28445 if (changed === true) {
28446 _this2.body.emitter.emit("_requestRedraw");
28447 }
28448 }, 1000);
28449
28450 this._cleanupCallbacks.push(function () {
28451 clearInterval(resizeTimer);
28452 });
28453 } // Automatically adapt to changing size of the browser.
28454
28455
28456 var resizeFunction = bind$5(_context2 = this._onResize).call(_context2, this);
28457
28458 addEventListener(window, "resize", resizeFunction);
28459
28460 this._cleanupCallbacks.push(function () {
28461 removeEventListener(window, "resize", resizeFunction);
28462 });
28463 }
28464 }
28465 /**
28466 * @private
28467 */
28468
28469 }, {
28470 key: "_cleanUp",
28471 value: function _cleanUp() {
28472 var _context3, _context4, _context5;
28473
28474 forEach$2(_context3 = reverse(_context4 = splice(_context5 = this._cleanupCallbacks).call(_context5, 0)).call(_context4)).call(_context3, function (callback) {
28475 try {
28476 callback();
28477 } catch (error) {
28478 console.error(error);
28479 }
28480 });
28481 }
28482 /**
28483 * @private
28484 */
28485
28486 }, {
28487 key: "_onResize",
28488 value: function _onResize() {
28489 this.setSize();
28490 this.body.emitter.emit("_redraw");
28491 }
28492 /**
28493 * Get and store the cameraState
28494 *
28495 * @param {number} [pixelRatio=this.pixelRatio]
28496 * @private
28497 */
28498
28499 }, {
28500 key: "_getCameraState",
28501 value: function _getCameraState() {
28502 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.pixelRatio;
28503
28504 if (this.initialized === true) {
28505 this.cameraState.previousWidth = this.frame.canvas.width / pixelRatio;
28506 this.cameraState.previousHeight = this.frame.canvas.height / pixelRatio;
28507 this.cameraState.scale = this.body.view.scale;
28508 this.cameraState.position = this.DOMtoCanvas({
28509 x: 0.5 * this.frame.canvas.width / pixelRatio,
28510 y: 0.5 * this.frame.canvas.height / pixelRatio
28511 });
28512 }
28513 }
28514 /**
28515 * Set the cameraState
28516 *
28517 * @private
28518 */
28519
28520 }, {
28521 key: "_setCameraState",
28522 value: function _setCameraState() {
28523 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) {
28524 var widthRatio = this.frame.canvas.width / this.pixelRatio / this.cameraState.previousWidth;
28525 var heightRatio = this.frame.canvas.height / this.pixelRatio / this.cameraState.previousHeight;
28526 var newScale = this.cameraState.scale;
28527
28528 if (widthRatio != 1 && heightRatio != 1) {
28529 newScale = this.cameraState.scale * 0.5 * (widthRatio + heightRatio);
28530 } else if (widthRatio != 1) {
28531 newScale = this.cameraState.scale * widthRatio;
28532 } else if (heightRatio != 1) {
28533 newScale = this.cameraState.scale * heightRatio;
28534 }
28535
28536 this.body.view.scale = newScale; // this comes from the view module.
28537
28538 var currentViewCenter = this.DOMtoCanvas({
28539 x: 0.5 * this.frame.canvas.clientWidth,
28540 y: 0.5 * this.frame.canvas.clientHeight
28541 });
28542 var distanceFromCenter = {
28543 // offset from view, distance view has to change by these x and y to center the node
28544 x: currentViewCenter.x - this.cameraState.position.x,
28545 y: currentViewCenter.y - this.cameraState.position.y
28546 };
28547 this.body.view.translation.x += distanceFromCenter.x * this.body.view.scale;
28548 this.body.view.translation.y += distanceFromCenter.y * this.body.view.scale;
28549 }
28550 }
28551 /**
28552 *
28553 * @param {number|string} value
28554 * @returns {string}
28555 * @private
28556 */
28557
28558 }, {
28559 key: "_prepareValue",
28560 value: function _prepareValue(value) {
28561 if (typeof value === "number") {
28562 return value + "px";
28563 } else if (typeof value === "string") {
28564 if (indexOf(value).call(value, "%") !== -1 || indexOf(value).call(value, "px") !== -1) {
28565 return value;
28566 } else if (indexOf(value).call(value, "%") === -1) {
28567 return value + "px";
28568 }
28569 }
28570
28571 throw new Error("Could not use the value supplied for width or height:" + value);
28572 }
28573 /**
28574 * Create the HTML
28575 */
28576
28577 }, {
28578 key: "_create",
28579 value: function _create() {
28580 // remove all elements from the container element.
28581 while (this.body.container.hasChildNodes()) {
28582 this.body.container.removeChild(this.body.container.firstChild);
28583 }
28584
28585 this.frame = document.createElement("div");
28586 this.frame.className = "vis-network";
28587 this.frame.style.position = "relative";
28588 this.frame.style.overflow = "hidden";
28589 this.frame.tabIndex = 0; // tab index is required for keycharm to bind keystrokes to the div instead of the window
28590 //////////////////////////////////////////////////////////////////
28591
28592 this.frame.canvas = document.createElement("canvas");
28593 this.frame.canvas.style.position = "relative";
28594 this.frame.appendChild(this.frame.canvas);
28595
28596 if (!this.frame.canvas.getContext) {
28597 var noCanvas = document.createElement("DIV");
28598 noCanvas.style.color = "red";
28599 noCanvas.style.fontWeight = "bold";
28600 noCanvas.style.padding = "10px";
28601 noCanvas.innerText = "Error: your browser does not support HTML canvas";
28602 this.frame.canvas.appendChild(noCanvas);
28603 } else {
28604 this._setPixelRatio();
28605
28606 this.setTransform();
28607 } // add the frame to the container element
28608
28609
28610 this.body.container.appendChild(this.frame);
28611 this.body.view.scale = 1;
28612 this.body.view.translation = {
28613 x: 0.5 * this.frame.canvas.clientWidth,
28614 y: 0.5 * this.frame.canvas.clientHeight
28615 };
28616
28617 this._bindHammer();
28618 }
28619 /**
28620 * This function binds hammer, it can be repeated over and over due to the uniqueness check.
28621 *
28622 * @private
28623 */
28624
28625 }, {
28626 key: "_bindHammer",
28627 value: function _bindHammer() {
28628 var _this3 = this;
28629
28630 if (this.hammer !== undefined) {
28631 this.hammer.destroy();
28632 }
28633
28634 this.drag = {};
28635 this.pinch = {}; // init hammer
28636
28637 this.hammer = new Hammer$1(this.frame.canvas);
28638 this.hammer.get("pinch").set({
28639 enable: true
28640 }); // enable to get better response, todo: test on mobile.
28641
28642 this.hammer.get("pan").set({
28643 threshold: 5,
28644 direction: Hammer$1.DIRECTION_ALL
28645 });
28646 onTouch(this.hammer, function (event) {
28647 _this3.body.eventListeners.onTouch(event);
28648 });
28649 this.hammer.on("tap", function (event) {
28650 _this3.body.eventListeners.onTap(event);
28651 });
28652 this.hammer.on("doubletap", function (event) {
28653 _this3.body.eventListeners.onDoubleTap(event);
28654 });
28655 this.hammer.on("press", function (event) {
28656 _this3.body.eventListeners.onHold(event);
28657 });
28658 this.hammer.on("panstart", function (event) {
28659 _this3.body.eventListeners.onDragStart(event);
28660 });
28661 this.hammer.on("panmove", function (event) {
28662 _this3.body.eventListeners.onDrag(event);
28663 });
28664 this.hammer.on("panend", function (event) {
28665 _this3.body.eventListeners.onDragEnd(event);
28666 });
28667 this.hammer.on("pinch", function (event) {
28668 _this3.body.eventListeners.onPinch(event);
28669 }); // TODO: neatly cleanup these handlers when re-creating the Canvas, IF these are done with hammer, event.stopPropagation will not work?
28670
28671 this.frame.canvas.addEventListener("wheel", function (event) {
28672 _this3.body.eventListeners.onMouseWheel(event);
28673 });
28674 this.frame.canvas.addEventListener("mousemove", function (event) {
28675 _this3.body.eventListeners.onMouseMove(event);
28676 });
28677 this.frame.canvas.addEventListener("contextmenu", function (event) {
28678 _this3.body.eventListeners.onContext(event);
28679 });
28680 this.hammerFrame = new Hammer$1(this.frame);
28681 onRelease(this.hammerFrame, function (event) {
28682 _this3.body.eventListeners.onRelease(event);
28683 });
28684 }
28685 /**
28686 * Set a new size for the network
28687 *
28688 * @param {string} width Width in pixels or percentage (for example '800px'
28689 * or '50%')
28690 * @param {string} height Height in pixels or percentage (for example '400px'
28691 * or '30%')
28692 * @returns {boolean}
28693 */
28694
28695 }, {
28696 key: "setSize",
28697 value: function setSize() {
28698 var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.width;
28699 var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.height;
28700 width = this._prepareValue(width);
28701 height = this._prepareValue(height);
28702 var emitEvent = false;
28703 var oldWidth = this.frame.canvas.width;
28704 var oldHeight = this.frame.canvas.height; // update the pixel ratio
28705 //
28706 // NOTE: Comment in following is rather inconsistent; this is the ONLY place in the code
28707 // where it is assumed that the pixel ratio could change at runtime.
28708 // The only way I can think of this happening is a rotating screen or tablet; but then
28709 // there should be a mechanism for reloading the data (TODO: check if this is present).
28710 //
28711 // If the assumption is true (i.e. pixel ratio can change at runtime), then *all* usage
28712 // of pixel ratio must be overhauled for this.
28713 //
28714 // For the time being, I will humor the assumption here, and in the rest of the code assume it is
28715 // constant.
28716
28717 var previousRatio = this.pixelRatio; // we cache this because the camera state storage needs the old value
28718
28719 this._setPixelRatio();
28720
28721 if (width != this.options.width || height != this.options.height || this.frame.style.width != width || this.frame.style.height != height) {
28722 this._getCameraState(previousRatio);
28723
28724 this.frame.style.width = width;
28725 this.frame.style.height = height;
28726 this.frame.canvas.style.width = "100%";
28727 this.frame.canvas.style.height = "100%";
28728 this.frame.canvas.width = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
28729 this.frame.canvas.height = Math.round(this.frame.canvas.clientHeight * this.pixelRatio);
28730 this.options.width = width;
28731 this.options.height = height;
28732 this.canvasViewCenter = {
28733 x: 0.5 * this.frame.clientWidth,
28734 y: 0.5 * this.frame.clientHeight
28735 };
28736 emitEvent = true;
28737 } else {
28738 // this would adapt the width of the canvas to the width from 100% if and only if
28739 // there is a change.
28740 var newWidth = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
28741 var newHeight = Math.round(this.frame.canvas.clientHeight * this.pixelRatio); // store the camera if there is a change in size.
28742
28743 if (this.frame.canvas.width !== newWidth || this.frame.canvas.height !== newHeight) {
28744 this._getCameraState(previousRatio);
28745 }
28746
28747 if (this.frame.canvas.width !== newWidth) {
28748 this.frame.canvas.width = newWidth;
28749 emitEvent = true;
28750 }
28751
28752 if (this.frame.canvas.height !== newHeight) {
28753 this.frame.canvas.height = newHeight;
28754 emitEvent = true;
28755 }
28756 }
28757
28758 if (emitEvent === true) {
28759 this.body.emitter.emit("resize", {
28760 width: Math.round(this.frame.canvas.width / this.pixelRatio),
28761 height: Math.round(this.frame.canvas.height / this.pixelRatio),
28762 oldWidth: Math.round(oldWidth / this.pixelRatio),
28763 oldHeight: Math.round(oldHeight / this.pixelRatio)
28764 }); // restore the camera on change.
28765
28766 this._setCameraState();
28767 } // set initialized so the get and set camera will work from now on.
28768
28769
28770 this.initialized = true;
28771 return emitEvent;
28772 }
28773 /**
28774 *
28775 * @returns {CanvasRenderingContext2D}
28776 */
28777
28778 }, {
28779 key: "getContext",
28780 value: function getContext() {
28781 return this.frame.canvas.getContext("2d");
28782 }
28783 /**
28784 * Determine the pixel ratio for various browsers.
28785 *
28786 * @returns {number}
28787 * @private
28788 */
28789
28790 }, {
28791 key: "_determinePixelRatio",
28792 value: function _determinePixelRatio() {
28793 var ctx = this.getContext();
28794
28795 if (ctx === undefined) {
28796 throw new Error("Could not get canvax context");
28797 }
28798
28799 var numerator = 1;
28800
28801 if (typeof window !== "undefined") {
28802 // (window !== undefined) doesn't work here!
28803 // Protection during unit tests, where 'window' can be missing
28804 numerator = window.devicePixelRatio || 1;
28805 }
28806
28807 var denominator = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
28808 return numerator / denominator;
28809 }
28810 /**
28811 * Lazy determination of pixel ratio.
28812 *
28813 * @private
28814 */
28815
28816 }, {
28817 key: "_setPixelRatio",
28818 value: function _setPixelRatio() {
28819 this.pixelRatio = this._determinePixelRatio();
28820 }
28821 /**
28822 * Set the transform in the contained context, based on its pixelRatio
28823 */
28824
28825 }, {
28826 key: "setTransform",
28827 value: function setTransform() {
28828 var ctx = this.getContext();
28829
28830 if (ctx === undefined) {
28831 throw new Error("Could not get canvax context");
28832 }
28833
28834 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
28835 }
28836 /**
28837 * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
28838 * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
28839 *
28840 * @param {number} x
28841 * @returns {number}
28842 * @private
28843 */
28844
28845 }, {
28846 key: "_XconvertDOMtoCanvas",
28847 value: function _XconvertDOMtoCanvas(x) {
28848 return (x - this.body.view.translation.x) / this.body.view.scale;
28849 }
28850 /**
28851 * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
28852 * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
28853 *
28854 * @param {number} x
28855 * @returns {number}
28856 * @private
28857 */
28858
28859 }, {
28860 key: "_XconvertCanvasToDOM",
28861 value: function _XconvertCanvasToDOM(x) {
28862 return x * this.body.view.scale + this.body.view.translation.x;
28863 }
28864 /**
28865 * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
28866 * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
28867 *
28868 * @param {number} y
28869 * @returns {number}
28870 * @private
28871 */
28872
28873 }, {
28874 key: "_YconvertDOMtoCanvas",
28875 value: function _YconvertDOMtoCanvas(y) {
28876 return (y - this.body.view.translation.y) / this.body.view.scale;
28877 }
28878 /**
28879 * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
28880 * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
28881 *
28882 * @param {number} y
28883 * @returns {number}
28884 * @private
28885 */
28886
28887 }, {
28888 key: "_YconvertCanvasToDOM",
28889 value: function _YconvertCanvasToDOM(y) {
28890 return y * this.body.view.scale + this.body.view.translation.y;
28891 }
28892 /**
28893 * @param {point} pos
28894 * @returns {point}
28895 */
28896
28897 }, {
28898 key: "canvasToDOM",
28899 value: function canvasToDOM(pos) {
28900 return {
28901 x: this._XconvertCanvasToDOM(pos.x),
28902 y: this._YconvertCanvasToDOM(pos.y)
28903 };
28904 }
28905 /**
28906 *
28907 * @param {point} pos
28908 * @returns {point}
28909 */
28910
28911 }, {
28912 key: "DOMtoCanvas",
28913 value: function DOMtoCanvas(pos) {
28914 return {
28915 x: this._XconvertDOMtoCanvas(pos.x),
28916 y: this._YconvertDOMtoCanvas(pos.y)
28917 };
28918 }
28919 }]);
28920
28921 return Canvas;
28922 }();
28923
28924 /**
28925 * Validate the fit options, replace missing optional values by defaults etc.
28926 *
28927 * @param rawOptions - The raw options.
28928 * @param allNodeIds - All node ids that will be used if nodes are omitted in
28929 * the raw options.
28930 *
28931 * @returns Options with everything filled in and validated.
28932 */
28933 function normalizeFitOptions(rawOptions, allNodeIds) {
28934 var options = assign$2({
28935 nodes: allNodeIds,
28936 minZoomLevel: Number.MIN_VALUE,
28937 maxZoomLevel: 1
28938 }, rawOptions !== null && rawOptions !== void 0 ? rawOptions : {});
28939
28940 if (!isArray$1(options.nodes)) {
28941 throw new TypeError("Nodes has to be an array of ids.");
28942 }
28943
28944 if (options.nodes.length === 0) {
28945 options.nodes = allNodeIds;
28946 }
28947
28948 if (!(typeof options.minZoomLevel === "number" && options.minZoomLevel > 0)) {
28949 throw new TypeError("Min zoom level has to be a number higher than zero.");
28950 }
28951
28952 if (!(typeof options.maxZoomLevel === "number" && options.minZoomLevel <= options.maxZoomLevel)) {
28953 throw new TypeError("Max zoom level has to be a number higher than min zoom level.");
28954 }
28955
28956 return options;
28957 }
28958
28959 /**
28960 * The view
28961 */
28962
28963 var View = /*#__PURE__*/function () {
28964 /**
28965 * @param {object} body
28966 * @param {Canvas} canvas
28967 */
28968 function View(body, canvas) {
28969 var _context,
28970 _this = this,
28971 _context2;
28972
28973 _classCallCheck(this, View);
28974
28975 this.body = body;
28976 this.canvas = canvas;
28977 this.animationSpeed = 1 / this.renderRefreshRate;
28978 this.animationEasingFunction = "easeInOutQuint";
28979 this.easingTime = 0;
28980 this.sourceScale = 0;
28981 this.targetScale = 0;
28982 this.sourceTranslation = 0;
28983 this.targetTranslation = 0;
28984 this.lockedOnNodeId = undefined;
28985 this.lockedOnNodeOffset = undefined;
28986 this.touchTime = 0;
28987 this.viewFunction = undefined;
28988 this.body.emitter.on("fit", bind$5(_context = this.fit).call(_context, this));
28989 this.body.emitter.on("animationFinished", function () {
28990 _this.body.emitter.emit("_stopRendering");
28991 });
28992 this.body.emitter.on("unlockNode", bind$5(_context2 = this.releaseNode).call(_context2, this));
28993 }
28994 /**
28995 *
28996 * @param {object} [options={}]
28997 */
28998
28999
29000 _createClass(View, [{
29001 key: "setOptions",
29002 value: function setOptions() {
29003 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
29004 this.options = options;
29005 }
29006 /**
29007 * This function zooms out to fit all data on screen based on amount of nodes
29008 *
29009 * @param {object} [options={{nodes=Array}}]
29010 * @param options
29011 * @param {boolean} [initialZoom=false] | zoom based on fitted formula or range, true = fitted, default = false;
29012 */
29013
29014 }, {
29015 key: "fit",
29016 value: function fit(options) {
29017 var initialZoom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
29018 options = normalizeFitOptions(options, this.body.nodeIndices);
29019 var canvasWidth = this.canvas.frame.canvas.clientWidth;
29020 var canvasHeight = this.canvas.frame.canvas.clientHeight;
29021 var range;
29022 var zoomLevel;
29023
29024 if (canvasWidth === 0 || canvasHeight === 0) {
29025 // There's no point in trying to fit into zero sized canvas. This could
29026 // potentially even result in invalid values being computed. For example
29027 // for network without nodes and zero sized canvas the zoom level would
29028 // end up being computed as 0/0 which results in NaN. In any other case
29029 // this would be 0/something which is again pointless to compute.
29030 zoomLevel = 1;
29031 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
29032 } else if (initialZoom === true) {
29033 // check if more than half of the nodes have a predefined position. If so, we use the range, not the approximation.
29034 var positionDefined = 0;
29035
29036 for (var nodeId in this.body.nodes) {
29037 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
29038 var node = this.body.nodes[nodeId];
29039
29040 if (node.predefinedPosition === true) {
29041 positionDefined += 1;
29042 }
29043 }
29044 }
29045
29046 if (positionDefined > 0.5 * this.body.nodeIndices.length) {
29047 this.fit(options, false);
29048 return;
29049 }
29050
29051 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
29052 var numberOfNodes = this.body.nodeIndices.length;
29053 zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
29054 // correct for larger canvasses.
29055
29056 var factor = Math.min(canvasWidth / 600, canvasHeight / 600);
29057 zoomLevel *= factor;
29058 } else {
29059 this.body.emitter.emit("_resizeNodes");
29060 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
29061 var xDistance = Math.abs(range.maxX - range.minX) * 1.1;
29062 var yDistance = Math.abs(range.maxY - range.minY) * 1.1;
29063 var xZoomLevel = canvasWidth / xDistance;
29064 var yZoomLevel = canvasHeight / yDistance;
29065 zoomLevel = xZoomLevel <= yZoomLevel ? xZoomLevel : yZoomLevel;
29066 }
29067
29068 if (zoomLevel > options.maxZoomLevel) {
29069 zoomLevel = options.maxZoomLevel;
29070 } else if (zoomLevel < options.minZoomLevel) {
29071 zoomLevel = options.minZoomLevel;
29072 }
29073
29074 var center = NetworkUtil.findCenter(range);
29075 var animationOptions = {
29076 position: center,
29077 scale: zoomLevel,
29078 animation: options.animation
29079 };
29080 this.moveTo(animationOptions);
29081 } // animation
29082
29083 /**
29084 * Center a node in view.
29085 *
29086 * @param {number} nodeId
29087 * @param {number} [options]
29088 */
29089
29090 }, {
29091 key: "focus",
29092 value: function focus(nodeId) {
29093 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
29094
29095 if (this.body.nodes[nodeId] !== undefined) {
29096 var nodePosition = {
29097 x: this.body.nodes[nodeId].x,
29098 y: this.body.nodes[nodeId].y
29099 };
29100 options.position = nodePosition;
29101 options.lockedOnNode = nodeId;
29102 this.moveTo(options);
29103 } else {
29104 console.error("Node: " + nodeId + " cannot be found.");
29105 }
29106 }
29107 /**
29108 *
29109 * @param {object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
29110 * | options.scale = number // scale to move to
29111 * | options.position = {x:number, y:number} // position to move to
29112 * | options.animation = {duration:number, easingFunction:String} || Boolean // position to move to
29113 */
29114
29115 }, {
29116 key: "moveTo",
29117 value: function moveTo(options) {
29118 if (options === undefined) {
29119 options = {};
29120 return;
29121 }
29122
29123 if (options.offset != null) {
29124 if (options.offset.x != null) {
29125 // Coerce and verify that x is valid.
29126 options.offset.x = +options.offset.x;
29127
29128 if (!_isFinite(options.offset.x)) {
29129 throw new TypeError('The option "offset.x" has to be a finite number.');
29130 }
29131 } else {
29132 options.offset.x = 0;
29133 }
29134
29135 if (options.offset.y != null) {
29136 // Coerce and verify that y is valid.
29137 options.offset.y = +options.offset.y;
29138
29139 if (!_isFinite(options.offset.y)) {
29140 throw new TypeError('The option "offset.y" has to be a finite number.');
29141 }
29142 } else {
29143 options.offset.x = 0;
29144 }
29145 } else {
29146 options.offset = {
29147 x: 0,
29148 y: 0
29149 };
29150 }
29151
29152 if (options.position != null) {
29153 if (options.position.x != null) {
29154 // Coerce and verify that x is valid.
29155 options.position.x = +options.position.x;
29156
29157 if (!_isFinite(options.position.x)) {
29158 throw new TypeError('The option "position.x" has to be a finite number.');
29159 }
29160 } else {
29161 options.position.x = 0;
29162 }
29163
29164 if (options.position.y != null) {
29165 // Coerce and verify that y is valid.
29166 options.position.y = +options.position.y;
29167
29168 if (!_isFinite(options.position.y)) {
29169 throw new TypeError('The option "position.y" has to be a finite number.');
29170 }
29171 } else {
29172 options.position.x = 0;
29173 }
29174 } else {
29175 options.position = this.getViewPosition();
29176 }
29177
29178 if (options.scale != null) {
29179 // Coerce and verify that the scale is valid.
29180 options.scale = +options.scale;
29181
29182 if (!(options.scale > 0)) {
29183 throw new TypeError('The option "scale" has to be a number greater than zero.');
29184 }
29185 } else {
29186 options.scale = this.body.view.scale;
29187 }
29188
29189 if (options.animation === undefined) {
29190 options.animation = {
29191 duration: 0
29192 };
29193 }
29194
29195 if (options.animation === false) {
29196 options.animation = {
29197 duration: 0
29198 };
29199 }
29200
29201 if (options.animation === true) {
29202 options.animation = {};
29203 }
29204
29205 if (options.animation.duration === undefined) {
29206 options.animation.duration = 1000;
29207 } // default duration
29208
29209
29210 if (options.animation.easingFunction === undefined) {
29211 options.animation.easingFunction = "easeInOutQuad";
29212 } // default easing function
29213
29214
29215 this.animateView(options);
29216 }
29217 /**
29218 *
29219 * @param {object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
29220 * | options.time = number // animation time in milliseconds
29221 * | options.scale = number // scale to animate to
29222 * | options.position = {x:number, y:number} // position to animate to
29223 * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad,
29224 * // easeInCubic, easeOutCubic, easeInOutCubic,
29225 * // easeInQuart, easeOutQuart, easeInOutQuart,
29226 * // easeInQuint, easeOutQuint, easeInOutQuint
29227 */
29228
29229 }, {
29230 key: "animateView",
29231 value: function animateView(options) {
29232 if (options === undefined) {
29233 return;
29234 }
29235
29236 this.animationEasingFunction = options.animation.easingFunction; // release if something focussed on the node
29237
29238 this.releaseNode();
29239
29240 if (options.locked === true) {
29241 this.lockedOnNodeId = options.lockedOnNode;
29242 this.lockedOnNodeOffset = options.offset;
29243 } // forcefully complete the old animation if it was still running
29244
29245
29246 if (this.easingTime != 0) {
29247 this._transitionRedraw(true); // by setting easingtime to 1, we finish the animation.
29248
29249 }
29250
29251 this.sourceScale = this.body.view.scale;
29252 this.sourceTranslation = this.body.view.translation;
29253 this.targetScale = options.scale; // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw
29254 // but at least then we'll have the target transition
29255
29256 this.body.view.scale = this.targetScale;
29257 var viewCenter = this.canvas.DOMtoCanvas({
29258 x: 0.5 * this.canvas.frame.canvas.clientWidth,
29259 y: 0.5 * this.canvas.frame.canvas.clientHeight
29260 });
29261 var distanceFromCenter = {
29262 // offset from view, distance view has to change by these x and y to center the node
29263 x: viewCenter.x - options.position.x,
29264 y: viewCenter.y - options.position.y
29265 };
29266 this.targetTranslation = {
29267 x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x,
29268 y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y
29269 }; // if the time is set to 0, don't do an animation
29270
29271 if (options.animation.duration === 0) {
29272 if (this.lockedOnNodeId != undefined) {
29273 var _context3;
29274
29275 this.viewFunction = bind$5(_context3 = this._lockedRedraw).call(_context3, this);
29276 this.body.emitter.on("initRedraw", this.viewFunction);
29277 } else {
29278 this.body.view.scale = this.targetScale;
29279 this.body.view.translation = this.targetTranslation;
29280 this.body.emitter.emit("_requestRedraw");
29281 }
29282 } else {
29283 var _context4;
29284
29285 this.animationSpeed = 1 / (60 * options.animation.duration * 0.001) || 1 / 60; // 60 for 60 seconds, 0.001 for milli's
29286
29287 this.animationEasingFunction = options.animation.easingFunction;
29288 this.viewFunction = bind$5(_context4 = this._transitionRedraw).call(_context4, this);
29289 this.body.emitter.on("initRedraw", this.viewFunction);
29290 this.body.emitter.emit("_startRendering");
29291 }
29292 }
29293 /**
29294 * used to animate smoothly by hijacking the redraw function.
29295 *
29296 * @private
29297 */
29298
29299 }, {
29300 key: "_lockedRedraw",
29301 value: function _lockedRedraw() {
29302 var nodePosition = {
29303 x: this.body.nodes[this.lockedOnNodeId].x,
29304 y: this.body.nodes[this.lockedOnNodeId].y
29305 };
29306 var viewCenter = this.canvas.DOMtoCanvas({
29307 x: 0.5 * this.canvas.frame.canvas.clientWidth,
29308 y: 0.5 * this.canvas.frame.canvas.clientHeight
29309 });
29310 var distanceFromCenter = {
29311 // offset from view, distance view has to change by these x and y to center the node
29312 x: viewCenter.x - nodePosition.x,
29313 y: viewCenter.y - nodePosition.y
29314 };
29315 var sourceTranslation = this.body.view.translation;
29316 var targetTranslation = {
29317 x: sourceTranslation.x + distanceFromCenter.x * this.body.view.scale + this.lockedOnNodeOffset.x,
29318 y: sourceTranslation.y + distanceFromCenter.y * this.body.view.scale + this.lockedOnNodeOffset.y
29319 };
29320 this.body.view.translation = targetTranslation;
29321 }
29322 /**
29323 * Resets state of a locked on Node
29324 */
29325
29326 }, {
29327 key: "releaseNode",
29328 value: function releaseNode() {
29329 if (this.lockedOnNodeId !== undefined && this.viewFunction !== undefined) {
29330 this.body.emitter.off("initRedraw", this.viewFunction);
29331 this.lockedOnNodeId = undefined;
29332 this.lockedOnNodeOffset = undefined;
29333 }
29334 }
29335 /**
29336 * @param {boolean} [finished=false]
29337 * @private
29338 */
29339
29340 }, {
29341 key: "_transitionRedraw",
29342 value: function _transitionRedraw() {
29343 var finished = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
29344 this.easingTime += this.animationSpeed;
29345 this.easingTime = finished === true ? 1.0 : this.easingTime;
29346 var progress = easingFunctions[this.animationEasingFunction](this.easingTime);
29347 this.body.view.scale = this.sourceScale + (this.targetScale - this.sourceScale) * progress;
29348 this.body.view.translation = {
29349 x: this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress,
29350 y: this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress
29351 }; // cleanup
29352
29353 if (this.easingTime >= 1.0) {
29354 this.body.emitter.off("initRedraw", this.viewFunction);
29355 this.easingTime = 0;
29356
29357 if (this.lockedOnNodeId != undefined) {
29358 var _context5;
29359
29360 this.viewFunction = bind$5(_context5 = this._lockedRedraw).call(_context5, this);
29361 this.body.emitter.on("initRedraw", this.viewFunction);
29362 }
29363
29364 this.body.emitter.emit("animationFinished");
29365 }
29366 }
29367 /**
29368 *
29369 * @returns {number}
29370 */
29371
29372 }, {
29373 key: "getScale",
29374 value: function getScale() {
29375 return this.body.view.scale;
29376 }
29377 /**
29378 *
29379 * @returns {{x: number, y: number}}
29380 */
29381
29382 }, {
29383 key: "getViewPosition",
29384 value: function getViewPosition() {
29385 return this.canvas.DOMtoCanvas({
29386 x: 0.5 * this.canvas.frame.canvas.clientWidth,
29387 y: 0.5 * this.canvas.frame.canvas.clientHeight
29388 });
29389 }
29390 }]);
29391
29392 return View;
29393 }();
29394
29395 /**
29396 * Created by Alex on 11/6/2014.
29397 */
29398 function keycharm(options) {
29399 var preventDefault = options && options.preventDefault || false;
29400 var container = options && options.container || window;
29401 var _exportFunctions = {};
29402 var _bound = {
29403 keydown: {},
29404 keyup: {}
29405 };
29406 var _keys = {};
29407 var i; // a - z
29408
29409 for (i = 97; i <= 122; i++) {
29410 _keys[String.fromCharCode(i)] = {
29411 code: 65 + (i - 97),
29412 shift: false
29413 };
29414 } // A - Z
29415
29416
29417 for (i = 65; i <= 90; i++) {
29418 _keys[String.fromCharCode(i)] = {
29419 code: i,
29420 shift: true
29421 };
29422 } // 0 - 9
29423
29424
29425 for (i = 0; i <= 9; i++) {
29426 _keys['' + i] = {
29427 code: 48 + i,
29428 shift: false
29429 };
29430 } // F1 - F12
29431
29432
29433 for (i = 1; i <= 12; i++) {
29434 _keys['F' + i] = {
29435 code: 111 + i,
29436 shift: false
29437 };
29438 } // num0 - num9
29439
29440
29441 for (i = 0; i <= 9; i++) {
29442 _keys['num' + i] = {
29443 code: 96 + i,
29444 shift: false
29445 };
29446 } // numpad misc
29447
29448
29449 _keys['num*'] = {
29450 code: 106,
29451 shift: false
29452 };
29453 _keys['num+'] = {
29454 code: 107,
29455 shift: false
29456 };
29457 _keys['num-'] = {
29458 code: 109,
29459 shift: false
29460 };
29461 _keys['num/'] = {
29462 code: 111,
29463 shift: false
29464 };
29465 _keys['num.'] = {
29466 code: 110,
29467 shift: false
29468 }; // arrows
29469
29470 _keys['left'] = {
29471 code: 37,
29472 shift: false
29473 };
29474 _keys['up'] = {
29475 code: 38,
29476 shift: false
29477 };
29478 _keys['right'] = {
29479 code: 39,
29480 shift: false
29481 };
29482 _keys['down'] = {
29483 code: 40,
29484 shift: false
29485 }; // extra keys
29486
29487 _keys['space'] = {
29488 code: 32,
29489 shift: false
29490 };
29491 _keys['enter'] = {
29492 code: 13,
29493 shift: false
29494 };
29495 _keys['shift'] = {
29496 code: 16,
29497 shift: undefined
29498 };
29499 _keys['esc'] = {
29500 code: 27,
29501 shift: false
29502 };
29503 _keys['backspace'] = {
29504 code: 8,
29505 shift: false
29506 };
29507 _keys['tab'] = {
29508 code: 9,
29509 shift: false
29510 };
29511 _keys['ctrl'] = {
29512 code: 17,
29513 shift: false
29514 };
29515 _keys['alt'] = {
29516 code: 18,
29517 shift: false
29518 };
29519 _keys['delete'] = {
29520 code: 46,
29521 shift: false
29522 };
29523 _keys['pageup'] = {
29524 code: 33,
29525 shift: false
29526 };
29527 _keys['pagedown'] = {
29528 code: 34,
29529 shift: false
29530 }; // symbols
29531
29532 _keys['='] = {
29533 code: 187,
29534 shift: false
29535 };
29536 _keys['-'] = {
29537 code: 189,
29538 shift: false
29539 };
29540 _keys[']'] = {
29541 code: 221,
29542 shift: false
29543 };
29544 _keys['['] = {
29545 code: 219,
29546 shift: false
29547 };
29548
29549 var down = function (event) {
29550 handleEvent(event, 'keydown');
29551 };
29552
29553 var up = function (event) {
29554 handleEvent(event, 'keyup');
29555 }; // handle the actualy bound key with the event
29556
29557
29558 var handleEvent = function (event, type) {
29559 if (_bound[type][event.keyCode] !== undefined) {
29560 var bound = _bound[type][event.keyCode];
29561
29562 for (var i = 0; i < bound.length; i++) {
29563 if (bound[i].shift === undefined) {
29564 bound[i].fn(event);
29565 } else if (bound[i].shift == true && event.shiftKey == true) {
29566 bound[i].fn(event);
29567 } else if (bound[i].shift == false && event.shiftKey == false) {
29568 bound[i].fn(event);
29569 }
29570 }
29571
29572 if (preventDefault == true) {
29573 event.preventDefault();
29574 }
29575 }
29576 }; // bind a key to a callback
29577
29578
29579 _exportFunctions.bind = function (key, callback, type) {
29580 if (type === undefined) {
29581 type = 'keydown';
29582 }
29583
29584 if (_keys[key] === undefined) {
29585 throw new Error("unsupported key: " + key);
29586 }
29587
29588 if (_bound[type][_keys[key].code] === undefined) {
29589 _bound[type][_keys[key].code] = [];
29590 }
29591
29592 _bound[type][_keys[key].code].push({
29593 fn: callback,
29594 shift: _keys[key].shift
29595 });
29596 }; // bind all keys to a call back (demo purposes)
29597
29598
29599 _exportFunctions.bindAll = function (callback, type) {
29600 if (type === undefined) {
29601 type = 'keydown';
29602 }
29603
29604 for (var key in _keys) {
29605 if (_keys.hasOwnProperty(key)) {
29606 _exportFunctions.bind(key, callback, type);
29607 }
29608 }
29609 }; // get the key label from an event
29610
29611
29612 _exportFunctions.getKey = function (event) {
29613 for (var key in _keys) {
29614 if (_keys.hasOwnProperty(key)) {
29615 if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) {
29616 return key;
29617 } else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) {
29618 return key;
29619 } else if (event.keyCode == _keys[key].code && key == 'shift') {
29620 return key;
29621 }
29622 }
29623 }
29624
29625 return "unknown key, currently not supported";
29626 }; // unbind either a specific callback from a key or all of them (by leaving callback undefined)
29627
29628
29629 _exportFunctions.unbind = function (key, callback, type) {
29630 if (type === undefined) {
29631 type = 'keydown';
29632 }
29633
29634 if (_keys[key] === undefined) {
29635 throw new Error("unsupported key: " + key);
29636 }
29637
29638 if (callback !== undefined) {
29639 var newBindings = [];
29640 var bound = _bound[type][_keys[key].code];
29641
29642 if (bound !== undefined) {
29643 for (var i = 0; i < bound.length; i++) {
29644 if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) {
29645 newBindings.push(_bound[type][_keys[key].code][i]);
29646 }
29647 }
29648 }
29649
29650 _bound[type][_keys[key].code] = newBindings;
29651 } else {
29652 _bound[type][_keys[key].code] = [];
29653 }
29654 }; // reset all bound variables.
29655
29656
29657 _exportFunctions.reset = function () {
29658 _bound = {
29659 keydown: {},
29660 keyup: {}
29661 };
29662 }; // unbind all listeners and reset all variables.
29663
29664
29665 _exportFunctions.destroy = function () {
29666 _bound = {
29667 keydown: {},
29668 keyup: {}
29669 };
29670 container.removeEventListener('keydown', down, true);
29671 container.removeEventListener('keyup', up, true);
29672 }; // create listeners.
29673
29674
29675 container.addEventListener('keydown', down, true);
29676 container.addEventListener('keyup', up, true); // return the public functions.
29677
29678 return _exportFunctions;
29679 }
29680
29681 /**
29682 * Navigation Handler
29683 */
29684
29685 var NavigationHandler = /*#__PURE__*/function () {
29686 /**
29687 * @param {object} body
29688 * @param {Canvas} canvas
29689 */
29690 function NavigationHandler(body, canvas) {
29691 var _this = this;
29692
29693 _classCallCheck(this, NavigationHandler);
29694
29695 this.body = body;
29696 this.canvas = canvas;
29697 this.iconsCreated = false;
29698 this.navigationHammers = [];
29699 this.boundFunctions = {};
29700 this.touchTime = 0;
29701 this.activated = false;
29702 this.body.emitter.on("activate", function () {
29703 _this.activated = true;
29704
29705 _this.configureKeyboardBindings();
29706 });
29707 this.body.emitter.on("deactivate", function () {
29708 _this.activated = false;
29709
29710 _this.configureKeyboardBindings();
29711 });
29712 this.body.emitter.on("destroy", function () {
29713 if (_this.keycharm !== undefined) {
29714 _this.keycharm.destroy();
29715 }
29716 });
29717 this.options = {};
29718 }
29719 /**
29720 *
29721 * @param {object} options
29722 */
29723
29724
29725 _createClass(NavigationHandler, [{
29726 key: "setOptions",
29727 value: function setOptions(options) {
29728 if (options !== undefined) {
29729 this.options = options;
29730 this.create();
29731 }
29732 }
29733 /**
29734 * Creates or refreshes navigation and sets key bindings
29735 */
29736
29737 }, {
29738 key: "create",
29739 value: function create() {
29740 if (this.options.navigationButtons === true) {
29741 if (this.iconsCreated === false) {
29742 this.loadNavigationElements();
29743 }
29744 } else if (this.iconsCreated === true) {
29745 this.cleanNavigation();
29746 }
29747
29748 this.configureKeyboardBindings();
29749 }
29750 /**
29751 * Cleans up previous navigation items
29752 */
29753
29754 }, {
29755 key: "cleanNavigation",
29756 value: function cleanNavigation() {
29757 // clean hammer bindings
29758 if (this.navigationHammers.length != 0) {
29759 for (var i = 0; i < this.navigationHammers.length; i++) {
29760 this.navigationHammers[i].destroy();
29761 }
29762
29763 this.navigationHammers = [];
29764 } // clean up previous navigation items
29765
29766
29767 if (this.navigationDOM && this.navigationDOM["wrapper"] && this.navigationDOM["wrapper"].parentNode) {
29768 this.navigationDOM["wrapper"].parentNode.removeChild(this.navigationDOM["wrapper"]);
29769 }
29770
29771 this.iconsCreated = false;
29772 }
29773 /**
29774 * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation
29775 * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent
29776 * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false.
29777 * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas.
29778 *
29779 * @private
29780 */
29781
29782 }, {
29783 key: "loadNavigationElements",
29784 value: function loadNavigationElements() {
29785 var _this2 = this;
29786
29787 this.cleanNavigation();
29788 this.navigationDOM = {};
29789 var navigationDivs = ["up", "down", "left", "right", "zoomIn", "zoomOut", "zoomExtends"];
29790 var navigationDivActions = ["_moveUp", "_moveDown", "_moveLeft", "_moveRight", "_zoomIn", "_zoomOut", "_fit"];
29791 this.navigationDOM["wrapper"] = document.createElement("div");
29792 this.navigationDOM["wrapper"].className = "vis-navigation";
29793 this.canvas.frame.appendChild(this.navigationDOM["wrapper"]);
29794
29795 for (var i = 0; i < navigationDivs.length; i++) {
29796 this.navigationDOM[navigationDivs[i]] = document.createElement("div");
29797 this.navigationDOM[navigationDivs[i]].className = "vis-button vis-" + navigationDivs[i];
29798 this.navigationDOM["wrapper"].appendChild(this.navigationDOM[navigationDivs[i]]);
29799 var hammer = new Hammer$1(this.navigationDOM[navigationDivs[i]]);
29800
29801 if (navigationDivActions[i] === "_fit") {
29802 var _context;
29803
29804 onTouch(hammer, bind$5(_context = this._fit).call(_context, this));
29805 } else {
29806 var _context2;
29807
29808 onTouch(hammer, bind$5(_context2 = this.bindToRedraw).call(_context2, this, navigationDivActions[i]));
29809 }
29810
29811 this.navigationHammers.push(hammer);
29812 } // use a hammer for the release so we do not require the one used in the rest of the network
29813 // the one the rest uses can be overloaded by the manipulation system.
29814
29815
29816 var hammerFrame = new Hammer$1(this.canvas.frame);
29817 onRelease(hammerFrame, function () {
29818 _this2._stopMovement();
29819 });
29820 this.navigationHammers.push(hammerFrame);
29821 this.iconsCreated = true;
29822 }
29823 /**
29824 *
29825 * @param {string} action
29826 */
29827
29828 }, {
29829 key: "bindToRedraw",
29830 value: function bindToRedraw(action) {
29831 if (this.boundFunctions[action] === undefined) {
29832 var _context3;
29833
29834 this.boundFunctions[action] = bind$5(_context3 = this[action]).call(_context3, this);
29835 this.body.emitter.on("initRedraw", this.boundFunctions[action]);
29836 this.body.emitter.emit("_startRendering");
29837 }
29838 }
29839 /**
29840 *
29841 * @param {string} action
29842 */
29843
29844 }, {
29845 key: "unbindFromRedraw",
29846 value: function unbindFromRedraw(action) {
29847 if (this.boundFunctions[action] !== undefined) {
29848 this.body.emitter.off("initRedraw", this.boundFunctions[action]);
29849 this.body.emitter.emit("_stopRendering");
29850 delete this.boundFunctions[action];
29851 }
29852 }
29853 /**
29854 * this stops all movement induced by the navigation buttons
29855 *
29856 * @private
29857 */
29858
29859 }, {
29860 key: "_fit",
29861 value: function _fit() {
29862 if (new Date().valueOf() - this.touchTime > 700) {
29863 // TODO: fix ugly hack to avoid hammer's double fireing of event (because we use release?)
29864 this.body.emitter.emit("fit", {
29865 duration: 700
29866 });
29867 this.touchTime = new Date().valueOf();
29868 }
29869 }
29870 /**
29871 * this stops all movement induced by the navigation buttons
29872 *
29873 * @private
29874 */
29875
29876 }, {
29877 key: "_stopMovement",
29878 value: function _stopMovement() {
29879 for (var boundAction in this.boundFunctions) {
29880 if (Object.prototype.hasOwnProperty.call(this.boundFunctions, boundAction)) {
29881 this.body.emitter.off("initRedraw", this.boundFunctions[boundAction]);
29882 this.body.emitter.emit("_stopRendering");
29883 }
29884 }
29885
29886 this.boundFunctions = {};
29887 }
29888 /**
29889 *
29890 * @private
29891 */
29892
29893 }, {
29894 key: "_moveUp",
29895 value: function _moveUp() {
29896 this.body.view.translation.y += this.options.keyboard.speed.y;
29897 }
29898 /**
29899 *
29900 * @private
29901 */
29902
29903 }, {
29904 key: "_moveDown",
29905 value: function _moveDown() {
29906 this.body.view.translation.y -= this.options.keyboard.speed.y;
29907 }
29908 /**
29909 *
29910 * @private
29911 */
29912
29913 }, {
29914 key: "_moveLeft",
29915 value: function _moveLeft() {
29916 this.body.view.translation.x += this.options.keyboard.speed.x;
29917 }
29918 /**
29919 *
29920 * @private
29921 */
29922
29923 }, {
29924 key: "_moveRight",
29925 value: function _moveRight() {
29926 this.body.view.translation.x -= this.options.keyboard.speed.x;
29927 }
29928 /**
29929 *
29930 * @private
29931 */
29932
29933 }, {
29934 key: "_zoomIn",
29935 value: function _zoomIn() {
29936 var scaleOld = this.body.view.scale;
29937 var scale = this.body.view.scale * (1 + this.options.keyboard.speed.zoom);
29938 var translation = this.body.view.translation;
29939 var scaleFrac = scale / scaleOld;
29940 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
29941 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
29942 this.body.view.scale = scale;
29943 this.body.view.translation = {
29944 x: tx,
29945 y: ty
29946 };
29947 this.body.emitter.emit("zoom", {
29948 direction: "+",
29949 scale: this.body.view.scale,
29950 pointer: null
29951 });
29952 }
29953 /**
29954 *
29955 * @private
29956 */
29957
29958 }, {
29959 key: "_zoomOut",
29960 value: function _zoomOut() {
29961 var scaleOld = this.body.view.scale;
29962 var scale = this.body.view.scale / (1 + this.options.keyboard.speed.zoom);
29963 var translation = this.body.view.translation;
29964 var scaleFrac = scale / scaleOld;
29965 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
29966 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
29967 this.body.view.scale = scale;
29968 this.body.view.translation = {
29969 x: tx,
29970 y: ty
29971 };
29972 this.body.emitter.emit("zoom", {
29973 direction: "-",
29974 scale: this.body.view.scale,
29975 pointer: null
29976 });
29977 }
29978 /**
29979 * bind all keys using keycharm.
29980 */
29981
29982 }, {
29983 key: "configureKeyboardBindings",
29984 value: function configureKeyboardBindings() {
29985 var _this3 = this;
29986
29987 if (this.keycharm !== undefined) {
29988 this.keycharm.destroy();
29989 }
29990
29991 if (this.options.keyboard.enabled === true) {
29992 if (this.options.keyboard.bindToWindow === true) {
29993 this.keycharm = keycharm({
29994 container: window,
29995 preventDefault: true
29996 });
29997 } else {
29998 this.keycharm = keycharm({
29999 container: this.canvas.frame,
30000 preventDefault: true
30001 });
30002 }
30003
30004 this.keycharm.reset();
30005
30006 if (this.activated === true) {
30007 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;
30008
30009 bind$5(_context4 = this.keycharm).call(_context4, "up", function () {
30010 _this3.bindToRedraw("_moveUp");
30011 }, "keydown");
30012
30013 bind$5(_context5 = this.keycharm).call(_context5, "down", function () {
30014 _this3.bindToRedraw("_moveDown");
30015 }, "keydown");
30016
30017 bind$5(_context6 = this.keycharm).call(_context6, "left", function () {
30018 _this3.bindToRedraw("_moveLeft");
30019 }, "keydown");
30020
30021 bind$5(_context7 = this.keycharm).call(_context7, "right", function () {
30022 _this3.bindToRedraw("_moveRight");
30023 }, "keydown");
30024
30025 bind$5(_context8 = this.keycharm).call(_context8, "=", function () {
30026 _this3.bindToRedraw("_zoomIn");
30027 }, "keydown");
30028
30029 bind$5(_context9 = this.keycharm).call(_context9, "num+", function () {
30030 _this3.bindToRedraw("_zoomIn");
30031 }, "keydown");
30032
30033 bind$5(_context10 = this.keycharm).call(_context10, "num-", function () {
30034 _this3.bindToRedraw("_zoomOut");
30035 }, "keydown");
30036
30037 bind$5(_context11 = this.keycharm).call(_context11, "-", function () {
30038 _this3.bindToRedraw("_zoomOut");
30039 }, "keydown");
30040
30041 bind$5(_context12 = this.keycharm).call(_context12, "[", function () {
30042 _this3.bindToRedraw("_zoomOut");
30043 }, "keydown");
30044
30045 bind$5(_context13 = this.keycharm).call(_context13, "]", function () {
30046 _this3.bindToRedraw("_zoomIn");
30047 }, "keydown");
30048
30049 bind$5(_context14 = this.keycharm).call(_context14, "pageup", function () {
30050 _this3.bindToRedraw("_zoomIn");
30051 }, "keydown");
30052
30053 bind$5(_context15 = this.keycharm).call(_context15, "pagedown", function () {
30054 _this3.bindToRedraw("_zoomOut");
30055 }, "keydown");
30056
30057 bind$5(_context16 = this.keycharm).call(_context16, "up", function () {
30058 _this3.unbindFromRedraw("_moveUp");
30059 }, "keyup");
30060
30061 bind$5(_context17 = this.keycharm).call(_context17, "down", function () {
30062 _this3.unbindFromRedraw("_moveDown");
30063 }, "keyup");
30064
30065 bind$5(_context18 = this.keycharm).call(_context18, "left", function () {
30066 _this3.unbindFromRedraw("_moveLeft");
30067 }, "keyup");
30068
30069 bind$5(_context19 = this.keycharm).call(_context19, "right", function () {
30070 _this3.unbindFromRedraw("_moveRight");
30071 }, "keyup");
30072
30073 bind$5(_context20 = this.keycharm).call(_context20, "=", function () {
30074 _this3.unbindFromRedraw("_zoomIn");
30075 }, "keyup");
30076
30077 bind$5(_context21 = this.keycharm).call(_context21, "num+", function () {
30078 _this3.unbindFromRedraw("_zoomIn");
30079 }, "keyup");
30080
30081 bind$5(_context22 = this.keycharm).call(_context22, "num-", function () {
30082 _this3.unbindFromRedraw("_zoomOut");
30083 }, "keyup");
30084
30085 bind$5(_context23 = this.keycharm).call(_context23, "-", function () {
30086 _this3.unbindFromRedraw("_zoomOut");
30087 }, "keyup");
30088
30089 bind$5(_context24 = this.keycharm).call(_context24, "[", function () {
30090 _this3.unbindFromRedraw("_zoomOut");
30091 }, "keyup");
30092
30093 bind$5(_context25 = this.keycharm).call(_context25, "]", function () {
30094 _this3.unbindFromRedraw("_zoomIn");
30095 }, "keyup");
30096
30097 bind$5(_context26 = this.keycharm).call(_context26, "pageup", function () {
30098 _this3.unbindFromRedraw("_zoomIn");
30099 }, "keyup");
30100
30101 bind$5(_context27 = this.keycharm).call(_context27, "pagedown", function () {
30102 _this3.unbindFromRedraw("_zoomOut");
30103 }, "keyup");
30104 }
30105 }
30106 }
30107 }]);
30108
30109 return NavigationHandler;
30110 }();
30111
30112 function _createForOfIteratorHelper$4(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$1(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; } } }; }
30113
30114 function _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$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$4(o, minLen); }
30115
30116 function _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; }
30117 /**
30118 * Handler for interactions
30119 */
30120
30121 var InteractionHandler = /*#__PURE__*/function () {
30122 /**
30123 * @param {object} body
30124 * @param {Canvas} canvas
30125 * @param {SelectionHandler} selectionHandler
30126 */
30127 function InteractionHandler(body, canvas, selectionHandler) {
30128 var _context, _context2, _context3, _context4, _context5, _context6, _context7, _context8, _context9, _context10, _context11, _context12, _context13;
30129
30130 _classCallCheck(this, InteractionHandler);
30131
30132 this.body = body;
30133 this.canvas = canvas;
30134 this.selectionHandler = selectionHandler;
30135 this.navigationHandler = new NavigationHandler(body, canvas); // bind the events from hammer to functions in this object
30136
30137 this.body.eventListeners.onTap = bind$5(_context = this.onTap).call(_context, this);
30138 this.body.eventListeners.onTouch = bind$5(_context2 = this.onTouch).call(_context2, this);
30139 this.body.eventListeners.onDoubleTap = bind$5(_context3 = this.onDoubleTap).call(_context3, this);
30140 this.body.eventListeners.onHold = bind$5(_context4 = this.onHold).call(_context4, this);
30141 this.body.eventListeners.onDragStart = bind$5(_context5 = this.onDragStart).call(_context5, this);
30142 this.body.eventListeners.onDrag = bind$5(_context6 = this.onDrag).call(_context6, this);
30143 this.body.eventListeners.onDragEnd = bind$5(_context7 = this.onDragEnd).call(_context7, this);
30144 this.body.eventListeners.onMouseWheel = bind$5(_context8 = this.onMouseWheel).call(_context8, this);
30145 this.body.eventListeners.onPinch = bind$5(_context9 = this.onPinch).call(_context9, this);
30146 this.body.eventListeners.onMouseMove = bind$5(_context10 = this.onMouseMove).call(_context10, this);
30147 this.body.eventListeners.onRelease = bind$5(_context11 = this.onRelease).call(_context11, this);
30148 this.body.eventListeners.onContext = bind$5(_context12 = this.onContext).call(_context12, this);
30149 this.touchTime = 0;
30150 this.drag = {};
30151 this.pinch = {};
30152 this.popup = undefined;
30153 this.popupObj = undefined;
30154 this.popupTimer = undefined;
30155 this.body.functions.getPointer = bind$5(_context13 = this.getPointer).call(_context13, this);
30156 this.options = {};
30157 this.defaultOptions = {
30158 dragNodes: true,
30159 dragView: true,
30160 hover: false,
30161 keyboard: {
30162 enabled: false,
30163 speed: {
30164 x: 10,
30165 y: 10,
30166 zoom: 0.02
30167 },
30168 bindToWindow: true,
30169 autoFocus: true
30170 },
30171 navigationButtons: false,
30172 tooltipDelay: 300,
30173 zoomView: true,
30174 zoomSpeed: 1
30175 };
30176
30177 assign$2(this.options, this.defaultOptions);
30178
30179 this.bindEventListeners();
30180 }
30181 /**
30182 * Binds event listeners
30183 */
30184
30185
30186 _createClass(InteractionHandler, [{
30187 key: "bindEventListeners",
30188 value: function bindEventListeners() {
30189 var _this = this;
30190
30191 this.body.emitter.on("destroy", function () {
30192 clearTimeout(_this.popupTimer);
30193 delete _this.body.functions.getPointer;
30194 });
30195 }
30196 /**
30197 *
30198 * @param {object} options
30199 */
30200
30201 }, {
30202 key: "setOptions",
30203 value: function setOptions(options) {
30204 if (options !== undefined) {
30205 // extend all but the values in fields
30206 var fields = ["hideEdgesOnDrag", "hideEdgesOnZoom", "hideNodesOnDrag", "keyboard", "multiselect", "selectable", "selectConnectedEdges"];
30207 selectiveNotDeepExtend(fields, this.options, options); // merge the keyboard options in.
30208
30209 mergeOptions(this.options, options, "keyboard");
30210
30211 if (options.tooltip) {
30212 assign$2(this.options.tooltip, options.tooltip);
30213
30214 if (options.tooltip.color) {
30215 this.options.tooltip.color = parseColor(options.tooltip.color);
30216 }
30217 }
30218 }
30219
30220 this.navigationHandler.setOptions(this.options);
30221 }
30222 /**
30223 * Get the pointer location from a touch location
30224 *
30225 * @param {{x: number, y: number}} touch
30226 * @returns {{x: number, y: number}} pointer
30227 * @private
30228 */
30229
30230 }, {
30231 key: "getPointer",
30232 value: function getPointer(touch) {
30233 return {
30234 x: touch.x - getAbsoluteLeft(this.canvas.frame.canvas),
30235 y: touch.y - getAbsoluteTop(this.canvas.frame.canvas)
30236 };
30237 }
30238 /**
30239 * On start of a touch gesture, store the pointer
30240 *
30241 * @param {Event} event The event
30242 * @private
30243 */
30244
30245 }, {
30246 key: "onTouch",
30247 value: function onTouch(event) {
30248 if (new Date().valueOf() - this.touchTime > 50) {
30249 this.drag.pointer = this.getPointer(event.center);
30250 this.drag.pinched = false;
30251 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)
30252
30253 this.touchTime = new Date().valueOf();
30254 }
30255 }
30256 /**
30257 * handle tap/click event: select/unselect a node
30258 *
30259 * @param {Event} event
30260 * @private
30261 */
30262
30263 }, {
30264 key: "onTap",
30265 value: function onTap(event) {
30266 var pointer = this.getPointer(event.center);
30267 var multiselect = this.selectionHandler.options.multiselect && (event.changedPointers[0].ctrlKey || event.changedPointers[0].metaKey);
30268 this.checkSelectionChanges(pointer, multiselect);
30269 this.selectionHandler.commitAndEmit(pointer, event);
30270 this.selectionHandler.generateClickEvent("click", event, pointer);
30271 }
30272 /**
30273 * handle doubletap event
30274 *
30275 * @param {Event} event
30276 * @private
30277 */
30278
30279 }, {
30280 key: "onDoubleTap",
30281 value: function onDoubleTap(event) {
30282 var pointer = this.getPointer(event.center);
30283 this.selectionHandler.generateClickEvent("doubleClick", event, pointer);
30284 }
30285 /**
30286 * handle long tap event: multi select nodes
30287 *
30288 * @param {Event} event
30289 * @private
30290 */
30291
30292 }, {
30293 key: "onHold",
30294 value: function onHold(event) {
30295 var pointer = this.getPointer(event.center);
30296 var multiselect = this.selectionHandler.options.multiselect;
30297 this.checkSelectionChanges(pointer, multiselect);
30298 this.selectionHandler.commitAndEmit(pointer, event);
30299 this.selectionHandler.generateClickEvent("click", event, pointer);
30300 this.selectionHandler.generateClickEvent("hold", event, pointer);
30301 }
30302 /**
30303 * handle the release of the screen
30304 *
30305 * @param {Event} event
30306 * @private
30307 */
30308
30309 }, {
30310 key: "onRelease",
30311 value: function onRelease(event) {
30312 if (new Date().valueOf() - this.touchTime > 10) {
30313 var pointer = this.getPointer(event.center);
30314 this.selectionHandler.generateClickEvent("release", event, pointer); // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
30315
30316 this.touchTime = new Date().valueOf();
30317 }
30318 }
30319 /**
30320 *
30321 * @param {Event} event
30322 */
30323
30324 }, {
30325 key: "onContext",
30326 value: function onContext(event) {
30327 var pointer = this.getPointer({
30328 x: event.clientX,
30329 y: event.clientY
30330 });
30331 this.selectionHandler.generateClickEvent("oncontext", event, pointer);
30332 }
30333 /**
30334 * Select and deselect nodes depending current selection change.
30335 *
30336 * @param {{x: number, y: number}} pointer
30337 * @param {boolean} [add=false]
30338 */
30339
30340 }, {
30341 key: "checkSelectionChanges",
30342 value: function checkSelectionChanges(pointer) {
30343 var add = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
30344
30345 if (add === true) {
30346 this.selectionHandler.selectAdditionalOnPoint(pointer);
30347 } else {
30348 this.selectionHandler.selectOnPoint(pointer);
30349 }
30350 }
30351 /**
30352 * Remove all node and edge id's from the first set that are present in the second one.
30353 *
30354 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} firstSet
30355 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} secondSet
30356 * @returns {{nodes: Array.<Node>, edges: Array.<vis.Edge>}}
30357 * @private
30358 */
30359
30360 }, {
30361 key: "_determineDifference",
30362 value: function _determineDifference(firstSet, secondSet) {
30363 var arrayDiff = function arrayDiff(firstArr, secondArr) {
30364 var result = [];
30365
30366 for (var i = 0; i < firstArr.length; i++) {
30367 var value = firstArr[i];
30368
30369 if (indexOf(secondArr).call(secondArr, value) === -1) {
30370 result.push(value);
30371 }
30372 }
30373
30374 return result;
30375 };
30376
30377 return {
30378 nodes: arrayDiff(firstSet.nodes, secondSet.nodes),
30379 edges: arrayDiff(firstSet.edges, secondSet.edges)
30380 };
30381 }
30382 /**
30383 * This function is called by onDragStart.
30384 * It is separated out because we can then overload it for the datamanipulation system.
30385 *
30386 * @param {Event} event
30387 * @private
30388 */
30389
30390 }, {
30391 key: "onDragStart",
30392 value: function onDragStart(event) {
30393 // if already dragging, do not start
30394 // this can happen on touch screens with multiple fingers
30395 if (this.drag.dragging) {
30396 return;
30397 } //in case the touch event was triggered on an external div, do the initial touch now.
30398
30399
30400 if (this.drag.pointer === undefined) {
30401 this.onTouch(event);
30402 } // note: drag.pointer is set in onTouch to get the initial touch location
30403
30404
30405 var node = this.selectionHandler.getNodeAt(this.drag.pointer);
30406 this.drag.dragging = true;
30407 this.drag.selection = [];
30408 this.drag.translation = assign$2({}, this.body.view.translation); // copy the object
30409
30410 this.drag.nodeId = undefined;
30411
30412 if (event.srcEvent.shiftKey) {
30413 this.body.selectionBox.show = true;
30414 var pointer = this.getPointer(event.center);
30415 this.body.selectionBox.position.start = {
30416 x: this.canvas._XconvertDOMtoCanvas(pointer.x),
30417 y: this.canvas._YconvertDOMtoCanvas(pointer.y)
30418 };
30419 this.body.selectionBox.position.end = {
30420 x: this.canvas._XconvertDOMtoCanvas(pointer.x),
30421 y: this.canvas._YconvertDOMtoCanvas(pointer.y)
30422 };
30423 }
30424
30425 if (node !== undefined && this.options.dragNodes === true) {
30426 this.drag.nodeId = node.id; // select the clicked node if not yet selected
30427
30428 if (node.isSelected() === false) {
30429 this.selectionHandler.unselectAll();
30430 this.selectionHandler.selectObject(node);
30431 } // after select to contain the node
30432
30433
30434 this.selectionHandler.generateClickEvent("dragStart", event, this.drag.pointer); // create an array with the selected nodes and their original location and status
30435
30436 var _iterator = _createForOfIteratorHelper$4(this.selectionHandler.getSelectedNodes()),
30437 _step;
30438
30439 try {
30440 for (_iterator.s(); !(_step = _iterator.n()).done;) {
30441 var _node = _step.value;
30442 var s = {
30443 id: _node.id,
30444 node: _node,
30445 // store original x, y, xFixed and yFixed, make the node temporarily Fixed
30446 x: _node.x,
30447 y: _node.y,
30448 xFixed: _node.options.fixed.x,
30449 yFixed: _node.options.fixed.y
30450 };
30451 _node.options.fixed.x = true;
30452 _node.options.fixed.y = true;
30453 this.drag.selection.push(s);
30454 }
30455 } catch (err) {
30456 _iterator.e(err);
30457 } finally {
30458 _iterator.f();
30459 }
30460 } else {
30461 // fallback if no node is selected and thus the view is dragged.
30462 this.selectionHandler.generateClickEvent("dragStart", event, this.drag.pointer, undefined, true);
30463 }
30464 }
30465 /**
30466 * handle drag event
30467 *
30468 * @param {Event} event
30469 * @private
30470 */
30471
30472 }, {
30473 key: "onDrag",
30474 value: function onDrag(event) {
30475 var _this2 = this;
30476
30477 if (this.drag.pinched === true) {
30478 return;
30479 } // remove the focus on node if it is focussed on by the focusOnNode
30480
30481
30482 this.body.emitter.emit("unlockNode");
30483 var pointer = this.getPointer(event.center);
30484 var selection = this.drag.selection;
30485
30486 if (selection && selection.length && this.options.dragNodes === true) {
30487 this.selectionHandler.generateClickEvent("dragging", event, pointer); // calculate delta's and new location
30488
30489 var deltaX = pointer.x - this.drag.pointer.x;
30490 var deltaY = pointer.y - this.drag.pointer.y; // update position of all selected nodes
30491
30492 forEach$2(selection).call(selection, function (selection) {
30493 var node = selection.node; // only move the node if it was not fixed initially
30494
30495 if (selection.xFixed === false) {
30496 node.x = _this2.canvas._XconvertDOMtoCanvas(_this2.canvas._XconvertCanvasToDOM(selection.x) + deltaX);
30497 } // only move the node if it was not fixed initially
30498
30499
30500 if (selection.yFixed === false) {
30501 node.y = _this2.canvas._YconvertDOMtoCanvas(_this2.canvas._YconvertCanvasToDOM(selection.y) + deltaY);
30502 }
30503 }); // start the simulation of the physics
30504
30505
30506 this.body.emitter.emit("startSimulation");
30507 } else {
30508 // create selection box
30509 if (event.srcEvent.shiftKey) {
30510 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.
30511
30512 if (this.drag.pointer === undefined) {
30513 this.onDragStart(event);
30514 return;
30515 }
30516
30517 this.body.selectionBox.position.end = {
30518 x: this.canvas._XconvertDOMtoCanvas(pointer.x),
30519 y: this.canvas._YconvertDOMtoCanvas(pointer.y)
30520 };
30521 this.body.emitter.emit("_requestRedraw");
30522 } // move the network
30523
30524
30525 if (this.options.dragView === true && !event.srcEvent.shiftKey) {
30526 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.
30527
30528 if (this.drag.pointer === undefined) {
30529 this.onDragStart(event);
30530 return;
30531 }
30532
30533 var diffX = pointer.x - this.drag.pointer.x;
30534 var diffY = pointer.y - this.drag.pointer.y;
30535 this.body.view.translation = {
30536 x: this.drag.translation.x + diffX,
30537 y: this.drag.translation.y + diffY
30538 };
30539 this.body.emitter.emit("_requestRedraw");
30540 }
30541 }
30542 }
30543 /**
30544 * handle drag start event
30545 *
30546 * @param {Event} event
30547 * @private
30548 */
30549
30550 }, {
30551 key: "onDragEnd",
30552 value: function onDragEnd(event) {
30553 var _this3 = this;
30554
30555 this.drag.dragging = false;
30556
30557 if (this.body.selectionBox.show) {
30558 var _context14;
30559
30560 this.body.selectionBox.show = false;
30561 var selectionBoxPosition = this.body.selectionBox.position;
30562 var selectionBoxPositionMinMax = {
30563 minX: Math.min(selectionBoxPosition.start.x, selectionBoxPosition.end.x),
30564 minY: Math.min(selectionBoxPosition.start.y, selectionBoxPosition.end.y),
30565 maxX: Math.max(selectionBoxPosition.start.x, selectionBoxPosition.end.x),
30566 maxY: Math.max(selectionBoxPosition.start.y, selectionBoxPosition.end.y)
30567 };
30568
30569 var toBeSelectedNodes = filter(_context14 = this.body.nodeIndices).call(_context14, function (nodeId) {
30570 var node = _this3.body.nodes[nodeId];
30571 return node.x >= selectionBoxPositionMinMax.minX && node.x <= selectionBoxPositionMinMax.maxX && node.y >= selectionBoxPositionMinMax.minY && node.y <= selectionBoxPositionMinMax.maxY;
30572 });
30573
30574 forEach$2(toBeSelectedNodes).call(toBeSelectedNodes, function (nodeId) {
30575 return _this3.selectionHandler.selectObject(_this3.body.nodes[nodeId]);
30576 });
30577
30578 var pointer = this.getPointer(event.center);
30579 this.selectionHandler.commitAndEmit(pointer, event);
30580 this.selectionHandler.generateClickEvent("dragEnd", event, this.getPointer(event.center), undefined, true);
30581 this.body.emitter.emit("_requestRedraw");
30582 } else {
30583 var selection = this.drag.selection;
30584
30585 if (selection && selection.length) {
30586 forEach$2(selection).call(selection, function (s) {
30587 // restore original xFixed and yFixed
30588 s.node.options.fixed.x = s.xFixed;
30589 s.node.options.fixed.y = s.yFixed;
30590 });
30591
30592 this.selectionHandler.generateClickEvent("dragEnd", event, this.getPointer(event.center));
30593 this.body.emitter.emit("startSimulation");
30594 } else {
30595 this.selectionHandler.generateClickEvent("dragEnd", event, this.getPointer(event.center), undefined, true);
30596 this.body.emitter.emit("_requestRedraw");
30597 }
30598 }
30599 }
30600 /**
30601 * Handle pinch event
30602 *
30603 * @param {Event} event The event
30604 * @private
30605 */
30606
30607 }, {
30608 key: "onPinch",
30609 value: function onPinch(event) {
30610 var pointer = this.getPointer(event.center);
30611 this.drag.pinched = true;
30612
30613 if (this.pinch["scale"] === undefined) {
30614 this.pinch.scale = 1;
30615 } // TODO: enabled moving while pinching?
30616
30617
30618 var scale = this.pinch.scale * event.scale;
30619 this.zoom(scale, pointer);
30620 }
30621 /**
30622 * Zoom the network in or out
30623 *
30624 * @param {number} scale a number around 1, and between 0.01 and 10
30625 * @param {{x: number, y: number}} pointer Position on screen
30626 * @private
30627 */
30628
30629 }, {
30630 key: "zoom",
30631 value: function zoom(scale, pointer) {
30632 if (this.options.zoomView === true) {
30633 var scaleOld = this.body.view.scale;
30634
30635 if (scale < 0.00001) {
30636 scale = 0.00001;
30637 }
30638
30639 if (scale > 10) {
30640 scale = 10;
30641 }
30642
30643 var preScaleDragPointer = undefined;
30644
30645 if (this.drag !== undefined) {
30646 if (this.drag.dragging === true) {
30647 preScaleDragPointer = this.canvas.DOMtoCanvas(this.drag.pointer);
30648 }
30649 } // + this.canvas.frame.canvas.clientHeight / 2
30650
30651
30652 var translation = this.body.view.translation;
30653 var scaleFrac = scale / scaleOld;
30654 var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
30655 var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
30656 this.body.view.scale = scale;
30657 this.body.view.translation = {
30658 x: tx,
30659 y: ty
30660 };
30661
30662 if (preScaleDragPointer != undefined) {
30663 var postScaleDragPointer = this.canvas.canvasToDOM(preScaleDragPointer);
30664 this.drag.pointer.x = postScaleDragPointer.x;
30665 this.drag.pointer.y = postScaleDragPointer.y;
30666 }
30667
30668 this.body.emitter.emit("_requestRedraw");
30669
30670 if (scaleOld < scale) {
30671 this.body.emitter.emit("zoom", {
30672 direction: "+",
30673 scale: this.body.view.scale,
30674 pointer: pointer
30675 });
30676 } else {
30677 this.body.emitter.emit("zoom", {
30678 direction: "-",
30679 scale: this.body.view.scale,
30680 pointer: pointer
30681 });
30682 }
30683 }
30684 }
30685 /**
30686 * Event handler for mouse wheel event, used to zoom the timeline
30687 * See http://adomas.org/javascript-mouse-wheel/
30688 * https://github.com/EightMedia/hammer.js/issues/256
30689 *
30690 * @param {MouseEvent} event
30691 * @private
30692 */
30693
30694 }, {
30695 key: "onMouseWheel",
30696 value: function onMouseWheel(event) {
30697 if (this.options.zoomView === true) {
30698 // If delta is nonzero, handle it.
30699 // Basically, delta is now positive if wheel was scrolled up,
30700 // and negative, if wheel was scrolled down.
30701 if (event.deltaY !== 0) {
30702 // calculate the new scale
30703 var scale = this.body.view.scale;
30704 scale *= 1 + (event.deltaY < 0 ? 1 : -1) * (this.options.zoomSpeed * 0.1); // calculate the pointer location
30705
30706 var pointer = this.getPointer({
30707 x: event.clientX,
30708 y: event.clientY
30709 }); // apply the new scale
30710
30711 this.zoom(scale, pointer);
30712 } // Prevent default actions caused by mouse wheel.
30713
30714
30715 event.preventDefault();
30716 }
30717 }
30718 /**
30719 * Mouse move handler for checking whether the title moves over a node with a title.
30720 *
30721 * @param {Event} event
30722 * @private
30723 */
30724
30725 }, {
30726 key: "onMouseMove",
30727 value: function onMouseMove(event) {
30728 var _this4 = this;
30729
30730 var pointer = this.getPointer({
30731 x: event.clientX,
30732 y: event.clientY
30733 });
30734 var popupVisible = false; // check if the previously selected node is still selected
30735
30736 if (this.popup !== undefined) {
30737 if (this.popup.hidden === false) {
30738 this._checkHidePopup(pointer);
30739 } // if the popup was not hidden above
30740
30741
30742 if (this.popup.hidden === false) {
30743 popupVisible = true;
30744 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
30745 this.popup.show();
30746 }
30747 } // if we bind the keyboard to the div, we have to highlight it to use it. This highlights it on mouse over.
30748
30749
30750 if (this.options.keyboard.autoFocus && this.options.keyboard.bindToWindow === false && this.options.keyboard.enabled === true) {
30751 this.canvas.frame.focus();
30752 } // start a timeout that will check if the mouse is positioned above an element
30753
30754
30755 if (popupVisible === false) {
30756 if (this.popupTimer !== undefined) {
30757 clearInterval(this.popupTimer); // stop any running calculationTimer
30758
30759 this.popupTimer = undefined;
30760 }
30761
30762 if (!this.drag.dragging) {
30763 this.popupTimer = setTimeout$1(function () {
30764 return _this4._checkShowPopup(pointer);
30765 }, this.options.tooltipDelay);
30766 }
30767 } // adding hover highlights
30768
30769
30770 if (this.options.hover === true) {
30771 this.selectionHandler.hoverObject(event, pointer);
30772 }
30773 }
30774 /**
30775 * Check if there is an element on the given position in the network
30776 * (a node or edge). If so, and if this element has a title,
30777 * show a popup window with its title.
30778 *
30779 * @param {{x:number, y:number}} pointer
30780 * @private
30781 */
30782
30783 }, {
30784 key: "_checkShowPopup",
30785 value: function _checkShowPopup(pointer) {
30786 var x = this.canvas._XconvertDOMtoCanvas(pointer.x);
30787
30788 var y = this.canvas._YconvertDOMtoCanvas(pointer.y);
30789
30790 var pointerObj = {
30791 left: x,
30792 top: y,
30793 right: x,
30794 bottom: y
30795 };
30796 var previousPopupObjId = this.popupObj === undefined ? undefined : this.popupObj.id;
30797 var nodeUnderCursor = false;
30798 var popupType = "node"; // check if a node is under the cursor.
30799
30800 if (this.popupObj === undefined) {
30801 // search the nodes for overlap, select the top one in case of multiple nodes
30802 var nodeIndices = this.body.nodeIndices;
30803 var nodes = this.body.nodes;
30804 var node;
30805 var overlappingNodes = [];
30806
30807 for (var i = 0; i < nodeIndices.length; i++) {
30808 node = nodes[nodeIndices[i]];
30809
30810 if (node.isOverlappingWith(pointerObj) === true) {
30811 nodeUnderCursor = true;
30812
30813 if (node.getTitle() !== undefined) {
30814 overlappingNodes.push(nodeIndices[i]);
30815 }
30816 }
30817 }
30818
30819 if (overlappingNodes.length > 0) {
30820 // if there are overlapping nodes, select the last one, this is the one which is drawn on top of the others
30821 this.popupObj = nodes[overlappingNodes[overlappingNodes.length - 1]]; // if you hover over a node, the title of the edge is not supposed to be shown.
30822
30823 nodeUnderCursor = true;
30824 }
30825 }
30826
30827 if (this.popupObj === undefined && nodeUnderCursor === false) {
30828 // search the edges for overlap
30829 var edgeIndices = this.body.edgeIndices;
30830 var edges = this.body.edges;
30831 var edge;
30832 var overlappingEdges = [];
30833
30834 for (var _i = 0; _i < edgeIndices.length; _i++) {
30835 edge = edges[edgeIndices[_i]];
30836
30837 if (edge.isOverlappingWith(pointerObj) === true) {
30838 if (edge.connected === true && edge.getTitle() !== undefined) {
30839 overlappingEdges.push(edgeIndices[_i]);
30840 }
30841 }
30842 }
30843
30844 if (overlappingEdges.length > 0) {
30845 this.popupObj = edges[overlappingEdges[overlappingEdges.length - 1]];
30846 popupType = "edge";
30847 }
30848 }
30849
30850 if (this.popupObj !== undefined) {
30851 // show popup message window
30852 if (this.popupObj.id !== previousPopupObjId) {
30853 if (this.popup === undefined) {
30854 this.popup = new Popup$1(this.canvas.frame);
30855 }
30856
30857 this.popup.popupTargetType = popupType;
30858 this.popup.popupTargetId = this.popupObj.id; // adjust a small offset such that the mouse cursor is located in the
30859 // bottom left location of the popup, and you can easily move over the
30860 // popup area
30861
30862 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
30863 this.popup.setText(this.popupObj.getTitle());
30864 this.popup.show();
30865 this.body.emitter.emit("showPopup", this.popupObj.id);
30866 }
30867 } else {
30868 if (this.popup !== undefined) {
30869 this.popup.hide();
30870 this.body.emitter.emit("hidePopup");
30871 }
30872 }
30873 }
30874 /**
30875 * Check if the popup must be hidden, which is the case when the mouse is no
30876 * longer hovering on the object
30877 *
30878 * @param {{x:number, y:number}} pointer
30879 * @private
30880 */
30881
30882 }, {
30883 key: "_checkHidePopup",
30884 value: function _checkHidePopup(pointer) {
30885 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
30886
30887 var stillOnObj = false;
30888
30889 if (this.popup.popupTargetType === "node") {
30890 if (this.body.nodes[this.popup.popupTargetId] !== undefined) {
30891 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.
30892 // we initially only check stillOnObj because this is much faster.
30893
30894 if (stillOnObj === true) {
30895 var overNode = this.selectionHandler.getNodeAt(pointer);
30896 stillOnObj = overNode === undefined ? false : overNode.id === this.popup.popupTargetId;
30897 }
30898 }
30899 } else {
30900 if (this.selectionHandler.getNodeAt(pointer) === undefined) {
30901 if (this.body.edges[this.popup.popupTargetId] !== undefined) {
30902 stillOnObj = this.body.edges[this.popup.popupTargetId].isOverlappingWith(pointerObj);
30903 }
30904 }
30905 }
30906
30907 if (stillOnObj === false) {
30908 this.popupObj = undefined;
30909 this.popup.hide();
30910 this.body.emitter.emit("hidePopup");
30911 }
30912 }
30913 }]);
30914
30915 return InteractionHandler;
30916 }();
30917
30918 var collection$1 = collection$3;
30919 var collectionStrong = collectionStrong$2; // `Set` constructor
30920 // https://tc39.es/ecma262/#sec-set-objects
30921
30922 collection$1('Set', function (init) {
30923 return function Set() {
30924 return init(this, arguments.length ? arguments[0] : undefined);
30925 };
30926 }, collectionStrong);
30927
30928 var path$1 = path$x;
30929 var set$2 = path$1.Set;
30930
30931 var parent$4 = set$2;
30932 var set$1 = parent$4;
30933
30934 var set = set$1;
30935
30936 var redefineAll$1 = redefineAll$3;
30937 var getWeakData = internalMetadata.exports.getWeakData;
30938 var anObject = anObject$c;
30939 var isObject$1 = isObject$j;
30940 var anInstance = anInstance$3;
30941 var iterate = iterate$3;
30942 var ArrayIterationModule = arrayIteration;
30943 var $has = has$c;
30944 var InternalStateModule = internalState;
30945 var setInternalState = InternalStateModule.set;
30946 var internalStateGetterFor = InternalStateModule.getterFor;
30947 var find = ArrayIterationModule.find;
30948 var findIndex = ArrayIterationModule.findIndex;
30949 var id = 0; // fallback for uncaught frozen keys
30950
30951 var uncaughtFrozenStore = function (store) {
30952 return store.frozen || (store.frozen = new UncaughtFrozenStore());
30953 };
30954
30955 var UncaughtFrozenStore = function () {
30956 this.entries = [];
30957 };
30958
30959 var findUncaughtFrozen = function (store, key) {
30960 return find(store.entries, function (it) {
30961 return it[0] === key;
30962 });
30963 };
30964
30965 UncaughtFrozenStore.prototype = {
30966 get: function (key) {
30967 var entry = findUncaughtFrozen(this, key);
30968 if (entry) return entry[1];
30969 },
30970 has: function (key) {
30971 return !!findUncaughtFrozen(this, key);
30972 },
30973 set: function (key, value) {
30974 var entry = findUncaughtFrozen(this, key);
30975 if (entry) entry[1] = value;else this.entries.push([key, value]);
30976 },
30977 'delete': function (key) {
30978 var index = findIndex(this.entries, function (it) {
30979 return it[0] === key;
30980 });
30981 if (~index) this.entries.splice(index, 1);
30982 return !!~index;
30983 }
30984 };
30985 var collectionWeak$1 = {
30986 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
30987 var C = wrapper(function (that, iterable) {
30988 anInstance(that, C, CONSTRUCTOR_NAME);
30989 setInternalState(that, {
30990 type: CONSTRUCTOR_NAME,
30991 id: id++,
30992 frozen: undefined
30993 });
30994 if (iterable != undefined) iterate(iterable, that[ADDER], {
30995 that: that,
30996 AS_ENTRIES: IS_MAP
30997 });
30998 });
30999 var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
31000
31001 var define = function (that, key, value) {
31002 var state = getInternalState(that);
31003 var data = getWeakData(anObject(key), true);
31004 if (data === true) uncaughtFrozenStore(state).set(key, value);else data[state.id] = value;
31005 return that;
31006 };
31007
31008 redefineAll$1(C.prototype, {
31009 // `{ WeakMap, WeakSet }.prototype.delete(key)` methods
31010 // https://tc39.es/ecma262/#sec-weakmap.prototype.delete
31011 // https://tc39.es/ecma262/#sec-weakset.prototype.delete
31012 'delete': function (key) {
31013 var state = getInternalState(this);
31014 if (!isObject$1(key)) return false;
31015 var data = getWeakData(key);
31016 if (data === true) return uncaughtFrozenStore(state)['delete'](key);
31017 return data && $has(data, state.id) && delete data[state.id];
31018 },
31019 // `{ WeakMap, WeakSet }.prototype.has(key)` methods
31020 // https://tc39.es/ecma262/#sec-weakmap.prototype.has
31021 // https://tc39.es/ecma262/#sec-weakset.prototype.has
31022 has: function has(key) {
31023 var state = getInternalState(this);
31024 if (!isObject$1(key)) return false;
31025 var data = getWeakData(key);
31026 if (data === true) return uncaughtFrozenStore(state).has(key);
31027 return data && $has(data, state.id);
31028 }
31029 });
31030 redefineAll$1(C.prototype, IS_MAP ? {
31031 // `WeakMap.prototype.get(key)` method
31032 // https://tc39.es/ecma262/#sec-weakmap.prototype.get
31033 get: function get(key) {
31034 var state = getInternalState(this);
31035
31036 if (isObject$1(key)) {
31037 var data = getWeakData(key);
31038 if (data === true) return uncaughtFrozenStore(state).get(key);
31039 return data ? data[state.id] : undefined;
31040 }
31041 },
31042 // `WeakMap.prototype.set(key, value)` method
31043 // https://tc39.es/ecma262/#sec-weakmap.prototype.set
31044 set: function set(key, value) {
31045 return define(this, key, value);
31046 }
31047 } : {
31048 // `WeakSet.prototype.add(value)` method
31049 // https://tc39.es/ecma262/#sec-weakset.prototype.add
31050 add: function add(value) {
31051 return define(this, value, true);
31052 }
31053 });
31054 return C;
31055 }
31056 };
31057
31058 var global$2 = global$k;
31059 var redefineAll = redefineAll$3;
31060 var InternalMetadataModule = internalMetadata.exports;
31061 var collection = collection$3;
31062 var collectionWeak = collectionWeak$1;
31063 var isObject = isObject$j;
31064 var enforceIternalState = internalState.enforce;
31065 var NATIVE_WEAK_MAP = nativeWeakMap;
31066 var IS_IE11 = !global$2.ActiveXObject && 'ActiveXObject' in global$2; // eslint-disable-next-line es/no-object-isextensible -- safe
31067
31068 var isExtensible = Object.isExtensible;
31069 var InternalWeakMap;
31070
31071 var wrapper = function (init) {
31072 return function WeakMap() {
31073 return init(this, arguments.length ? arguments[0] : undefined);
31074 };
31075 }; // `WeakMap` constructor
31076 // https://tc39.es/ecma262/#sec-weakmap-constructor
31077
31078
31079 var $WeakMap = collection('WeakMap', wrapper, collectionWeak); // IE11 WeakMap frozen keys fix
31080 // We can't use feature detection because it crash some old IE builds
31081 // https://github.com/zloirock/core-js/issues/485
31082
31083 if (NATIVE_WEAK_MAP && IS_IE11) {
31084 InternalWeakMap = collectionWeak.getConstructor(wrapper, 'WeakMap', true);
31085 InternalMetadataModule.enable();
31086 var WeakMapPrototype = $WeakMap.prototype;
31087 var nativeDelete = WeakMapPrototype['delete'];
31088 var nativeHas = WeakMapPrototype.has;
31089 var nativeGet = WeakMapPrototype.get;
31090 var nativeSet = WeakMapPrototype.set;
31091 redefineAll(WeakMapPrototype, {
31092 'delete': function (key) {
31093 if (isObject(key) && !isExtensible(key)) {
31094 var state = enforceIternalState(this);
31095 if (!state.frozen) state.frozen = new InternalWeakMap();
31096 return nativeDelete.call(this, key) || state.frozen['delete'](key);
31097 }
31098
31099 return nativeDelete.call(this, key);
31100 },
31101 has: function has(key) {
31102 if (isObject(key) && !isExtensible(key)) {
31103 var state = enforceIternalState(this);
31104 if (!state.frozen) state.frozen = new InternalWeakMap();
31105 return nativeHas.call(this, key) || state.frozen.has(key);
31106 }
31107
31108 return nativeHas.call(this, key);
31109 },
31110 get: function get(key) {
31111 if (isObject(key) && !isExtensible(key)) {
31112 var state = enforceIternalState(this);
31113 if (!state.frozen) state.frozen = new InternalWeakMap();
31114 return nativeHas.call(this, key) ? nativeGet.call(this, key) : state.frozen.get(key);
31115 }
31116
31117 return nativeGet.call(this, key);
31118 },
31119 set: function set(key, value) {
31120 if (isObject(key) && !isExtensible(key)) {
31121 var state = enforceIternalState(this);
31122 if (!state.frozen) state.frozen = new InternalWeakMap();
31123 nativeHas.call(this, key) ? nativeSet.call(this, key, value) : state.frozen.set(key, value);
31124 } else nativeSet.call(this, key, value);
31125
31126 return this;
31127 }
31128 });
31129 }
31130
31131 var path = path$x;
31132 var weakMap$2 = path.WeakMap;
31133
31134 var parent$3 = weakMap$2;
31135 var weakMap$1 = parent$3;
31136
31137 var weakMap = weakMap$1;
31138
31139 /*! *****************************************************************************
31140 Copyright (c) Microsoft Corporation.
31141
31142 Permission to use, copy, modify, and/or distribute this software for any
31143 purpose with or without fee is hereby granted.
31144
31145 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
31146 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
31147 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
31148 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
31149 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
31150 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
31151 PERFORMANCE OF THIS SOFTWARE.
31152 ***************************************************************************** */
31153 function __classPrivateFieldGet(receiver, state, kind, f) {
31154 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
31155 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");
31156 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
31157 }
31158 function __classPrivateFieldSet(receiver, state, value, kind, f) {
31159 if (kind === "m") throw new TypeError("Private method is not writable");
31160 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
31161 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");
31162 return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
31163 }
31164
31165 function _createForOfIteratorHelper$3(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$1(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; } } }; }
31166
31167 function _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$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$3(o, minLen); }
31168
31169 function _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; }
31170
31171 var _SingleTypeSelectionAccumulator_previousSelection, _SingleTypeSelectionAccumulator_selection, _SelectionAccumulator_nodes, _SelectionAccumulator_edges, _SelectionAccumulator_commitHandler;
31172 /**
31173 * @param prev
31174 * @param next
31175 */
31176
31177 function diffSets(prev, next) {
31178 var diff = new set();
31179
31180 var _iterator = _createForOfIteratorHelper$3(next),
31181 _step;
31182
31183 try {
31184 for (_iterator.s(); !(_step = _iterator.n()).done;) {
31185 var item = _step.value;
31186
31187 if (!prev.has(item)) {
31188 diff.add(item);
31189 }
31190 }
31191 } catch (err) {
31192 _iterator.e(err);
31193 } finally {
31194 _iterator.f();
31195 }
31196
31197 return diff;
31198 }
31199
31200 var SingleTypeSelectionAccumulator = /*#__PURE__*/function () {
31201 function SingleTypeSelectionAccumulator() {
31202 _classCallCheck(this, SingleTypeSelectionAccumulator);
31203
31204 _SingleTypeSelectionAccumulator_previousSelection.set(this, new set());
31205
31206 _SingleTypeSelectionAccumulator_selection.set(this, new set());
31207 }
31208
31209 _createClass(SingleTypeSelectionAccumulator, [{
31210 key: "size",
31211 get: function get() {
31212 return __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").size;
31213 }
31214 }, {
31215 key: "add",
31216 value: function add() {
31217 for (var _len = arguments.length, items = new Array(_len), _key = 0; _key < _len; _key++) {
31218 items[_key] = arguments[_key];
31219 }
31220
31221 for (var _i = 0, _items = items; _i < _items.length; _i++) {
31222 var item = _items[_i];
31223
31224 __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").add(item);
31225 }
31226 }
31227 }, {
31228 key: "delete",
31229 value: function _delete() {
31230 for (var _len2 = arguments.length, items = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
31231 items[_key2] = arguments[_key2];
31232 }
31233
31234 for (var _i2 = 0, _items2 = items; _i2 < _items2.length; _i2++) {
31235 var item = _items2[_i2];
31236
31237 __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").delete(item);
31238 }
31239 }
31240 }, {
31241 key: "clear",
31242 value: function clear() {
31243 __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").clear();
31244 }
31245 }, {
31246 key: "getSelection",
31247 value: function getSelection() {
31248 return _toConsumableArray(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"));
31249 }
31250 }, {
31251 key: "getChanges",
31252 value: function getChanges() {
31253 return {
31254 added: _toConsumableArray(diffSets(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f"), __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"))),
31255 deleted: _toConsumableArray(diffSets(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"), __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f"))),
31256 previous: _toConsumableArray(new set(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f"))),
31257 current: _toConsumableArray(new set(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f")))
31258 };
31259 }
31260 }, {
31261 key: "commit",
31262 value: function commit() {
31263 var changes = this.getChanges();
31264
31265 __classPrivateFieldSet(this, _SingleTypeSelectionAccumulator_previousSelection, __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"), "f");
31266
31267 __classPrivateFieldSet(this, _SingleTypeSelectionAccumulator_selection, new set(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f")), "f");
31268
31269 var _iterator2 = _createForOfIteratorHelper$3(changes.added),
31270 _step2;
31271
31272 try {
31273 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
31274 var item = _step2.value;
31275 item.select();
31276 }
31277 } catch (err) {
31278 _iterator2.e(err);
31279 } finally {
31280 _iterator2.f();
31281 }
31282
31283 var _iterator3 = _createForOfIteratorHelper$3(changes.deleted),
31284 _step3;
31285
31286 try {
31287 for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
31288 var _item = _step3.value;
31289
31290 _item.unselect();
31291 }
31292 } catch (err) {
31293 _iterator3.e(err);
31294 } finally {
31295 _iterator3.f();
31296 }
31297
31298 return changes;
31299 }
31300 }]);
31301
31302 return SingleTypeSelectionAccumulator;
31303 }();
31304
31305 _SingleTypeSelectionAccumulator_previousSelection = new weakMap(), _SingleTypeSelectionAccumulator_selection = new weakMap();
31306 var SelectionAccumulator = /*#__PURE__*/function () {
31307 function SelectionAccumulator() {
31308 var commitHandler = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
31309
31310 _classCallCheck(this, SelectionAccumulator);
31311
31312 _SelectionAccumulator_nodes.set(this, new SingleTypeSelectionAccumulator());
31313
31314 _SelectionAccumulator_edges.set(this, new SingleTypeSelectionAccumulator());
31315
31316 _SelectionAccumulator_commitHandler.set(this, void 0);
31317
31318 __classPrivateFieldSet(this, _SelectionAccumulator_commitHandler, commitHandler, "f");
31319 }
31320
31321 _createClass(SelectionAccumulator, [{
31322 key: "sizeNodes",
31323 get: function get() {
31324 return __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").size;
31325 }
31326 }, {
31327 key: "sizeEdges",
31328 get: function get() {
31329 return __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").size;
31330 }
31331 }, {
31332 key: "getNodes",
31333 value: function getNodes() {
31334 return __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").getSelection();
31335 }
31336 }, {
31337 key: "getEdges",
31338 value: function getEdges() {
31339 return __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").getSelection();
31340 }
31341 }, {
31342 key: "addNodes",
31343 value: function addNodes() {
31344 var _classPrivateFieldGe;
31345
31346 (_classPrivateFieldGe = __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f")).add.apply(_classPrivateFieldGe, arguments);
31347 }
31348 }, {
31349 key: "addEdges",
31350 value: function addEdges() {
31351 var _classPrivateFieldGe2;
31352
31353 (_classPrivateFieldGe2 = __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f")).add.apply(_classPrivateFieldGe2, arguments);
31354 }
31355 }, {
31356 key: "deleteNodes",
31357 value: function deleteNodes(node) {
31358 __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").delete(node);
31359 }
31360 }, {
31361 key: "deleteEdges",
31362 value: function deleteEdges(edge) {
31363 __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").delete(edge);
31364 }
31365 }, {
31366 key: "clear",
31367 value: function clear() {
31368 __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").clear();
31369
31370 __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").clear();
31371 }
31372 }, {
31373 key: "commit",
31374 value: function commit() {
31375 var _classPrivateFieldGe3, _context;
31376
31377 var summary = {
31378 nodes: __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").commit(),
31379 edges: __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").commit()
31380 };
31381
31382 for (var _len3 = arguments.length, rest = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
31383 rest[_key3] = arguments[_key3];
31384 }
31385
31386 (_classPrivateFieldGe3 = __classPrivateFieldGet(this, _SelectionAccumulator_commitHandler, "f")).call.apply(_classPrivateFieldGe3, concat(_context = [this, summary]).call(_context, rest));
31387
31388 return summary;
31389 }
31390 }]);
31391
31392 return SelectionAccumulator;
31393 }();
31394 _SelectionAccumulator_nodes = new weakMap(), _SelectionAccumulator_edges = new weakMap(), _SelectionAccumulator_commitHandler = new weakMap();
31395
31396 function _createForOfIteratorHelper$2(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$1(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; } } }; }
31397
31398 function _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$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$2(o, minLen); }
31399
31400 function _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; }
31401 /**
31402 * The handler for selections
31403 */
31404
31405 var SelectionHandler = /*#__PURE__*/function () {
31406 /**
31407 * @param {object} body
31408 * @param {Canvas} canvas
31409 */
31410 function SelectionHandler(body, canvas) {
31411 var _this = this;
31412
31413 _classCallCheck(this, SelectionHandler);
31414
31415 this.body = body;
31416 this.canvas = canvas; // TODO: Consider firing an event on any change to the selection, not
31417 // only those caused by clicks and taps. It would be easy to implement
31418 // now and (at least to me) it seems like something that could be
31419 // quite useful.
31420
31421 this._selectionAccumulator = new SelectionAccumulator();
31422 this.hoverObj = {
31423 nodes: {},
31424 edges: {}
31425 };
31426 this.options = {};
31427 this.defaultOptions = {
31428 multiselect: false,
31429 selectable: true,
31430 selectConnectedEdges: true,
31431 hoverConnectedEdges: true
31432 };
31433
31434 assign$2(this.options, this.defaultOptions);
31435
31436 this.body.emitter.on("_dataChanged", function () {
31437 _this.updateSelection();
31438 });
31439 }
31440 /**
31441 *
31442 * @param {object} [options]
31443 */
31444
31445
31446 _createClass(SelectionHandler, [{
31447 key: "setOptions",
31448 value: function setOptions(options) {
31449 if (options !== undefined) {
31450 var fields = ["multiselect", "hoverConnectedEdges", "selectable", "selectConnectedEdges"];
31451 selectiveDeepExtend(fields, this.options, options);
31452 }
31453 }
31454 /**
31455 * handles the selection part of the tap;
31456 *
31457 * @param {{x: number, y: number}} pointer
31458 * @returns {boolean}
31459 */
31460
31461 }, {
31462 key: "selectOnPoint",
31463 value: function selectOnPoint(pointer) {
31464 var selected = false;
31465
31466 if (this.options.selectable === true) {
31467 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer); // unselect after getting the objects in order to restore width and height.
31468
31469 this.unselectAll();
31470
31471 if (obj !== undefined) {
31472 selected = this.selectObject(obj);
31473 }
31474
31475 this.body.emitter.emit("_requestRedraw");
31476 }
31477
31478 return selected;
31479 }
31480 /**
31481 *
31482 * @param {{x: number, y: number}} pointer
31483 * @returns {boolean}
31484 */
31485
31486 }, {
31487 key: "selectAdditionalOnPoint",
31488 value: function selectAdditionalOnPoint(pointer) {
31489 var selectionChanged = false;
31490
31491 if (this.options.selectable === true) {
31492 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
31493
31494 if (obj !== undefined) {
31495 selectionChanged = true;
31496
31497 if (obj.isSelected() === true) {
31498 this.deselectObject(obj);
31499 } else {
31500 this.selectObject(obj);
31501 }
31502
31503 this.body.emitter.emit("_requestRedraw");
31504 }
31505 }
31506
31507 return selectionChanged;
31508 }
31509 /**
31510 * Create an object containing the standard fields for an event.
31511 *
31512 * @param {Event} event
31513 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
31514 * @returns {{}}
31515 * @private
31516 */
31517
31518 }, {
31519 key: "_initBaseEvent",
31520 value: function _initBaseEvent(event, pointer) {
31521 var properties = {};
31522 properties["pointer"] = {
31523 DOM: {
31524 x: pointer.x,
31525 y: pointer.y
31526 },
31527 canvas: this.canvas.DOMtoCanvas(pointer)
31528 };
31529 properties["event"] = event;
31530 return properties;
31531 }
31532 /**
31533 * Generate an event which the user can catch.
31534 *
31535 * This adds some extra data to the event with respect to cursor position and
31536 * selected nodes and edges.
31537 *
31538 * @param {string} eventType Name of event to send
31539 * @param {Event} event
31540 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
31541 * @param {object | undefined} oldSelection If present, selection state before event occured
31542 * @param {boolean|undefined} [emptySelection=false] Indicate if selection data should be passed
31543 */
31544
31545 }, {
31546 key: "generateClickEvent",
31547 value: function generateClickEvent(eventType, event, pointer, oldSelection) {
31548 var emptySelection = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
31549
31550 var properties = this._initBaseEvent(event, pointer);
31551
31552 if (emptySelection === true) {
31553 properties.nodes = [];
31554 properties.edges = [];
31555 } else {
31556 var tmp = this.getSelection();
31557 properties.nodes = tmp.nodes;
31558 properties.edges = tmp.edges;
31559 }
31560
31561 if (oldSelection !== undefined) {
31562 properties["previousSelection"] = oldSelection;
31563 }
31564
31565 if (eventType == "click") {
31566 // For the time being, restrict this functionality to
31567 // just the click event.
31568 properties.items = this.getClickedItems(pointer);
31569 }
31570
31571 if (event.controlEdge !== undefined) {
31572 properties.controlEdge = event.controlEdge;
31573 }
31574
31575 this.body.emitter.emit(eventType, properties);
31576 }
31577 /**
31578 *
31579 * @param {object} obj
31580 * @param {boolean} [highlightEdges=this.options.selectConnectedEdges]
31581 * @returns {boolean}
31582 */
31583
31584 }, {
31585 key: "selectObject",
31586 value: function selectObject(obj) {
31587 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.selectConnectedEdges;
31588
31589 if (obj !== undefined) {
31590 if (obj instanceof Node) {
31591 if (highlightEdges === true) {
31592 var _this$_selectionAccum;
31593
31594 (_this$_selectionAccum = this._selectionAccumulator).addEdges.apply(_this$_selectionAccum, _toConsumableArray(obj.edges));
31595 }
31596
31597 this._selectionAccumulator.addNodes(obj);
31598 } else {
31599 this._selectionAccumulator.addEdges(obj);
31600 }
31601
31602 return true;
31603 }
31604
31605 return false;
31606 }
31607 /**
31608 *
31609 * @param {object} obj
31610 */
31611
31612 }, {
31613 key: "deselectObject",
31614 value: function deselectObject(obj) {
31615 if (obj.isSelected() === true) {
31616 obj.selected = false;
31617
31618 this._removeFromSelection(obj);
31619 }
31620 }
31621 /**
31622 * retrieve all nodes overlapping with given object
31623 *
31624 * @param {object} object An object with parameters left, top, right, bottom
31625 * @returns {number[]} An array with id's of the overlapping nodes
31626 * @private
31627 */
31628
31629 }, {
31630 key: "_getAllNodesOverlappingWith",
31631 value: function _getAllNodesOverlappingWith(object) {
31632 var overlappingNodes = [];
31633 var nodes = this.body.nodes;
31634
31635 for (var i = 0; i < this.body.nodeIndices.length; i++) {
31636 var nodeId = this.body.nodeIndices[i];
31637
31638 if (nodes[nodeId].isOverlappingWith(object)) {
31639 overlappingNodes.push(nodeId);
31640 }
31641 }
31642
31643 return overlappingNodes;
31644 }
31645 /**
31646 * Return a position object in canvasspace from a single point in screenspace
31647 *
31648 * @param {{x: number, y: number}} pointer
31649 * @returns {{left: number, top: number, right: number, bottom: number}}
31650 * @private
31651 */
31652
31653 }, {
31654 key: "_pointerToPositionObject",
31655 value: function _pointerToPositionObject(pointer) {
31656 var canvasPos = this.canvas.DOMtoCanvas(pointer);
31657 return {
31658 left: canvasPos.x - 1,
31659 top: canvasPos.y + 1,
31660 right: canvasPos.x + 1,
31661 bottom: canvasPos.y - 1
31662 };
31663 }
31664 /**
31665 * Get the top node at the passed point (like a click)
31666 *
31667 * @param {{x: number, y: number}} pointer
31668 * @param {boolean} [returnNode=true]
31669 * @returns {Node | undefined} node
31670 */
31671
31672 }, {
31673 key: "getNodeAt",
31674 value: function getNodeAt(pointer) {
31675 var returnNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
31676
31677 // we first check if this is an navigation controls element
31678 var positionObject = this._pointerToPositionObject(pointer);
31679
31680 var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); // if there are overlapping nodes, select the last one, this is the
31681 // one which is drawn on top of the others
31682
31683
31684 if (overlappingNodes.length > 0) {
31685 if (returnNode === true) {
31686 return this.body.nodes[overlappingNodes[overlappingNodes.length - 1]];
31687 } else {
31688 return overlappingNodes[overlappingNodes.length - 1];
31689 }
31690 } else {
31691 return undefined;
31692 }
31693 }
31694 /**
31695 * retrieve all edges overlapping with given object, selector is around center
31696 *
31697 * @param {object} object An object with parameters left, top, right, bottom
31698 * @param {number[]} overlappingEdges An array with id's of the overlapping nodes
31699 * @private
31700 */
31701
31702 }, {
31703 key: "_getEdgesOverlappingWith",
31704 value: function _getEdgesOverlappingWith(object, overlappingEdges) {
31705 var edges = this.body.edges;
31706
31707 for (var i = 0; i < this.body.edgeIndices.length; i++) {
31708 var edgeId = this.body.edgeIndices[i];
31709
31710 if (edges[edgeId].isOverlappingWith(object)) {
31711 overlappingEdges.push(edgeId);
31712 }
31713 }
31714 }
31715 /**
31716 * retrieve all nodes overlapping with given object
31717 *
31718 * @param {object} object An object with parameters left, top, right, bottom
31719 * @returns {number[]} An array with id's of the overlapping nodes
31720 * @private
31721 */
31722
31723 }, {
31724 key: "_getAllEdgesOverlappingWith",
31725 value: function _getAllEdgesOverlappingWith(object) {
31726 var overlappingEdges = [];
31727
31728 this._getEdgesOverlappingWith(object, overlappingEdges);
31729
31730 return overlappingEdges;
31731 }
31732 /**
31733 * Get the edges nearest to the passed point (like a click)
31734 *
31735 * @param {{x: number, y: number}} pointer
31736 * @param {boolean} [returnEdge=true]
31737 * @returns {Edge | undefined} node
31738 */
31739
31740 }, {
31741 key: "getEdgeAt",
31742 value: function getEdgeAt(pointer) {
31743 var returnEdge = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
31744 // Iterate over edges, pick closest within 10
31745 var canvasPos = this.canvas.DOMtoCanvas(pointer);
31746 var mindist = 10;
31747 var overlappingEdge = null;
31748 var edges = this.body.edges;
31749
31750 for (var i = 0; i < this.body.edgeIndices.length; i++) {
31751 var edgeId = this.body.edgeIndices[i];
31752 var edge = edges[edgeId];
31753
31754 if (edge.connected) {
31755 var xFrom = edge.from.x;
31756 var yFrom = edge.from.y;
31757 var xTo = edge.to.x;
31758 var yTo = edge.to.y;
31759 var dist = edge.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, canvasPos.x, canvasPos.y);
31760
31761 if (dist < mindist) {
31762 overlappingEdge = edgeId;
31763 mindist = dist;
31764 }
31765 }
31766 }
31767
31768 if (overlappingEdge !== null) {
31769 if (returnEdge === true) {
31770 return this.body.edges[overlappingEdge];
31771 } else {
31772 return overlappingEdge;
31773 }
31774 } else {
31775 return undefined;
31776 }
31777 }
31778 /**
31779 * Add object to the selection array.
31780 *
31781 * @param {object} obj
31782 * @private
31783 */
31784
31785 }, {
31786 key: "_addToHover",
31787 value: function _addToHover(obj) {
31788 if (obj instanceof Node) {
31789 this.hoverObj.nodes[obj.id] = obj;
31790 } else {
31791 this.hoverObj.edges[obj.id] = obj;
31792 }
31793 }
31794 /**
31795 * Remove a single option from selection.
31796 *
31797 * @param {object} obj
31798 * @private
31799 */
31800
31801 }, {
31802 key: "_removeFromSelection",
31803 value: function _removeFromSelection(obj) {
31804 if (obj instanceof Node) {
31805 var _this$_selectionAccum2;
31806
31807 this._selectionAccumulator.deleteNodes(obj);
31808
31809 (_this$_selectionAccum2 = this._selectionAccumulator).deleteEdges.apply(_this$_selectionAccum2, _toConsumableArray(obj.edges));
31810 } else {
31811 this._selectionAccumulator.deleteEdges(obj);
31812 }
31813 }
31814 /**
31815 * Unselect all nodes and edges.
31816 */
31817
31818 }, {
31819 key: "unselectAll",
31820 value: function unselectAll() {
31821 this._selectionAccumulator.clear();
31822 }
31823 /**
31824 * return the number of selected nodes
31825 *
31826 * @returns {number}
31827 */
31828
31829 }, {
31830 key: "getSelectedNodeCount",
31831 value: function getSelectedNodeCount() {
31832 return this._selectionAccumulator.sizeNodes;
31833 }
31834 /**
31835 * return the number of selected edges
31836 *
31837 * @returns {number}
31838 */
31839
31840 }, {
31841 key: "getSelectedEdgeCount",
31842 value: function getSelectedEdgeCount() {
31843 return this._selectionAccumulator.sizeEdges;
31844 }
31845 /**
31846 * select the edges connected to the node that is being selected
31847 *
31848 * @param {Node} node
31849 * @private
31850 */
31851
31852 }, {
31853 key: "_hoverConnectedEdges",
31854 value: function _hoverConnectedEdges(node) {
31855 for (var i = 0; i < node.edges.length; i++) {
31856 var edge = node.edges[i];
31857 edge.hover = true;
31858
31859 this._addToHover(edge);
31860 }
31861 }
31862 /**
31863 * Remove the highlight from a node or edge, in response to mouse movement
31864 *
31865 * @param {Event} event
31866 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
31867 * @param {Node|vis.Edge} object
31868 * @private
31869 */
31870
31871 }, {
31872 key: "emitBlurEvent",
31873 value: function emitBlurEvent(event, pointer, object) {
31874 var properties = this._initBaseEvent(event, pointer);
31875
31876 if (object.hover === true) {
31877 object.hover = false;
31878
31879 if (object instanceof Node) {
31880 properties.node = object.id;
31881 this.body.emitter.emit("blurNode", properties);
31882 } else {
31883 properties.edge = object.id;
31884 this.body.emitter.emit("blurEdge", properties);
31885 }
31886 }
31887 }
31888 /**
31889 * Create the highlight for a node or edge, in response to mouse movement
31890 *
31891 * @param {Event} event
31892 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
31893 * @param {Node|vis.Edge} object
31894 * @returns {boolean} hoverChanged
31895 * @private
31896 */
31897
31898 }, {
31899 key: "emitHoverEvent",
31900 value: function emitHoverEvent(event, pointer, object) {
31901 var properties = this._initBaseEvent(event, pointer);
31902
31903 var hoverChanged = false;
31904
31905 if (object.hover === false) {
31906 object.hover = true;
31907
31908 this._addToHover(object);
31909
31910 hoverChanged = true;
31911
31912 if (object instanceof Node) {
31913 properties.node = object.id;
31914 this.body.emitter.emit("hoverNode", properties);
31915 } else {
31916 properties.edge = object.id;
31917 this.body.emitter.emit("hoverEdge", properties);
31918 }
31919 }
31920
31921 return hoverChanged;
31922 }
31923 /**
31924 * Perform actions in response to a mouse movement.
31925 *
31926 * @param {Event} event
31927 * @param {{x: number, y: number}} pointer | object with the x and y screen coordinates of the mouse
31928 */
31929
31930 }, {
31931 key: "hoverObject",
31932 value: function hoverObject(event, pointer) {
31933 var object = this.getNodeAt(pointer);
31934
31935 if (object === undefined) {
31936 object = this.getEdgeAt(pointer);
31937 }
31938
31939 var hoverChanged = false; // remove all node hover highlights
31940
31941 for (var nodeId in this.hoverObj.nodes) {
31942 if (Object.prototype.hasOwnProperty.call(this.hoverObj.nodes, nodeId)) {
31943 if (object === undefined || object instanceof Node && object.id != nodeId || object instanceof Edge) {
31944 this.emitBlurEvent(event, pointer, this.hoverObj.nodes[nodeId]);
31945 delete this.hoverObj.nodes[nodeId];
31946 hoverChanged = true;
31947 }
31948 }
31949 } // removing all edge hover highlights
31950
31951
31952 for (var edgeId in this.hoverObj.edges) {
31953 if (Object.prototype.hasOwnProperty.call(this.hoverObj.edges, edgeId)) {
31954 // if the hover has been changed here it means that the node has been hovered over or off
31955 // we then do not use the emitBlurEvent method here.
31956 if (hoverChanged === true) {
31957 this.hoverObj.edges[edgeId].hover = false;
31958 delete this.hoverObj.edges[edgeId];
31959 } // if the blur remains the same and the object is undefined (mouse off) or another
31960 // edge has been hovered, or another node has been hovered we blur the edge.
31961 else if (object === undefined || object instanceof Edge && object.id != edgeId || object instanceof Node && !object.hover) {
31962 this.emitBlurEvent(event, pointer, this.hoverObj.edges[edgeId]);
31963 delete this.hoverObj.edges[edgeId];
31964 hoverChanged = true;
31965 }
31966 }
31967 }
31968
31969 if (object !== undefined) {
31970 var hoveredEdgesCount = keys(this.hoverObj.edges).length;
31971
31972 var hoveredNodesCount = keys(this.hoverObj.nodes).length;
31973
31974 var newOnlyHoveredEdge = object instanceof Edge && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
31975 var newOnlyHoveredNode = object instanceof Node && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
31976
31977 if (hoverChanged || newOnlyHoveredEdge || newOnlyHoveredNode) {
31978 hoverChanged = this.emitHoverEvent(event, pointer, object);
31979 }
31980
31981 if (object instanceof Node && this.options.hoverConnectedEdges === true) {
31982 this._hoverConnectedEdges(object);
31983 }
31984 }
31985
31986 if (hoverChanged === true) {
31987 this.body.emitter.emit("_requestRedraw");
31988 }
31989 }
31990 /**
31991 * Commit the selection changes but don't emit any events.
31992 */
31993
31994 }, {
31995 key: "commitWithoutEmitting",
31996 value: function commitWithoutEmitting() {
31997 this._selectionAccumulator.commit();
31998 }
31999 /**
32000 * Select and deselect nodes depending current selection change.
32001 *
32002 * For changing nodes, select/deselect events are fired.
32003 *
32004 * NOTE: For a given edge, if one connecting node is deselected and with the
32005 * same click the other node is selected, no events for the edge will fire. It
32006 * was selected and it will remain selected.
32007 *
32008 * @param {{x: number, y: number}} pointer - The x and y coordinates of the
32009 * click, tap, dragend… that triggered this.
32010 * @param {UIEvent} event - The event that triggered this.
32011 */
32012
32013 }, {
32014 key: "commitAndEmit",
32015 value: function commitAndEmit(pointer, event) {
32016 var selected = false;
32017
32018 var selectionChanges = this._selectionAccumulator.commit();
32019
32020 var previousSelection = {
32021 nodes: selectionChanges.nodes.previous,
32022 edges: selectionChanges.edges.previous
32023 };
32024
32025 if (selectionChanges.edges.deleted.length > 0) {
32026 this.generateClickEvent("deselectEdge", event, pointer, previousSelection);
32027 selected = true;
32028 }
32029
32030 if (selectionChanges.nodes.deleted.length > 0) {
32031 this.generateClickEvent("deselectNode", event, pointer, previousSelection);
32032 selected = true;
32033 }
32034
32035 if (selectionChanges.nodes.added.length > 0) {
32036 this.generateClickEvent("selectNode", event, pointer);
32037 selected = true;
32038 }
32039
32040 if (selectionChanges.edges.added.length > 0) {
32041 this.generateClickEvent("selectEdge", event, pointer);
32042 selected = true;
32043 } // fire the select event if anything has been selected or deselected
32044
32045
32046 if (selected === true) {
32047 // select or unselect
32048 this.generateClickEvent("select", event, pointer);
32049 }
32050 }
32051 /**
32052 * Retrieve the currently selected node and edge ids.
32053 *
32054 * @returns {{nodes: Array.<string>, edges: Array.<string>}} Arrays with the
32055 * ids of the selected nodes and edges.
32056 */
32057
32058 }, {
32059 key: "getSelection",
32060 value: function getSelection() {
32061 return {
32062 nodes: this.getSelectedNodeIds(),
32063 edges: this.getSelectedEdgeIds()
32064 };
32065 }
32066 /**
32067 * Retrieve the currently selected nodes.
32068 *
32069 * @returns {Array} An array with selected nodes.
32070 */
32071
32072 }, {
32073 key: "getSelectedNodes",
32074 value: function getSelectedNodes() {
32075 return this._selectionAccumulator.getNodes();
32076 }
32077 /**
32078 * Retrieve the currently selected edges.
32079 *
32080 * @returns {Array} An array with selected edges.
32081 */
32082
32083 }, {
32084 key: "getSelectedEdges",
32085 value: function getSelectedEdges() {
32086 return this._selectionAccumulator.getEdges();
32087 }
32088 /**
32089 * Retrieve the currently selected node ids.
32090 *
32091 * @returns {Array} An array with the ids of the selected nodes.
32092 */
32093
32094 }, {
32095 key: "getSelectedNodeIds",
32096 value: function getSelectedNodeIds() {
32097 var _context;
32098
32099 return map$3(_context = this._selectionAccumulator.getNodes()).call(_context, function (node) {
32100 return node.id;
32101 });
32102 }
32103 /**
32104 * Retrieve the currently selected edge ids.
32105 *
32106 * @returns {Array} An array with the ids of the selected edges.
32107 */
32108
32109 }, {
32110 key: "getSelectedEdgeIds",
32111 value: function getSelectedEdgeIds() {
32112 var _context2;
32113
32114 return map$3(_context2 = this._selectionAccumulator.getEdges()).call(_context2, function (edge) {
32115 return edge.id;
32116 });
32117 }
32118 /**
32119 * Updates the current selection
32120 *
32121 * @param {{nodes: Array.<string>, edges: Array.<string>}} selection
32122 * @param {object} options Options
32123 */
32124
32125 }, {
32126 key: "setSelection",
32127 value: function setSelection(selection) {
32128 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
32129
32130 if (!selection || !selection.nodes && !selection.edges) {
32131 throw new TypeError("Selection must be an object with nodes and/or edges properties");
32132 } // first unselect any selected node, if option is true or undefined
32133
32134
32135 if (options.unselectAll || options.unselectAll === undefined) {
32136 this.unselectAll();
32137 }
32138
32139 if (selection.nodes) {
32140 var _iterator = _createForOfIteratorHelper$2(selection.nodes),
32141 _step;
32142
32143 try {
32144 for (_iterator.s(); !(_step = _iterator.n()).done;) {
32145 var id = _step.value;
32146 var node = this.body.nodes[id];
32147
32148 if (!node) {
32149 throw new RangeError('Node with id "' + id + '" not found');
32150 } // don't select edges with it
32151
32152
32153 this.selectObject(node, options.highlightEdges);
32154 }
32155 } catch (err) {
32156 _iterator.e(err);
32157 } finally {
32158 _iterator.f();
32159 }
32160 }
32161
32162 if (selection.edges) {
32163 var _iterator2 = _createForOfIteratorHelper$2(selection.edges),
32164 _step2;
32165
32166 try {
32167 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
32168 var _id = _step2.value;
32169 var edge = this.body.edges[_id];
32170
32171 if (!edge) {
32172 throw new RangeError('Edge with id "' + _id + '" not found');
32173 }
32174
32175 this.selectObject(edge);
32176 }
32177 } catch (err) {
32178 _iterator2.e(err);
32179 } finally {
32180 _iterator2.f();
32181 }
32182 }
32183
32184 this.body.emitter.emit("_requestRedraw");
32185
32186 this._selectionAccumulator.commit();
32187 }
32188 /**
32189 * select zero or more nodes with the option to highlight edges
32190 *
32191 * @param {number[] | string[]} selection An array with the ids of the
32192 * selected nodes.
32193 * @param {boolean} [highlightEdges]
32194 */
32195
32196 }, {
32197 key: "selectNodes",
32198 value: function selectNodes(selection) {
32199 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
32200 if (!selection || selection.length === undefined) throw "Selection must be an array with ids";
32201 this.setSelection({
32202 nodes: selection
32203 }, {
32204 highlightEdges: highlightEdges
32205 });
32206 }
32207 /**
32208 * select zero or more edges
32209 *
32210 * @param {number[] | string[]} selection An array with the ids of the
32211 * selected nodes.
32212 */
32213
32214 }, {
32215 key: "selectEdges",
32216 value: function selectEdges(selection) {
32217 if (!selection || selection.length === undefined) throw "Selection must be an array with ids";
32218 this.setSelection({
32219 edges: selection
32220 });
32221 }
32222 /**
32223 * Validate the selection: remove ids of nodes which no longer exist
32224 *
32225 * @private
32226 */
32227
32228 }, {
32229 key: "updateSelection",
32230 value: function updateSelection() {
32231 for (var node in this._selectionAccumulator.getNodes()) {
32232 if (!Object.prototype.hasOwnProperty.call(this.body.nodes, node.id)) {
32233 this._selectionAccumulator.deleteNodes(node);
32234 }
32235 }
32236
32237 for (var edge in this._selectionAccumulator.getEdges()) {
32238 if (!Object.prototype.hasOwnProperty.call(this.body.edges, edge.id)) {
32239 this._selectionAccumulator.deleteEdges(edge);
32240 }
32241 }
32242 }
32243 /**
32244 * Determine all the visual elements clicked which are on the given point.
32245 *
32246 * All elements are returned; this includes nodes, edges and their labels.
32247 * The order returned is from highest to lowest, i.e. element 0 of the return
32248 * value is the topmost item clicked on.
32249 *
32250 * The return value consists of an array of the following possible elements:
32251 *
32252 * - `{nodeId:number}` - node with given id clicked on
32253 * - `{nodeId:number, labelId:0}` - label of node with given id clicked on
32254 * - `{edgeId:number}` - edge with given id clicked on
32255 * - `{edge:number, labelId:0}` - label of edge with given id clicked on
32256 *
32257 * ## NOTES
32258 *
32259 * - Currently, there is only one label associated with a node or an edge,
32260 * but this is expected to change somewhere in the future.
32261 * - Since there is no z-indexing yet, it is not really possible to set the nodes and
32262 * edges in the correct order. For the time being, nodes come first.
32263 *
32264 * @param {point} pointer mouse position in screen coordinates
32265 * @returns {Array.<nodeClickItem|nodeLabelClickItem|edgeClickItem|edgeLabelClickItem>}
32266 * @private
32267 */
32268
32269 }, {
32270 key: "getClickedItems",
32271 value: function getClickedItems(pointer) {
32272 var point = this.canvas.DOMtoCanvas(pointer);
32273 var items = []; // Note reverse order; we want the topmost clicked items to be first in the array
32274 // Also note that selected nodes are disregarded here; these normally display on top
32275
32276 var nodeIndices = this.body.nodeIndices;
32277 var nodes = this.body.nodes;
32278
32279 for (var i = nodeIndices.length - 1; i >= 0; i--) {
32280 var node = nodes[nodeIndices[i]];
32281 var ret = node.getItemsOnPoint(point);
32282 items.push.apply(items, ret); // Append the return value to the running list.
32283 }
32284
32285 var edgeIndices = this.body.edgeIndices;
32286 var edges = this.body.edges;
32287
32288 for (var _i = edgeIndices.length - 1; _i >= 0; _i--) {
32289 var edge = edges[edgeIndices[_i]];
32290
32291 var _ret = edge.getItemsOnPoint(point);
32292
32293 items.push.apply(items, _ret); // Append the return value to the running list.
32294 }
32295
32296 return items;
32297 }
32298 }]);
32299
32300 return SelectionHandler;
32301 }();
32302
32303 var floor = Math.floor;
32304
32305 var mergeSort = function (array, comparefn) {
32306 var length = array.length;
32307 var middle = floor(length / 2);
32308 return length < 8 ? insertionSort(array, comparefn) : merge(mergeSort(array.slice(0, middle), comparefn), mergeSort(array.slice(middle), comparefn), comparefn);
32309 };
32310
32311 var insertionSort = function (array, comparefn) {
32312 var length = array.length;
32313 var i = 1;
32314 var element, j;
32315
32316 while (i < length) {
32317 j = i;
32318 element = array[i];
32319
32320 while (j && comparefn(array[j - 1], element) > 0) {
32321 array[j] = array[--j];
32322 }
32323
32324 if (j !== i++) array[j] = element;
32325 }
32326
32327 return array;
32328 };
32329
32330 var merge = function (left, right, comparefn) {
32331 var llength = left.length;
32332 var rlength = right.length;
32333 var lindex = 0;
32334 var rindex = 0;
32335 var result = [];
32336
32337 while (lindex < llength || rindex < rlength) {
32338 if (lindex < llength && rindex < rlength) {
32339 result.push(comparefn(left[lindex], right[rindex]) <= 0 ? left[lindex++] : right[rindex++]);
32340 } else {
32341 result.push(lindex < llength ? left[lindex++] : right[rindex++]);
32342 }
32343 }
32344
32345 return result;
32346 };
32347
32348 var arraySort = mergeSort;
32349
32350 var userAgent$1 = engineUserAgent;
32351 var firefox = userAgent$1.match(/firefox\/(\d+)/i);
32352 var engineFfVersion = !!firefox && +firefox[1];
32353
32354 var UA = engineUserAgent;
32355 var engineIsIeOrEdge = /MSIE|Trident/.test(UA);
32356
32357 var userAgent = engineUserAgent;
32358 var webkit = userAgent.match(/AppleWebKit\/(\d+)\./);
32359 var engineWebkitVersion = !!webkit && +webkit[1];
32360
32361 var $$2 = _export;
32362 var aFunction$1 = aFunction$5;
32363 var toObject$1 = toObject$d;
32364 var toLength$1 = toLength$a;
32365 var toString = toString$9;
32366 var fails = fails$m;
32367 var internalSort = arraySort;
32368 var arrayMethodIsStrict$2 = arrayMethodIsStrict$6;
32369 var FF = engineFfVersion;
32370 var IE_OR_EDGE = engineIsIeOrEdge;
32371 var V8 = engineV8Version;
32372 var WEBKIT = engineWebkitVersion;
32373 var test = [];
32374 var nativeSort = test.sort; // IE8-
32375
32376 var FAILS_ON_UNDEFINED = fails(function () {
32377 test.sort(undefined);
32378 }); // V8 bug
32379
32380 var FAILS_ON_NULL = fails(function () {
32381 test.sort(null);
32382 }); // Old WebKit
32383
32384 var STRICT_METHOD$2 = arrayMethodIsStrict$2('sort');
32385 var STABLE_SORT = !fails(function () {
32386 // feature detection can be too slow, so check engines versions
32387 if (V8) return V8 < 70;
32388 if (FF && FF > 3) return;
32389 if (IE_OR_EDGE) return true;
32390 if (WEBKIT) return WEBKIT < 603;
32391 var result = '';
32392 var code, chr, value, index; // generate an array with more 512 elements (Chakra and old V8 fails only in this case)
32393
32394 for (code = 65; code < 76; code++) {
32395 chr = String.fromCharCode(code);
32396
32397 switch (code) {
32398 case 66:
32399 case 69:
32400 case 70:
32401 case 72:
32402 value = 3;
32403 break;
32404
32405 case 68:
32406 case 71:
32407 value = 4;
32408 break;
32409
32410 default:
32411 value = 2;
32412 }
32413
32414 for (index = 0; index < 47; index++) {
32415 test.push({
32416 k: chr + index,
32417 v: value
32418 });
32419 }
32420 }
32421
32422 test.sort(function (a, b) {
32423 return b.v - a.v;
32424 });
32425
32426 for (index = 0; index < test.length; index++) {
32427 chr = test[index].k.charAt(0);
32428 if (result.charAt(result.length - 1) !== chr) result += chr;
32429 }
32430
32431 return result !== 'DGBEFHACIJK';
32432 });
32433 var FORCED = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$2 || !STABLE_SORT;
32434
32435 var getSortCompare = function (comparefn) {
32436 return function (x, y) {
32437 if (y === undefined) return -1;
32438 if (x === undefined) return 1;
32439 if (comparefn !== undefined) return +comparefn(x, y) || 0;
32440 return toString(x) > toString(y) ? 1 : -1;
32441 };
32442 }; // `Array.prototype.sort` method
32443 // https://tc39.es/ecma262/#sec-array.prototype.sort
32444
32445
32446 $$2({
32447 target: 'Array',
32448 proto: true,
32449 forced: FORCED
32450 }, {
32451 sort: function sort(comparefn) {
32452 if (comparefn !== undefined) aFunction$1(comparefn);
32453 var array = toObject$1(this);
32454 if (STABLE_SORT) return comparefn === undefined ? nativeSort.call(array) : nativeSort.call(array, comparefn);
32455 var items = [];
32456 var arrayLength = toLength$1(array.length);
32457 var itemsLength, index;
32458
32459 for (index = 0; index < arrayLength; index++) {
32460 if (index in array) items.push(array[index]);
32461 }
32462
32463 items = internalSort(items, getSortCompare(comparefn));
32464 itemsLength = items.length;
32465 index = 0;
32466
32467 while (index < itemsLength) array[index] = items[index++];
32468
32469 while (index < arrayLength) delete array[index++];
32470
32471 return array;
32472 }
32473 });
32474
32475 var entryVirtual$2 = entryVirtual$i;
32476 var sort$3 = entryVirtual$2('Array').sort;
32477
32478 var sort$2 = sort$3;
32479 var ArrayPrototype$2 = Array.prototype;
32480
32481 var sort_1 = function (it) {
32482 var own = it.sort;
32483 return it === ArrayPrototype$2 || it instanceof Array && own === ArrayPrototype$2.sort ? sort$2 : own;
32484 };
32485
32486 var parent$2 = sort_1;
32487 var sort$1 = parent$2;
32488
32489 var sort = sort$1;
32490
32491 var aFunction = aFunction$5;
32492 var toObject = toObject$d;
32493 var IndexedObject = indexedObject;
32494 var toLength = toLength$a; // `Array.prototype.{ reduce, reduceRight }` methods implementation
32495
32496 var createMethod = function (IS_RIGHT) {
32497 return function (that, callbackfn, argumentsLength, memo) {
32498 aFunction(callbackfn);
32499 var O = toObject(that);
32500 var self = IndexedObject(O);
32501 var length = toLength(O.length);
32502 var index = IS_RIGHT ? length - 1 : 0;
32503 var i = IS_RIGHT ? -1 : 1;
32504 if (argumentsLength < 2) while (true) {
32505 if (index in self) {
32506 memo = self[index];
32507 index += i;
32508 break;
32509 }
32510
32511 index += i;
32512
32513 if (IS_RIGHT ? index < 0 : length <= index) {
32514 throw TypeError('Reduce of empty array with no initial value');
32515 }
32516 }
32517
32518 for (; IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
32519 memo = callbackfn(memo, self[index], index, O);
32520 }
32521
32522 return memo;
32523 };
32524 };
32525
32526 var arrayReduce = {
32527 // `Array.prototype.reduce` method
32528 // https://tc39.es/ecma262/#sec-array.prototype.reduce
32529 left: createMethod(false),
32530 // `Array.prototype.reduceRight` method
32531 // https://tc39.es/ecma262/#sec-array.prototype.reduceright
32532 right: createMethod(true)
32533 };
32534
32535 var classof = classofRaw$1;
32536 var global$1 = global$k;
32537 var engineIsNode = classof(global$1.process) == 'process';
32538
32539 var $$1 = _export;
32540 var $reduce = arrayReduce.left;
32541 var arrayMethodIsStrict$1 = arrayMethodIsStrict$6;
32542 var CHROME_VERSION = engineV8Version;
32543 var IS_NODE = engineIsNode;
32544 var STRICT_METHOD$1 = arrayMethodIsStrict$1('reduce'); // Chrome 80-82 has a critical bug
32545 // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
32546
32547 var CHROME_BUG = !IS_NODE && CHROME_VERSION > 79 && CHROME_VERSION < 83; // `Array.prototype.reduce` method
32548 // https://tc39.es/ecma262/#sec-array.prototype.reduce
32549
32550 $$1({
32551 target: 'Array',
32552 proto: true,
32553 forced: !STRICT_METHOD$1 || CHROME_BUG
32554 }, {
32555 reduce: function reduce(callbackfn
32556 /* , initialValue */
32557 ) {
32558 return $reduce(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
32559 }
32560 });
32561
32562 var entryVirtual$1 = entryVirtual$i;
32563 var reduce$3 = entryVirtual$1('Array').reduce;
32564
32565 var reduce$2 = reduce$3;
32566 var ArrayPrototype$1 = Array.prototype;
32567
32568 var reduce_1 = function (it) {
32569 var own = it.reduce;
32570 return it === ArrayPrototype$1 || it instanceof Array && own === ArrayPrototype$1.reduce ? reduce$2 : own;
32571 };
32572
32573 var parent$1 = reduce_1;
32574 var reduce$1 = parent$1;
32575
32576 var reduce = reduce$1;
32577
32578 var timsort$1 = {};
32579
32580 /****
32581 * The MIT License
32582 *
32583 * Copyright (c) 2015 Marco Ziccardi
32584 *
32585 * Permission is hereby granted, free of charge, to any person obtaining a copy
32586 * of this software and associated documentation files (the "Software"), to deal
32587 * in the Software without restriction, including without limitation the rights
32588 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32589 * copies of the Software, and to permit persons to whom the Software is
32590 * furnished to do so, subject to the following conditions:
32591 *
32592 * The above copyright notice and this permission notice shall be included in
32593 * all copies or substantial portions of the Software.
32594 *
32595 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32596 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32597 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32598 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32599 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32600 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32601 * THE SOFTWARE.
32602 *
32603 ****/
32604
32605 (function (exports) {
32606 (function (global, factory) {
32607 {
32608 factory(exports);
32609 }
32610 })(commonjsGlobal, function (exports) {
32611
32612 exports.__esModule = true;
32613 exports.sort = sort;
32614
32615 function _classCallCheck(instance, Constructor) {
32616 if (!(instance instanceof Constructor)) {
32617 throw new TypeError('Cannot call a class as a function');
32618 }
32619 }
32620
32621 var DEFAULT_MIN_MERGE = 32;
32622 var DEFAULT_MIN_GALLOPING = 7;
32623 var DEFAULT_TMP_STORAGE_LENGTH = 256;
32624 var POWERS_OF_TEN = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9];
32625
32626 function log10(x) {
32627 if (x < 1e5) {
32628 if (x < 1e2) {
32629 return x < 1e1 ? 0 : 1;
32630 }
32631
32632 if (x < 1e4) {
32633 return x < 1e3 ? 2 : 3;
32634 }
32635
32636 return 4;
32637 }
32638
32639 if (x < 1e7) {
32640 return x < 1e6 ? 5 : 6;
32641 }
32642
32643 if (x < 1e9) {
32644 return x < 1e8 ? 7 : 8;
32645 }
32646
32647 return 9;
32648 }
32649
32650 function alphabeticalCompare(a, b) {
32651 if (a === b) {
32652 return 0;
32653 }
32654
32655 if (~~a === a && ~~b === b) {
32656 if (a === 0 || b === 0) {
32657 return a < b ? -1 : 1;
32658 }
32659
32660 if (a < 0 || b < 0) {
32661 if (b >= 0) {
32662 return -1;
32663 }
32664
32665 if (a >= 0) {
32666 return 1;
32667 }
32668
32669 a = -a;
32670 b = -b;
32671 }
32672
32673 var al = log10(a);
32674 var bl = log10(b);
32675 var t = 0;
32676
32677 if (al < bl) {
32678 a *= POWERS_OF_TEN[bl - al - 1];
32679 b /= 10;
32680 t = -1;
32681 } else if (al > bl) {
32682 b *= POWERS_OF_TEN[al - bl - 1];
32683 a /= 10;
32684 t = 1;
32685 }
32686
32687 if (a === b) {
32688 return t;
32689 }
32690
32691 return a < b ? -1 : 1;
32692 }
32693
32694 var aStr = String(a);
32695 var bStr = String(b);
32696
32697 if (aStr === bStr) {
32698 return 0;
32699 }
32700
32701 return aStr < bStr ? -1 : 1;
32702 }
32703
32704 function minRunLength(n) {
32705 var r = 0;
32706
32707 while (n >= DEFAULT_MIN_MERGE) {
32708 r |= n & 1;
32709 n >>= 1;
32710 }
32711
32712 return n + r;
32713 }
32714
32715 function makeAscendingRun(array, lo, hi, compare) {
32716 var runHi = lo + 1;
32717
32718 if (runHi === hi) {
32719 return 1;
32720 }
32721
32722 if (compare(array[runHi++], array[lo]) < 0) {
32723 while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
32724 runHi++;
32725 }
32726
32727 reverseRun(array, lo, runHi);
32728 } else {
32729 while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
32730 runHi++;
32731 }
32732 }
32733
32734 return runHi - lo;
32735 }
32736
32737 function reverseRun(array, lo, hi) {
32738 hi--;
32739
32740 while (lo < hi) {
32741 var t = array[lo];
32742 array[lo++] = array[hi];
32743 array[hi--] = t;
32744 }
32745 }
32746
32747 function binaryInsertionSort(array, lo, hi, start, compare) {
32748 if (start === lo) {
32749 start++;
32750 }
32751
32752 for (; start < hi; start++) {
32753 var pivot = array[start];
32754 var left = lo;
32755 var right = start;
32756
32757 while (left < right) {
32758 var mid = left + right >>> 1;
32759
32760 if (compare(pivot, array[mid]) < 0) {
32761 right = mid;
32762 } else {
32763 left = mid + 1;
32764 }
32765 }
32766
32767 var n = start - left;
32768
32769 switch (n) {
32770 case 3:
32771 array[left + 3] = array[left + 2];
32772
32773 case 2:
32774 array[left + 2] = array[left + 1];
32775
32776 case 1:
32777 array[left + 1] = array[left];
32778 break;
32779
32780 default:
32781 while (n > 0) {
32782 array[left + n] = array[left + n - 1];
32783 n--;
32784 }
32785
32786 }
32787
32788 array[left] = pivot;
32789 }
32790 }
32791
32792 function gallopLeft(value, array, start, length, hint, compare) {
32793 var lastOffset = 0;
32794 var maxOffset = 0;
32795 var offset = 1;
32796
32797 if (compare(value, array[start + hint]) > 0) {
32798 maxOffset = length - hint;
32799
32800 while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
32801 lastOffset = offset;
32802 offset = (offset << 1) + 1;
32803
32804 if (offset <= 0) {
32805 offset = maxOffset;
32806 }
32807 }
32808
32809 if (offset > maxOffset) {
32810 offset = maxOffset;
32811 }
32812
32813 lastOffset += hint;
32814 offset += hint;
32815 } else {
32816 maxOffset = hint + 1;
32817
32818 while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
32819 lastOffset = offset;
32820 offset = (offset << 1) + 1;
32821
32822 if (offset <= 0) {
32823 offset = maxOffset;
32824 }
32825 }
32826
32827 if (offset > maxOffset) {
32828 offset = maxOffset;
32829 }
32830
32831 var tmp = lastOffset;
32832 lastOffset = hint - offset;
32833 offset = hint - tmp;
32834 }
32835
32836 lastOffset++;
32837
32838 while (lastOffset < offset) {
32839 var m = lastOffset + (offset - lastOffset >>> 1);
32840
32841 if (compare(value, array[start + m]) > 0) {
32842 lastOffset = m + 1;
32843 } else {
32844 offset = m;
32845 }
32846 }
32847
32848 return offset;
32849 }
32850
32851 function gallopRight(value, array, start, length, hint, compare) {
32852 var lastOffset = 0;
32853 var maxOffset = 0;
32854 var offset = 1;
32855
32856 if (compare(value, array[start + hint]) < 0) {
32857 maxOffset = hint + 1;
32858
32859 while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
32860 lastOffset = offset;
32861 offset = (offset << 1) + 1;
32862
32863 if (offset <= 0) {
32864 offset = maxOffset;
32865 }
32866 }
32867
32868 if (offset > maxOffset) {
32869 offset = maxOffset;
32870 }
32871
32872 var tmp = lastOffset;
32873 lastOffset = hint - offset;
32874 offset = hint - tmp;
32875 } else {
32876 maxOffset = length - hint;
32877
32878 while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
32879 lastOffset = offset;
32880 offset = (offset << 1) + 1;
32881
32882 if (offset <= 0) {
32883 offset = maxOffset;
32884 }
32885 }
32886
32887 if (offset > maxOffset) {
32888 offset = maxOffset;
32889 }
32890
32891 lastOffset += hint;
32892 offset += hint;
32893 }
32894
32895 lastOffset++;
32896
32897 while (lastOffset < offset) {
32898 var m = lastOffset + (offset - lastOffset >>> 1);
32899
32900 if (compare(value, array[start + m]) < 0) {
32901 offset = m;
32902 } else {
32903 lastOffset = m + 1;
32904 }
32905 }
32906
32907 return offset;
32908 }
32909
32910 var TimSort = function () {
32911 function TimSort(array, compare) {
32912 _classCallCheck(this, TimSort);
32913
32914 this.array = null;
32915 this.compare = null;
32916 this.minGallop = DEFAULT_MIN_GALLOPING;
32917 this.length = 0;
32918 this.tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
32919 this.stackLength = 0;
32920 this.runStart = null;
32921 this.runLength = null;
32922 this.stackSize = 0;
32923 this.array = array;
32924 this.compare = compare;
32925 this.length = array.length;
32926
32927 if (this.length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
32928 this.tmpStorageLength = this.length >>> 1;
32929 }
32930
32931 this.tmp = new Array(this.tmpStorageLength);
32932 this.stackLength = this.length < 120 ? 5 : this.length < 1542 ? 10 : this.length < 119151 ? 19 : 40;
32933 this.runStart = new Array(this.stackLength);
32934 this.runLength = new Array(this.stackLength);
32935 }
32936
32937 TimSort.prototype.pushRun = function pushRun(runStart, runLength) {
32938 this.runStart[this.stackSize] = runStart;
32939 this.runLength[this.stackSize] = runLength;
32940 this.stackSize += 1;
32941 };
32942
32943 TimSort.prototype.mergeRuns = function mergeRuns() {
32944 while (this.stackSize > 1) {
32945 var n = this.stackSize - 2;
32946
32947 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]) {
32948 if (this.runLength[n - 1] < this.runLength[n + 1]) {
32949 n--;
32950 }
32951 } else if (this.runLength[n] > this.runLength[n + 1]) {
32952 break;
32953 }
32954
32955 this.mergeAt(n);
32956 }
32957 };
32958
32959 TimSort.prototype.forceMergeRuns = function forceMergeRuns() {
32960 while (this.stackSize > 1) {
32961 var n = this.stackSize - 2;
32962
32963 if (n > 0 && this.runLength[n - 1] < this.runLength[n + 1]) {
32964 n--;
32965 }
32966
32967 this.mergeAt(n);
32968 }
32969 };
32970
32971 TimSort.prototype.mergeAt = function mergeAt(i) {
32972 var compare = this.compare;
32973 var array = this.array;
32974 var start1 = this.runStart[i];
32975 var length1 = this.runLength[i];
32976 var start2 = this.runStart[i + 1];
32977 var length2 = this.runLength[i + 1];
32978 this.runLength[i] = length1 + length2;
32979
32980 if (i === this.stackSize - 3) {
32981 this.runStart[i + 1] = this.runStart[i + 2];
32982 this.runLength[i + 1] = this.runLength[i + 2];
32983 }
32984
32985 this.stackSize--;
32986 var k = gallopRight(array[start2], array, start1, length1, 0, compare);
32987 start1 += k;
32988 length1 -= k;
32989
32990 if (length1 === 0) {
32991 return;
32992 }
32993
32994 length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
32995
32996 if (length2 === 0) {
32997 return;
32998 }
32999
33000 if (length1 <= length2) {
33001 this.mergeLow(start1, length1, start2, length2);
33002 } else {
33003 this.mergeHigh(start1, length1, start2, length2);
33004 }
33005 };
33006
33007 TimSort.prototype.mergeLow = function mergeLow(start1, length1, start2, length2) {
33008 var compare = this.compare;
33009 var array = this.array;
33010 var tmp = this.tmp;
33011 var i = 0;
33012
33013 for (i = 0; i < length1; i++) {
33014 tmp[i] = array[start1 + i];
33015 }
33016
33017 var cursor1 = 0;
33018 var cursor2 = start2;
33019 var dest = start1;
33020 array[dest++] = array[cursor2++];
33021
33022 if (--length2 === 0) {
33023 for (i = 0; i < length1; i++) {
33024 array[dest + i] = tmp[cursor1 + i];
33025 }
33026
33027 return;
33028 }
33029
33030 if (length1 === 1) {
33031 for (i = 0; i < length2; i++) {
33032 array[dest + i] = array[cursor2 + i];
33033 }
33034
33035 array[dest + length2] = tmp[cursor1];
33036 return;
33037 }
33038
33039 var minGallop = this.minGallop;
33040
33041 while (true) {
33042 var count1 = 0;
33043 var count2 = 0;
33044 var exit = false;
33045
33046 do {
33047 if (compare(array[cursor2], tmp[cursor1]) < 0) {
33048 array[dest++] = array[cursor2++];
33049 count2++;
33050 count1 = 0;
33051
33052 if (--length2 === 0) {
33053 exit = true;
33054 break;
33055 }
33056 } else {
33057 array[dest++] = tmp[cursor1++];
33058 count1++;
33059 count2 = 0;
33060
33061 if (--length1 === 1) {
33062 exit = true;
33063 break;
33064 }
33065 }
33066 } while ((count1 | count2) < minGallop);
33067
33068 if (exit) {
33069 break;
33070 }
33071
33072 do {
33073 count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
33074
33075 if (count1 !== 0) {
33076 for (i = 0; i < count1; i++) {
33077 array[dest + i] = tmp[cursor1 + i];
33078 }
33079
33080 dest += count1;
33081 cursor1 += count1;
33082 length1 -= count1;
33083
33084 if (length1 <= 1) {
33085 exit = true;
33086 break;
33087 }
33088 }
33089
33090 array[dest++] = array[cursor2++];
33091
33092 if (--length2 === 0) {
33093 exit = true;
33094 break;
33095 }
33096
33097 count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
33098
33099 if (count2 !== 0) {
33100 for (i = 0; i < count2; i++) {
33101 array[dest + i] = array[cursor2 + i];
33102 }
33103
33104 dest += count2;
33105 cursor2 += count2;
33106 length2 -= count2;
33107
33108 if (length2 === 0) {
33109 exit = true;
33110 break;
33111 }
33112 }
33113
33114 array[dest++] = tmp[cursor1++];
33115
33116 if (--length1 === 1) {
33117 exit = true;
33118 break;
33119 }
33120
33121 minGallop--;
33122 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
33123
33124 if (exit) {
33125 break;
33126 }
33127
33128 if (minGallop < 0) {
33129 minGallop = 0;
33130 }
33131
33132 minGallop += 2;
33133 }
33134
33135 this.minGallop = minGallop;
33136
33137 if (minGallop < 1) {
33138 this.minGallop = 1;
33139 }
33140
33141 if (length1 === 1) {
33142 for (i = 0; i < length2; i++) {
33143 array[dest + i] = array[cursor2 + i];
33144 }
33145
33146 array[dest + length2] = tmp[cursor1];
33147 } else if (length1 === 0) {
33148 throw new Error('mergeLow preconditions were not respected');
33149 } else {
33150 for (i = 0; i < length1; i++) {
33151 array[dest + i] = tmp[cursor1 + i];
33152 }
33153 }
33154 };
33155
33156 TimSort.prototype.mergeHigh = function mergeHigh(start1, length1, start2, length2) {
33157 var compare = this.compare;
33158 var array = this.array;
33159 var tmp = this.tmp;
33160 var i = 0;
33161
33162 for (i = 0; i < length2; i++) {
33163 tmp[i] = array[start2 + i];
33164 }
33165
33166 var cursor1 = start1 + length1 - 1;
33167 var cursor2 = length2 - 1;
33168 var dest = start2 + length2 - 1;
33169 var customCursor = 0;
33170 var customDest = 0;
33171 array[dest--] = array[cursor1--];
33172
33173 if (--length1 === 0) {
33174 customCursor = dest - (length2 - 1);
33175
33176 for (i = 0; i < length2; i++) {
33177 array[customCursor + i] = tmp[i];
33178 }
33179
33180 return;
33181 }
33182
33183 if (length2 === 1) {
33184 dest -= length1;
33185 cursor1 -= length1;
33186 customDest = dest + 1;
33187 customCursor = cursor1 + 1;
33188
33189 for (i = length1 - 1; i >= 0; i--) {
33190 array[customDest + i] = array[customCursor + i];
33191 }
33192
33193 array[dest] = tmp[cursor2];
33194 return;
33195 }
33196
33197 var minGallop = this.minGallop;
33198
33199 while (true) {
33200 var count1 = 0;
33201 var count2 = 0;
33202 var exit = false;
33203
33204 do {
33205 if (compare(tmp[cursor2], array[cursor1]) < 0) {
33206 array[dest--] = array[cursor1--];
33207 count1++;
33208 count2 = 0;
33209
33210 if (--length1 === 0) {
33211 exit = true;
33212 break;
33213 }
33214 } else {
33215 array[dest--] = tmp[cursor2--];
33216 count2++;
33217 count1 = 0;
33218
33219 if (--length2 === 1) {
33220 exit = true;
33221 break;
33222 }
33223 }
33224 } while ((count1 | count2) < minGallop);
33225
33226 if (exit) {
33227 break;
33228 }
33229
33230 do {
33231 count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
33232
33233 if (count1 !== 0) {
33234 dest -= count1;
33235 cursor1 -= count1;
33236 length1 -= count1;
33237 customDest = dest + 1;
33238 customCursor = cursor1 + 1;
33239
33240 for (i = count1 - 1; i >= 0; i--) {
33241 array[customDest + i] = array[customCursor + i];
33242 }
33243
33244 if (length1 === 0) {
33245 exit = true;
33246 break;
33247 }
33248 }
33249
33250 array[dest--] = tmp[cursor2--];
33251
33252 if (--length2 === 1) {
33253 exit = true;
33254 break;
33255 }
33256
33257 count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
33258
33259 if (count2 !== 0) {
33260 dest -= count2;
33261 cursor2 -= count2;
33262 length2 -= count2;
33263 customDest = dest + 1;
33264 customCursor = cursor2 + 1;
33265
33266 for (i = 0; i < count2; i++) {
33267 array[customDest + i] = tmp[customCursor + i];
33268 }
33269
33270 if (length2 <= 1) {
33271 exit = true;
33272 break;
33273 }
33274 }
33275
33276 array[dest--] = array[cursor1--];
33277
33278 if (--length1 === 0) {
33279 exit = true;
33280 break;
33281 }
33282
33283 minGallop--;
33284 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
33285
33286 if (exit) {
33287 break;
33288 }
33289
33290 if (minGallop < 0) {
33291 minGallop = 0;
33292 }
33293
33294 minGallop += 2;
33295 }
33296
33297 this.minGallop = minGallop;
33298
33299 if (minGallop < 1) {
33300 this.minGallop = 1;
33301 }
33302
33303 if (length2 === 1) {
33304 dest -= length1;
33305 cursor1 -= length1;
33306 customDest = dest + 1;
33307 customCursor = cursor1 + 1;
33308
33309 for (i = length1 - 1; i >= 0; i--) {
33310 array[customDest + i] = array[customCursor + i];
33311 }
33312
33313 array[dest] = tmp[cursor2];
33314 } else if (length2 === 0) {
33315 throw new Error('mergeHigh preconditions were not respected');
33316 } else {
33317 customCursor = dest - (length2 - 1);
33318
33319 for (i = 0; i < length2; i++) {
33320 array[customCursor + i] = tmp[i];
33321 }
33322 }
33323 };
33324
33325 return TimSort;
33326 }();
33327
33328 function sort(array, compare, lo, hi) {
33329 if (!Array.isArray(array)) {
33330 throw new TypeError('Can only sort arrays');
33331 }
33332
33333 if (!compare) {
33334 compare = alphabeticalCompare;
33335 } else if (typeof compare !== 'function') {
33336 hi = lo;
33337 lo = compare;
33338 compare = alphabeticalCompare;
33339 }
33340
33341 if (!lo) {
33342 lo = 0;
33343 }
33344
33345 if (!hi) {
33346 hi = array.length;
33347 }
33348
33349 var remaining = hi - lo;
33350
33351 if (remaining < 2) {
33352 return;
33353 }
33354
33355 var runLength = 0;
33356
33357 if (remaining < DEFAULT_MIN_MERGE) {
33358 runLength = makeAscendingRun(array, lo, hi, compare);
33359 binaryInsertionSort(array, lo, hi, lo + runLength, compare);
33360 return;
33361 }
33362
33363 var ts = new TimSort(array, compare);
33364 var minRun = minRunLength(remaining);
33365
33366 do {
33367 runLength = makeAscendingRun(array, lo, hi, compare);
33368
33369 if (runLength < minRun) {
33370 var force = remaining;
33371
33372 if (force > minRun) {
33373 force = minRun;
33374 }
33375
33376 binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
33377 runLength = force;
33378 }
33379
33380 ts.pushRun(lo, runLength);
33381 ts.mergeRuns();
33382 remaining -= runLength;
33383 lo += runLength;
33384 } while (remaining !== 0);
33385
33386 ts.forceMergeRuns();
33387 }
33388 });
33389 })(timsort$1);
33390
33391 var timsort = timsort$1;
33392
33393 function _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); }; }
33394
33395 function _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; } }
33396 /**
33397 * Interface definition for direction strategy classes.
33398 *
33399 * This class describes the interface for the Strategy
33400 * pattern classes used to differentiate horizontal and vertical
33401 * direction of hierarchical results.
33402 *
33403 * For a given direction, one coordinate will be 'fixed', meaning that it is
33404 * determined by level.
33405 * The other coordinate is 'unfixed', meaning that the nodes on a given level
33406 * can still move along that coordinate. So:
33407 *
33408 * - `vertical` layout: `x` unfixed, `y` fixed per level
33409 * - `horizontal` layout: `x` fixed per level, `y` unfixed
33410 *
33411 * The local methods are stubs and should be regarded as abstract.
33412 * Derived classes **must** implement all the methods themselves.
33413 *
33414 * @private
33415 */
33416
33417 var DirectionInterface = /*#__PURE__*/function () {
33418 function DirectionInterface() {
33419 _classCallCheck(this, DirectionInterface);
33420 }
33421
33422 _createClass(DirectionInterface, [{
33423 key: "abstract",
33424 value:
33425 /**
33426 * @ignore
33427 */
33428 function abstract() {
33429 throw new Error("Can't instantiate abstract class!");
33430 }
33431 /**
33432 * This is a dummy call which is used to suppress the jsdoc errors of type:
33433 *
33434 * "'param' is assigned a value but never used"
33435 *
33436 * @ignore
33437 **/
33438
33439 }, {
33440 key: "fake_use",
33441 value: function fake_use() {// Do nothing special
33442 }
33443 /**
33444 * Type to use to translate dynamic curves to, in the case of hierarchical layout.
33445 * Dynamic curves do not work for these.
33446 *
33447 * The value should be perpendicular to the actual direction of the layout.
33448 *
33449 * @returns {string} Direction, either 'vertical' or 'horizontal'
33450 */
33451
33452 }, {
33453 key: "curveType",
33454 value: function curveType() {
33455 return this.abstract();
33456 }
33457 /**
33458 * Return the value of the coordinate that is not fixed for this direction.
33459 *
33460 * @param {Node} node The node to read
33461 * @returns {number} Value of the unfixed coordinate
33462 */
33463
33464 }, {
33465 key: "getPosition",
33466 value: function getPosition(node) {
33467 this.fake_use(node);
33468 return this.abstract();
33469 }
33470 /**
33471 * Set the value of the coordinate that is not fixed for this direction.
33472 *
33473 * @param {Node} node The node to adjust
33474 * @param {number} position
33475 * @param {number} [level] if specified, the hierarchy level that this node should be fixed to
33476 */
33477
33478 }, {
33479 key: "setPosition",
33480 value: function setPosition(node, position) {
33481 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
33482 this.fake_use(node, position, level);
33483 this.abstract();
33484 }
33485 /**
33486 * Get the width of a tree.
33487 *
33488 * A `tree` here is a subset of nodes within the network which are not connected to other nodes,
33489 * only among themselves. In essence, it is a sub-network.
33490 *
33491 * @param {number} index The index number of a tree
33492 * @returns {number} the width of a tree in the view coordinates
33493 */
33494
33495 }, {
33496 key: "getTreeSize",
33497 value: function getTreeSize(index) {
33498 this.fake_use(index);
33499 return this.abstract();
33500 }
33501 /**
33502 * Sort array of nodes on the unfixed coordinates.
33503 *
33504 * **Note:** chrome has non-stable sorting implementation, which
33505 * has a tendency to change the order of the array items,
33506 * even if the custom sort function returns 0.
33507 *
33508 * For this reason, an external sort implementation is used,
33509 * which has the added benefit of being faster than the standard
33510 * platforms implementation. This has been verified on `node.js`,
33511 * `firefox` and `chrome` (all linux).
33512 *
33513 * @param {Array.<Node>} nodeArray array of nodes to sort
33514 */
33515
33516 }, {
33517 key: "sort",
33518 value: function sort(nodeArray) {
33519 this.fake_use(nodeArray);
33520 this.abstract();
33521 }
33522 /**
33523 * Assign the fixed coordinate of the node to the given level
33524 *
33525 * @param {Node} node The node to adjust
33526 * @param {number} level The level to fix to
33527 */
33528
33529 }, {
33530 key: "fix",
33531 value: function fix(node, level) {
33532 this.fake_use(node, level);
33533 this.abstract();
33534 }
33535 /**
33536 * Add an offset to the unfixed coordinate of the given node.
33537 *
33538 * @param {NodeId} nodeId Id of the node to adjust
33539 * @param {number} diff Offset to add to the unfixed coordinate
33540 */
33541
33542 }, {
33543 key: "shift",
33544 value: function shift(nodeId, diff) {
33545 this.fake_use(nodeId, diff);
33546 this.abstract();
33547 }
33548 }]);
33549
33550 return DirectionInterface;
33551 }();
33552 /**
33553 * Vertical Strategy
33554 *
33555 * Coordinate `y` is fixed on levels, coordinate `x` is unfixed.
33556 *
33557 * @augments DirectionInterface
33558 * @private
33559 */
33560
33561
33562 var VerticalStrategy = /*#__PURE__*/function (_DirectionInterface) {
33563 _inherits(VerticalStrategy, _DirectionInterface);
33564
33565 var _super = _createSuper(VerticalStrategy);
33566
33567 /**
33568 * Constructor
33569 *
33570 * @param {object} layout reference to the parent LayoutEngine instance.
33571 */
33572 function VerticalStrategy(layout) {
33573 var _this;
33574
33575 _classCallCheck(this, VerticalStrategy);
33576
33577 _this = _super.call(this);
33578 _this.layout = layout;
33579 return _this;
33580 }
33581 /** @inheritDoc */
33582
33583
33584 _createClass(VerticalStrategy, [{
33585 key: "curveType",
33586 value: function curveType() {
33587 return "horizontal";
33588 }
33589 /** @inheritDoc */
33590
33591 }, {
33592 key: "getPosition",
33593 value: function getPosition(node) {
33594 return node.x;
33595 }
33596 /** @inheritDoc */
33597
33598 }, {
33599 key: "setPosition",
33600 value: function setPosition(node, position) {
33601 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
33602
33603 if (level !== undefined) {
33604 this.layout.hierarchical.addToOrdering(node, level);
33605 }
33606
33607 node.x = position;
33608 }
33609 /** @inheritDoc */
33610
33611 }, {
33612 key: "getTreeSize",
33613 value: function getTreeSize(index) {
33614 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
33615 return {
33616 min: res.min_x,
33617 max: res.max_x
33618 };
33619 }
33620 /** @inheritDoc */
33621
33622 }, {
33623 key: "sort",
33624 value: function sort(nodeArray) {
33625 timsort.sort(nodeArray, function (a, b) {
33626 return a.x - b.x;
33627 });
33628 }
33629 /** @inheritDoc */
33630
33631 }, {
33632 key: "fix",
33633 value: function fix(node, level) {
33634 node.y = this.layout.options.hierarchical.levelSeparation * level;
33635 node.options.fixed.y = true;
33636 }
33637 /** @inheritDoc */
33638
33639 }, {
33640 key: "shift",
33641 value: function shift(nodeId, diff) {
33642 this.layout.body.nodes[nodeId].x += diff;
33643 }
33644 }]);
33645
33646 return VerticalStrategy;
33647 }(DirectionInterface);
33648 /**
33649 * Horizontal Strategy
33650 *
33651 * Coordinate `x` is fixed on levels, coordinate `y` is unfixed.
33652 *
33653 * @augments DirectionInterface
33654 * @private
33655 */
33656
33657
33658 var HorizontalStrategy = /*#__PURE__*/function (_DirectionInterface2) {
33659 _inherits(HorizontalStrategy, _DirectionInterface2);
33660
33661 var _super2 = _createSuper(HorizontalStrategy);
33662
33663 /**
33664 * Constructor
33665 *
33666 * @param {object} layout reference to the parent LayoutEngine instance.
33667 */
33668 function HorizontalStrategy(layout) {
33669 var _this2;
33670
33671 _classCallCheck(this, HorizontalStrategy);
33672
33673 _this2 = _super2.call(this);
33674 _this2.layout = layout;
33675 return _this2;
33676 }
33677 /** @inheritDoc */
33678
33679
33680 _createClass(HorizontalStrategy, [{
33681 key: "curveType",
33682 value: function curveType() {
33683 return "vertical";
33684 }
33685 /** @inheritDoc */
33686
33687 }, {
33688 key: "getPosition",
33689 value: function getPosition(node) {
33690 return node.y;
33691 }
33692 /** @inheritDoc */
33693
33694 }, {
33695 key: "setPosition",
33696 value: function setPosition(node, position) {
33697 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
33698
33699 if (level !== undefined) {
33700 this.layout.hierarchical.addToOrdering(node, level);
33701 }
33702
33703 node.y = position;
33704 }
33705 /** @inheritDoc */
33706
33707 }, {
33708 key: "getTreeSize",
33709 value: function getTreeSize(index) {
33710 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
33711 return {
33712 min: res.min_y,
33713 max: res.max_y
33714 };
33715 }
33716 /** @inheritDoc */
33717
33718 }, {
33719 key: "sort",
33720 value: function sort(nodeArray) {
33721 timsort.sort(nodeArray, function (a, b) {
33722 return a.y - b.y;
33723 });
33724 }
33725 /** @inheritDoc */
33726
33727 }, {
33728 key: "fix",
33729 value: function fix(node, level) {
33730 node.x = this.layout.options.hierarchical.levelSeparation * level;
33731 node.options.fixed.x = true;
33732 }
33733 /** @inheritDoc */
33734
33735 }, {
33736 key: "shift",
33737 value: function shift(nodeId, diff) {
33738 this.layout.body.nodes[nodeId].y += diff;
33739 }
33740 }]);
33741
33742 return HorizontalStrategy;
33743 }(DirectionInterface);
33744
33745 var $ = _export;
33746 var $every = arrayIteration.every;
33747 var arrayMethodIsStrict = arrayMethodIsStrict$6;
33748 var STRICT_METHOD = arrayMethodIsStrict('every'); // `Array.prototype.every` method
33749 // https://tc39.es/ecma262/#sec-array.prototype.every
33750
33751 $({
33752 target: 'Array',
33753 proto: true,
33754 forced: !STRICT_METHOD
33755 }, {
33756 every: function every(callbackfn
33757 /* , thisArg */
33758 ) {
33759 return $every(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
33760 }
33761 });
33762
33763 var entryVirtual = entryVirtual$i;
33764 var every$3 = entryVirtual('Array').every;
33765
33766 var every$2 = every$3;
33767 var ArrayPrototype = Array.prototype;
33768
33769 var every_1 = function (it) {
33770 var own = it.every;
33771 return it === ArrayPrototype || it instanceof Array && own === ArrayPrototype.every ? every$2 : own;
33772 };
33773
33774 var parent = every_1;
33775 var every$1 = parent;
33776
33777 var every = every$1;
33778
33779 function _createForOfIteratorHelper$1(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$1(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; } } }; }
33780
33781 function _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$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); }
33782
33783 function _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; }
33784
33785 /**
33786 * Try to assign levels to nodes according to their positions in the cyclic “hierarchy”.
33787 *
33788 * @param nodes - Visible nodes of the graph.
33789 * @param levels - If present levels will be added to it, if not a new object will be created.
33790 *
33791 * @returns Populated node levels.
33792 */
33793 function fillLevelsByDirectionCyclic(nodes, levels) {
33794 var edges = new set();
33795
33796 forEach$2(nodes).call(nodes, function (node) {
33797 var _context;
33798
33799 forEach$2(_context = node.edges).call(_context, function (edge) {
33800 if (edge.connected) {
33801 edges.add(edge);
33802 }
33803 });
33804 });
33805
33806 forEach$2(edges).call(edges, function (edge) {
33807 var fromId = edge.from.id;
33808 var toId = edge.to.id;
33809
33810 if (levels[fromId] == null) {
33811 levels[fromId] = 0;
33812 }
33813
33814 if (levels[toId] == null || levels[fromId] >= levels[toId]) {
33815 levels[toId] = levels[fromId] + 1;
33816 }
33817 });
33818
33819 return levels;
33820 }
33821 /**
33822 * 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.
33823 *
33824 * @param nodes - Visible nodes of the graph.
33825 *
33826 * @returns Populated node levels.
33827 */
33828
33829
33830 function fillLevelsByDirectionLeaves(nodes) {
33831 return fillLevelsByDirection( // Pick only leaves (nodes without children).
33832 function (node) {
33833 var _context2, _context3;
33834
33835 return every(_context2 = filter(_context3 = node.edges // Take only visible nodes into account.
33836 ).call(_context3, function (edge) {
33837 return nodes.has(edge.toId);
33838 }) // Check that all edges lead to this node (leaf).
33839 ).call(_context2, function (edge) {
33840 return edge.to === node;
33841 });
33842 }, // Use the lowest level.
33843 function (newLevel, oldLevel) {
33844 return oldLevel > newLevel;
33845 }, // Go against the direction of the edges.
33846 "from", nodes);
33847 }
33848 /**
33849 * 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.
33850 *
33851 * @param nodes - Visible nodes of the graph.
33852 *
33853 * @returns Populated node levels.
33854 */
33855
33856 function fillLevelsByDirectionRoots(nodes) {
33857 return fillLevelsByDirection( // Pick only roots (nodes without parents).
33858 function (node) {
33859 var _context4, _context5;
33860
33861 return every(_context4 = filter(_context5 = node.edges // Take only visible nodes into account.
33862 ).call(_context5, function (edge) {
33863 return nodes.has(edge.toId);
33864 }) // Check that all edges lead from this node (root).
33865 ).call(_context4, function (edge) {
33866 return edge.from === node;
33867 });
33868 }, // Use the highest level.
33869 function (newLevel, oldLevel) {
33870 return oldLevel < newLevel;
33871 }, // Go in the direction of the edges.
33872 "to", nodes);
33873 }
33874 /**
33875 * Assign levels to nodes according to their positions in the hierarchy.
33876 *
33877 * @param isEntryNode - Checks and return true if the graph should be traversed from this node.
33878 * @param shouldLevelBeReplaced - Checks and returns true if the level of given node should be updated to the new value.
33879 * @param direction - Wheter the graph should be traversed in the direction of the edges `"to"` or in the other way `"from"`.
33880 * @param nodes - Visible nodes of the graph.
33881 *
33882 * @returns Populated node levels.
33883 */
33884
33885 function fillLevelsByDirection(isEntryNode, shouldLevelBeReplaced, direction, nodes) {
33886 var _context6;
33887
33888 var levels = create$4(null); // If acyclic, the graph can be walked through with (most likely way) fewer
33889 // steps than the number bellow. The exact value isn't too important as long
33890 // as it's quick to compute (doesn't impact acyclic graphs too much), is
33891 // higher than the number of steps actually needed (doesn't cut off before
33892 // acyclic graph is walked through) and prevents infinite loops (cuts off for
33893 // cyclic graphs).
33894
33895
33896 var limit = reduce(_context6 = _toConsumableArray(values(nodes).call(nodes))).call(_context6, function (acc, node) {
33897 return acc + 1 + node.edges.length;
33898 }, 0);
33899
33900 var edgeIdProp = direction + "Id";
33901 var newLevelDiff = direction === "to" ? 1 : -1;
33902
33903 var _iterator = _createForOfIteratorHelper$1(nodes),
33904 _step;
33905
33906 try {
33907 var _loop = function _loop() {
33908 var _step$value = _slicedToArray(_step.value, 2),
33909 entryNodeId = _step$value[0],
33910 entryNode = _step$value[1];
33911
33912 if ( // Skip if the node is not visible.
33913 !nodes.has(entryNodeId) || // Skip if the node is not an entry node.
33914 !isEntryNode(entryNode)) {
33915 return "continue";
33916 } // Line up all the entry nodes on level 0.
33917
33918
33919 levels[entryNodeId] = 0;
33920 var stack = [entryNode];
33921 var done = 0;
33922 var node = void 0;
33923
33924 var _loop2 = function _loop2() {
33925 var _context7, _context8;
33926
33927 if (!nodes.has(entryNodeId)) {
33928 // Skip if the node is not visible.
33929 return "continue";
33930 }
33931
33932 var newLevel = levels[node.id] + newLevelDiff;
33933
33934 forEach$2(_context7 = filter(_context8 = node.edges).call(_context8, function (edge) {
33935 return (// Ignore disconnected edges.
33936 edge.connected && // Ignore circular edges.
33937 edge.to !== edge.from && // Ignore edges leading to the node that's currently being processed.
33938 edge[direction] !== node && // Ignore edges connecting to an invisible node.
33939 nodes.has(edge.toId) && // Ignore edges connecting from an invisible node.
33940 nodes.has(edge.fromId)
33941 );
33942 })).call(_context7, function (edge) {
33943 var targetNodeId = edge[edgeIdProp];
33944 var oldLevel = levels[targetNodeId];
33945
33946 if (oldLevel == null || shouldLevelBeReplaced(newLevel, oldLevel)) {
33947 levels[targetNodeId] = newLevel;
33948 stack.push(edge[direction]);
33949 }
33950 });
33951
33952 if (done > limit) {
33953 // This would run forever on a cyclic graph.
33954 return {
33955 v: {
33956 v: fillLevelsByDirectionCyclic(nodes, levels)
33957 }
33958 };
33959 } else {
33960 ++done;
33961 }
33962 };
33963
33964 while (node = stack.pop()) {
33965 var _ret2 = _loop2();
33966
33967 if (_ret2 === "continue") continue;
33968 if (_typeof(_ret2) === "object") return _ret2.v;
33969 }
33970 };
33971
33972 for (_iterator.s(); !(_step = _iterator.n()).done;) {
33973 var _ret = _loop();
33974
33975 if (_ret === "continue") continue;
33976 if (_typeof(_ret) === "object") return _ret.v;
33977 }
33978 } catch (err) {
33979 _iterator.e(err);
33980 } finally {
33981 _iterator.f();
33982 }
33983
33984 return levels;
33985 }
33986
33987 /**
33988 * There's a mix-up with terms in the code. Following are the formal definitions:
33989 *
33990 * tree - a strict hierarchical network, i.e. every node has at most one parent
33991 * forest - a collection of trees. These distinct trees are thus not connected.
33992 *
33993 * So:
33994 * - in a network that is not a tree, there exist nodes with multiple parents.
33995 * - a network consisting of unconnected sub-networks, of which at least one
33996 * is not a tree, is not a forest.
33997 *
33998 * In the code, the definitions are:
33999 *
34000 * tree - any disconnected sub-network, strict hierarchical or not.
34001 * forest - a bunch of these sub-networks
34002 *
34003 * The difference between tree and not-tree is important in the code, notably within
34004 * to the block-shifting algorithm. The algorithm assumes formal trees and fails
34005 * for not-trees, often in a spectacular manner (search for 'exploding network' in the issues).
34006 *
34007 * In order to distinguish the definitions in the following code, the adjective 'formal' is
34008 * used. If 'formal' is absent, you must assume the non-formal definition.
34009 *
34010 * ----------------------------------------------------------------------------------
34011 * NOTES
34012 * =====
34013 *
34014 * A hierarchical layout is a different thing from a hierarchical network.
34015 * The layout is a way to arrange the nodes in the view; this can be done
34016 * on non-hierarchical networks as well. The converse is also possible.
34017 */
34018 /**
34019 * Container for derived data on current network, relating to hierarchy.
34020 *
34021 * @private
34022 */
34023
34024 var HierarchicalStatus = /*#__PURE__*/function () {
34025 /**
34026 * @ignore
34027 */
34028 function HierarchicalStatus() {
34029 _classCallCheck(this, HierarchicalStatus);
34030
34031 this.childrenReference = {}; // child id's per node id
34032
34033 this.parentReference = {}; // parent id's per node id
34034
34035 this.trees = {}; // tree id per node id; i.e. to which tree does given node id belong
34036
34037 this.distributionOrdering = {}; // The nodes per level, in the display order
34038
34039 this.levels = {}; // hierarchy level per node id
34040
34041 this.distributionIndex = {}; // The position of the node in the level sorting order, per node id.
34042
34043 this.isTree = false; // True if current network is a formal tree
34044
34045 this.treeIndex = -1; // Highest tree id in current network.
34046 }
34047 /**
34048 * Add the relation between given nodes to the current state.
34049 *
34050 * @param {Node.id} parentNodeId
34051 * @param {Node.id} childNodeId
34052 */
34053
34054
34055 _createClass(HierarchicalStatus, [{
34056 key: "addRelation",
34057 value: function addRelation(parentNodeId, childNodeId) {
34058 if (this.childrenReference[parentNodeId] === undefined) {
34059 this.childrenReference[parentNodeId] = [];
34060 }
34061
34062 this.childrenReference[parentNodeId].push(childNodeId);
34063
34064 if (this.parentReference[childNodeId] === undefined) {
34065 this.parentReference[childNodeId] = [];
34066 }
34067
34068 this.parentReference[childNodeId].push(parentNodeId);
34069 }
34070 /**
34071 * Check if the current state is for a formal tree or formal forest.
34072 *
34073 * This is the case if every node has at most one parent.
34074 *
34075 * Pre: parentReference init'ed properly for current network
34076 */
34077
34078 }, {
34079 key: "checkIfTree",
34080 value: function checkIfTree() {
34081 for (var i in this.parentReference) {
34082 if (this.parentReference[i].length > 1) {
34083 this.isTree = false;
34084 return;
34085 }
34086 }
34087
34088 this.isTree = true;
34089 }
34090 /**
34091 * Return the number of separate trees in the current network.
34092 *
34093 * @returns {number}
34094 */
34095
34096 }, {
34097 key: "numTrees",
34098 value: function numTrees() {
34099 return this.treeIndex + 1; // This assumes the indexes are assigned consecitively
34100 }
34101 /**
34102 * Assign a tree id to a node
34103 *
34104 * @param {Node} node
34105 * @param {string|number} treeId
34106 */
34107
34108 }, {
34109 key: "setTreeIndex",
34110 value: function setTreeIndex(node, treeId) {
34111 if (treeId === undefined) return; // Don't bother
34112
34113 if (this.trees[node.id] === undefined) {
34114 this.trees[node.id] = treeId;
34115 this.treeIndex = Math.max(treeId, this.treeIndex);
34116 }
34117 }
34118 /**
34119 * Ensure level for given id is defined.
34120 *
34121 * Sets level to zero for given node id if not already present
34122 *
34123 * @param {Node.id} nodeId
34124 */
34125
34126 }, {
34127 key: "ensureLevel",
34128 value: function ensureLevel(nodeId) {
34129 if (this.levels[nodeId] === undefined) {
34130 this.levels[nodeId] = 0;
34131 }
34132 }
34133 /**
34134 * get the maximum level of a branch.
34135 *
34136 * TODO: Never entered; find a test case to test this!
34137 *
34138 * @param {Node.id} nodeId
34139 * @returns {number}
34140 */
34141
34142 }, {
34143 key: "getMaxLevel",
34144 value: function getMaxLevel(nodeId) {
34145 var _this = this;
34146
34147 var accumulator = {};
34148
34149 var _getMaxLevel = function _getMaxLevel(nodeId) {
34150 if (accumulator[nodeId] !== undefined) {
34151 return accumulator[nodeId];
34152 }
34153
34154 var level = _this.levels[nodeId];
34155
34156 if (_this.childrenReference[nodeId]) {
34157 var children = _this.childrenReference[nodeId];
34158
34159 if (children.length > 0) {
34160 for (var i = 0; i < children.length; i++) {
34161 level = Math.max(level, _getMaxLevel(children[i]));
34162 }
34163 }
34164 }
34165
34166 accumulator[nodeId] = level;
34167 return level;
34168 };
34169
34170 return _getMaxLevel(nodeId);
34171 }
34172 /**
34173 *
34174 * @param {Node} nodeA
34175 * @param {Node} nodeB
34176 */
34177
34178 }, {
34179 key: "levelDownstream",
34180 value: function levelDownstream(nodeA, nodeB) {
34181 if (this.levels[nodeB.id] === undefined) {
34182 // set initial level
34183 if (this.levels[nodeA.id] === undefined) {
34184 this.levels[nodeA.id] = 0;
34185 } // set level
34186
34187
34188 this.levels[nodeB.id] = this.levels[nodeA.id] + 1;
34189 }
34190 }
34191 /**
34192 * Small util method to set the minimum levels of the nodes to zero.
34193 *
34194 * @param {Array.<Node>} nodes
34195 */
34196
34197 }, {
34198 key: "setMinLevelToZero",
34199 value: function setMinLevelToZero(nodes) {
34200 var minLevel = 1e9; // get the minimum level
34201
34202 for (var nodeId in nodes) {
34203 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
34204 if (this.levels[nodeId] !== undefined) {
34205 minLevel = Math.min(this.levels[nodeId], minLevel);
34206 }
34207 }
34208 } // subtract the minimum from the set so we have a range starting from 0
34209
34210
34211 for (var _nodeId in nodes) {
34212 if (Object.prototype.hasOwnProperty.call(nodes, _nodeId)) {
34213 if (this.levels[_nodeId] !== undefined) {
34214 this.levels[_nodeId] -= minLevel;
34215 }
34216 }
34217 }
34218 }
34219 /**
34220 * Get the min and max xy-coordinates of a given tree
34221 *
34222 * @param {Array.<Node>} nodes
34223 * @param {number} index
34224 * @returns {{min_x: number, max_x: number, min_y: number, max_y: number}}
34225 */
34226
34227 }, {
34228 key: "getTreeSize",
34229 value: function getTreeSize(nodes, index) {
34230 var min_x = 1e9;
34231 var max_x = -1e9;
34232 var min_y = 1e9;
34233 var max_y = -1e9;
34234
34235 for (var nodeId in this.trees) {
34236 if (Object.prototype.hasOwnProperty.call(this.trees, nodeId)) {
34237 if (this.trees[nodeId] === index) {
34238 var node = nodes[nodeId];
34239 min_x = Math.min(node.x, min_x);
34240 max_x = Math.max(node.x, max_x);
34241 min_y = Math.min(node.y, min_y);
34242 max_y = Math.max(node.y, max_y);
34243 }
34244 }
34245 }
34246
34247 return {
34248 min_x: min_x,
34249 max_x: max_x,
34250 min_y: min_y,
34251 max_y: max_y
34252 };
34253 }
34254 /**
34255 * Check if two nodes have the same parent(s)
34256 *
34257 * @param {Node} node1
34258 * @param {Node} node2
34259 * @returns {boolean} true if the two nodes have a same ancestor node, false otherwise
34260 */
34261
34262 }, {
34263 key: "hasSameParent",
34264 value: function hasSameParent(node1, node2) {
34265 var parents1 = this.parentReference[node1.id];
34266 var parents2 = this.parentReference[node2.id];
34267
34268 if (parents1 === undefined || parents2 === undefined) {
34269 return false;
34270 }
34271
34272 for (var i = 0; i < parents1.length; i++) {
34273 for (var j = 0; j < parents2.length; j++) {
34274 if (parents1[i] == parents2[j]) {
34275 return true;
34276 }
34277 }
34278 }
34279
34280 return false;
34281 }
34282 /**
34283 * Check if two nodes are in the same tree.
34284 *
34285 * @param {Node} node1
34286 * @param {Node} node2
34287 * @returns {boolean} true if this is so, false otherwise
34288 */
34289
34290 }, {
34291 key: "inSameSubNetwork",
34292 value: function inSameSubNetwork(node1, node2) {
34293 return this.trees[node1.id] === this.trees[node2.id];
34294 }
34295 /**
34296 * Get a list of the distinct levels in the current network
34297 *
34298 * @returns {Array}
34299 */
34300
34301 }, {
34302 key: "getLevels",
34303 value: function getLevels() {
34304 return keys(this.distributionOrdering);
34305 }
34306 /**
34307 * Add a node to the ordering per level
34308 *
34309 * @param {Node} node
34310 * @param {number} level
34311 */
34312
34313 }, {
34314 key: "addToOrdering",
34315 value: function addToOrdering(node, level) {
34316 if (this.distributionOrdering[level] === undefined) {
34317 this.distributionOrdering[level] = [];
34318 }
34319
34320 var isPresent = false;
34321 var curLevel = this.distributionOrdering[level];
34322
34323 for (var n in curLevel) {
34324 //if (curLevel[n].id === node.id) {
34325 if (curLevel[n] === node) {
34326 isPresent = true;
34327 break;
34328 }
34329 }
34330
34331 if (!isPresent) {
34332 this.distributionOrdering[level].push(node);
34333 this.distributionIndex[node.id] = this.distributionOrdering[level].length - 1;
34334 }
34335 }
34336 }]);
34337
34338 return HierarchicalStatus;
34339 }();
34340 /**
34341 * The Layout Engine
34342 */
34343
34344
34345 var LayoutEngine = /*#__PURE__*/function () {
34346 /**
34347 * @param {object} body
34348 */
34349 function LayoutEngine(body) {
34350 _classCallCheck(this, LayoutEngine);
34351
34352 this.body = body; // Make sure there always is some RNG because the setOptions method won't
34353 // set it unless there's a seed for it.
34354
34355 this._resetRNG(Math.random() + ":" + now$1());
34356
34357 this.setPhysics = false;
34358 this.options = {};
34359 this.optionsBackup = {
34360 physics: {}
34361 };
34362 this.defaultOptions = {
34363 randomSeed: undefined,
34364 improvedLayout: true,
34365 clusterThreshold: 150,
34366 hierarchical: {
34367 enabled: false,
34368 levelSeparation: 150,
34369 nodeSpacing: 100,
34370 treeSpacing: 200,
34371 blockShifting: true,
34372 edgeMinimization: true,
34373 parentCentralization: true,
34374 direction: "UD",
34375 // UD, DU, LR, RL
34376 sortMethod: "hubsize" // hubsize, directed
34377
34378 }
34379 };
34380
34381 assign$2(this.options, this.defaultOptions);
34382
34383 this.bindEventListeners();
34384 }
34385 /**
34386 * Binds event listeners
34387 */
34388
34389
34390 _createClass(LayoutEngine, [{
34391 key: "bindEventListeners",
34392 value: function bindEventListeners() {
34393 var _this2 = this;
34394
34395 this.body.emitter.on("_dataChanged", function () {
34396 _this2.setupHierarchicalLayout();
34397 });
34398 this.body.emitter.on("_dataLoaded", function () {
34399 _this2.layoutNetwork();
34400 });
34401 this.body.emitter.on("_resetHierarchicalLayout", function () {
34402 _this2.setupHierarchicalLayout();
34403 });
34404 this.body.emitter.on("_adjustEdgesForHierarchicalLayout", function () {
34405 if (_this2.options.hierarchical.enabled !== true) {
34406 return;
34407 } // get the type of static smooth curve in case it is required
34408
34409
34410 var type = _this2.direction.curveType(); // force all edges into static smooth curves.
34411
34412
34413 _this2.body.emitter.emit("_forceDisableDynamicCurves", type, false);
34414 });
34415 }
34416 /**
34417 *
34418 * @param {object} options
34419 * @param {object} allOptions
34420 * @returns {object}
34421 */
34422
34423 }, {
34424 key: "setOptions",
34425 value: function setOptions(options, allOptions) {
34426 if (options !== undefined) {
34427 var hierarchical = this.options.hierarchical;
34428 var prevHierarchicalState = hierarchical.enabled;
34429 selectiveDeepExtend(["randomSeed", "improvedLayout", "clusterThreshold"], this.options, options);
34430 mergeOptions(this.options, options, "hierarchical");
34431
34432 if (options.randomSeed !== undefined) {
34433 this._resetRNG(options.randomSeed);
34434 }
34435
34436 if (hierarchical.enabled === true) {
34437 if (prevHierarchicalState === true) {
34438 // refresh the overridden options for nodes and edges.
34439 this.body.emitter.emit("refresh", true);
34440 } // make sure the level separation is the right way up
34441
34442
34443 if (hierarchical.direction === "RL" || hierarchical.direction === "DU") {
34444 if (hierarchical.levelSeparation > 0) {
34445 hierarchical.levelSeparation *= -1;
34446 }
34447 } else {
34448 if (hierarchical.levelSeparation < 0) {
34449 hierarchical.levelSeparation *= -1;
34450 }
34451 }
34452
34453 this.setDirectionStrategy();
34454 this.body.emitter.emit("_resetHierarchicalLayout"); // because the hierarchical system needs it's own physics and smooth curve settings,
34455 // we adapt the other options if needed.
34456
34457 return this.adaptAllOptionsForHierarchicalLayout(allOptions);
34458 } else {
34459 if (prevHierarchicalState === true) {
34460 // refresh the overridden options for nodes and edges.
34461 this.body.emitter.emit("refresh");
34462 return deepExtend(allOptions, this.optionsBackup);
34463 }
34464 }
34465 }
34466
34467 return allOptions;
34468 }
34469 /**
34470 * Reset the random number generator with given seed.
34471 *
34472 * @param {any} seed - The seed that will be forwarded the the RNG.
34473 */
34474
34475 }, {
34476 key: "_resetRNG",
34477 value: function _resetRNG(seed) {
34478 this.initialRandomSeed = seed;
34479 this._rng = Alea(this.initialRandomSeed);
34480 }
34481 /**
34482 *
34483 * @param {object} allOptions
34484 * @returns {object}
34485 */
34486
34487 }, {
34488 key: "adaptAllOptionsForHierarchicalLayout",
34489 value: function adaptAllOptionsForHierarchicalLayout(allOptions) {
34490 if (this.options.hierarchical.enabled === true) {
34491 var backupPhysics = this.optionsBackup.physics; // set the physics
34492
34493 if (allOptions.physics === undefined || allOptions.physics === true) {
34494 allOptions.physics = {
34495 enabled: backupPhysics.enabled === undefined ? true : backupPhysics.enabled,
34496 solver: "hierarchicalRepulsion"
34497 };
34498 backupPhysics.enabled = backupPhysics.enabled === undefined ? true : backupPhysics.enabled;
34499 backupPhysics.solver = backupPhysics.solver || "barnesHut";
34500 } else if (_typeof(allOptions.physics) === "object") {
34501 backupPhysics.enabled = allOptions.physics.enabled === undefined ? true : allOptions.physics.enabled;
34502 backupPhysics.solver = allOptions.physics.solver || "barnesHut";
34503 allOptions.physics.solver = "hierarchicalRepulsion";
34504 } else if (allOptions.physics !== false) {
34505 backupPhysics.solver = "barnesHut";
34506 allOptions.physics = {
34507 solver: "hierarchicalRepulsion"
34508 };
34509 } // get the type of static smooth curve in case it is required
34510
34511
34512 var type = this.direction.curveType(); // disable smooth curves if nothing is defined. If smooth curves have been turned on,
34513 // turn them into static smooth curves.
34514
34515 if (allOptions.edges === undefined) {
34516 this.optionsBackup.edges = {
34517 smooth: {
34518 enabled: true,
34519 type: "dynamic"
34520 }
34521 };
34522 allOptions.edges = {
34523 smooth: false
34524 };
34525 } else if (allOptions.edges.smooth === undefined) {
34526 this.optionsBackup.edges = {
34527 smooth: {
34528 enabled: true,
34529 type: "dynamic"
34530 }
34531 };
34532 allOptions.edges.smooth = false;
34533 } else {
34534 if (typeof allOptions.edges.smooth === "boolean") {
34535 this.optionsBackup.edges = {
34536 smooth: allOptions.edges.smooth
34537 };
34538 allOptions.edges.smooth = {
34539 enabled: allOptions.edges.smooth,
34540 type: type
34541 };
34542 } else {
34543 var smooth = allOptions.edges.smooth; // allow custom types except for dynamic
34544
34545 if (smooth.type !== undefined && smooth.type !== "dynamic") {
34546 type = smooth.type;
34547 } // TODO: this is options merging; see if the standard routines can be used here.
34548
34549
34550 this.optionsBackup.edges = {
34551 smooth: {
34552 enabled: smooth.enabled === undefined ? true : smooth.enabled,
34553 type: smooth.type === undefined ? "dynamic" : smooth.type,
34554 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
34555 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
34556 }
34557 }; // NOTE: Copying an object to self; this is basically setting defaults for undefined variables
34558
34559 allOptions.edges.smooth = {
34560 enabled: smooth.enabled === undefined ? true : smooth.enabled,
34561 type: type,
34562 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
34563 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
34564 };
34565 }
34566 } // Force all edges into static smooth curves.
34567 // Only applies to edges that do not use the global options for smooth.
34568
34569
34570 this.body.emitter.emit("_forceDisableDynamicCurves", type);
34571 }
34572
34573 return allOptions;
34574 }
34575 /**
34576 *
34577 * @param {Array.<Node>} nodesArray
34578 */
34579
34580 }, {
34581 key: "positionInitially",
34582 value: function positionInitially(nodesArray) {
34583 if (this.options.hierarchical.enabled !== true) {
34584 this._resetRNG(this.initialRandomSeed);
34585
34586 var radius = nodesArray.length + 50;
34587
34588 for (var i = 0; i < nodesArray.length; i++) {
34589 var node = nodesArray[i];
34590
34591 var angle = 2 * Math.PI * this._rng();
34592
34593 if (node.x === undefined) {
34594 node.x = radius * Math.cos(angle);
34595 }
34596
34597 if (node.y === undefined) {
34598 node.y = radius * Math.sin(angle);
34599 }
34600 }
34601 }
34602 }
34603 /**
34604 * Use Kamada Kawai to position nodes. This is quite a heavy algorithm so if there are a lot of nodes we
34605 * cluster them first to reduce the amount.
34606 */
34607
34608 }, {
34609 key: "layoutNetwork",
34610 value: function layoutNetwork() {
34611 if (this.options.hierarchical.enabled !== true && this.options.improvedLayout === true) {
34612 var indices = this.body.nodeIndices; // first check if we should Kamada Kawai to layout. The threshold is if less than half of the visible
34613 // nodes have predefined positions we use this.
34614
34615 var positionDefined = 0;
34616
34617 for (var i = 0; i < indices.length; i++) {
34618 var node = this.body.nodes[indices[i]];
34619
34620 if (node.predefinedPosition === true) {
34621 positionDefined += 1;
34622 }
34623 } // if less than half of the nodes have a predefined position we continue
34624
34625
34626 if (positionDefined < 0.5 * indices.length) {
34627 var MAX_LEVELS = 10;
34628 var level = 0;
34629 var clusterThreshold = this.options.clusterThreshold; //
34630 // Define the options for the hidden cluster nodes
34631 // These options don't propagate outside the clustering phase.
34632 //
34633 // Some options are explicitly disabled, because they may be set in group or default node options.
34634 // The clusters are never displayed, so most explicit settings here serve as performance optimizations.
34635 //
34636 // The explicit setting of 'shape' is to avoid `shape: 'image'`; images are not passed to the hidden
34637 // cluster nodes, leading to an exception on creation.
34638 //
34639 // All settings here are performance related, except when noted otherwise.
34640 //
34641
34642 var clusterOptions = {
34643 clusterNodeProperties: {
34644 shape: "ellipse",
34645 // Bugfix: avoid type 'image', no images supplied
34646 label: "",
34647 // avoid label handling
34648 group: "",
34649 // avoid group handling
34650 font: {
34651 multi: false
34652 } // avoid font propagation
34653
34654 },
34655 clusterEdgeProperties: {
34656 label: "",
34657 // avoid label handling
34658 font: {
34659 multi: false
34660 },
34661 // avoid font propagation
34662 smooth: {
34663 enabled: false // avoid drawing penalty for complex edges
34664
34665 }
34666 }
34667 }; // if there are a lot of nodes, we cluster before we run the algorithm.
34668 // NOTE: this part fails to find clusters for large scale-free networks, which should
34669 // be easily clusterable.
34670 // TODO: examine why this is so
34671
34672 if (indices.length > clusterThreshold) {
34673 var startLength = indices.length;
34674
34675 while (indices.length > clusterThreshold && level <= MAX_LEVELS) {
34676 //console.time("clustering")
34677 level += 1;
34678 var before = indices.length; // if there are many nodes we do a hubsize cluster
34679
34680 if (level % 3 === 0) {
34681 this.body.modules.clustering.clusterBridges(clusterOptions);
34682 } else {
34683 this.body.modules.clustering.clusterOutliers(clusterOptions);
34684 }
34685
34686 var after = indices.length;
34687
34688 if (before == after && level % 3 !== 0) {
34689 this._declusterAll();
34690
34691 this.body.emitter.emit("_layoutFailed");
34692 console.info("This network could not be positioned by this version of the improved layout algorithm." + " Please disable improvedLayout for better performance.");
34693 return;
34694 } //console.timeEnd("clustering")
34695 //console.log(before,level,after);
34696
34697 } // increase the size of the edges
34698
34699
34700 this.body.modules.kamadaKawai.setOptions({
34701 springLength: Math.max(150, 2 * startLength)
34702 });
34703 }
34704
34705 if (level > MAX_LEVELS) {
34706 console.info("The clustering didn't succeed within the amount of interations allowed," + " progressing with partial result.");
34707 } // position the system for these nodes and edges
34708
34709
34710 this.body.modules.kamadaKawai.solve(indices, this.body.edgeIndices, true); // shift to center point
34711
34712 this._shiftToCenter(); // perturb the nodes a little bit to force the physics to kick in
34713
34714
34715 var offset = 70;
34716
34717 for (var _i = 0; _i < indices.length; _i++) {
34718 // Only perturb the nodes that aren't fixed
34719 var _node = this.body.nodes[indices[_i]];
34720
34721 if (_node.predefinedPosition === false) {
34722 _node.x += (0.5 - this._rng()) * offset;
34723 _node.y += (0.5 - this._rng()) * offset;
34724 }
34725 } // uncluster all clusters
34726
34727
34728 this._declusterAll(); // reposition all bezier nodes.
34729
34730
34731 this.body.emitter.emit("_repositionBezierNodes");
34732 }
34733 }
34734 }
34735 /**
34736 * Move all the nodes towards to the center so gravitational pull wil not move the nodes away from view
34737 *
34738 * @private
34739 */
34740
34741 }, {
34742 key: "_shiftToCenter",
34743 value: function _shiftToCenter() {
34744 var range = NetworkUtil.getRangeCore(this.body.nodes, this.body.nodeIndices);
34745 var center = NetworkUtil.findCenter(range);
34746
34747 for (var i = 0; i < this.body.nodeIndices.length; i++) {
34748 var node = this.body.nodes[this.body.nodeIndices[i]];
34749 node.x -= center.x;
34750 node.y -= center.y;
34751 }
34752 }
34753 /**
34754 * Expands all clusters
34755 *
34756 * @private
34757 */
34758
34759 }, {
34760 key: "_declusterAll",
34761 value: function _declusterAll() {
34762 var clustersPresent = true;
34763
34764 while (clustersPresent === true) {
34765 clustersPresent = false;
34766
34767 for (var i = 0; i < this.body.nodeIndices.length; i++) {
34768 if (this.body.nodes[this.body.nodeIndices[i]].isCluster === true) {
34769 clustersPresent = true;
34770 this.body.modules.clustering.openCluster(this.body.nodeIndices[i], {}, false);
34771 }
34772 }
34773
34774 if (clustersPresent === true) {
34775 this.body.emitter.emit("_dataChanged");
34776 }
34777 }
34778 }
34779 /**
34780 *
34781 * @returns {number|*}
34782 */
34783
34784 }, {
34785 key: "getSeed",
34786 value: function getSeed() {
34787 return this.initialRandomSeed;
34788 }
34789 /**
34790 * This is the main function to layout the nodes in a hierarchical way.
34791 * It checks if the node details are supplied correctly
34792 *
34793 * @private
34794 */
34795
34796 }, {
34797 key: "setupHierarchicalLayout",
34798 value: function setupHierarchicalLayout() {
34799 if (this.options.hierarchical.enabled === true && this.body.nodeIndices.length > 0) {
34800 // get the size of the largest hubs and check if the user has defined a level for a node.
34801 var node, nodeId;
34802 var definedLevel = false;
34803 var undefinedLevel = false;
34804 this.lastNodeOnLevel = {};
34805 this.hierarchical = new HierarchicalStatus();
34806
34807 for (nodeId in this.body.nodes) {
34808 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
34809 node = this.body.nodes[nodeId];
34810
34811 if (node.options.level !== undefined) {
34812 definedLevel = true;
34813 this.hierarchical.levels[nodeId] = node.options.level;
34814 } else {
34815 undefinedLevel = true;
34816 }
34817 }
34818 } // if the user defined some levels but not all, alert and run without hierarchical layout
34819
34820
34821 if (undefinedLevel === true && definedLevel === true) {
34822 throw new Error("To use the hierarchical layout, nodes require either no predefined levels" + " or levels have to be defined for all nodes.");
34823 } else {
34824 // define levels if undefined by the users. Based on hubsize.
34825 if (undefinedLevel === true) {
34826 var sortMethod = this.options.hierarchical.sortMethod;
34827
34828 if (sortMethod === "hubsize") {
34829 this._determineLevelsByHubsize();
34830 } else if (sortMethod === "directed") {
34831 this._determineLevelsDirected();
34832 } else if (sortMethod === "custom") {
34833 this._determineLevelsCustomCallback();
34834 }
34835 } // fallback for cases where there are nodes but no edges
34836
34837
34838 for (var _nodeId2 in this.body.nodes) {
34839 if (Object.prototype.hasOwnProperty.call(this.body.nodes, _nodeId2)) {
34840 this.hierarchical.ensureLevel(_nodeId2);
34841 }
34842 } // check the distribution of the nodes per level.
34843
34844
34845 var distribution = this._getDistribution(); // get the parent children relations.
34846
34847
34848 this._generateMap(); // place the nodes on the canvas.
34849
34850
34851 this._placeNodesByHierarchy(distribution); // condense the whitespace.
34852
34853
34854 this._condenseHierarchy(); // shift to center so gravity does not have to do much
34855
34856
34857 this._shiftToCenter();
34858 }
34859 }
34860 }
34861 /**
34862 * @private
34863 */
34864
34865 }, {
34866 key: "_condenseHierarchy",
34867 value: function _condenseHierarchy() {
34868 var _this3 = this;
34869
34870 // Global var in this scope to define when the movement has stopped.
34871 var stillShifting = false;
34872 var branches = {}; // first we have some methods to help shifting trees around.
34873 // the main method to shift the trees
34874
34875 var shiftTrees = function shiftTrees() {
34876 var treeSizes = getTreeSizes();
34877 var shiftBy = 0;
34878
34879 for (var i = 0; i < treeSizes.length - 1; i++) {
34880 var diff = treeSizes[i].max - treeSizes[i + 1].min;
34881 shiftBy += diff + _this3.options.hierarchical.treeSpacing;
34882 shiftTree(i + 1, shiftBy);
34883 }
34884 }; // shift a single tree by an offset
34885
34886
34887 var shiftTree = function shiftTree(index, offset) {
34888 var trees = _this3.hierarchical.trees;
34889
34890 for (var nodeId in trees) {
34891 if (Object.prototype.hasOwnProperty.call(trees, nodeId)) {
34892 if (trees[nodeId] === index) {
34893 _this3.direction.shift(nodeId, offset);
34894 }
34895 }
34896 }
34897 }; // get the width of all trees
34898
34899
34900 var getTreeSizes = function getTreeSizes() {
34901 var treeWidths = [];
34902
34903 for (var i = 0; i < _this3.hierarchical.numTrees(); i++) {
34904 treeWidths.push(_this3.direction.getTreeSize(i));
34905 }
34906
34907 return treeWidths;
34908 }; // get a map of all nodes in this branch
34909
34910
34911 var getBranchNodes = function getBranchNodes(source, map) {
34912 if (map[source.id]) {
34913 return;
34914 }
34915
34916 map[source.id] = true;
34917
34918 if (_this3.hierarchical.childrenReference[source.id]) {
34919 var children = _this3.hierarchical.childrenReference[source.id];
34920
34921 if (children.length > 0) {
34922 for (var i = 0; i < children.length; i++) {
34923 getBranchNodes(_this3.body.nodes[children[i]], map);
34924 }
34925 }
34926 }
34927 }; // get a min max width as well as the maximum movement space it has on either sides
34928 // we use min max terminology because width and height can interchange depending on the direction of the layout
34929
34930
34931 var getBranchBoundary = function getBranchBoundary(branchMap) {
34932 var maxLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1e9;
34933 var minSpace = 1e9;
34934 var maxSpace = 1e9;
34935 var min = 1e9;
34936 var max = -1e9;
34937
34938 for (var branchNode in branchMap) {
34939 if (Object.prototype.hasOwnProperty.call(branchMap, branchNode)) {
34940 var node = _this3.body.nodes[branchNode];
34941 var level = _this3.hierarchical.levels[node.id];
34942
34943 var position = _this3.direction.getPosition(node); // get the space around the node.
34944
34945
34946 var _this3$_getSpaceAroun = _this3._getSpaceAroundNode(node, branchMap),
34947 _this3$_getSpaceAroun2 = _slicedToArray(_this3$_getSpaceAroun, 2),
34948 minSpaceNode = _this3$_getSpaceAroun2[0],
34949 maxSpaceNode = _this3$_getSpaceAroun2[1];
34950
34951 minSpace = Math.min(minSpaceNode, minSpace);
34952 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.
34953
34954 if (level <= maxLevel) {
34955 min = Math.min(position, min);
34956 max = Math.max(position, max);
34957 }
34958 }
34959 }
34960
34961 return [min, max, minSpace, maxSpace];
34962 }; // check what the maximum level is these nodes have in common.
34963
34964
34965 var getCollisionLevel = function getCollisionLevel(node1, node2) {
34966 var maxLevel1 = _this3.hierarchical.getMaxLevel(node1.id);
34967
34968 var maxLevel2 = _this3.hierarchical.getMaxLevel(node2.id);
34969
34970 return Math.min(maxLevel1, maxLevel2);
34971 };
34972 /**
34973 * Condense elements. These can be nodes or branches depending on the callback.
34974 *
34975 * @param {Function} callback
34976 * @param {Array.<number>} levels
34977 * @param {*} centerParents
34978 */
34979
34980
34981 var shiftElementsCloser = function shiftElementsCloser(callback, levels, centerParents) {
34982 var hier = _this3.hierarchical;
34983
34984 for (var i = 0; i < levels.length; i++) {
34985 var level = levels[i];
34986 var levelNodes = hier.distributionOrdering[level];
34987
34988 if (levelNodes.length > 1) {
34989 for (var j = 0; j < levelNodes.length - 1; j++) {
34990 var node1 = levelNodes[j];
34991 var node2 = levelNodes[j + 1]; // NOTE: logic maintained as it was; if nodes have same ancestor,
34992 // then of course they are in the same sub-network.
34993
34994 if (hier.hasSameParent(node1, node2) && hier.inSameSubNetwork(node1, node2)) {
34995 callback(node1, node2, centerParents);
34996 }
34997 }
34998 }
34999 }
35000 }; // callback for shifting branches
35001
35002
35003 var branchShiftCallback = function branchShiftCallback(node1, node2) {
35004 var centerParent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
35005
35006 //window.CALLBACKS.push(() => {
35007 var pos1 = _this3.direction.getPosition(node1);
35008
35009 var pos2 = _this3.direction.getPosition(node2);
35010
35011 var diffAbs = Math.abs(pos2 - pos1);
35012 var nodeSpacing = _this3.options.hierarchical.nodeSpacing; //console.log("NOW CHECKING:", node1.id, node2.id, diffAbs);
35013
35014 if (diffAbs > nodeSpacing) {
35015 var branchNodes1 = {};
35016 var branchNodes2 = {};
35017 getBranchNodes(node1, branchNodes1);
35018 getBranchNodes(node2, branchNodes2); // check the largest distance between the branches
35019
35020 var maxLevel = getCollisionLevel(node1, node2);
35021 var branchNodeBoundary1 = getBranchBoundary(branchNodes1, maxLevel);
35022 var branchNodeBoundary2 = getBranchBoundary(branchNodes2, maxLevel);
35023 var max1 = branchNodeBoundary1[1];
35024 var min2 = branchNodeBoundary2[0];
35025 var minSpace2 = branchNodeBoundary2[2]; //console.log(node1.id, getBranchBoundary(branchNodes1, maxLevel), node2.id,
35026 // getBranchBoundary(branchNodes2, maxLevel), maxLevel);
35027
35028 var diffBranch = Math.abs(max1 - min2);
35029
35030 if (diffBranch > nodeSpacing) {
35031 var offset = max1 - min2 + nodeSpacing;
35032
35033 if (offset < -minSpace2 + nodeSpacing) {
35034 offset = -minSpace2 + nodeSpacing; //console.log("RESETTING OFFSET", max1 - min2 + this.options.hierarchical.nodeSpacing, -minSpace2, offset);
35035 }
35036
35037 if (offset < 0) {
35038 //console.log("SHIFTING", node2.id, offset);
35039 _this3._shiftBlock(node2.id, offset);
35040
35041 stillShifting = true;
35042 if (centerParent === true) _this3._centerParent(node2);
35043 }
35044 }
35045 } //this.body.emitter.emit("_redraw");})
35046
35047 };
35048
35049 var minimizeEdgeLength = function minimizeEdgeLength(iterations, node) {
35050 //window.CALLBACKS.push(() => {
35051 // console.log("ts",node.id);
35052 var nodeId = node.id;
35053 var allEdges = node.edges;
35054 var nodeLevel = _this3.hierarchical.levels[node.id]; // gather constants
35055
35056 var C2 = _this3.options.hierarchical.levelSeparation * _this3.options.hierarchical.levelSeparation;
35057 var referenceNodes = {};
35058 var aboveEdges = [];
35059
35060 for (var i = 0; i < allEdges.length; i++) {
35061 var edge = allEdges[i];
35062
35063 if (edge.toId != edge.fromId) {
35064 var otherNode = edge.toId == nodeId ? edge.from : edge.to;
35065 referenceNodes[allEdges[i].id] = otherNode;
35066
35067 if (_this3.hierarchical.levels[otherNode.id] < nodeLevel) {
35068 aboveEdges.push(edge);
35069 }
35070 }
35071 } // differentiated sum of lengths based on only moving one node over one axis
35072
35073
35074 var getFx = function getFx(point, edges) {
35075 var sum = 0;
35076
35077 for (var _i2 = 0; _i2 < edges.length; _i2++) {
35078 if (referenceNodes[edges[_i2].id] !== undefined) {
35079 var a = _this3.direction.getPosition(referenceNodes[edges[_i2].id]) - point;
35080 sum += a / Math.sqrt(a * a + C2);
35081 }
35082 }
35083
35084 return sum;
35085 }; // doubly differentiated sum of lengths based on only moving one node over one axis
35086
35087
35088 var getDFx = function getDFx(point, edges) {
35089 var sum = 0;
35090
35091 for (var _i3 = 0; _i3 < edges.length; _i3++) {
35092 if (referenceNodes[edges[_i3].id] !== undefined) {
35093 var a = _this3.direction.getPosition(referenceNodes[edges[_i3].id]) - point;
35094 sum -= C2 * Math.pow(a * a + C2, -1.5);
35095 }
35096 }
35097
35098 return sum;
35099 };
35100
35101 var getGuess = function getGuess(iterations, edges) {
35102 var guess = _this3.direction.getPosition(node); // Newton's method for optimization
35103
35104
35105 var guessMap = {};
35106
35107 for (var _i4 = 0; _i4 < iterations; _i4++) {
35108 var fx = getFx(guess, edges);
35109 var dfx = getDFx(guess, edges); // we limit the movement to avoid instability.
35110
35111 var limit = 40;
35112 var ratio = Math.max(-limit, Math.min(limit, Math.round(fx / dfx)));
35113 guess = guess - ratio; // reduce duplicates
35114
35115 if (guessMap[guess] !== undefined) {
35116 break;
35117 }
35118
35119 guessMap[guess] = _i4;
35120 }
35121
35122 return guess;
35123 };
35124
35125 var moveBranch = function moveBranch(guess) {
35126 // position node if there is space
35127 var nodePosition = _this3.direction.getPosition(node); // check movable area of the branch
35128
35129
35130 if (branches[node.id] === undefined) {
35131 var branchNodes = {};
35132 getBranchNodes(node, branchNodes);
35133 branches[node.id] = branchNodes;
35134 }
35135
35136 var branchBoundary = getBranchBoundary(branches[node.id]);
35137 var minSpaceBranch = branchBoundary[2];
35138 var maxSpaceBranch = branchBoundary[3];
35139 var diff = guess - nodePosition; // check if we are allowed to move the node:
35140
35141 var branchOffset = 0;
35142
35143 if (diff > 0) {
35144 branchOffset = Math.min(diff, maxSpaceBranch - _this3.options.hierarchical.nodeSpacing);
35145 } else if (diff < 0) {
35146 branchOffset = -Math.min(-diff, minSpaceBranch - _this3.options.hierarchical.nodeSpacing);
35147 }
35148
35149 if (branchOffset != 0) {
35150 //console.log("moving branch:",branchOffset, maxSpaceBranch, minSpaceBranch)
35151 _this3._shiftBlock(node.id, branchOffset); //this.body.emitter.emit("_redraw");
35152
35153
35154 stillShifting = true;
35155 }
35156 };
35157
35158 var moveNode = function moveNode(guess) {
35159 var nodePosition = _this3.direction.getPosition(node); // position node if there is space
35160
35161
35162 var _this3$_getSpaceAroun3 = _this3._getSpaceAroundNode(node),
35163 _this3$_getSpaceAroun4 = _slicedToArray(_this3$_getSpaceAroun3, 2),
35164 minSpace = _this3$_getSpaceAroun4[0],
35165 maxSpace = _this3$_getSpaceAroun4[1];
35166
35167 var diff = guess - nodePosition; // check if we are allowed to move the node:
35168
35169 var newPosition = nodePosition;
35170
35171 if (diff > 0) {
35172 newPosition = Math.min(nodePosition + (maxSpace - _this3.options.hierarchical.nodeSpacing), guess);
35173 } else if (diff < 0) {
35174 newPosition = Math.max(nodePosition - (minSpace - _this3.options.hierarchical.nodeSpacing), guess);
35175 }
35176
35177 if (newPosition !== nodePosition) {
35178 //console.log("moving Node:",diff, minSpace, maxSpace);
35179 _this3.direction.setPosition(node, newPosition); //this.body.emitter.emit("_redraw");
35180
35181
35182 stillShifting = true;
35183 }
35184 };
35185
35186 var guess = getGuess(iterations, aboveEdges);
35187 moveBranch(guess);
35188 guess = getGuess(iterations, allEdges);
35189 moveNode(guess); //})
35190 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
35191
35192
35193 var minimizeEdgeLengthBottomUp = function minimizeEdgeLengthBottomUp(iterations) {
35194 var levels = _this3.hierarchical.getLevels();
35195
35196 levels = reverse(levels).call(levels);
35197
35198 for (var i = 0; i < iterations; i++) {
35199 stillShifting = false;
35200
35201 for (var j = 0; j < levels.length; j++) {
35202 var level = levels[j];
35203 var levelNodes = _this3.hierarchical.distributionOrdering[level];
35204
35205 for (var k = 0; k < levelNodes.length; k++) {
35206 minimizeEdgeLength(1000, levelNodes[k]);
35207 }
35208 }
35209
35210 if (stillShifting !== true) {
35211 //console.log("FINISHED minimizeEdgeLengthBottomUp IN " + i);
35212 break;
35213 }
35214 }
35215 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
35216
35217
35218 var shiftBranchesCloserBottomUp = function shiftBranchesCloserBottomUp(iterations) {
35219 var levels = _this3.hierarchical.getLevels();
35220
35221 levels = reverse(levels).call(levels);
35222
35223 for (var i = 0; i < iterations; i++) {
35224 stillShifting = false;
35225 shiftElementsCloser(branchShiftCallback, levels, true);
35226
35227 if (stillShifting !== true) {
35228 //console.log("FINISHED shiftBranchesCloserBottomUp IN " + (i+1));
35229 break;
35230 }
35231 }
35232 }; // center all parents
35233
35234
35235 var centerAllParents = function centerAllParents() {
35236 for (var nodeId in _this3.body.nodes) {
35237 if (Object.prototype.hasOwnProperty.call(_this3.body.nodes, nodeId)) _this3._centerParent(_this3.body.nodes[nodeId]);
35238 }
35239 }; // center all parents
35240
35241
35242 var centerAllParentsBottomUp = function centerAllParentsBottomUp() {
35243 var levels = _this3.hierarchical.getLevels();
35244
35245 levels = reverse(levels).call(levels);
35246
35247 for (var i = 0; i < levels.length; i++) {
35248 var level = levels[i];
35249 var levelNodes = _this3.hierarchical.distributionOrdering[level];
35250
35251 for (var j = 0; j < levelNodes.length; j++) {
35252 _this3._centerParent(levelNodes[j]);
35253 }
35254 }
35255 }; // the actual work is done here.
35256
35257
35258 if (this.options.hierarchical.blockShifting === true) {
35259 shiftBranchesCloserBottomUp(5);
35260 centerAllParents();
35261 } // minimize edge length
35262
35263
35264 if (this.options.hierarchical.edgeMinimization === true) {
35265 minimizeEdgeLengthBottomUp(20);
35266 }
35267
35268 if (this.options.hierarchical.parentCentralization === true) {
35269 centerAllParentsBottomUp();
35270 }
35271
35272 shiftTrees();
35273 }
35274 /**
35275 * This gives the space around the node. IF a map is supplied, it will only check against nodes NOT in the map.
35276 * This is used to only get the distances to nodes outside of a branch.
35277 *
35278 * @param {Node} node
35279 * @param {{Node.id: vis.Node}} map
35280 * @returns {number[]}
35281 * @private
35282 */
35283
35284 }, {
35285 key: "_getSpaceAroundNode",
35286 value: function _getSpaceAroundNode(node, map) {
35287 var useMap = true;
35288
35289 if (map === undefined) {
35290 useMap = false;
35291 }
35292
35293 var level = this.hierarchical.levels[node.id];
35294
35295 if (level !== undefined) {
35296 var index = this.hierarchical.distributionIndex[node.id];
35297 var position = this.direction.getPosition(node);
35298 var ordering = this.hierarchical.distributionOrdering[level];
35299 var minSpace = 1e9;
35300 var maxSpace = 1e9;
35301
35302 if (index !== 0) {
35303 var prevNode = ordering[index - 1];
35304
35305 if (useMap === true && map[prevNode.id] === undefined || useMap === false) {
35306 var prevPos = this.direction.getPosition(prevNode);
35307 minSpace = position - prevPos;
35308 }
35309 }
35310
35311 if (index != ordering.length - 1) {
35312 var nextNode = ordering[index + 1];
35313
35314 if (useMap === true && map[nextNode.id] === undefined || useMap === false) {
35315 var nextPos = this.direction.getPosition(nextNode);
35316 maxSpace = Math.min(maxSpace, nextPos - position);
35317 }
35318 }
35319
35320 return [minSpace, maxSpace];
35321 } else {
35322 return [0, 0];
35323 }
35324 }
35325 /**
35326 * We use this method to center a parent node and check if it does not cross other nodes when it does.
35327 *
35328 * @param {Node} node
35329 * @private
35330 */
35331
35332 }, {
35333 key: "_centerParent",
35334 value: function _centerParent(node) {
35335 if (this.hierarchical.parentReference[node.id]) {
35336 var parents = this.hierarchical.parentReference[node.id];
35337
35338 for (var i = 0; i < parents.length; i++) {
35339 var parentId = parents[i];
35340 var parentNode = this.body.nodes[parentId];
35341 var children = this.hierarchical.childrenReference[parentId];
35342
35343 if (children !== undefined) {
35344 // get the range of the children
35345 var newPosition = this._getCenterPosition(children);
35346
35347 var position = this.direction.getPosition(parentNode);
35348
35349 var _this$_getSpaceAround = this._getSpaceAroundNode(parentNode),
35350 _this$_getSpaceAround2 = _slicedToArray(_this$_getSpaceAround, 2),
35351 minSpace = _this$_getSpaceAround2[0],
35352 maxSpace = _this$_getSpaceAround2[1];
35353
35354 var diff = position - newPosition;
35355
35356 if (diff < 0 && Math.abs(diff) < maxSpace - this.options.hierarchical.nodeSpacing || diff > 0 && Math.abs(diff) < minSpace - this.options.hierarchical.nodeSpacing) {
35357 this.direction.setPosition(parentNode, newPosition);
35358 }
35359 }
35360 }
35361 }
35362 }
35363 /**
35364 * This function places the nodes on the canvas based on the hierarchial distribution.
35365 *
35366 * @param {object} distribution | obtained by the function this._getDistribution()
35367 * @private
35368 */
35369
35370 }, {
35371 key: "_placeNodesByHierarchy",
35372 value: function _placeNodesByHierarchy(distribution) {
35373 this.positionedNodes = {}; // start placing all the level 0 nodes first. Then recursively position their branches.
35374
35375 for (var level in distribution) {
35376 if (Object.prototype.hasOwnProperty.call(distribution, level)) {
35377 var _context;
35378
35379 // sort nodes in level by position:
35380 var nodeArray = keys(distribution[level]);
35381
35382 nodeArray = this._indexArrayToNodes(nodeArray);
35383
35384 sort(_context = this.direction).call(_context, nodeArray);
35385
35386 var handledNodeCount = 0;
35387
35388 for (var i = 0; i < nodeArray.length; i++) {
35389 var node = nodeArray[i];
35390
35391 if (this.positionedNodes[node.id] === undefined) {
35392 var spacing = this.options.hierarchical.nodeSpacing;
35393 var pos = spacing * handledNodeCount; // We get the X or Y values we need and store them in pos and previousPos.
35394 // The get and set make sure we get X or Y
35395
35396 if (handledNodeCount > 0) {
35397 pos = this.direction.getPosition(nodeArray[i - 1]) + spacing;
35398 }
35399
35400 this.direction.setPosition(node, pos, level);
35401
35402 this._validatePositionAndContinue(node, level, pos);
35403
35404 handledNodeCount++;
35405 }
35406 }
35407 }
35408 }
35409 }
35410 /**
35411 * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes
35412 * on a X position that ensures there will be no overlap.
35413 *
35414 * @param {Node.id} parentId
35415 * @param {number} parentLevel
35416 * @private
35417 */
35418
35419 }, {
35420 key: "_placeBranchNodes",
35421 value: function _placeBranchNodes(parentId, parentLevel) {
35422 var _context2;
35423
35424 var childRef = this.hierarchical.childrenReference[parentId]; // if this is not a parent, cancel the placing. This can happen with multiple parents to one child.
35425
35426 if (childRef === undefined) {
35427 return;
35428 } // get a list of childNodes
35429
35430
35431 var childNodes = [];
35432
35433 for (var i = 0; i < childRef.length; i++) {
35434 childNodes.push(this.body.nodes[childRef[i]]);
35435 } // use the positions to order the nodes.
35436
35437
35438 sort(_context2 = this.direction).call(_context2, childNodes); // position the childNodes
35439
35440
35441 for (var _i5 = 0; _i5 < childNodes.length; _i5++) {
35442 var childNode = childNodes[_i5];
35443 var childNodeLevel = this.hierarchical.levels[childNode.id]; // check if the child node is below the parent node and if it has already been positioned.
35444
35445 if (childNodeLevel > parentLevel && this.positionedNodes[childNode.id] === undefined) {
35446 // get the amount of space required for this node. If parent the width is based on the amount of children.
35447 var spacing = this.options.hierarchical.nodeSpacing;
35448 var pos = void 0; // we get the X or Y values we need and store them in pos and previousPos.
35449 // The get and set make sure we get X or Y
35450
35451 if (_i5 === 0) {
35452 pos = this.direction.getPosition(this.body.nodes[parentId]);
35453 } else {
35454 pos = this.direction.getPosition(childNodes[_i5 - 1]) + spacing;
35455 }
35456
35457 this.direction.setPosition(childNode, pos, childNodeLevel);
35458
35459 this._validatePositionAndContinue(childNode, childNodeLevel, pos);
35460 } else {
35461 return;
35462 }
35463 } // center the parent nodes.
35464
35465
35466 var center = this._getCenterPosition(childNodes);
35467
35468 this.direction.setPosition(this.body.nodes[parentId], center, parentLevel);
35469 }
35470 /**
35471 * This method checks for overlap and if required shifts the branch. It also keeps records of positioned nodes.
35472 * Finally it will call _placeBranchNodes to place the branch nodes.
35473 *
35474 * @param {Node} node
35475 * @param {number} level
35476 * @param {number} pos
35477 * @private
35478 */
35479
35480 }, {
35481 key: "_validatePositionAndContinue",
35482 value: function _validatePositionAndContinue(node, level, pos) {
35483 // This method only works for formal trees and formal forests
35484 // Early exit if this is not the case
35485 if (!this.hierarchical.isTree) return; // if overlap has been detected, we shift the branch
35486
35487 if (this.lastNodeOnLevel[level] !== undefined) {
35488 var previousPos = this.direction.getPosition(this.body.nodes[this.lastNodeOnLevel[level]]);
35489
35490 if (pos - previousPos < this.options.hierarchical.nodeSpacing) {
35491 var diff = previousPos + this.options.hierarchical.nodeSpacing - pos;
35492
35493 var sharedParent = this._findCommonParent(this.lastNodeOnLevel[level], node.id);
35494
35495 this._shiftBlock(sharedParent.withChild, diff);
35496 }
35497 }
35498
35499 this.lastNodeOnLevel[level] = node.id; // store change in position.
35500
35501 this.positionedNodes[node.id] = true;
35502
35503 this._placeBranchNodes(node.id, level);
35504 }
35505 /**
35506 * Receives an array with node indices and returns an array with the actual node references.
35507 * Used for sorting based on node properties.
35508 *
35509 * @param {Array.<Node.id>} idArray
35510 * @returns {Array.<Node>}
35511 */
35512
35513 }, {
35514 key: "_indexArrayToNodes",
35515 value: function _indexArrayToNodes(idArray) {
35516 var array = [];
35517
35518 for (var i = 0; i < idArray.length; i++) {
35519 array.push(this.body.nodes[idArray[i]]);
35520 }
35521
35522 return array;
35523 }
35524 /**
35525 * This function get the distribution of levels based on hubsize
35526 *
35527 * @returns {object}
35528 * @private
35529 */
35530
35531 }, {
35532 key: "_getDistribution",
35533 value: function _getDistribution() {
35534 var distribution = {};
35535 var nodeId, node; // we fix Y because the hierarchy is vertical,
35536 // we fix X so we do not give a node an x position for a second time.
35537 // the fix of X is removed after the x value has been set.
35538
35539 for (nodeId in this.body.nodes) {
35540 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
35541 node = this.body.nodes[nodeId];
35542 var level = this.hierarchical.levels[nodeId] === undefined ? 0 : this.hierarchical.levels[nodeId];
35543 this.direction.fix(node, level);
35544
35545 if (distribution[level] === undefined) {
35546 distribution[level] = {};
35547 }
35548
35549 distribution[level][nodeId] = node;
35550 }
35551 }
35552
35553 return distribution;
35554 }
35555 /**
35556 * Return the active (i.e. visible) edges for this node
35557 *
35558 * @param {Node} node
35559 * @returns {Array.<vis.Edge>} Array of edge instances
35560 * @private
35561 */
35562
35563 }, {
35564 key: "_getActiveEdges",
35565 value: function _getActiveEdges(node) {
35566 var _this4 = this;
35567
35568 var result = [];
35569 forEach$1(node.edges, function (edge) {
35570 var _context3;
35571
35572 if (indexOf(_context3 = _this4.body.edgeIndices).call(_context3, edge.id) !== -1) {
35573 result.push(edge);
35574 }
35575 });
35576 return result;
35577 }
35578 /**
35579 * Get the hubsizes for all active nodes.
35580 *
35581 * @returns {number}
35582 * @private
35583 */
35584
35585 }, {
35586 key: "_getHubSizes",
35587 value: function _getHubSizes() {
35588 var _this5 = this;
35589
35590 var hubSizes = {};
35591 var nodeIds = this.body.nodeIndices;
35592 forEach$1(nodeIds, function (nodeId) {
35593 var node = _this5.body.nodes[nodeId];
35594
35595 var hubSize = _this5._getActiveEdges(node).length;
35596
35597 hubSizes[hubSize] = true;
35598 }); // Make an array of the size sorted descending
35599
35600 var result = [];
35601 forEach$1(hubSizes, function (size) {
35602 result.push(Number(size));
35603 });
35604
35605 sort(timsort).call(timsort, result, function (a, b) {
35606 return b - a;
35607 });
35608
35609 return result;
35610 }
35611 /**
35612 * this function allocates nodes in levels based on the recursive branching from the largest hubs.
35613 *
35614 * @private
35615 */
35616
35617 }, {
35618 key: "_determineLevelsByHubsize",
35619 value: function _determineLevelsByHubsize() {
35620 var _this6 = this;
35621
35622 var levelDownstream = function levelDownstream(nodeA, nodeB) {
35623 _this6.hierarchical.levelDownstream(nodeA, nodeB);
35624 };
35625
35626 var hubSizes = this._getHubSizes();
35627
35628 var _loop = function _loop(i) {
35629 var hubSize = hubSizes[i];
35630 if (hubSize === 0) return "break";
35631 forEach$1(_this6.body.nodeIndices, function (nodeId) {
35632 var node = _this6.body.nodes[nodeId];
35633
35634 if (hubSize === _this6._getActiveEdges(node).length) {
35635 _this6._crawlNetwork(levelDownstream, nodeId);
35636 }
35637 });
35638 };
35639
35640 for (var i = 0; i < hubSizes.length; ++i) {
35641 var _ret = _loop(i);
35642
35643 if (_ret === "break") break;
35644 }
35645 }
35646 /**
35647 * TODO: release feature
35648 * TODO: Determine if this feature is needed at all
35649 *
35650 * @private
35651 */
35652
35653 }, {
35654 key: "_determineLevelsCustomCallback",
35655 value: function _determineLevelsCustomCallback() {
35656 var _this7 = this;
35657
35658 var minLevel = 100000; // TODO: this should come from options.
35659 // eslint-disable-next-line no-unused-vars -- This should eventually be implemented with these parameters used.
35660
35661 var customCallback = function customCallback(nodeA, nodeB, edge) {}; // TODO: perhaps move to HierarchicalStatus.
35662 // But I currently don't see the point, this method is not used.
35663
35664
35665 var levelByDirection = function levelByDirection(nodeA, nodeB, edge) {
35666 var levelA = _this7.hierarchical.levels[nodeA.id]; // set initial level
35667
35668 if (levelA === undefined) {
35669 levelA = _this7.hierarchical.levels[nodeA.id] = minLevel;
35670 }
35671
35672 var diff = customCallback(NetworkUtil.cloneOptions(nodeA, "node"), NetworkUtil.cloneOptions(nodeB, "node"), NetworkUtil.cloneOptions(edge, "edge"));
35673 _this7.hierarchical.levels[nodeB.id] = levelA + diff;
35674 };
35675
35676 this._crawlNetwork(levelByDirection);
35677
35678 this.hierarchical.setMinLevelToZero(this.body.nodes);
35679 }
35680 /**
35681 * Allocate nodes in levels based on the direction of the edges.
35682 *
35683 * @private
35684 */
35685
35686 }, {
35687 key: "_determineLevelsDirected",
35688 value: function _determineLevelsDirected() {
35689 var _context4,
35690 _this8 = this;
35691
35692 var nodes = reduce(_context4 = this.body.nodeIndices).call(_context4, function (acc, id) {
35693 acc.set(id, _this8.body.nodes[id]);
35694 return acc;
35695 }, new map());
35696
35697 if (this.options.hierarchical.shakeTowards === "roots") {
35698 this.hierarchical.levels = fillLevelsByDirectionRoots(nodes);
35699 } else {
35700 this.hierarchical.levels = fillLevelsByDirectionLeaves(nodes);
35701 }
35702
35703 this.hierarchical.setMinLevelToZero(this.body.nodes);
35704 }
35705 /**
35706 * Update the bookkeeping of parent and child.
35707 *
35708 * @private
35709 */
35710
35711 }, {
35712 key: "_generateMap",
35713 value: function _generateMap() {
35714 var _this9 = this;
35715
35716 var fillInRelations = function fillInRelations(parentNode, childNode) {
35717 if (_this9.hierarchical.levels[childNode.id] > _this9.hierarchical.levels[parentNode.id]) {
35718 _this9.hierarchical.addRelation(parentNode.id, childNode.id);
35719 }
35720 };
35721
35722 this._crawlNetwork(fillInRelations);
35723
35724 this.hierarchical.checkIfTree();
35725 }
35726 /**
35727 * Crawl over the entire network and use a callback on each node couple that is connected to each other.
35728 *
35729 * @param {Function} [callback=function(){}] | will receive nodeA, nodeB and the connecting edge. A and B are distinct.
35730 * @param {Node.id} startingNodeId
35731 * @private
35732 */
35733
35734 }, {
35735 key: "_crawlNetwork",
35736 value: function _crawlNetwork() {
35737 var _this10 = this;
35738
35739 var callback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
35740 var startingNodeId = arguments.length > 1 ? arguments[1] : undefined;
35741 var progress = {};
35742
35743 var crawler = function crawler(node, tree) {
35744 if (progress[node.id] === undefined) {
35745 _this10.hierarchical.setTreeIndex(node, tree);
35746
35747 progress[node.id] = true;
35748 var childNode;
35749
35750 var edges = _this10._getActiveEdges(node);
35751
35752 for (var i = 0; i < edges.length; i++) {
35753 var edge = edges[i];
35754
35755 if (edge.connected === true) {
35756 if (edge.toId == node.id) {
35757 // Not '===' because id's can be string and numeric
35758 childNode = edge.from;
35759 } else {
35760 childNode = edge.to;
35761 }
35762
35763 if (node.id != childNode.id) {
35764 // Not '!==' because id's can be string and numeric
35765 callback(node, childNode, edge);
35766 crawler(childNode, tree);
35767 }
35768 }
35769 }
35770 }
35771 };
35772
35773 if (startingNodeId === undefined) {
35774 // Crawl over all nodes
35775 var treeIndex = 0; // Serves to pass a unique id for the current distinct tree
35776
35777 for (var i = 0; i < this.body.nodeIndices.length; i++) {
35778 var nodeId = this.body.nodeIndices[i];
35779
35780 if (progress[nodeId] === undefined) {
35781 var node = this.body.nodes[nodeId];
35782 crawler(node, treeIndex);
35783 treeIndex += 1;
35784 }
35785 }
35786 } else {
35787 // Crawl from the given starting node
35788 var _node2 = this.body.nodes[startingNodeId];
35789
35790 if (_node2 === undefined) {
35791 console.error("Node not found:", startingNodeId);
35792 return;
35793 }
35794
35795 crawler(_node2);
35796 }
35797 }
35798 /**
35799 * Shift a branch a certain distance
35800 *
35801 * @param {Node.id} parentId
35802 * @param {number} diff
35803 * @private
35804 */
35805
35806 }, {
35807 key: "_shiftBlock",
35808 value: function _shiftBlock(parentId, diff) {
35809 var _this11 = this;
35810
35811 var progress = {};
35812
35813 var shifter = function shifter(parentId) {
35814 if (progress[parentId]) {
35815 return;
35816 }
35817
35818 progress[parentId] = true;
35819
35820 _this11.direction.shift(parentId, diff);
35821
35822 var childRef = _this11.hierarchical.childrenReference[parentId];
35823
35824 if (childRef !== undefined) {
35825 for (var i = 0; i < childRef.length; i++) {
35826 shifter(childRef[i]);
35827 }
35828 }
35829 };
35830
35831 shifter(parentId);
35832 }
35833 /**
35834 * Find a common parent between branches.
35835 *
35836 * @param {Node.id} childA
35837 * @param {Node.id} childB
35838 * @returns {{foundParent, withChild}}
35839 * @private
35840 */
35841
35842 }, {
35843 key: "_findCommonParent",
35844 value: function _findCommonParent(childA, childB) {
35845 var _this12 = this;
35846
35847 var parents = {};
35848
35849 var iterateParents = function iterateParents(parents, child) {
35850 var parentRef = _this12.hierarchical.parentReference[child];
35851
35852 if (parentRef !== undefined) {
35853 for (var i = 0; i < parentRef.length; i++) {
35854 var parent = parentRef[i];
35855 parents[parent] = true;
35856 iterateParents(parents, parent);
35857 }
35858 }
35859 };
35860
35861 var findParent = function findParent(parents, child) {
35862 var parentRef = _this12.hierarchical.parentReference[child];
35863
35864 if (parentRef !== undefined) {
35865 for (var i = 0; i < parentRef.length; i++) {
35866 var parent = parentRef[i];
35867
35868 if (parents[parent] !== undefined) {
35869 return {
35870 foundParent: parent,
35871 withChild: child
35872 };
35873 }
35874
35875 var branch = findParent(parents, parent);
35876
35877 if (branch.foundParent !== null) {
35878 return branch;
35879 }
35880 }
35881 }
35882
35883 return {
35884 foundParent: null,
35885 withChild: child
35886 };
35887 };
35888
35889 iterateParents(parents, childA);
35890 return findParent(parents, childB);
35891 }
35892 /**
35893 * Set the strategy pattern for handling the coordinates given the current direction.
35894 *
35895 * The individual instances contain all the operations and data specific to a layout direction.
35896 *
35897 * @param {Node} node
35898 * @param {{x: number, y: number}} position
35899 * @param {number} level
35900 * @param {boolean} [doNotUpdate=false]
35901 * @private
35902 */
35903
35904 }, {
35905 key: "setDirectionStrategy",
35906 value: function setDirectionStrategy() {
35907 var isVertical = this.options.hierarchical.direction === "UD" || this.options.hierarchical.direction === "DU";
35908
35909 if (isVertical) {
35910 this.direction = new VerticalStrategy(this);
35911 } else {
35912 this.direction = new HorizontalStrategy(this);
35913 }
35914 }
35915 /**
35916 * Determine the center position of a branch from the passed list of child nodes
35917 *
35918 * This takes into account the positions of all the child nodes.
35919 *
35920 * @param {Array.<Node|vis.Node.id>} childNodes Array of either child nodes or node id's
35921 * @returns {number}
35922 * @private
35923 */
35924
35925 }, {
35926 key: "_getCenterPosition",
35927 value: function _getCenterPosition(childNodes) {
35928 var minPos = 1e9;
35929 var maxPos = -1e9;
35930
35931 for (var i = 0; i < childNodes.length; i++) {
35932 var childNode = void 0;
35933
35934 if (childNodes[i].id !== undefined) {
35935 childNode = childNodes[i];
35936 } else {
35937 var childNodeId = childNodes[i];
35938 childNode = this.body.nodes[childNodeId];
35939 }
35940
35941 var position = this.direction.getPosition(childNode);
35942 minPos = Math.min(minPos, position);
35943 maxPos = Math.max(maxPos, position);
35944 }
35945
35946 return 0.5 * (minPos + maxPos);
35947 }
35948 }]);
35949
35950 return LayoutEngine;
35951 }();
35952
35953 function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$1(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; } } }; }
35954
35955 function _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$2(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
35956
35957 function _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; }
35958 /**
35959 * Clears the toolbar div element of children
35960 *
35961 * @private
35962 */
35963
35964 var ManipulationSystem = /*#__PURE__*/function () {
35965 /**
35966 * @param {object} body
35967 * @param {Canvas} canvas
35968 * @param {SelectionHandler} selectionHandler
35969 * @param {InteractionHandler} interactionHandler
35970 */
35971 function ManipulationSystem(body, canvas, selectionHandler, interactionHandler) {
35972 var _this = this,
35973 _context,
35974 _context2;
35975
35976 _classCallCheck(this, ManipulationSystem);
35977
35978 this.body = body;
35979 this.canvas = canvas;
35980 this.selectionHandler = selectionHandler;
35981 this.interactionHandler = interactionHandler;
35982 this.editMode = false;
35983 this.manipulationDiv = undefined;
35984 this.editModeDiv = undefined;
35985 this.closeDiv = undefined;
35986 this._domEventListenerCleanupQueue = [];
35987 this.temporaryUIFunctions = {};
35988 this.temporaryEventFunctions = [];
35989 this.touchTime = 0;
35990 this.temporaryIds = {
35991 nodes: [],
35992 edges: []
35993 };
35994 this.guiEnabled = false;
35995 this.inMode = false;
35996 this.selectedControlNode = undefined;
35997 this.options = {};
35998 this.defaultOptions = {
35999 enabled: false,
36000 initiallyActive: false,
36001 addNode: true,
36002 addEdge: true,
36003 editNode: undefined,
36004 editEdge: true,
36005 deleteNode: true,
36006 deleteEdge: true,
36007 controlNodeStyle: {
36008 shape: "dot",
36009 size: 6,
36010 color: {
36011 background: "#ff0000",
36012 border: "#3c3c3c",
36013 highlight: {
36014 background: "#07f968",
36015 border: "#3c3c3c"
36016 }
36017 },
36018 borderWidth: 2,
36019 borderWidthSelected: 2
36020 }
36021 };
36022
36023 assign$2(this.options, this.defaultOptions);
36024
36025 this.body.emitter.on("destroy", function () {
36026 _this._clean();
36027 });
36028 this.body.emitter.on("_dataChanged", bind$5(_context = this._restore).call(_context, this));
36029 this.body.emitter.on("_resetData", bind$5(_context2 = this._restore).call(_context2, this));
36030 }
36031 /**
36032 * If something changes in the data during editing, switch back to the initial datamanipulation state and close all edit modes.
36033 *
36034 * @private
36035 */
36036
36037
36038 _createClass(ManipulationSystem, [{
36039 key: "_restore",
36040 value: function _restore() {
36041 if (this.inMode !== false) {
36042 if (this.options.initiallyActive === true) {
36043 this.enableEditMode();
36044 } else {
36045 this.disableEditMode();
36046 }
36047 }
36048 }
36049 /**
36050 * Set the Options
36051 *
36052 * @param {object} options
36053 * @param {object} allOptions
36054 * @param {object} globalOptions
36055 */
36056
36057 }, {
36058 key: "setOptions",
36059 value: function setOptions(options, allOptions, globalOptions) {
36060 if (allOptions !== undefined) {
36061 if (allOptions.locale !== undefined) {
36062 this.options.locale = allOptions.locale;
36063 } else {
36064 this.options.locale = globalOptions.locale;
36065 }
36066
36067 if (allOptions.locales !== undefined) {
36068 this.options.locales = allOptions.locales;
36069 } else {
36070 this.options.locales = globalOptions.locales;
36071 }
36072 }
36073
36074 if (options !== undefined) {
36075 if (typeof options === "boolean") {
36076 this.options.enabled = options;
36077 } else {
36078 this.options.enabled = true;
36079 deepExtend(this.options, options);
36080 }
36081
36082 if (this.options.initiallyActive === true) {
36083 this.editMode = true;
36084 }
36085
36086 this._setup();
36087 }
36088 }
36089 /**
36090 * Enable or disable edit-mode. Draws the DOM required and cleans up after itself.
36091 *
36092 * @private
36093 */
36094
36095 }, {
36096 key: "toggleEditMode",
36097 value: function toggleEditMode() {
36098 if (this.editMode === true) {
36099 this.disableEditMode();
36100 } else {
36101 this.enableEditMode();
36102 }
36103 }
36104 /**
36105 * Enables Edit Mode
36106 */
36107
36108 }, {
36109 key: "enableEditMode",
36110 value: function enableEditMode() {
36111 this.editMode = true;
36112
36113 this._clean();
36114
36115 if (this.guiEnabled === true) {
36116 this.manipulationDiv.style.display = "block";
36117 this.closeDiv.style.display = "block";
36118 this.editModeDiv.style.display = "none";
36119 this.showManipulatorToolbar();
36120 }
36121 }
36122 /**
36123 * Disables Edit Mode
36124 */
36125
36126 }, {
36127 key: "disableEditMode",
36128 value: function disableEditMode() {
36129 this.editMode = false;
36130
36131 this._clean();
36132
36133 if (this.guiEnabled === true) {
36134 this.manipulationDiv.style.display = "none";
36135 this.closeDiv.style.display = "none";
36136 this.editModeDiv.style.display = "block";
36137
36138 this._createEditButton();
36139 }
36140 }
36141 /**
36142 * Creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar.
36143 *
36144 * @private
36145 */
36146
36147 }, {
36148 key: "showManipulatorToolbar",
36149 value: function showManipulatorToolbar() {
36150 // restore the state of any bound functions or events, remove control nodes, restore physics
36151 this._clean(); // reset global variables
36152
36153
36154 this.manipulationDOM = {}; // if the gui is enabled, draw all elements.
36155
36156 if (this.guiEnabled === true) {
36157 var _context3, _context4;
36158
36159 // a _restore will hide these menus
36160 this.editMode = true;
36161 this.manipulationDiv.style.display = "block";
36162 this.closeDiv.style.display = "block";
36163 var selectedNodeCount = this.selectionHandler.getSelectedNodeCount();
36164 var selectedEdgeCount = this.selectionHandler.getSelectedEdgeCount();
36165 var selectedTotalCount = selectedNodeCount + selectedEdgeCount;
36166 var locale = this.options.locales[this.options.locale];
36167 var needSeperator = false;
36168
36169 if (this.options.addNode !== false) {
36170 this._createAddNodeButton(locale);
36171
36172 needSeperator = true;
36173 }
36174
36175 if (this.options.addEdge !== false) {
36176 if (needSeperator === true) {
36177 this._createSeperator(1);
36178 } else {
36179 needSeperator = true;
36180 }
36181
36182 this._createAddEdgeButton(locale);
36183 }
36184
36185 if (selectedNodeCount === 1 && typeof this.options.editNode === "function") {
36186 if (needSeperator === true) {
36187 this._createSeperator(2);
36188 } else {
36189 needSeperator = true;
36190 }
36191
36192 this._createEditNodeButton(locale);
36193 } else if (selectedEdgeCount === 1 && selectedNodeCount === 0 && this.options.editEdge !== false) {
36194 if (needSeperator === true) {
36195 this._createSeperator(3);
36196 } else {
36197 needSeperator = true;
36198 }
36199
36200 this._createEditEdgeButton(locale);
36201 } // remove buttons
36202
36203
36204 if (selectedTotalCount !== 0) {
36205 if (selectedNodeCount > 0 && this.options.deleteNode !== false) {
36206 if (needSeperator === true) {
36207 this._createSeperator(4);
36208 }
36209
36210 this._createDeleteButton(locale);
36211 } else if (selectedNodeCount === 0 && this.options.deleteEdge !== false) {
36212 if (needSeperator === true) {
36213 this._createSeperator(4);
36214 }
36215
36216 this._createDeleteButton(locale);
36217 }
36218 } // bind the close button
36219
36220
36221 this._bindElementEvents(this.closeDiv, bind$5(_context3 = this.toggleEditMode).call(_context3, this)); // refresh this bar based on what has been selected
36222
36223
36224 this._temporaryBindEvent("select", bind$5(_context4 = this.showManipulatorToolbar).call(_context4, this));
36225 } // redraw to show any possible changes
36226
36227
36228 this.body.emitter.emit("_redraw");
36229 }
36230 /**
36231 * Create the toolbar for adding Nodes
36232 */
36233
36234 }, {
36235 key: "addNodeMode",
36236 value: function addNodeMode() {
36237 var _context6;
36238
36239 // when using the gui, enable edit mode if it wasnt already.
36240 if (this.editMode !== true) {
36241 this.enableEditMode();
36242 } // restore the state of any bound functions or events, remove control nodes, restore physics
36243
36244
36245 this._clean();
36246
36247 this.inMode = "addNode";
36248
36249 if (this.guiEnabled === true) {
36250 var _context5;
36251
36252 var locale = this.options.locales[this.options.locale];
36253 this.manipulationDOM = {};
36254
36255 this._createBackButton(locale);
36256
36257 this._createSeperator();
36258
36259 this._createDescription(locale["addDescription"] || this.options.locales["en"]["addDescription"]); // bind the close button
36260
36261
36262 this._bindElementEvents(this.closeDiv, bind$5(_context5 = this.toggleEditMode).call(_context5, this));
36263 }
36264
36265 this._temporaryBindEvent("click", bind$5(_context6 = this._performAddNode).call(_context6, this));
36266 }
36267 /**
36268 * call the bound function to handle the editing of the node. The node has to be selected.
36269 */
36270
36271 }, {
36272 key: "editNode",
36273 value: function editNode() {
36274 var _this2 = this;
36275
36276 // when using the gui, enable edit mode if it wasnt already.
36277 if (this.editMode !== true) {
36278 this.enableEditMode();
36279 } // restore the state of any bound functions or events, remove control nodes, restore physics
36280
36281
36282 this._clean();
36283
36284 var node = this.selectionHandler.getSelectedNodes()[0];
36285
36286 if (node !== undefined) {
36287 this.inMode = "editNode";
36288
36289 if (typeof this.options.editNode === "function") {
36290 if (node.isCluster !== true) {
36291 var data = deepExtend({}, node.options, false);
36292 data.x = node.x;
36293 data.y = node.y;
36294
36295 if (this.options.editNode.length === 2) {
36296 this.options.editNode(data, function (finalizedData) {
36297 if (finalizedData !== null && finalizedData !== undefined && _this2.inMode === "editNode") {
36298 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
36299 _this2.body.data.nodes.getDataSet().update(finalizedData);
36300 }
36301
36302 _this2.showManipulatorToolbar();
36303 });
36304 } else {
36305 throw new Error("The function for edit does not support two arguments (data, callback)");
36306 }
36307 } else {
36308 alert(this.options.locales[this.options.locale]["editClusterError"] || this.options.locales["en"]["editClusterError"]);
36309 }
36310 } else {
36311 throw new Error("No function has been configured to handle the editing of nodes.");
36312 }
36313 } else {
36314 this.showManipulatorToolbar();
36315 }
36316 }
36317 /**
36318 * create the toolbar to connect nodes
36319 */
36320
36321 }, {
36322 key: "addEdgeMode",
36323 value: function addEdgeMode() {
36324 var _context8, _context9, _context10, _context11, _context12;
36325
36326 // when using the gui, enable edit mode if it wasnt already.
36327 if (this.editMode !== true) {
36328 this.enableEditMode();
36329 } // restore the state of any bound functions or events, remove control nodes, restore physics
36330
36331
36332 this._clean();
36333
36334 this.inMode = "addEdge";
36335
36336 if (this.guiEnabled === true) {
36337 var _context7;
36338
36339 var locale = this.options.locales[this.options.locale];
36340 this.manipulationDOM = {};
36341
36342 this._createBackButton(locale);
36343
36344 this._createSeperator();
36345
36346 this._createDescription(locale["edgeDescription"] || this.options.locales["en"]["edgeDescription"]); // bind the close button
36347
36348
36349 this._bindElementEvents(this.closeDiv, bind$5(_context7 = this.toggleEditMode).call(_context7, this));
36350 } // temporarily overload functions
36351
36352
36353 this._temporaryBindUI("onTouch", bind$5(_context8 = this._handleConnect).call(_context8, this));
36354
36355 this._temporaryBindUI("onDragEnd", bind$5(_context9 = this._finishConnect).call(_context9, this));
36356
36357 this._temporaryBindUI("onDrag", bind$5(_context10 = this._dragControlNode).call(_context10, this));
36358
36359 this._temporaryBindUI("onRelease", bind$5(_context11 = this._finishConnect).call(_context11, this));
36360
36361 this._temporaryBindUI("onDragStart", bind$5(_context12 = this._dragStartEdge).call(_context12, this));
36362
36363 this._temporaryBindUI("onHold", function () {});
36364 }
36365 /**
36366 * create the toolbar to edit edges
36367 */
36368
36369 }, {
36370 key: "editEdgeMode",
36371 value: function editEdgeMode() {
36372 // when using the gui, enable edit mode if it wasn't already.
36373 if (this.editMode !== true) {
36374 this.enableEditMode();
36375 } // restore the state of any bound functions or events, remove control nodes, restore physics
36376
36377
36378 this._clean();
36379
36380 this.inMode = "editEdge";
36381
36382 if (_typeof(this.options.editEdge) === "object" && typeof this.options.editEdge.editWithoutDrag === "function") {
36383 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdgeIds()[0];
36384
36385 if (this.edgeBeingEditedId !== undefined) {
36386 var edge = this.body.edges[this.edgeBeingEditedId];
36387
36388 this._performEditEdge(edge.from.id, edge.to.id);
36389
36390 return;
36391 }
36392 }
36393
36394 if (this.guiEnabled === true) {
36395 var _context13;
36396
36397 var locale = this.options.locales[this.options.locale];
36398 this.manipulationDOM = {};
36399
36400 this._createBackButton(locale);
36401
36402 this._createSeperator();
36403
36404 this._createDescription(locale["editEdgeDescription"] || this.options.locales["en"]["editEdgeDescription"]); // bind the close button
36405
36406
36407 this._bindElementEvents(this.closeDiv, bind$5(_context13 = this.toggleEditMode).call(_context13, this));
36408 }
36409
36410 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdgeIds()[0];
36411
36412 if (this.edgeBeingEditedId !== undefined) {
36413 var _context14, _context15, _context16, _context17;
36414
36415 var _edge = this.body.edges[this.edgeBeingEditedId]; // create control nodes
36416
36417 var controlNodeFrom = this._getNewTargetNode(_edge.from.x, _edge.from.y);
36418
36419 var controlNodeTo = this._getNewTargetNode(_edge.to.x, _edge.to.y);
36420
36421 this.temporaryIds.nodes.push(controlNodeFrom.id);
36422 this.temporaryIds.nodes.push(controlNodeTo.id);
36423 this.body.nodes[controlNodeFrom.id] = controlNodeFrom;
36424 this.body.nodeIndices.push(controlNodeFrom.id);
36425 this.body.nodes[controlNodeTo.id] = controlNodeTo;
36426 this.body.nodeIndices.push(controlNodeTo.id); // temporarily overload UI functions, cleaned up automatically because of _temporaryBindUI
36427
36428 this._temporaryBindUI("onTouch", bind$5(_context14 = this._controlNodeTouch).call(_context14, this)); // used to get the position
36429
36430
36431 this._temporaryBindUI("onTap", function () {}); // disabled
36432
36433
36434 this._temporaryBindUI("onHold", function () {}); // disabled
36435
36436
36437 this._temporaryBindUI("onDragStart", bind$5(_context15 = this._controlNodeDragStart).call(_context15, this)); // used to select control node
36438
36439
36440 this._temporaryBindUI("onDrag", bind$5(_context16 = this._controlNodeDrag).call(_context16, this)); // used to drag control node
36441
36442
36443 this._temporaryBindUI("onDragEnd", bind$5(_context17 = this._controlNodeDragEnd).call(_context17, this)); // used to connect or revert control nodes
36444
36445
36446 this._temporaryBindUI("onMouseMove", function () {}); // disabled
36447 // create function to position control nodes correctly on movement
36448 // automatically cleaned up because we use the temporary bind
36449
36450
36451 this._temporaryBindEvent("beforeDrawing", function (ctx) {
36452 var positions = _edge.edgeType.findBorderPositions(ctx);
36453
36454 if (controlNodeFrom.selected === false) {
36455 controlNodeFrom.x = positions.from.x;
36456 controlNodeFrom.y = positions.from.y;
36457 }
36458
36459 if (controlNodeTo.selected === false) {
36460 controlNodeTo.x = positions.to.x;
36461 controlNodeTo.y = positions.to.y;
36462 }
36463 });
36464
36465 this.body.emitter.emit("_redraw");
36466 } else {
36467 this.showManipulatorToolbar();
36468 }
36469 }
36470 /**
36471 * delete everything in the selection
36472 */
36473
36474 }, {
36475 key: "deleteSelected",
36476 value: function deleteSelected() {
36477 var _this3 = this;
36478
36479 // when using the gui, enable edit mode if it wasnt already.
36480 if (this.editMode !== true) {
36481 this.enableEditMode();
36482 } // restore the state of any bound functions or events, remove control nodes, restore physics
36483
36484
36485 this._clean();
36486
36487 this.inMode = "delete";
36488 var selectedNodes = this.selectionHandler.getSelectedNodeIds();
36489 var selectedEdges = this.selectionHandler.getSelectedEdgeIds();
36490 var deleteFunction = undefined;
36491
36492 if (selectedNodes.length > 0) {
36493 for (var i = 0; i < selectedNodes.length; i++) {
36494 if (this.body.nodes[selectedNodes[i]].isCluster === true) {
36495 alert(this.options.locales[this.options.locale]["deleteClusterError"] || this.options.locales["en"]["deleteClusterError"]);
36496 return;
36497 }
36498 }
36499
36500 if (typeof this.options.deleteNode === "function") {
36501 deleteFunction = this.options.deleteNode;
36502 }
36503 } else if (selectedEdges.length > 0) {
36504 if (typeof this.options.deleteEdge === "function") {
36505 deleteFunction = this.options.deleteEdge;
36506 }
36507 }
36508
36509 if (typeof deleteFunction === "function") {
36510 var data = {
36511 nodes: selectedNodes,
36512 edges: selectedEdges
36513 };
36514
36515 if (deleteFunction.length === 2) {
36516 deleteFunction(data, function (finalizedData) {
36517 if (finalizedData !== null && finalizedData !== undefined && _this3.inMode === "delete") {
36518 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
36519 _this3.body.data.edges.getDataSet().remove(finalizedData.edges);
36520
36521 _this3.body.data.nodes.getDataSet().remove(finalizedData.nodes);
36522
36523 _this3.body.emitter.emit("startSimulation");
36524
36525 _this3.showManipulatorToolbar();
36526 } else {
36527 _this3.body.emitter.emit("startSimulation");
36528
36529 _this3.showManipulatorToolbar();
36530 }
36531 });
36532 } else {
36533 throw new Error("The function for delete does not support two arguments (data, callback)");
36534 }
36535 } else {
36536 this.body.data.edges.getDataSet().remove(selectedEdges);
36537 this.body.data.nodes.getDataSet().remove(selectedNodes);
36538 this.body.emitter.emit("startSimulation");
36539 this.showManipulatorToolbar();
36540 }
36541 } //********************************************** PRIVATE ***************************************//
36542
36543 /**
36544 * draw or remove the DOM
36545 *
36546 * @private
36547 */
36548
36549 }, {
36550 key: "_setup",
36551 value: function _setup() {
36552 if (this.options.enabled === true) {
36553 // Enable the GUI
36554 this.guiEnabled = true;
36555
36556 this._createWrappers();
36557
36558 if (this.editMode === false) {
36559 this._createEditButton();
36560 } else {
36561 this.showManipulatorToolbar();
36562 }
36563 } else {
36564 this._removeManipulationDOM(); // disable the gui
36565
36566
36567 this.guiEnabled = false;
36568 }
36569 }
36570 /**
36571 * create the div overlays that contain the DOM
36572 *
36573 * @private
36574 */
36575
36576 }, {
36577 key: "_createWrappers",
36578 value: function _createWrappers() {
36579 // load the manipulator HTML elements. All styling done in css.
36580 if (this.manipulationDiv === undefined) {
36581 this.manipulationDiv = document.createElement("div");
36582 this.manipulationDiv.className = "vis-manipulation";
36583
36584 if (this.editMode === true) {
36585 this.manipulationDiv.style.display = "block";
36586 } else {
36587 this.manipulationDiv.style.display = "none";
36588 }
36589
36590 this.canvas.frame.appendChild(this.manipulationDiv);
36591 } // container for the edit button.
36592
36593
36594 if (this.editModeDiv === undefined) {
36595 this.editModeDiv = document.createElement("div");
36596 this.editModeDiv.className = "vis-edit-mode";
36597
36598 if (this.editMode === true) {
36599 this.editModeDiv.style.display = "none";
36600 } else {
36601 this.editModeDiv.style.display = "block";
36602 }
36603
36604 this.canvas.frame.appendChild(this.editModeDiv);
36605 } // container for the close div button
36606
36607
36608 if (this.closeDiv === undefined) {
36609 var _this$options$locales, _this$options$locales2;
36610
36611 this.closeDiv = document.createElement("button");
36612 this.closeDiv.className = "vis-close";
36613 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"]);
36614 this.closeDiv.style.display = this.manipulationDiv.style.display;
36615 this.canvas.frame.appendChild(this.closeDiv);
36616 }
36617 }
36618 /**
36619 * generate a new target node. Used for creating new edges and editing edges
36620 *
36621 * @param {number} x
36622 * @param {number} y
36623 * @returns {Node}
36624 * @private
36625 */
36626
36627 }, {
36628 key: "_getNewTargetNode",
36629 value: function _getNewTargetNode(x, y) {
36630 var controlNodeStyle = deepExtend({}, this.options.controlNodeStyle);
36631 controlNodeStyle.id = "targetNode" + v4();
36632 controlNodeStyle.hidden = false;
36633 controlNodeStyle.physics = false;
36634 controlNodeStyle.x = x;
36635 controlNodeStyle.y = y; // we have to define the bounding box in order for the nodes to be drawn immediately
36636
36637 var node = this.body.functions.createNode(controlNodeStyle);
36638 node.shape.boundingBox = {
36639 left: x,
36640 right: x,
36641 top: y,
36642 bottom: y
36643 };
36644 return node;
36645 }
36646 /**
36647 * Create the edit button
36648 */
36649
36650 }, {
36651 key: "_createEditButton",
36652 value: function _createEditButton() {
36653 var _context18;
36654
36655 // restore everything to it's original state (if applicable)
36656 this._clean(); // reset the manipulationDOM
36657
36658
36659 this.manipulationDOM = {}; // empty the editModeDiv
36660
36661 recursiveDOMDelete(this.editModeDiv); // create the contents for the editMode button
36662
36663 var locale = this.options.locales[this.options.locale];
36664
36665 var button = this._createButton("editMode", "vis-edit vis-edit-mode", locale["edit"] || this.options.locales["en"]["edit"]);
36666
36667 this.editModeDiv.appendChild(button); // bind a hammer listener to the button, calling the function toggleEditMode.
36668
36669 this._bindElementEvents(button, bind$5(_context18 = this.toggleEditMode).call(_context18, this));
36670 }
36671 /**
36672 * this function cleans up after everything this module does. Temporary elements, functions and events are removed, physics restored, hammers removed.
36673 *
36674 * @private
36675 */
36676
36677 }, {
36678 key: "_clean",
36679 value: function _clean() {
36680 // not in mode
36681 this.inMode = false; // _clean the divs
36682
36683 if (this.guiEnabled === true) {
36684 recursiveDOMDelete(this.editModeDiv);
36685 recursiveDOMDelete(this.manipulationDiv); // removes all the bindings and overloads
36686
36687 this._cleanupDOMEventListeners();
36688 } // remove temporary nodes and edges
36689
36690
36691 this._cleanupTemporaryNodesAndEdges(); // restore overloaded UI functions
36692
36693
36694 this._unbindTemporaryUIs(); // remove the temporaryEventFunctions
36695
36696
36697 this._unbindTemporaryEvents(); // restore the physics if required
36698
36699
36700 this.body.emitter.emit("restorePhysics");
36701 }
36702 /**
36703 * Each dom element has it's own hammer. They are stored in this.manipulationHammers. This cleans them up.
36704 *
36705 * @private
36706 */
36707
36708 }, {
36709 key: "_cleanupDOMEventListeners",
36710 value: function _cleanupDOMEventListeners() {
36711 var _context19;
36712
36713 // _clean DOM event listener bindings
36714 var _iterator = _createForOfIteratorHelper(splice(_context19 = this._domEventListenerCleanupQueue).call(_context19, 0)),
36715 _step;
36716
36717 try {
36718 for (_iterator.s(); !(_step = _iterator.n()).done;) {
36719 var callback = _step.value;
36720 callback();
36721 }
36722 } catch (err) {
36723 _iterator.e(err);
36724 } finally {
36725 _iterator.f();
36726 }
36727 }
36728 /**
36729 * Remove all DOM elements created by this module.
36730 *
36731 * @private
36732 */
36733
36734 }, {
36735 key: "_removeManipulationDOM",
36736 value: function _removeManipulationDOM() {
36737 // removes all the bindings and overloads
36738 this._clean(); // empty the manipulation divs
36739
36740
36741 recursiveDOMDelete(this.manipulationDiv);
36742 recursiveDOMDelete(this.editModeDiv);
36743 recursiveDOMDelete(this.closeDiv); // remove the manipulation divs
36744
36745 if (this.manipulationDiv) {
36746 this.canvas.frame.removeChild(this.manipulationDiv);
36747 }
36748
36749 if (this.editModeDiv) {
36750 this.canvas.frame.removeChild(this.editModeDiv);
36751 }
36752
36753 if (this.closeDiv) {
36754 this.canvas.frame.removeChild(this.closeDiv);
36755 } // set the references to undefined
36756
36757
36758 this.manipulationDiv = undefined;
36759 this.editModeDiv = undefined;
36760 this.closeDiv = undefined;
36761 }
36762 /**
36763 * create a seperator line. the index is to differentiate in the manipulation dom
36764 *
36765 * @param {number} [index=1]
36766 * @private
36767 */
36768
36769 }, {
36770 key: "_createSeperator",
36771 value: function _createSeperator() {
36772 var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
36773 this.manipulationDOM["seperatorLineDiv" + index] = document.createElement("div");
36774 this.manipulationDOM["seperatorLineDiv" + index].className = "vis-separator-line";
36775 this.manipulationDiv.appendChild(this.manipulationDOM["seperatorLineDiv" + index]);
36776 } // ---------------------- DOM functions for buttons --------------------------//
36777
36778 /**
36779 *
36780 * @param {Locale} locale
36781 * @private
36782 */
36783
36784 }, {
36785 key: "_createAddNodeButton",
36786 value: function _createAddNodeButton(locale) {
36787 var _context20;
36788
36789 var button = this._createButton("addNode", "vis-add", locale["addNode"] || this.options.locales["en"]["addNode"]);
36790
36791 this.manipulationDiv.appendChild(button);
36792
36793 this._bindElementEvents(button, bind$5(_context20 = this.addNodeMode).call(_context20, this));
36794 }
36795 /**
36796 *
36797 * @param {Locale} locale
36798 * @private
36799 */
36800
36801 }, {
36802 key: "_createAddEdgeButton",
36803 value: function _createAddEdgeButton(locale) {
36804 var _context21;
36805
36806 var button = this._createButton("addEdge", "vis-connect", locale["addEdge"] || this.options.locales["en"]["addEdge"]);
36807
36808 this.manipulationDiv.appendChild(button);
36809
36810 this._bindElementEvents(button, bind$5(_context21 = this.addEdgeMode).call(_context21, this));
36811 }
36812 /**
36813 *
36814 * @param {Locale} locale
36815 * @private
36816 */
36817
36818 }, {
36819 key: "_createEditNodeButton",
36820 value: function _createEditNodeButton(locale) {
36821 var _context22;
36822
36823 var button = this._createButton("editNode", "vis-edit", locale["editNode"] || this.options.locales["en"]["editNode"]);
36824
36825 this.manipulationDiv.appendChild(button);
36826
36827 this._bindElementEvents(button, bind$5(_context22 = this.editNode).call(_context22, this));
36828 }
36829 /**
36830 *
36831 * @param {Locale} locale
36832 * @private
36833 */
36834
36835 }, {
36836 key: "_createEditEdgeButton",
36837 value: function _createEditEdgeButton(locale) {
36838 var _context23;
36839
36840 var button = this._createButton("editEdge", "vis-edit", locale["editEdge"] || this.options.locales["en"]["editEdge"]);
36841
36842 this.manipulationDiv.appendChild(button);
36843
36844 this._bindElementEvents(button, bind$5(_context23 = this.editEdgeMode).call(_context23, this));
36845 }
36846 /**
36847 *
36848 * @param {Locale} locale
36849 * @private
36850 */
36851
36852 }, {
36853 key: "_createDeleteButton",
36854 value: function _createDeleteButton(locale) {
36855 var _context24;
36856
36857 var deleteBtnClass;
36858
36859 if (this.options.rtl) {
36860 deleteBtnClass = "vis-delete-rtl";
36861 } else {
36862 deleteBtnClass = "vis-delete";
36863 }
36864
36865 var button = this._createButton("delete", deleteBtnClass, locale["del"] || this.options.locales["en"]["del"]);
36866
36867 this.manipulationDiv.appendChild(button);
36868
36869 this._bindElementEvents(button, bind$5(_context24 = this.deleteSelected).call(_context24, this));
36870 }
36871 /**
36872 *
36873 * @param {Locale} locale
36874 * @private
36875 */
36876
36877 }, {
36878 key: "_createBackButton",
36879 value: function _createBackButton(locale) {
36880 var _context25;
36881
36882 var button = this._createButton("back", "vis-back", locale["back"] || this.options.locales["en"]["back"]);
36883
36884 this.manipulationDiv.appendChild(button);
36885
36886 this._bindElementEvents(button, bind$5(_context25 = this.showManipulatorToolbar).call(_context25, this));
36887 }
36888 /**
36889 *
36890 * @param {number|string} id
36891 * @param {string} className
36892 * @param {label} label
36893 * @param {string} labelClassName
36894 * @returns {HTMLElement}
36895 * @private
36896 */
36897
36898 }, {
36899 key: "_createButton",
36900 value: function _createButton(id, className, label) {
36901 var labelClassName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "vis-label";
36902 this.manipulationDOM[id + "Div"] = document.createElement("button");
36903 this.manipulationDOM[id + "Div"].className = "vis-button " + className;
36904 this.manipulationDOM[id + "Label"] = document.createElement("div");
36905 this.manipulationDOM[id + "Label"].className = labelClassName;
36906 this.manipulationDOM[id + "Label"].innerText = label;
36907 this.manipulationDOM[id + "Div"].appendChild(this.manipulationDOM[id + "Label"]);
36908 return this.manipulationDOM[id + "Div"];
36909 }
36910 /**
36911 *
36912 * @param {Label} label
36913 * @private
36914 */
36915
36916 }, {
36917 key: "_createDescription",
36918 value: function _createDescription(label) {
36919 this.manipulationDOM["descriptionLabel"] = document.createElement("div");
36920 this.manipulationDOM["descriptionLabel"].className = "vis-none";
36921 this.manipulationDOM["descriptionLabel"].innerText = label;
36922 this.manipulationDiv.appendChild(this.manipulationDOM["descriptionLabel"]);
36923 } // -------------------------- End of DOM functions for buttons ------------------------------//
36924
36925 /**
36926 * this binds an event until cleanup by the clean functions.
36927 *
36928 * @param {Event} event The event
36929 * @param {Function} newFunction
36930 * @private
36931 */
36932
36933 }, {
36934 key: "_temporaryBindEvent",
36935 value: function _temporaryBindEvent(event, newFunction) {
36936 this.temporaryEventFunctions.push({
36937 event: event,
36938 boundFunction: newFunction
36939 });
36940 this.body.emitter.on(event, newFunction);
36941 }
36942 /**
36943 * this overrides an UI function until cleanup by the clean function
36944 *
36945 * @param {string} UIfunctionName
36946 * @param {Function} newFunction
36947 * @private
36948 */
36949
36950 }, {
36951 key: "_temporaryBindUI",
36952 value: function _temporaryBindUI(UIfunctionName, newFunction) {
36953 if (this.body.eventListeners[UIfunctionName] !== undefined) {
36954 this.temporaryUIFunctions[UIfunctionName] = this.body.eventListeners[UIfunctionName];
36955 this.body.eventListeners[UIfunctionName] = newFunction;
36956 } else {
36957 throw new Error("This UI function does not exist. Typo? You tried: " + UIfunctionName + " possible are: " + stringify$1(keys(this.body.eventListeners)));
36958 }
36959 }
36960 /**
36961 * Restore the overridden UI functions to their original state.
36962 *
36963 * @private
36964 */
36965
36966 }, {
36967 key: "_unbindTemporaryUIs",
36968 value: function _unbindTemporaryUIs() {
36969 for (var functionName in this.temporaryUIFunctions) {
36970 if (Object.prototype.hasOwnProperty.call(this.temporaryUIFunctions, functionName)) {
36971 this.body.eventListeners[functionName] = this.temporaryUIFunctions[functionName];
36972 delete this.temporaryUIFunctions[functionName];
36973 }
36974 }
36975
36976 this.temporaryUIFunctions = {};
36977 }
36978 /**
36979 * Unbind the events created by _temporaryBindEvent
36980 *
36981 * @private
36982 */
36983
36984 }, {
36985 key: "_unbindTemporaryEvents",
36986 value: function _unbindTemporaryEvents() {
36987 for (var i = 0; i < this.temporaryEventFunctions.length; i++) {
36988 var eventName = this.temporaryEventFunctions[i].event;
36989 var boundFunction = this.temporaryEventFunctions[i].boundFunction;
36990 this.body.emitter.off(eventName, boundFunction);
36991 }
36992
36993 this.temporaryEventFunctions = [];
36994 }
36995 /**
36996 * Bind an hammer instance to a DOM element.
36997 *
36998 * @param {Element} domElement
36999 * @param {Function} boundFunction
37000 */
37001
37002 }, {
37003 key: "_bindElementEvents",
37004 value: function _bindElementEvents(domElement, boundFunction) {
37005 // Bind touch events.
37006 var hammer = new Hammer$1(domElement, {});
37007 onTouch(hammer, boundFunction);
37008
37009 this._domEventListenerCleanupQueue.push(function () {
37010 hammer.destroy();
37011 }); // Bind keyboard events.
37012
37013
37014 var keyupListener = function keyupListener(_ref) {
37015 var keyCode = _ref.keyCode,
37016 key = _ref.key;
37017
37018 if (key === "Enter" || key === " " || keyCode === 13 || keyCode === 32) {
37019 boundFunction();
37020 }
37021 };
37022
37023 domElement.addEventListener("keyup", keyupListener, false);
37024
37025 this._domEventListenerCleanupQueue.push(function () {
37026 domElement.removeEventListener("keyup", keyupListener, false);
37027 });
37028 }
37029 /**
37030 * Neatly clean up temporary edges and nodes
37031 *
37032 * @private
37033 */
37034
37035 }, {
37036 key: "_cleanupTemporaryNodesAndEdges",
37037 value: function _cleanupTemporaryNodesAndEdges() {
37038 // _clean temporary edges
37039 for (var i = 0; i < this.temporaryIds.edges.length; i++) {
37040 var _context26;
37041
37042 this.body.edges[this.temporaryIds.edges[i]].disconnect();
37043 delete this.body.edges[this.temporaryIds.edges[i]];
37044
37045 var indexTempEdge = indexOf(_context26 = this.body.edgeIndices).call(_context26, this.temporaryIds.edges[i]);
37046
37047 if (indexTempEdge !== -1) {
37048 var _context27;
37049
37050 splice(_context27 = this.body.edgeIndices).call(_context27, indexTempEdge, 1);
37051 }
37052 } // _clean temporary nodes
37053
37054
37055 for (var _i = 0; _i < this.temporaryIds.nodes.length; _i++) {
37056 var _context28;
37057
37058 delete this.body.nodes[this.temporaryIds.nodes[_i]];
37059
37060 var indexTempNode = indexOf(_context28 = this.body.nodeIndices).call(_context28, this.temporaryIds.nodes[_i]);
37061
37062 if (indexTempNode !== -1) {
37063 var _context29;
37064
37065 splice(_context29 = this.body.nodeIndices).call(_context29, indexTempNode, 1);
37066 }
37067 }
37068
37069 this.temporaryIds = {
37070 nodes: [],
37071 edges: []
37072 };
37073 } // ------------------------------------------ EDIT EDGE FUNCTIONS -----------------------------------------//
37074
37075 /**
37076 * the touch is used to get the position of the initial click
37077 *
37078 * @param {Event} event The event
37079 * @private
37080 */
37081
37082 }, {
37083 key: "_controlNodeTouch",
37084 value: function _controlNodeTouch(event) {
37085 this.selectionHandler.unselectAll();
37086 this.lastTouch = this.body.functions.getPointer(event.center);
37087 this.lastTouch.translation = assign$2({}, this.body.view.translation); // copy the object
37088 }
37089 /**
37090 * the drag start is used to mark one of the control nodes as selected.
37091 *
37092 * @private
37093 */
37094
37095 }, {
37096 key: "_controlNodeDragStart",
37097 value: function _controlNodeDragStart() {
37098 var pointer = this.lastTouch;
37099
37100 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
37101
37102 var from = this.body.nodes[this.temporaryIds.nodes[0]];
37103 var to = this.body.nodes[this.temporaryIds.nodes[1]];
37104 var edge = this.body.edges[this.edgeBeingEditedId];
37105 this.selectedControlNode = undefined;
37106 var fromSelect = from.isOverlappingWith(pointerObj);
37107 var toSelect = to.isOverlappingWith(pointerObj);
37108
37109 if (fromSelect === true) {
37110 this.selectedControlNode = from;
37111 edge.edgeType.from = from;
37112 } else if (toSelect === true) {
37113 this.selectedControlNode = to;
37114 edge.edgeType.to = to;
37115 } // we use the selection to find the node that is being dragged. We explicitly select it here.
37116
37117
37118 if (this.selectedControlNode !== undefined) {
37119 this.selectionHandler.selectObject(this.selectedControlNode);
37120 }
37121
37122 this.body.emitter.emit("_redraw");
37123 }
37124 /**
37125 * dragging the control nodes or the canvas
37126 *
37127 * @param {Event} event The event
37128 * @private
37129 */
37130
37131 }, {
37132 key: "_controlNodeDrag",
37133 value: function _controlNodeDrag(event) {
37134 this.body.emitter.emit("disablePhysics");
37135 var pointer = this.body.functions.getPointer(event.center);
37136 var pos = this.canvas.DOMtoCanvas(pointer);
37137
37138 if (this.selectedControlNode !== undefined) {
37139 this.selectedControlNode.x = pos.x;
37140 this.selectedControlNode.y = pos.y;
37141 } else {
37142 this.interactionHandler.onDrag(event);
37143 }
37144
37145 this.body.emitter.emit("_redraw");
37146 }
37147 /**
37148 * connecting or restoring the control nodes.
37149 *
37150 * @param {Event} event The event
37151 * @private
37152 */
37153
37154 }, {
37155 key: "_controlNodeDragEnd",
37156 value: function _controlNodeDragEnd(event) {
37157 var pointer = this.body.functions.getPointer(event.center);
37158
37159 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
37160
37161 var edge = this.body.edges[this.edgeBeingEditedId]; // if the node that was dragged is not a control node, return
37162
37163 if (this.selectedControlNode === undefined) {
37164 return;
37165 } // we use the selection to find the node that is being dragged. We explicitly DEselect the control node here.
37166
37167
37168 this.selectionHandler.unselectAll();
37169
37170 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
37171
37172 var node = undefined;
37173
37174 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
37175 if (overlappingNodeIds[i] !== this.selectedControlNode.id) {
37176 node = this.body.nodes[overlappingNodeIds[i]];
37177 break;
37178 }
37179 } // perform the connection
37180
37181
37182 if (node !== undefined && this.selectedControlNode !== undefined) {
37183 if (node.isCluster === true) {
37184 alert(this.options.locales[this.options.locale]["createEdgeError"] || this.options.locales["en"]["createEdgeError"]);
37185 } else {
37186 var from = this.body.nodes[this.temporaryIds.nodes[0]];
37187
37188 if (this.selectedControlNode.id === from.id) {
37189 this._performEditEdge(node.id, edge.to.id);
37190 } else {
37191 this._performEditEdge(edge.from.id, node.id);
37192 }
37193 }
37194 } else {
37195 edge.updateEdgeType();
37196 this.body.emitter.emit("restorePhysics");
37197 }
37198
37199 this.body.emitter.emit("_redraw");
37200 } // ------------------------------------ END OF EDIT EDGE FUNCTIONS -----------------------------------------//
37201 // ------------------------------------------- ADD EDGE FUNCTIONS -----------------------------------------//
37202
37203 /**
37204 * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
37205 * to walk the user through the process.
37206 *
37207 * @param {Event} event
37208 * @private
37209 */
37210
37211 }, {
37212 key: "_handleConnect",
37213 value: function _handleConnect(event) {
37214 // check to avoid double fireing of this function.
37215 if (new Date().valueOf() - this.touchTime > 100) {
37216 this.lastTouch = this.body.functions.getPointer(event.center);
37217 this.lastTouch.translation = assign$2({}, this.body.view.translation); // copy the object
37218
37219 this.interactionHandler.drag.pointer = this.lastTouch; // Drag pointer is not updated when adding edges
37220
37221 this.interactionHandler.drag.translation = this.lastTouch.translation;
37222 var pointer = this.lastTouch;
37223 var node = this.selectionHandler.getNodeAt(pointer);
37224
37225 if (node !== undefined) {
37226 if (node.isCluster === true) {
37227 alert(this.options.locales[this.options.locale]["createEdgeError"] || this.options.locales["en"]["createEdgeError"]);
37228 } else {
37229 // create a node the temporary line can look at
37230 var targetNode = this._getNewTargetNode(node.x, node.y);
37231
37232 this.body.nodes[targetNode.id] = targetNode;
37233 this.body.nodeIndices.push(targetNode.id); // create a temporary edge
37234
37235 var connectionEdge = this.body.functions.createEdge({
37236 id: "connectionEdge" + v4(),
37237 from: node.id,
37238 to: targetNode.id,
37239 physics: false,
37240 smooth: {
37241 enabled: true,
37242 type: "continuous",
37243 roundness: 0.5
37244 }
37245 });
37246 this.body.edges[connectionEdge.id] = connectionEdge;
37247 this.body.edgeIndices.push(connectionEdge.id);
37248 this.temporaryIds.nodes.push(targetNode.id);
37249 this.temporaryIds.edges.push(connectionEdge.id);
37250 }
37251 }
37252
37253 this.touchTime = new Date().valueOf();
37254 }
37255 }
37256 /**
37257 *
37258 * @param {Event} event
37259 * @private
37260 */
37261
37262 }, {
37263 key: "_dragControlNode",
37264 value: function _dragControlNode(event) {
37265 var pointer = this.body.functions.getPointer(event.center);
37266
37267 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
37268
37269
37270 var connectFromId = undefined;
37271
37272 if (this.temporaryIds.edges[0] !== undefined) {
37273 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
37274 } // get the overlapping node but NOT the temporary node;
37275
37276
37277 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
37278
37279 var node = undefined;
37280
37281 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
37282 var _context30;
37283
37284 // if the node id is NOT a temporary node, accept the node.
37285 if (indexOf(_context30 = this.temporaryIds.nodes).call(_context30, overlappingNodeIds[i]) === -1) {
37286 node = this.body.nodes[overlappingNodeIds[i]];
37287 break;
37288 }
37289 }
37290
37291 event.controlEdge = {
37292 from: connectFromId,
37293 to: node ? node.id : undefined
37294 };
37295 this.selectionHandler.generateClickEvent("controlNodeDragging", event, pointer);
37296
37297 if (this.temporaryIds.nodes[0] !== undefined) {
37298 var targetNode = this.body.nodes[this.temporaryIds.nodes[0]]; // there is only one temp node in the add edge mode.
37299
37300 targetNode.x = this.canvas._XconvertDOMtoCanvas(pointer.x);
37301 targetNode.y = this.canvas._YconvertDOMtoCanvas(pointer.y);
37302 this.body.emitter.emit("_redraw");
37303 } else {
37304 this.interactionHandler.onDrag(event);
37305 }
37306 }
37307 /**
37308 * Connect the new edge to the target if one exists, otherwise remove temp line
37309 *
37310 * @param {Event} event The event
37311 * @private
37312 */
37313
37314 }, {
37315 key: "_finishConnect",
37316 value: function _finishConnect(event) {
37317 var pointer = this.body.functions.getPointer(event.center);
37318
37319 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
37320
37321
37322 var connectFromId = undefined;
37323
37324 if (this.temporaryIds.edges[0] !== undefined) {
37325 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
37326 } // get the overlapping node but NOT the temporary node;
37327
37328
37329 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
37330
37331 var node = undefined;
37332
37333 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
37334 var _context31;
37335
37336 // if the node id is NOT a temporary node, accept the node.
37337 if (indexOf(_context31 = this.temporaryIds.nodes).call(_context31, overlappingNodeIds[i]) === -1) {
37338 node = this.body.nodes[overlappingNodeIds[i]];
37339 break;
37340 }
37341 } // clean temporary nodes and edges.
37342
37343
37344 this._cleanupTemporaryNodesAndEdges(); // perform the connection
37345
37346
37347 if (node !== undefined) {
37348 if (node.isCluster === true) {
37349 alert(this.options.locales[this.options.locale]["createEdgeError"] || this.options.locales["en"]["createEdgeError"]);
37350 } else {
37351 if (this.body.nodes[connectFromId] !== undefined && this.body.nodes[node.id] !== undefined) {
37352 this._performAddEdge(connectFromId, node.id);
37353 }
37354 }
37355 }
37356
37357 event.controlEdge = {
37358 from: connectFromId,
37359 to: node ? node.id : undefined
37360 };
37361 this.selectionHandler.generateClickEvent("controlNodeDragEnd", event, pointer); // No need to do _generateclickevent('dragEnd') here, the regular dragEnd event fires.
37362
37363 this.body.emitter.emit("_redraw");
37364 }
37365 /**
37366 *
37367 * @param {Event} event
37368 * @private
37369 */
37370
37371 }, {
37372 key: "_dragStartEdge",
37373 value: function _dragStartEdge(event) {
37374 var pointer = this.lastTouch;
37375 this.selectionHandler.generateClickEvent("dragStart", event, pointer, undefined, true);
37376 } // --------------------------------------- END OF ADD EDGE FUNCTIONS -------------------------------------//
37377 // ------------------------------ Performing all the actual data manipulation ------------------------//
37378
37379 /**
37380 * Adds a node on the specified location
37381 *
37382 * @param {object} clickData
37383 * @private
37384 */
37385
37386 }, {
37387 key: "_performAddNode",
37388 value: function _performAddNode(clickData) {
37389 var _this4 = this;
37390
37391 var defaultData = {
37392 id: v4(),
37393 x: clickData.pointer.canvas.x,
37394 y: clickData.pointer.canvas.y,
37395 label: "new"
37396 };
37397
37398 if (typeof this.options.addNode === "function") {
37399 if (this.options.addNode.length === 2) {
37400 this.options.addNode(defaultData, function (finalizedData) {
37401 if (finalizedData !== null && finalizedData !== undefined && _this4.inMode === "addNode") {
37402 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
37403 _this4.body.data.nodes.getDataSet().add(finalizedData);
37404 }
37405
37406 _this4.showManipulatorToolbar();
37407 });
37408 } else {
37409 this.showManipulatorToolbar();
37410 throw new Error("The function for add does not support two arguments (data,callback)");
37411 }
37412 } else {
37413 this.body.data.nodes.getDataSet().add(defaultData);
37414 this.showManipulatorToolbar();
37415 }
37416 }
37417 /**
37418 * connect two nodes with a new edge.
37419 *
37420 * @param {Node.id} sourceNodeId
37421 * @param {Node.id} targetNodeId
37422 * @private
37423 */
37424
37425 }, {
37426 key: "_performAddEdge",
37427 value: function _performAddEdge(sourceNodeId, targetNodeId) {
37428 var _this5 = this;
37429
37430 var defaultData = {
37431 from: sourceNodeId,
37432 to: targetNodeId
37433 };
37434
37435 if (typeof this.options.addEdge === "function") {
37436 if (this.options.addEdge.length === 2) {
37437 this.options.addEdge(defaultData, function (finalizedData) {
37438 if (finalizedData !== null && finalizedData !== undefined && _this5.inMode === "addEdge") {
37439 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
37440 _this5.body.data.edges.getDataSet().add(finalizedData);
37441
37442 _this5.selectionHandler.unselectAll();
37443
37444 _this5.showManipulatorToolbar();
37445 }
37446 });
37447 } else {
37448 throw new Error("The function for connect does not support two arguments (data,callback)");
37449 }
37450 } else {
37451 this.body.data.edges.getDataSet().add(defaultData);
37452 this.selectionHandler.unselectAll();
37453 this.showManipulatorToolbar();
37454 }
37455 }
37456 /**
37457 * connect two nodes with a new edge.
37458 *
37459 * @param {Node.id} sourceNodeId
37460 * @param {Node.id} targetNodeId
37461 * @private
37462 */
37463
37464 }, {
37465 key: "_performEditEdge",
37466 value: function _performEditEdge(sourceNodeId, targetNodeId) {
37467 var _this6 = this;
37468
37469 var defaultData = {
37470 id: this.edgeBeingEditedId,
37471 from: sourceNodeId,
37472 to: targetNodeId,
37473 label: this.body.data.edges.get(this.edgeBeingEditedId).label
37474 };
37475 var eeFunct = this.options.editEdge;
37476
37477 if (_typeof(eeFunct) === "object") {
37478 eeFunct = eeFunct.editWithoutDrag;
37479 }
37480
37481 if (typeof eeFunct === "function") {
37482 if (eeFunct.length === 2) {
37483 eeFunct(defaultData, function (finalizedData) {
37484 if (finalizedData === null || finalizedData === undefined || _this6.inMode !== "editEdge") {
37485 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
37486 _this6.body.edges[defaultData.id].updateEdgeType();
37487
37488 _this6.body.emitter.emit("_redraw");
37489
37490 _this6.showManipulatorToolbar();
37491 } else {
37492 _this6.body.data.edges.getDataSet().update(finalizedData);
37493
37494 _this6.selectionHandler.unselectAll();
37495
37496 _this6.showManipulatorToolbar();
37497 }
37498 });
37499 } else {
37500 throw new Error("The function for edit does not support two arguments (data, callback)");
37501 }
37502 } else {
37503 this.body.data.edges.getDataSet().update(defaultData);
37504 this.selectionHandler.unselectAll();
37505 this.showManipulatorToolbar();
37506 }
37507 }
37508 }]);
37509
37510 return ManipulationSystem;
37511 }();
37512
37513 /**
37514 * This object contains all possible options. It will check if the types are correct, if required if the option is one
37515 * of the allowed values.
37516 *
37517 * __any__ means that the name of the property does not matter.
37518 * __type__ is a required field for all objects and contains the allowed types of all objects
37519 */
37520 var string = "string";
37521 var bool = "boolean";
37522 var number = "number";
37523 var array = "array";
37524 var object = "object"; // should only be in a __type__ property
37525
37526 var dom = "dom";
37527 var any = "any"; // List of endpoints
37528
37529 var endPoints = ["arrow", "bar", "box", "circle", "crow", "curve", "diamond", "image", "inv_curve", "inv_triangle", "triangle", "vee"];
37530 /* eslint-disable @typescript-eslint/naming-convention -- The __*__ format is used to prevent collisions with actual option names. */
37531
37532 var nodeOptions = {
37533 borderWidth: {
37534 number: number
37535 },
37536 borderWidthSelected: {
37537 number: number,
37538 undefined: "undefined"
37539 },
37540 brokenImage: {
37541 string: string,
37542 undefined: "undefined"
37543 },
37544 chosen: {
37545 label: {
37546 boolean: bool,
37547 function: "function"
37548 },
37549 node: {
37550 boolean: bool,
37551 function: "function"
37552 },
37553 __type__: {
37554 object: object,
37555 boolean: bool
37556 }
37557 },
37558 color: {
37559 border: {
37560 string: string
37561 },
37562 background: {
37563 string: string
37564 },
37565 highlight: {
37566 border: {
37567 string: string
37568 },
37569 background: {
37570 string: string
37571 },
37572 __type__: {
37573 object: object,
37574 string: string
37575 }
37576 },
37577 hover: {
37578 border: {
37579 string: string
37580 },
37581 background: {
37582 string: string
37583 },
37584 __type__: {
37585 object: object,
37586 string: string
37587 }
37588 },
37589 __type__: {
37590 object: object,
37591 string: string
37592 }
37593 },
37594 opacity: {
37595 number: number,
37596 undefined: "undefined"
37597 },
37598 fixed: {
37599 x: {
37600 boolean: bool
37601 },
37602 y: {
37603 boolean: bool
37604 },
37605 __type__: {
37606 object: object,
37607 boolean: bool
37608 }
37609 },
37610 font: {
37611 align: {
37612 string: string
37613 },
37614 color: {
37615 string: string
37616 },
37617 size: {
37618 number: number
37619 },
37620 face: {
37621 string: string
37622 },
37623 background: {
37624 string: string
37625 },
37626 strokeWidth: {
37627 number: number
37628 },
37629 strokeColor: {
37630 string: string
37631 },
37632 vadjust: {
37633 number: number
37634 },
37635 multi: {
37636 boolean: bool,
37637 string: string
37638 },
37639 bold: {
37640 color: {
37641 string: string
37642 },
37643 size: {
37644 number: number
37645 },
37646 face: {
37647 string: string
37648 },
37649 mod: {
37650 string: string
37651 },
37652 vadjust: {
37653 number: number
37654 },
37655 __type__: {
37656 object: object,
37657 string: string
37658 }
37659 },
37660 boldital: {
37661 color: {
37662 string: string
37663 },
37664 size: {
37665 number: number
37666 },
37667 face: {
37668 string: string
37669 },
37670 mod: {
37671 string: string
37672 },
37673 vadjust: {
37674 number: number
37675 },
37676 __type__: {
37677 object: object,
37678 string: string
37679 }
37680 },
37681 ital: {
37682 color: {
37683 string: string
37684 },
37685 size: {
37686 number: number
37687 },
37688 face: {
37689 string: string
37690 },
37691 mod: {
37692 string: string
37693 },
37694 vadjust: {
37695 number: number
37696 },
37697 __type__: {
37698 object: object,
37699 string: string
37700 }
37701 },
37702 mono: {
37703 color: {
37704 string: string
37705 },
37706 size: {
37707 number: number
37708 },
37709 face: {
37710 string: string
37711 },
37712 mod: {
37713 string: string
37714 },
37715 vadjust: {
37716 number: number
37717 },
37718 __type__: {
37719 object: object,
37720 string: string
37721 }
37722 },
37723 __type__: {
37724 object: object,
37725 string: string
37726 }
37727 },
37728 group: {
37729 string: string,
37730 number: number,
37731 undefined: "undefined"
37732 },
37733 heightConstraint: {
37734 minimum: {
37735 number: number
37736 },
37737 valign: {
37738 string: string
37739 },
37740 __type__: {
37741 object: object,
37742 boolean: bool,
37743 number: number
37744 }
37745 },
37746 hidden: {
37747 boolean: bool
37748 },
37749 icon: {
37750 face: {
37751 string: string
37752 },
37753 code: {
37754 string: string
37755 },
37756 size: {
37757 number: number
37758 },
37759 color: {
37760 string: string
37761 },
37762 weight: {
37763 string: string,
37764 number: number
37765 },
37766 __type__: {
37767 object: object
37768 }
37769 },
37770 id: {
37771 string: string,
37772 number: number
37773 },
37774 image: {
37775 selected: {
37776 string: string,
37777 undefined: "undefined"
37778 },
37779 unselected: {
37780 string: string,
37781 undefined: "undefined"
37782 },
37783 __type__: {
37784 object: object,
37785 string: string
37786 }
37787 },
37788 imagePadding: {
37789 top: {
37790 number: number
37791 },
37792 right: {
37793 number: number
37794 },
37795 bottom: {
37796 number: number
37797 },
37798 left: {
37799 number: number
37800 },
37801 __type__: {
37802 object: object,
37803 number: number
37804 }
37805 },
37806 label: {
37807 string: string,
37808 undefined: "undefined"
37809 },
37810 labelHighlightBold: {
37811 boolean: bool
37812 },
37813 level: {
37814 number: number,
37815 undefined: "undefined"
37816 },
37817 margin: {
37818 top: {
37819 number: number
37820 },
37821 right: {
37822 number: number
37823 },
37824 bottom: {
37825 number: number
37826 },
37827 left: {
37828 number: number
37829 },
37830 __type__: {
37831 object: object,
37832 number: number
37833 }
37834 },
37835 mass: {
37836 number: number
37837 },
37838 physics: {
37839 boolean: bool
37840 },
37841 scaling: {
37842 min: {
37843 number: number
37844 },
37845 max: {
37846 number: number
37847 },
37848 label: {
37849 enabled: {
37850 boolean: bool
37851 },
37852 min: {
37853 number: number
37854 },
37855 max: {
37856 number: number
37857 },
37858 maxVisible: {
37859 number: number
37860 },
37861 drawThreshold: {
37862 number: number
37863 },
37864 __type__: {
37865 object: object,
37866 boolean: bool
37867 }
37868 },
37869 customScalingFunction: {
37870 function: "function"
37871 },
37872 __type__: {
37873 object: object
37874 }
37875 },
37876 shadow: {
37877 enabled: {
37878 boolean: bool
37879 },
37880 color: {
37881 string: string
37882 },
37883 size: {
37884 number: number
37885 },
37886 x: {
37887 number: number
37888 },
37889 y: {
37890 number: number
37891 },
37892 __type__: {
37893 object: object,
37894 boolean: bool
37895 }
37896 },
37897 shape: {
37898 string: ["custom", "ellipse", "circle", "database", "box", "text", "image", "circularImage", "diamond", "dot", "star", "triangle", "triangleDown", "square", "icon", "hexagon"]
37899 },
37900 ctxRenderer: {
37901 function: "function"
37902 },
37903 shapeProperties: {
37904 borderDashes: {
37905 boolean: bool,
37906 array: array
37907 },
37908 borderRadius: {
37909 number: number
37910 },
37911 interpolation: {
37912 boolean: bool
37913 },
37914 useImageSize: {
37915 boolean: bool
37916 },
37917 useBorderWithImage: {
37918 boolean: bool
37919 },
37920 coordinateOrigin: {
37921 string: ["center", "top-left"]
37922 },
37923 __type__: {
37924 object: object
37925 }
37926 },
37927 size: {
37928 number: number
37929 },
37930 title: {
37931 string: string,
37932 dom: dom,
37933 undefined: "undefined"
37934 },
37935 value: {
37936 number: number,
37937 undefined: "undefined"
37938 },
37939 widthConstraint: {
37940 minimum: {
37941 number: number
37942 },
37943 maximum: {
37944 number: number
37945 },
37946 __type__: {
37947 object: object,
37948 boolean: bool,
37949 number: number
37950 }
37951 },
37952 x: {
37953 number: number
37954 },
37955 y: {
37956 number: number
37957 },
37958 __type__: {
37959 object: object
37960 }
37961 };
37962 var allOptions = {
37963 configure: {
37964 enabled: {
37965 boolean: bool
37966 },
37967 filter: {
37968 boolean: bool,
37969 string: string,
37970 array: array,
37971 function: "function"
37972 },
37973 container: {
37974 dom: dom
37975 },
37976 showButton: {
37977 boolean: bool
37978 },
37979 __type__: {
37980 object: object,
37981 boolean: bool,
37982 string: string,
37983 array: array,
37984 function: "function"
37985 }
37986 },
37987 edges: {
37988 arrows: {
37989 to: {
37990 enabled: {
37991 boolean: bool
37992 },
37993 scaleFactor: {
37994 number: number
37995 },
37996 type: {
37997 string: endPoints
37998 },
37999 imageHeight: {
38000 number: number
38001 },
38002 imageWidth: {
38003 number: number
38004 },
38005 src: {
38006 string: string
38007 },
38008 __type__: {
38009 object: object,
38010 boolean: bool
38011 }
38012 },
38013 middle: {
38014 enabled: {
38015 boolean: bool
38016 },
38017 scaleFactor: {
38018 number: number
38019 },
38020 type: {
38021 string: endPoints
38022 },
38023 imageWidth: {
38024 number: number
38025 },
38026 imageHeight: {
38027 number: number
38028 },
38029 src: {
38030 string: string
38031 },
38032 __type__: {
38033 object: object,
38034 boolean: bool
38035 }
38036 },
38037 from: {
38038 enabled: {
38039 boolean: bool
38040 },
38041 scaleFactor: {
38042 number: number
38043 },
38044 type: {
38045 string: endPoints
38046 },
38047 imageWidth: {
38048 number: number
38049 },
38050 imageHeight: {
38051 number: number
38052 },
38053 src: {
38054 string: string
38055 },
38056 __type__: {
38057 object: object,
38058 boolean: bool
38059 }
38060 },
38061 __type__: {
38062 string: ["from", "to", "middle"],
38063 object: object
38064 }
38065 },
38066 endPointOffset: {
38067 from: {
38068 number: number
38069 },
38070 to: {
38071 number: number
38072 },
38073 __type__: {
38074 object: object,
38075 number: number
38076 }
38077 },
38078 arrowStrikethrough: {
38079 boolean: bool
38080 },
38081 background: {
38082 enabled: {
38083 boolean: bool
38084 },
38085 color: {
38086 string: string
38087 },
38088 size: {
38089 number: number
38090 },
38091 dashes: {
38092 boolean: bool,
38093 array: array
38094 },
38095 __type__: {
38096 object: object,
38097 boolean: bool
38098 }
38099 },
38100 chosen: {
38101 label: {
38102 boolean: bool,
38103 function: "function"
38104 },
38105 edge: {
38106 boolean: bool,
38107 function: "function"
38108 },
38109 __type__: {
38110 object: object,
38111 boolean: bool
38112 }
38113 },
38114 color: {
38115 color: {
38116 string: string
38117 },
38118 highlight: {
38119 string: string
38120 },
38121 hover: {
38122 string: string
38123 },
38124 inherit: {
38125 string: ["from", "to", "both"],
38126 boolean: bool
38127 },
38128 opacity: {
38129 number: number
38130 },
38131 __type__: {
38132 object: object,
38133 string: string
38134 }
38135 },
38136 dashes: {
38137 boolean: bool,
38138 array: array
38139 },
38140 font: {
38141 color: {
38142 string: string
38143 },
38144 size: {
38145 number: number
38146 },
38147 face: {
38148 string: string
38149 },
38150 background: {
38151 string: string
38152 },
38153 strokeWidth: {
38154 number: number
38155 },
38156 strokeColor: {
38157 string: string
38158 },
38159 align: {
38160 string: ["horizontal", "top", "middle", "bottom"]
38161 },
38162 vadjust: {
38163 number: number
38164 },
38165 multi: {
38166 boolean: bool,
38167 string: string
38168 },
38169 bold: {
38170 color: {
38171 string: string
38172 },
38173 size: {
38174 number: number
38175 },
38176 face: {
38177 string: string
38178 },
38179 mod: {
38180 string: string
38181 },
38182 vadjust: {
38183 number: number
38184 },
38185 __type__: {
38186 object: object,
38187 string: string
38188 }
38189 },
38190 boldital: {
38191 color: {
38192 string: string
38193 },
38194 size: {
38195 number: number
38196 },
38197 face: {
38198 string: string
38199 },
38200 mod: {
38201 string: string
38202 },
38203 vadjust: {
38204 number: number
38205 },
38206 __type__: {
38207 object: object,
38208 string: string
38209 }
38210 },
38211 ital: {
38212 color: {
38213 string: string
38214 },
38215 size: {
38216 number: number
38217 },
38218 face: {
38219 string: string
38220 },
38221 mod: {
38222 string: string
38223 },
38224 vadjust: {
38225 number: number
38226 },
38227 __type__: {
38228 object: object,
38229 string: string
38230 }
38231 },
38232 mono: {
38233 color: {
38234 string: string
38235 },
38236 size: {
38237 number: number
38238 },
38239 face: {
38240 string: string
38241 },
38242 mod: {
38243 string: string
38244 },
38245 vadjust: {
38246 number: number
38247 },
38248 __type__: {
38249 object: object,
38250 string: string
38251 }
38252 },
38253 __type__: {
38254 object: object,
38255 string: string
38256 }
38257 },
38258 hidden: {
38259 boolean: bool
38260 },
38261 hoverWidth: {
38262 function: "function",
38263 number: number
38264 },
38265 label: {
38266 string: string,
38267 undefined: "undefined"
38268 },
38269 labelHighlightBold: {
38270 boolean: bool
38271 },
38272 length: {
38273 number: number,
38274 undefined: "undefined"
38275 },
38276 physics: {
38277 boolean: bool
38278 },
38279 scaling: {
38280 min: {
38281 number: number
38282 },
38283 max: {
38284 number: number
38285 },
38286 label: {
38287 enabled: {
38288 boolean: bool
38289 },
38290 min: {
38291 number: number
38292 },
38293 max: {
38294 number: number
38295 },
38296 maxVisible: {
38297 number: number
38298 },
38299 drawThreshold: {
38300 number: number
38301 },
38302 __type__: {
38303 object: object,
38304 boolean: bool
38305 }
38306 },
38307 customScalingFunction: {
38308 function: "function"
38309 },
38310 __type__: {
38311 object: object
38312 }
38313 },
38314 selectionWidth: {
38315 function: "function",
38316 number: number
38317 },
38318 selfReferenceSize: {
38319 number: number
38320 },
38321 selfReference: {
38322 size: {
38323 number: number
38324 },
38325 angle: {
38326 number: number
38327 },
38328 renderBehindTheNode: {
38329 boolean: bool
38330 },
38331 __type__: {
38332 object: object
38333 }
38334 },
38335 shadow: {
38336 enabled: {
38337 boolean: bool
38338 },
38339 color: {
38340 string: string
38341 },
38342 size: {
38343 number: number
38344 },
38345 x: {
38346 number: number
38347 },
38348 y: {
38349 number: number
38350 },
38351 __type__: {
38352 object: object,
38353 boolean: bool
38354 }
38355 },
38356 smooth: {
38357 enabled: {
38358 boolean: bool
38359 },
38360 type: {
38361 string: ["dynamic", "continuous", "discrete", "diagonalCross", "straightCross", "horizontal", "vertical", "curvedCW", "curvedCCW", "cubicBezier"]
38362 },
38363 roundness: {
38364 number: number
38365 },
38366 forceDirection: {
38367 string: ["horizontal", "vertical", "none"],
38368 boolean: bool
38369 },
38370 __type__: {
38371 object: object,
38372 boolean: bool
38373 }
38374 },
38375 title: {
38376 string: string,
38377 undefined: "undefined"
38378 },
38379 width: {
38380 number: number
38381 },
38382 widthConstraint: {
38383 maximum: {
38384 number: number
38385 },
38386 __type__: {
38387 object: object,
38388 boolean: bool,
38389 number: number
38390 }
38391 },
38392 value: {
38393 number: number,
38394 undefined: "undefined"
38395 },
38396 __type__: {
38397 object: object
38398 }
38399 },
38400 groups: {
38401 useDefaultGroups: {
38402 boolean: bool
38403 },
38404 __any__: nodeOptions,
38405 __type__: {
38406 object: object
38407 }
38408 },
38409 interaction: {
38410 dragNodes: {
38411 boolean: bool
38412 },
38413 dragView: {
38414 boolean: bool
38415 },
38416 hideEdgesOnDrag: {
38417 boolean: bool
38418 },
38419 hideEdgesOnZoom: {
38420 boolean: bool
38421 },
38422 hideNodesOnDrag: {
38423 boolean: bool
38424 },
38425 hover: {
38426 boolean: bool
38427 },
38428 keyboard: {
38429 enabled: {
38430 boolean: bool
38431 },
38432 speed: {
38433 x: {
38434 number: number
38435 },
38436 y: {
38437 number: number
38438 },
38439 zoom: {
38440 number: number
38441 },
38442 __type__: {
38443 object: object
38444 }
38445 },
38446 bindToWindow: {
38447 boolean: bool
38448 },
38449 autoFocus: {
38450 boolean: bool
38451 },
38452 __type__: {
38453 object: object,
38454 boolean: bool
38455 }
38456 },
38457 multiselect: {
38458 boolean: bool
38459 },
38460 navigationButtons: {
38461 boolean: bool
38462 },
38463 selectable: {
38464 boolean: bool
38465 },
38466 selectConnectedEdges: {
38467 boolean: bool
38468 },
38469 hoverConnectedEdges: {
38470 boolean: bool
38471 },
38472 tooltipDelay: {
38473 number: number
38474 },
38475 zoomView: {
38476 boolean: bool
38477 },
38478 zoomSpeed: {
38479 number: number
38480 },
38481 __type__: {
38482 object: object
38483 }
38484 },
38485 layout: {
38486 randomSeed: {
38487 undefined: "undefined",
38488 number: number,
38489 string: string
38490 },
38491 improvedLayout: {
38492 boolean: bool
38493 },
38494 clusterThreshold: {
38495 number: number
38496 },
38497 hierarchical: {
38498 enabled: {
38499 boolean: bool
38500 },
38501 levelSeparation: {
38502 number: number
38503 },
38504 nodeSpacing: {
38505 number: number
38506 },
38507 treeSpacing: {
38508 number: number
38509 },
38510 blockShifting: {
38511 boolean: bool
38512 },
38513 edgeMinimization: {
38514 boolean: bool
38515 },
38516 parentCentralization: {
38517 boolean: bool
38518 },
38519 direction: {
38520 string: ["UD", "DU", "LR", "RL"]
38521 },
38522 sortMethod: {
38523 string: ["hubsize", "directed"]
38524 },
38525 shakeTowards: {
38526 string: ["leaves", "roots"]
38527 },
38528 __type__: {
38529 object: object,
38530 boolean: bool
38531 }
38532 },
38533 __type__: {
38534 object: object
38535 }
38536 },
38537 manipulation: {
38538 enabled: {
38539 boolean: bool
38540 },
38541 initiallyActive: {
38542 boolean: bool
38543 },
38544 addNode: {
38545 boolean: bool,
38546 function: "function"
38547 },
38548 addEdge: {
38549 boolean: bool,
38550 function: "function"
38551 },
38552 editNode: {
38553 function: "function"
38554 },
38555 editEdge: {
38556 editWithoutDrag: {
38557 function: "function"
38558 },
38559 __type__: {
38560 object: object,
38561 boolean: bool,
38562 function: "function"
38563 }
38564 },
38565 deleteNode: {
38566 boolean: bool,
38567 function: "function"
38568 },
38569 deleteEdge: {
38570 boolean: bool,
38571 function: "function"
38572 },
38573 controlNodeStyle: nodeOptions,
38574 __type__: {
38575 object: object,
38576 boolean: bool
38577 }
38578 },
38579 nodes: nodeOptions,
38580 physics: {
38581 enabled: {
38582 boolean: bool
38583 },
38584 barnesHut: {
38585 theta: {
38586 number: number
38587 },
38588 gravitationalConstant: {
38589 number: number
38590 },
38591 centralGravity: {
38592 number: number
38593 },
38594 springLength: {
38595 number: number
38596 },
38597 springConstant: {
38598 number: number
38599 },
38600 damping: {
38601 number: number
38602 },
38603 avoidOverlap: {
38604 number: number
38605 },
38606 __type__: {
38607 object: object
38608 }
38609 },
38610 forceAtlas2Based: {
38611 theta: {
38612 number: number
38613 },
38614 gravitationalConstant: {
38615 number: number
38616 },
38617 centralGravity: {
38618 number: number
38619 },
38620 springLength: {
38621 number: number
38622 },
38623 springConstant: {
38624 number: number
38625 },
38626 damping: {
38627 number: number
38628 },
38629 avoidOverlap: {
38630 number: number
38631 },
38632 __type__: {
38633 object: object
38634 }
38635 },
38636 repulsion: {
38637 centralGravity: {
38638 number: number
38639 },
38640 springLength: {
38641 number: number
38642 },
38643 springConstant: {
38644 number: number
38645 },
38646 nodeDistance: {
38647 number: number
38648 },
38649 damping: {
38650 number: number
38651 },
38652 __type__: {
38653 object: object
38654 }
38655 },
38656 hierarchicalRepulsion: {
38657 centralGravity: {
38658 number: number
38659 },
38660 springLength: {
38661 number: number
38662 },
38663 springConstant: {
38664 number: number
38665 },
38666 nodeDistance: {
38667 number: number
38668 },
38669 damping: {
38670 number: number
38671 },
38672 avoidOverlap: {
38673 number: number
38674 },
38675 __type__: {
38676 object: object
38677 }
38678 },
38679 maxVelocity: {
38680 number: number
38681 },
38682 minVelocity: {
38683 number: number
38684 },
38685 solver: {
38686 string: ["barnesHut", "repulsion", "hierarchicalRepulsion", "forceAtlas2Based"]
38687 },
38688 stabilization: {
38689 enabled: {
38690 boolean: bool
38691 },
38692 iterations: {
38693 number: number
38694 },
38695 updateInterval: {
38696 number: number
38697 },
38698 onlyDynamicEdges: {
38699 boolean: bool
38700 },
38701 fit: {
38702 boolean: bool
38703 },
38704 __type__: {
38705 object: object,
38706 boolean: bool
38707 }
38708 },
38709 timestep: {
38710 number: number
38711 },
38712 adaptiveTimestep: {
38713 boolean: bool
38714 },
38715 wind: {
38716 x: {
38717 number: number
38718 },
38719 y: {
38720 number: number
38721 },
38722 __type__: {
38723 object: object
38724 }
38725 },
38726 __type__: {
38727 object: object,
38728 boolean: bool
38729 }
38730 },
38731 //globals :
38732 autoResize: {
38733 boolean: bool
38734 },
38735 clickToUse: {
38736 boolean: bool
38737 },
38738 locale: {
38739 string: string
38740 },
38741 locales: {
38742 __any__: {
38743 any: any
38744 },
38745 __type__: {
38746 object: object
38747 }
38748 },
38749 height: {
38750 string: string
38751 },
38752 width: {
38753 string: string
38754 },
38755 __type__: {
38756 object: object
38757 }
38758 };
38759 /* eslint-enable @typescript-eslint/naming-convention */
38760
38761 /**
38762 * This provides ranges, initial values, steps and dropdown menu choices for the
38763 * configuration.
38764 *
38765 * @remarks
38766 * Checkbox: `boolean`
38767 * The value supllied will be used as the initial value.
38768 *
38769 * Text field: `string`
38770 * The passed text will be used as the initial value. Any text will be
38771 * accepted afterwards.
38772 *
38773 * Number range: `[number, number, number, number]`
38774 * The meanings are `[initial value, min, max, step]`.
38775 *
38776 * Dropdown: `[Exclude<string, "color">, ...(string | number | boolean)[]]`
38777 * Translations for people with poor understanding of TypeScript: the first
38778 * value always has to be a string but never `"color"`, the rest can be any
38779 * combination of strings, numbers and booleans.
38780 *
38781 * Color picker: `["color", string]`
38782 * The first value says this will be a color picker not a dropdown menu. The
38783 * next value is the initial color.
38784 */
38785
38786 var configureOptions = {
38787 nodes: {
38788 borderWidth: [1, 0, 10, 1],
38789 borderWidthSelected: [2, 0, 10, 1],
38790 color: {
38791 border: ["color", "#2B7CE9"],
38792 background: ["color", "#97C2FC"],
38793 highlight: {
38794 border: ["color", "#2B7CE9"],
38795 background: ["color", "#D2E5FF"]
38796 },
38797 hover: {
38798 border: ["color", "#2B7CE9"],
38799 background: ["color", "#D2E5FF"]
38800 }
38801 },
38802 opacity: [0, 0, 1, 0.1],
38803 fixed: {
38804 x: false,
38805 y: false
38806 },
38807 font: {
38808 color: ["color", "#343434"],
38809 size: [14, 0, 100, 1],
38810 face: ["arial", "verdana", "tahoma"],
38811 background: ["color", "none"],
38812 strokeWidth: [0, 0, 50, 1],
38813 strokeColor: ["color", "#ffffff"]
38814 },
38815 //group: 'string',
38816 hidden: false,
38817 labelHighlightBold: true,
38818 //icon: {
38819 // face: 'string', //'FontAwesome',
38820 // code: 'string', //'\uf007',
38821 // size: [50, 0, 200, 1], //50,
38822 // color: ['color','#2B7CE9'] //'#aa00ff'
38823 //},
38824 //image: 'string', // --> URL
38825 physics: true,
38826 scaling: {
38827 min: [10, 0, 200, 1],
38828 max: [30, 0, 200, 1],
38829 label: {
38830 enabled: false,
38831 min: [14, 0, 200, 1],
38832 max: [30, 0, 200, 1],
38833 maxVisible: [30, 0, 200, 1],
38834 drawThreshold: [5, 0, 20, 1]
38835 }
38836 },
38837 shadow: {
38838 enabled: false,
38839 color: "rgba(0,0,0,0.5)",
38840 size: [10, 0, 20, 1],
38841 x: [5, -30, 30, 1],
38842 y: [5, -30, 30, 1]
38843 },
38844 shape: ["ellipse", "box", "circle", "database", "diamond", "dot", "square", "star", "text", "triangle", "triangleDown", "hexagon"],
38845 shapeProperties: {
38846 borderDashes: false,
38847 borderRadius: [6, 0, 20, 1],
38848 interpolation: true,
38849 useImageSize: false
38850 },
38851 size: [25, 0, 200, 1]
38852 },
38853 edges: {
38854 arrows: {
38855 to: {
38856 enabled: false,
38857 scaleFactor: [1, 0, 3, 0.05],
38858 type: "arrow"
38859 },
38860 middle: {
38861 enabled: false,
38862 scaleFactor: [1, 0, 3, 0.05],
38863 type: "arrow"
38864 },
38865 from: {
38866 enabled: false,
38867 scaleFactor: [1, 0, 3, 0.05],
38868 type: "arrow"
38869 }
38870 },
38871 endPointOffset: {
38872 from: [0, -10, 10, 1],
38873 to: [0, -10, 10, 1]
38874 },
38875 arrowStrikethrough: true,
38876 color: {
38877 color: ["color", "#848484"],
38878 highlight: ["color", "#848484"],
38879 hover: ["color", "#848484"],
38880 inherit: ["from", "to", "both", true, false],
38881 opacity: [1, 0, 1, 0.05]
38882 },
38883 dashes: false,
38884 font: {
38885 color: ["color", "#343434"],
38886 size: [14, 0, 100, 1],
38887 face: ["arial", "verdana", "tahoma"],
38888 background: ["color", "none"],
38889 strokeWidth: [2, 0, 50, 1],
38890 strokeColor: ["color", "#ffffff"],
38891 align: ["horizontal", "top", "middle", "bottom"]
38892 },
38893 hidden: false,
38894 hoverWidth: [1.5, 0, 5, 0.1],
38895 labelHighlightBold: true,
38896 physics: true,
38897 scaling: {
38898 min: [1, 0, 100, 1],
38899 max: [15, 0, 100, 1],
38900 label: {
38901 enabled: true,
38902 min: [14, 0, 200, 1],
38903 max: [30, 0, 200, 1],
38904 maxVisible: [30, 0, 200, 1],
38905 drawThreshold: [5, 0, 20, 1]
38906 }
38907 },
38908 selectionWidth: [1.5, 0, 5, 0.1],
38909 selfReferenceSize: [20, 0, 200, 1],
38910 selfReference: {
38911 size: [20, 0, 200, 1],
38912 angle: [Math.PI / 2, -6 * Math.PI, 6 * Math.PI, Math.PI / 8],
38913 renderBehindTheNode: true
38914 },
38915 shadow: {
38916 enabled: false,
38917 color: "rgba(0,0,0,0.5)",
38918 size: [10, 0, 20, 1],
38919 x: [5, -30, 30, 1],
38920 y: [5, -30, 30, 1]
38921 },
38922 smooth: {
38923 enabled: true,
38924 type: ["dynamic", "continuous", "discrete", "diagonalCross", "straightCross", "horizontal", "vertical", "curvedCW", "curvedCCW", "cubicBezier"],
38925 forceDirection: ["horizontal", "vertical", "none"],
38926 roundness: [0.5, 0, 1, 0.05]
38927 },
38928 width: [1, 0, 30, 1]
38929 },
38930 layout: {
38931 //randomSeed: [0, 0, 500, 1],
38932 //improvedLayout: true,
38933 hierarchical: {
38934 enabled: false,
38935 levelSeparation: [150, 20, 500, 5],
38936 nodeSpacing: [100, 20, 500, 5],
38937 treeSpacing: [200, 20, 500, 5],
38938 blockShifting: true,
38939 edgeMinimization: true,
38940 parentCentralization: true,
38941 direction: ["UD", "DU", "LR", "RL"],
38942 sortMethod: ["hubsize", "directed"],
38943 shakeTowards: ["leaves", "roots"] // leaves, roots
38944
38945 }
38946 },
38947 interaction: {
38948 dragNodes: true,
38949 dragView: true,
38950 hideEdgesOnDrag: false,
38951 hideEdgesOnZoom: false,
38952 hideNodesOnDrag: false,
38953 hover: false,
38954 keyboard: {
38955 enabled: false,
38956 speed: {
38957 x: [10, 0, 40, 1],
38958 y: [10, 0, 40, 1],
38959 zoom: [0.02, 0, 0.1, 0.005]
38960 },
38961 bindToWindow: true,
38962 autoFocus: true
38963 },
38964 multiselect: false,
38965 navigationButtons: false,
38966 selectable: true,
38967 selectConnectedEdges: true,
38968 hoverConnectedEdges: true,
38969 tooltipDelay: [300, 0, 1000, 25],
38970 zoomView: true,
38971 zoomSpeed: [1, 0.1, 2, 0.1]
38972 },
38973 manipulation: {
38974 enabled: false,
38975 initiallyActive: false
38976 },
38977 physics: {
38978 enabled: true,
38979 barnesHut: {
38980 theta: [0.5, 0.1, 1, 0.05],
38981 gravitationalConstant: [-2000, -30000, 0, 50],
38982 centralGravity: [0.3, 0, 10, 0.05],
38983 springLength: [95, 0, 500, 5],
38984 springConstant: [0.04, 0, 1.2, 0.005],
38985 damping: [0.09, 0, 1, 0.01],
38986 avoidOverlap: [0, 0, 1, 0.01]
38987 },
38988 forceAtlas2Based: {
38989 theta: [0.5, 0.1, 1, 0.05],
38990 gravitationalConstant: [-50, -500, 0, 1],
38991 centralGravity: [0.01, 0, 1, 0.005],
38992 springLength: [95, 0, 500, 5],
38993 springConstant: [0.08, 0, 1.2, 0.005],
38994 damping: [0.4, 0, 1, 0.01],
38995 avoidOverlap: [0, 0, 1, 0.01]
38996 },
38997 repulsion: {
38998 centralGravity: [0.2, 0, 10, 0.05],
38999 springLength: [200, 0, 500, 5],
39000 springConstant: [0.05, 0, 1.2, 0.005],
39001 nodeDistance: [100, 0, 500, 5],
39002 damping: [0.09, 0, 1, 0.01]
39003 },
39004 hierarchicalRepulsion: {
39005 centralGravity: [0.2, 0, 10, 0.05],
39006 springLength: [100, 0, 500, 5],
39007 springConstant: [0.01, 0, 1.2, 0.005],
39008 nodeDistance: [120, 0, 500, 5],
39009 damping: [0.09, 0, 1, 0.01],
39010 avoidOverlap: [0, 0, 1, 0.01]
39011 },
39012 maxVelocity: [50, 0, 150, 1],
39013 minVelocity: [0.1, 0.01, 0.5, 0.01],
39014 solver: ["barnesHut", "forceAtlas2Based", "repulsion", "hierarchicalRepulsion"],
39015 timestep: [0.5, 0.01, 1, 0.01],
39016 wind: {
39017 x: [0, -10, 10, 0.1],
39018 y: [0, -10, 10, 0.1]
39019 } //adaptiveTimestep: true
39020
39021 }
39022 };
39023 var configuratorHideOption = function configuratorHideOption(parentPath, optionName, options) {
39024 var _context;
39025
39026 if (includes(parentPath).call(parentPath, "physics") && includes(_context = configureOptions.physics.solver).call(_context, optionName) && options.physics.solver !== optionName && optionName !== "wind") {
39027 return true;
39028 }
39029
39030 return false;
39031 };
39032
39033 var options = /*#__PURE__*/Object.freeze({
39034 __proto__: null,
39035 configuratorHideOption: configuratorHideOption,
39036 allOptions: allOptions,
39037 configureOptions: configureOptions
39038 });
39039
39040 /**
39041 * The Floyd–Warshall algorithm is an algorithm for finding shortest paths in
39042 * a weighted graph with positive or negative edge weights (but with no negative
39043 * cycles). - https://en.wikipedia.org/wiki/Floyd–Warshall_algorithm
39044 */
39045 var FloydWarshall = /*#__PURE__*/function () {
39046 /**
39047 * @ignore
39048 */
39049 function FloydWarshall() {
39050 _classCallCheck(this, FloydWarshall);
39051 }
39052 /**
39053 *
39054 * @param {object} body
39055 * @param {Array.<Node>} nodesArray
39056 * @param {Array.<Edge>} edgesArray
39057 * @returns {{}}
39058 */
39059
39060
39061 _createClass(FloydWarshall, [{
39062 key: "getDistances",
39063 value: function getDistances(body, nodesArray, edgesArray) {
39064 var D_matrix = {};
39065 var edges = body.edges; // prepare matrix with large numbers
39066
39067 for (var i = 0; i < nodesArray.length; i++) {
39068 var node = nodesArray[i];
39069 var cell = {};
39070 D_matrix[node] = cell;
39071
39072 for (var j = 0; j < nodesArray.length; j++) {
39073 cell[nodesArray[j]] = i == j ? 0 : 1e9;
39074 }
39075 } // put the weights for the edges in. This assumes unidirectionality.
39076
39077
39078 for (var _i = 0; _i < edgesArray.length; _i++) {
39079 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
39080
39081 if (edge.connected === true && D_matrix[edge.fromId] !== undefined && D_matrix[edge.toId] !== undefined) {
39082 D_matrix[edge.fromId][edge.toId] = 1;
39083 D_matrix[edge.toId][edge.fromId] = 1;
39084 }
39085 }
39086
39087 var nodeCount = nodesArray.length; // Adapted FloydWarshall based on unidirectionality to greatly reduce complexity.
39088
39089 for (var k = 0; k < nodeCount; k++) {
39090 var knode = nodesArray[k];
39091 var kcolm = D_matrix[knode];
39092
39093 for (var _i2 = 0; _i2 < nodeCount - 1; _i2++) {
39094 var inode = nodesArray[_i2];
39095 var icolm = D_matrix[inode];
39096
39097 for (var _j = _i2 + 1; _j < nodeCount; _j++) {
39098 var jnode = nodesArray[_j];
39099 var jcolm = D_matrix[jnode];
39100 var val = Math.min(icolm[jnode], icolm[knode] + kcolm[jnode]);
39101 icolm[jnode] = val;
39102 jcolm[inode] = val;
39103 }
39104 }
39105 }
39106
39107 return D_matrix;
39108 }
39109 }]);
39110
39111 return FloydWarshall;
39112 }();
39113
39114 /**
39115 * KamadaKawai positions the nodes initially based on
39116 *
39117 * "AN ALGORITHM FOR DRAWING GENERAL UNDIRECTED GRAPHS"
39118 * -- Tomihisa KAMADA and Satoru KAWAI in 1989
39119 *
39120 * Possible optimizations in the distance calculation can be implemented.
39121 */
39122
39123 var KamadaKawai = /*#__PURE__*/function () {
39124 /**
39125 * @param {object} body
39126 * @param {number} edgeLength
39127 * @param {number} edgeStrength
39128 */
39129 function KamadaKawai(body, edgeLength, edgeStrength) {
39130 _classCallCheck(this, KamadaKawai);
39131
39132 this.body = body;
39133 this.springLength = edgeLength;
39134 this.springConstant = edgeStrength;
39135 this.distanceSolver = new FloydWarshall();
39136 }
39137 /**
39138 * Not sure if needed but can be used to update the spring length and spring constant
39139 *
39140 * @param {object} options
39141 */
39142
39143
39144 _createClass(KamadaKawai, [{
39145 key: "setOptions",
39146 value: function setOptions(options) {
39147 if (options) {
39148 if (options.springLength) {
39149 this.springLength = options.springLength;
39150 }
39151
39152 if (options.springConstant) {
39153 this.springConstant = options.springConstant;
39154 }
39155 }
39156 }
39157 /**
39158 * Position the system
39159 *
39160 * @param {Array.<Node>} nodesArray
39161 * @param {Array.<vis.Edge>} edgesArray
39162 * @param {boolean} [ignoreClusters=false]
39163 */
39164
39165 }, {
39166 key: "solve",
39167 value: function solve(nodesArray, edgesArray) {
39168 var ignoreClusters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
39169 // get distance matrix
39170 var D_matrix = this.distanceSolver.getDistances(this.body, nodesArray, edgesArray); // distance matrix
39171 // get the L Matrix
39172
39173 this._createL_matrix(D_matrix); // get the K Matrix
39174
39175
39176 this._createK_matrix(D_matrix); // initial E Matrix
39177
39178
39179 this._createE_matrix(); // calculate positions
39180
39181
39182 var threshold = 0.01;
39183 var innerThreshold = 1;
39184 var iterations = 0;
39185 var maxIterations = Math.max(1000, Math.min(10 * this.body.nodeIndices.length, 6000));
39186 var maxInnerIterations = 5;
39187 var maxEnergy = 1e9;
39188 var highE_nodeId = 0,
39189 dE_dx = 0,
39190 dE_dy = 0,
39191 delta_m = 0,
39192 subIterations = 0;
39193
39194 while (maxEnergy > threshold && iterations < maxIterations) {
39195 iterations += 1;
39196
39197 var _this$_getHighestEner = this._getHighestEnergyNode(ignoreClusters);
39198
39199 var _this$_getHighestEner2 = _slicedToArray(_this$_getHighestEner, 4);
39200
39201 highE_nodeId = _this$_getHighestEner2[0];
39202 maxEnergy = _this$_getHighestEner2[1];
39203 dE_dx = _this$_getHighestEner2[2];
39204 dE_dy = _this$_getHighestEner2[3];
39205 delta_m = maxEnergy;
39206 subIterations = 0;
39207
39208 while (delta_m > innerThreshold && subIterations < maxInnerIterations) {
39209 subIterations += 1;
39210
39211 this._moveNode(highE_nodeId, dE_dx, dE_dy);
39212
39213 var _this$_getEnergy = this._getEnergy(highE_nodeId);
39214
39215 var _this$_getEnergy2 = _slicedToArray(_this$_getEnergy, 3);
39216
39217 delta_m = _this$_getEnergy2[0];
39218 dE_dx = _this$_getEnergy2[1];
39219 dE_dy = _this$_getEnergy2[2];
39220 }
39221 }
39222 }
39223 /**
39224 * get the node with the highest energy
39225 *
39226 * @param {boolean} ignoreClusters
39227 * @returns {number[]}
39228 * @private
39229 */
39230
39231 }, {
39232 key: "_getHighestEnergyNode",
39233 value: function _getHighestEnergyNode(ignoreClusters) {
39234 var nodesArray = this.body.nodeIndices;
39235 var nodes = this.body.nodes;
39236 var maxEnergy = 0;
39237 var maxEnergyNodeId = nodesArray[0];
39238 var dE_dx_max = 0,
39239 dE_dy_max = 0;
39240
39241 for (var nodeIdx = 0; nodeIdx < nodesArray.length; nodeIdx++) {
39242 var m = nodesArray[nodeIdx]; // by not evaluating nodes with predefined positions we should only move nodes that have no positions.
39243
39244 if (nodes[m].predefinedPosition !== true || nodes[m].isCluster === true && ignoreClusters === true || nodes[m].options.fixed.x !== true || nodes[m].options.fixed.y !== true) {
39245 var _this$_getEnergy3 = this._getEnergy(m),
39246 _this$_getEnergy4 = _slicedToArray(_this$_getEnergy3, 3),
39247 delta_m = _this$_getEnergy4[0],
39248 dE_dx = _this$_getEnergy4[1],
39249 dE_dy = _this$_getEnergy4[2];
39250
39251 if (maxEnergy < delta_m) {
39252 maxEnergy = delta_m;
39253 maxEnergyNodeId = m;
39254 dE_dx_max = dE_dx;
39255 dE_dy_max = dE_dy;
39256 }
39257 }
39258 }
39259
39260 return [maxEnergyNodeId, maxEnergy, dE_dx_max, dE_dy_max];
39261 }
39262 /**
39263 * calculate the energy of a single node
39264 *
39265 * @param {Node.id} m
39266 * @returns {number[]}
39267 * @private
39268 */
39269
39270 }, {
39271 key: "_getEnergy",
39272 value: function _getEnergy(m) {
39273 var _this$E_sums$m = _slicedToArray(this.E_sums[m], 2),
39274 dE_dx = _this$E_sums$m[0],
39275 dE_dy = _this$E_sums$m[1];
39276
39277 var delta_m = Math.sqrt(Math.pow(dE_dx, 2) + Math.pow(dE_dy, 2));
39278 return [delta_m, dE_dx, dE_dy];
39279 }
39280 /**
39281 * move the node based on it's energy
39282 * the dx and dy are calculated from the linear system proposed by Kamada and Kawai
39283 *
39284 * @param {number} m
39285 * @param {number} dE_dx
39286 * @param {number} dE_dy
39287 * @private
39288 */
39289
39290 }, {
39291 key: "_moveNode",
39292 value: function _moveNode(m, dE_dx, dE_dy) {
39293 var nodesArray = this.body.nodeIndices;
39294 var nodes = this.body.nodes;
39295 var d2E_dx2 = 0;
39296 var d2E_dxdy = 0;
39297 var d2E_dy2 = 0;
39298 var x_m = nodes[m].x;
39299 var y_m = nodes[m].y;
39300 var km = this.K_matrix[m];
39301 var lm = this.L_matrix[m];
39302
39303 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
39304 var i = nodesArray[iIdx];
39305
39306 if (i !== m) {
39307 var x_i = nodes[i].x;
39308 var y_i = nodes[i].y;
39309 var kmat = km[i];
39310 var lmat = lm[i];
39311 var denominator = 1.0 / Math.pow(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2), 1.5);
39312 d2E_dx2 += kmat * (1 - lmat * Math.pow(y_m - y_i, 2) * denominator);
39313 d2E_dxdy += kmat * (lmat * (x_m - x_i) * (y_m - y_i) * denominator);
39314 d2E_dy2 += kmat * (1 - lmat * Math.pow(x_m - x_i, 2) * denominator);
39315 }
39316 } // make the variable names easier to make the solving of the linear system easier to read
39317
39318
39319 var A = d2E_dx2,
39320 B = d2E_dxdy,
39321 C = dE_dx,
39322 D = d2E_dy2,
39323 E = dE_dy; // solve the linear system for dx and dy
39324
39325 var dy = (C / A + E / B) / (B / A - D / B);
39326 var dx = -(B * dy + C) / A; // move the node
39327
39328 nodes[m].x += dx;
39329 nodes[m].y += dy; // Recalculate E_matrix (should be incremental)
39330
39331 this._updateE_matrix(m);
39332 }
39333 /**
39334 * Create the L matrix: edge length times shortest path
39335 *
39336 * @param {object} D_matrix
39337 * @private
39338 */
39339
39340 }, {
39341 key: "_createL_matrix",
39342 value: function _createL_matrix(D_matrix) {
39343 var nodesArray = this.body.nodeIndices;
39344 var edgeLength = this.springLength;
39345 this.L_matrix = [];
39346
39347 for (var i = 0; i < nodesArray.length; i++) {
39348 this.L_matrix[nodesArray[i]] = {};
39349
39350 for (var j = 0; j < nodesArray.length; j++) {
39351 this.L_matrix[nodesArray[i]][nodesArray[j]] = edgeLength * D_matrix[nodesArray[i]][nodesArray[j]];
39352 }
39353 }
39354 }
39355 /**
39356 * Create the K matrix: spring constants times shortest path
39357 *
39358 * @param {object} D_matrix
39359 * @private
39360 */
39361
39362 }, {
39363 key: "_createK_matrix",
39364 value: function _createK_matrix(D_matrix) {
39365 var nodesArray = this.body.nodeIndices;
39366 var edgeStrength = this.springConstant;
39367 this.K_matrix = [];
39368
39369 for (var i = 0; i < nodesArray.length; i++) {
39370 this.K_matrix[nodesArray[i]] = {};
39371
39372 for (var j = 0; j < nodesArray.length; j++) {
39373 this.K_matrix[nodesArray[i]][nodesArray[j]] = edgeStrength * Math.pow(D_matrix[nodesArray[i]][nodesArray[j]], -2);
39374 }
39375 }
39376 }
39377 /**
39378 * Create matrix with all energies between nodes
39379 *
39380 * @private
39381 */
39382
39383 }, {
39384 key: "_createE_matrix",
39385 value: function _createE_matrix() {
39386 var nodesArray = this.body.nodeIndices;
39387 var nodes = this.body.nodes;
39388 this.E_matrix = {};
39389 this.E_sums = {};
39390
39391 for (var mIdx = 0; mIdx < nodesArray.length; mIdx++) {
39392 this.E_matrix[nodesArray[mIdx]] = [];
39393 }
39394
39395 for (var _mIdx = 0; _mIdx < nodesArray.length; _mIdx++) {
39396 var m = nodesArray[_mIdx];
39397 var x_m = nodes[m].x;
39398 var y_m = nodes[m].y;
39399 var dE_dx = 0;
39400 var dE_dy = 0;
39401
39402 for (var iIdx = _mIdx; iIdx < nodesArray.length; iIdx++) {
39403 var i = nodesArray[iIdx];
39404
39405 if (i !== m) {
39406 var x_i = nodes[i].x;
39407 var y_i = nodes[i].y;
39408 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
39409 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)];
39410 this.E_matrix[i][_mIdx] = this.E_matrix[m][iIdx];
39411 dE_dx += this.E_matrix[m][iIdx][0];
39412 dE_dy += this.E_matrix[m][iIdx][1];
39413 }
39414 } //Store sum
39415
39416
39417 this.E_sums[m] = [dE_dx, dE_dy];
39418 }
39419 }
39420 /**
39421 * Update method, just doing single column (rows are auto-updated) (update all sums)
39422 *
39423 * @param {number} m
39424 * @private
39425 */
39426
39427 }, {
39428 key: "_updateE_matrix",
39429 value: function _updateE_matrix(m) {
39430 var nodesArray = this.body.nodeIndices;
39431 var nodes = this.body.nodes;
39432 var colm = this.E_matrix[m];
39433 var kcolm = this.K_matrix[m];
39434 var lcolm = this.L_matrix[m];
39435 var x_m = nodes[m].x;
39436 var y_m = nodes[m].y;
39437 var dE_dx = 0;
39438 var dE_dy = 0;
39439
39440 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
39441 var i = nodesArray[iIdx];
39442
39443 if (i !== m) {
39444 //Keep old energy value for sum modification below
39445 var cell = colm[iIdx];
39446 var oldDx = cell[0];
39447 var oldDy = cell[1]; //Calc new energy:
39448
39449 var x_i = nodes[i].x;
39450 var y_i = nodes[i].y;
39451 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
39452 var dx = kcolm[i] * (x_m - x_i - lcolm[i] * (x_m - x_i) * denominator);
39453 var dy = kcolm[i] * (y_m - y_i - lcolm[i] * (y_m - y_i) * denominator);
39454 colm[iIdx] = [dx, dy];
39455 dE_dx += dx;
39456 dE_dy += dy; //add new energy to sum of each column
39457
39458 var sum = this.E_sums[i];
39459 sum[0] += dx - oldDx;
39460 sum[1] += dy - oldDy;
39461 }
39462 } //Store sum at -1 index
39463
39464
39465 this.E_sums[m] = [dE_dx, dE_dy];
39466 }
39467 }]);
39468
39469 return KamadaKawai;
39470 }();
39471
39472 /**
39473 * Create a network visualization, displaying nodes and edges.
39474 *
39475 * @param {Element} container The DOM element in which the Network will
39476 * be created. Normally a div element.
39477 * @param {object} data An object containing parameters
39478 * {Array} nodes
39479 * {Array} edges
39480 * @param {object} options Options
39481 * @class Network
39482 */
39483
39484 function Network(container, data, options) {
39485 var _context,
39486 _context2,
39487 _context3,
39488 _context4,
39489 _this = this;
39490
39491 if (!(this instanceof Network)) {
39492 throw new SyntaxError("Constructor must be called with the new operator");
39493 } // set constant values
39494
39495
39496 this.options = {};
39497 this.defaultOptions = {
39498 locale: "en",
39499 locales: locales,
39500 clickToUse: false
39501 };
39502
39503 assign$2(this.options, this.defaultOptions);
39504 /**
39505 * Containers for nodes and edges.
39506 *
39507 * 'edges' and 'nodes' contain the full definitions of all the network elements.
39508 * 'nodeIndices' and 'edgeIndices' contain the id's of the active elements.
39509 *
39510 * The distinction is important, because a defined node need not be active, i.e.
39511 * visible on the canvas. This happens in particular when clusters are defined, in
39512 * that case there will be nodes and edges not displayed.
39513 * The bottom line is that all code with actions related to visibility, *must* use
39514 * 'nodeIndices' and 'edgeIndices', not 'nodes' and 'edges' directly.
39515 */
39516
39517
39518 this.body = {
39519 container: container,
39520 // See comment above for following fields
39521 nodes: {},
39522 nodeIndices: [],
39523 edges: {},
39524 edgeIndices: [],
39525 emitter: {
39526 on: bind$5(_context = this.on).call(_context, this),
39527 off: bind$5(_context2 = this.off).call(_context2, this),
39528 emit: bind$5(_context3 = this.emit).call(_context3, this),
39529 once: bind$5(_context4 = this.once).call(_context4, this)
39530 },
39531 eventListeners: {
39532 onTap: function onTap() {},
39533 onTouch: function onTouch() {},
39534 onDoubleTap: function onDoubleTap() {},
39535 onHold: function onHold() {},
39536 onDragStart: function onDragStart() {},
39537 onDrag: function onDrag() {},
39538 onDragEnd: function onDragEnd() {},
39539 onMouseWheel: function onMouseWheel() {},
39540 onPinch: function onPinch() {},
39541 onMouseMove: function onMouseMove() {},
39542 onRelease: function onRelease() {},
39543 onContext: function onContext() {}
39544 },
39545 data: {
39546 nodes: null,
39547 // A DataSet or DataView
39548 edges: null // A DataSet or DataView
39549
39550 },
39551 functions: {
39552 createNode: function createNode() {},
39553 createEdge: function createEdge() {},
39554 getPointer: function getPointer() {}
39555 },
39556 modules: {},
39557 view: {
39558 scale: 1,
39559 translation: {
39560 x: 0,
39561 y: 0
39562 }
39563 },
39564 selectionBox: {
39565 show: false,
39566 position: {
39567 start: {
39568 x: 0,
39569 y: 0
39570 },
39571 end: {
39572 x: 0,
39573 y: 0
39574 }
39575 }
39576 }
39577 }; // bind the event listeners
39578
39579 this.bindEventListeners(); // setting up all modules
39580
39581 this.images = new Images(function () {
39582 return _this.body.emitter.emit("_requestRedraw");
39583 }); // object with images
39584
39585 this.groups = new Groups(); // object with groups
39586
39587 this.canvas = new Canvas(this.body); // DOM handler
39588
39589 this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler
39590
39591 this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key
39592
39593 this.view = new View(this.body, this.canvas); // camera handler, does animations and zooms
39594
39595 this.renderer = new CanvasRenderer(this.body, this.canvas); // renderer, starts renderloop, has events that modules can hook into
39596
39597 this.physics = new PhysicsEngine(this.body); // physics engine, does all the simulations
39598
39599 this.layoutEngine = new LayoutEngine(this.body); // layout engine for inital layout and hierarchical layout
39600
39601 this.clustering = new ClusterEngine(this.body); // clustering api
39602
39603 this.manipulation = new ManipulationSystem(this.body, this.canvas, this.selectionHandler, this.interactionHandler); // data manipulation system
39604
39605 this.nodesHandler = new NodesHandler(this.body, this.images, this.groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
39606
39607 this.edgesHandler = new EdgesHandler(this.body, this.images, this.groups); // Handle adding, deleting and updating of edges as well as global options
39608
39609 this.body.modules["kamadaKawai"] = new KamadaKawai(this.body, 150, 0.05); // Layouting algorithm.
39610
39611 this.body.modules["clustering"] = this.clustering; // create the DOM elements
39612
39613 this.canvas._create(); // apply options
39614
39615
39616 this.setOptions(options); // load data (the disable start variable will be the same as the enabled clustering)
39617
39618 this.setData(data);
39619 } // Extend Network with an Emitter mixin
39620
39621 Emitter(Network.prototype);
39622 /**
39623 * Set options
39624 *
39625 * @param {object} options
39626 */
39627
39628 Network.prototype.setOptions = function (options) {
39629 var _this2 = this;
39630
39631 if (options === null) {
39632 options = undefined; // This ensures that options handling doesn't crash in the handling
39633 }
39634
39635 if (options !== undefined) {
39636 var errorFound = Validator$1.validate(options, allOptions);
39637
39638 if (errorFound === true) {
39639 console.error("%cErrors have been found in the supplied options object.", VALIDATOR_PRINT_STYLE$1);
39640 } // copy the global fields over
39641
39642
39643 var fields = ["locale", "locales", "clickToUse"];
39644 selectiveDeepExtend(fields, this.options, options); // normalize the locale or use English
39645
39646 if (options.locale !== undefined) {
39647 options.locale = normalizeLanguageCode(options.locales || this.options.locales, options.locale);
39648 } // the hierarchical system can adapt the edges and the physics to it's own options because not all combinations work with the hierarichical system.
39649
39650
39651 options = this.layoutEngine.setOptions(options.layout, options);
39652 this.canvas.setOptions(options); // options for canvas are in globals
39653 // pass the options to the modules
39654
39655 this.groups.setOptions(options.groups);
39656 this.nodesHandler.setOptions(options.nodes);
39657 this.edgesHandler.setOptions(options.edges);
39658 this.physics.setOptions(options.physics);
39659 this.manipulation.setOptions(options.manipulation, options, this.options); // manipulation uses the locales in the globals
39660
39661 this.interactionHandler.setOptions(options.interaction);
39662 this.renderer.setOptions(options.interaction); // options for rendering are in interaction
39663
39664 this.selectionHandler.setOptions(options.interaction); // options for selection are in interaction
39665 // reload the settings of the nodes to apply changes in groups that are not referenced by pointer.
39666
39667 if (options.groups !== undefined) {
39668 this.body.emitter.emit("refreshNodes");
39669 } // these two do not have options at the moment, here for completeness
39670 //this.view.setOptions(options.view);
39671 //this.clustering.setOptions(options.clustering);
39672
39673
39674 if ("configure" in options) {
39675 if (!this.configurator) {
39676 this.configurator = new Configurator$1(this, this.body.container, configureOptions, this.canvas.pixelRatio, configuratorHideOption);
39677 }
39678
39679 this.configurator.setOptions(options.configure);
39680 } // if the configuration system is enabled, copy all options and put them into the config system
39681
39682
39683 if (this.configurator && this.configurator.options.enabled === true) {
39684 var networkOptions = {
39685 nodes: {},
39686 edges: {},
39687 layout: {},
39688 interaction: {},
39689 manipulation: {},
39690 physics: {},
39691 global: {}
39692 };
39693 deepExtend(networkOptions.nodes, this.nodesHandler.options);
39694 deepExtend(networkOptions.edges, this.edgesHandler.options);
39695 deepExtend(networkOptions.layout, this.layoutEngine.options); // load the selectionHandler and render default options in to the interaction group
39696
39697 deepExtend(networkOptions.interaction, this.selectionHandler.options);
39698 deepExtend(networkOptions.interaction, this.renderer.options);
39699 deepExtend(networkOptions.interaction, this.interactionHandler.options);
39700 deepExtend(networkOptions.manipulation, this.manipulation.options);
39701 deepExtend(networkOptions.physics, this.physics.options); // load globals into the global object
39702
39703 deepExtend(networkOptions.global, this.canvas.options);
39704 deepExtend(networkOptions.global, this.options);
39705 this.configurator.setModuleOptions(networkOptions);
39706 } // handle network global options
39707
39708
39709 if (options.clickToUse !== undefined) {
39710 if (options.clickToUse === true) {
39711 if (this.activator === undefined) {
39712 this.activator = new Activator$1(this.canvas.frame);
39713 this.activator.on("change", function () {
39714 _this2.body.emitter.emit("activate");
39715 });
39716 }
39717 } else {
39718 if (this.activator !== undefined) {
39719 this.activator.destroy();
39720 delete this.activator;
39721 }
39722
39723 this.body.emitter.emit("activate");
39724 }
39725 } else {
39726 this.body.emitter.emit("activate");
39727 }
39728
39729 this.canvas.setSize(); // start the physics simulation. Can be safely called multiple times.
39730
39731 this.body.emitter.emit("startSimulation");
39732 }
39733 };
39734 /**
39735 * Update the visible nodes and edges list with the most recent node state.
39736 *
39737 * Visible nodes are stored in this.body.nodeIndices.
39738 * Visible edges are stored in this.body.edgeIndices.
39739 * A node or edges is visible if it is not hidden or clustered.
39740 *
39741 * @private
39742 */
39743
39744
39745 Network.prototype._updateVisibleIndices = function () {
39746 var nodes = this.body.nodes;
39747 var edges = this.body.edges;
39748 this.body.nodeIndices = [];
39749 this.body.edgeIndices = [];
39750
39751 for (var nodeId in nodes) {
39752 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
39753 if (!this.clustering._isClusteredNode(nodeId) && nodes[nodeId].options.hidden === false) {
39754 this.body.nodeIndices.push(nodes[nodeId].id);
39755 }
39756 }
39757 }
39758
39759 for (var edgeId in edges) {
39760 if (Object.prototype.hasOwnProperty.call(edges, edgeId)) {
39761 var edge = edges[edgeId]; // It can happen that this is executed *after* a node edge has been removed,
39762 // but *before* the edge itself has been removed. Taking this into account.
39763
39764 var fromNode = nodes[edge.fromId];
39765 var toNode = nodes[edge.toId];
39766 var edgeNodesPresent = fromNode !== undefined && toNode !== undefined;
39767 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
39768 toNode.options.hidden === false; // idem
39769
39770 if (isVisible) {
39771 this.body.edgeIndices.push(edge.id);
39772 }
39773 }
39774 }
39775 };
39776 /**
39777 * Bind all events
39778 */
39779
39780
39781 Network.prototype.bindEventListeners = function () {
39782 var _this3 = this;
39783
39784 // This event will trigger a rebuilding of the cache everything.
39785 // Used when nodes or edges have been added or removed.
39786 this.body.emitter.on("_dataChanged", function () {
39787 _this3.edgesHandler._updateState();
39788
39789 _this3.body.emitter.emit("_dataUpdated");
39790 }); // this is called when options of EXISTING nodes or edges have changed.
39791
39792 this.body.emitter.on("_dataUpdated", function () {
39793 // Order important in following block
39794 _this3.clustering._updateState();
39795
39796 _this3._updateVisibleIndices();
39797
39798 _this3._updateValueRange(_this3.body.nodes);
39799
39800 _this3._updateValueRange(_this3.body.edges); // start simulation (can be called safely, even if already running)
39801
39802
39803 _this3.body.emitter.emit("startSimulation");
39804
39805 _this3.body.emitter.emit("_requestRedraw");
39806 });
39807 };
39808 /**
39809 * Set nodes and edges, and optionally options as well.
39810 *
39811 * @param {object} data Object containing parameters:
39812 * {Array | DataSet | DataView} [nodes] Array with nodes
39813 * {Array | DataSet | DataView} [edges] Array with edges
39814 * {String} [dot] String containing data in DOT format
39815 * {String} [gephi] String containing data in gephi JSON format
39816 * {Options} [options] Object with options
39817 */
39818
39819
39820 Network.prototype.setData = function (data) {
39821 // reset the physics engine.
39822 this.body.emitter.emit("resetPhysics");
39823 this.body.emitter.emit("_resetData"); // unselect all to ensure no selections from old data are carried over.
39824
39825 this.selectionHandler.unselectAll();
39826
39827 if (data && data.dot && (data.nodes || data.edges)) {
39828 throw new SyntaxError('Data must contain either parameter "dot" or ' + ' parameter pair "nodes" and "edges", but not both.');
39829 } // set options
39830
39831
39832 this.setOptions(data && data.options); // set all data
39833
39834 if (data && data.dot) {
39835 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
39836
39837 var dotData = DOTToGraph(data.dot);
39838 this.setData(dotData);
39839 return;
39840 } else if (data && data.gephi) {
39841 // parse DOT file
39842 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);");
39843 var gephiData = parseGephi(data.gephi);
39844 this.setData(gephiData);
39845 return;
39846 } else {
39847 this.nodesHandler.setData(data && data.nodes, true);
39848 this.edgesHandler.setData(data && data.edges, true);
39849 } // emit change in data
39850
39851
39852 this.body.emitter.emit("_dataChanged"); // emit data loaded
39853
39854 this.body.emitter.emit("_dataLoaded"); // find a stable position or start animating to a stable position
39855
39856 this.body.emitter.emit("initPhysics");
39857 };
39858 /**
39859 * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function.
39860 * var network = new vis.Network(..);
39861 * network.destroy();
39862 * network = null;
39863 */
39864
39865
39866 Network.prototype.destroy = function () {
39867 this.body.emitter.emit("destroy"); // clear events
39868
39869 this.body.emitter.off();
39870 this.off(); // delete modules
39871
39872 delete this.groups;
39873 delete this.canvas;
39874 delete this.selectionHandler;
39875 delete this.interactionHandler;
39876 delete this.view;
39877 delete this.renderer;
39878 delete this.physics;
39879 delete this.layoutEngine;
39880 delete this.clustering;
39881 delete this.manipulation;
39882 delete this.nodesHandler;
39883 delete this.edgesHandler;
39884 delete this.configurator;
39885 delete this.images;
39886
39887 for (var nodeId in this.body.nodes) {
39888 if (!Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) continue;
39889 delete this.body.nodes[nodeId];
39890 }
39891
39892 for (var edgeId in this.body.edges) {
39893 if (!Object.prototype.hasOwnProperty.call(this.body.edges, edgeId)) continue;
39894 delete this.body.edges[edgeId];
39895 } // remove the container and everything inside it recursively
39896
39897
39898 recursiveDOMDelete(this.body.container);
39899 };
39900 /**
39901 * Update the values of all object in the given array according to the current
39902 * value range of the objects in the array.
39903 *
39904 * @param {object} obj An object containing a set of Edges or Nodes
39905 * The objects must have a method getValue() and
39906 * setValueRange(min, max).
39907 * @private
39908 */
39909
39910
39911 Network.prototype._updateValueRange = function (obj) {
39912 var id; // determine the range of the objects
39913
39914 var valueMin = undefined;
39915 var valueMax = undefined;
39916 var valueTotal = 0;
39917
39918 for (id in obj) {
39919 if (Object.prototype.hasOwnProperty.call(obj, id)) {
39920 var value = obj[id].getValue();
39921
39922 if (value !== undefined) {
39923 valueMin = valueMin === undefined ? value : Math.min(value, valueMin);
39924 valueMax = valueMax === undefined ? value : Math.max(value, valueMax);
39925 valueTotal += value;
39926 }
39927 }
39928 } // adjust the range of all objects
39929
39930
39931 if (valueMin !== undefined && valueMax !== undefined) {
39932 for (id in obj) {
39933 if (Object.prototype.hasOwnProperty.call(obj, id)) {
39934 obj[id].setValueRange(valueMin, valueMax, valueTotal);
39935 }
39936 }
39937 }
39938 };
39939 /**
39940 * Returns true when the Network is active.
39941 *
39942 * @returns {boolean}
39943 */
39944
39945
39946 Network.prototype.isActive = function () {
39947 return !this.activator || this.activator.active;
39948 };
39949
39950 Network.prototype.setSize = function () {
39951 return this.canvas.setSize.apply(this.canvas, arguments);
39952 };
39953
39954 Network.prototype.canvasToDOM = function () {
39955 return this.canvas.canvasToDOM.apply(this.canvas, arguments);
39956 };
39957
39958 Network.prototype.DOMtoCanvas = function () {
39959 return this.canvas.DOMtoCanvas.apply(this.canvas, arguments);
39960 };
39961 /**
39962 * Nodes can be in clusters. Clusters can also be in clusters. This function returns and array of
39963 * nodeIds showing where the node is.
39964 *
39965 * If any nodeId in the chain, especially the first passed in as a parameter, is not present in
39966 * the current nodes list, an empty array is returned.
39967 *
39968 * Example:
39969 * cluster 'A' contains cluster 'B',
39970 * cluster 'B' contains cluster 'C',
39971 * cluster 'C' contains node 'fred'.
39972 * `jsnetwork.clustering.findNode('fred')` will return `['A','B','C','fred']`.
39973 *
39974 * @param {string|number} nodeId
39975 * @returns {Array}
39976 */
39977
39978
39979 Network.prototype.findNode = function () {
39980 return this.clustering.findNode.apply(this.clustering, arguments);
39981 };
39982
39983 Network.prototype.isCluster = function () {
39984 return this.clustering.isCluster.apply(this.clustering, arguments);
39985 };
39986
39987 Network.prototype.openCluster = function () {
39988 return this.clustering.openCluster.apply(this.clustering, arguments);
39989 };
39990
39991 Network.prototype.cluster = function () {
39992 return this.clustering.cluster.apply(this.clustering, arguments);
39993 };
39994
39995 Network.prototype.getNodesInCluster = function () {
39996 return this.clustering.getNodesInCluster.apply(this.clustering, arguments);
39997 };
39998
39999 Network.prototype.clusterByConnection = function () {
40000 return this.clustering.clusterByConnection.apply(this.clustering, arguments);
40001 };
40002
40003 Network.prototype.clusterByHubsize = function () {
40004 return this.clustering.clusterByHubsize.apply(this.clustering, arguments);
40005 };
40006
40007 Network.prototype.updateClusteredNode = function () {
40008 return this.clustering.updateClusteredNode.apply(this.clustering, arguments);
40009 };
40010
40011 Network.prototype.getClusteredEdges = function () {
40012 return this.clustering.getClusteredEdges.apply(this.clustering, arguments);
40013 };
40014
40015 Network.prototype.getBaseEdge = function () {
40016 return this.clustering.getBaseEdge.apply(this.clustering, arguments);
40017 };
40018
40019 Network.prototype.getBaseEdges = function () {
40020 return this.clustering.getBaseEdges.apply(this.clustering, arguments);
40021 };
40022
40023 Network.prototype.updateEdge = function () {
40024 return this.clustering.updateEdge.apply(this.clustering, arguments);
40025 };
40026 /**
40027 * This method will cluster all nodes with 1 edge with their respective connected node.
40028 * The options object is explained in full <a data-scroll="" data-options="{ &quot;easing&quot;: &quot;easeInCubic&quot; }" href="#optionsObject">below</a>.
40029 *
40030 * @param {object} [options]
40031 * @returns {undefined}
40032 */
40033
40034
40035 Network.prototype.clusterOutliers = function () {
40036 return this.clustering.clusterOutliers.apply(this.clustering, arguments);
40037 };
40038
40039 Network.prototype.getSeed = function () {
40040 return this.layoutEngine.getSeed.apply(this.layoutEngine, arguments);
40041 };
40042
40043 Network.prototype.enableEditMode = function () {
40044 return this.manipulation.enableEditMode.apply(this.manipulation, arguments);
40045 };
40046
40047 Network.prototype.disableEditMode = function () {
40048 return this.manipulation.disableEditMode.apply(this.manipulation, arguments);
40049 };
40050
40051 Network.prototype.addNodeMode = function () {
40052 return this.manipulation.addNodeMode.apply(this.manipulation, arguments);
40053 };
40054
40055 Network.prototype.editNode = function () {
40056 return this.manipulation.editNode.apply(this.manipulation, arguments);
40057 };
40058
40059 Network.prototype.editNodeMode = function () {
40060 console.warn("Deprecated: Please use editNode instead of editNodeMode.");
40061 return this.manipulation.editNode.apply(this.manipulation, arguments);
40062 };
40063
40064 Network.prototype.addEdgeMode = function () {
40065 return this.manipulation.addEdgeMode.apply(this.manipulation, arguments);
40066 };
40067
40068 Network.prototype.editEdgeMode = function () {
40069 return this.manipulation.editEdgeMode.apply(this.manipulation, arguments);
40070 };
40071
40072 Network.prototype.deleteSelected = function () {
40073 return this.manipulation.deleteSelected.apply(this.manipulation, arguments);
40074 };
40075
40076 Network.prototype.getPositions = function () {
40077 return this.nodesHandler.getPositions.apply(this.nodesHandler, arguments);
40078 };
40079
40080 Network.prototype.getPosition = function () {
40081 return this.nodesHandler.getPosition.apply(this.nodesHandler, arguments);
40082 };
40083
40084 Network.prototype.storePositions = function () {
40085 return this.nodesHandler.storePositions.apply(this.nodesHandler, arguments);
40086 };
40087
40088 Network.prototype.moveNode = function () {
40089 return this.nodesHandler.moveNode.apply(this.nodesHandler, arguments);
40090 };
40091
40092 Network.prototype.getBoundingBox = function () {
40093 return this.nodesHandler.getBoundingBox.apply(this.nodesHandler, arguments);
40094 };
40095
40096 Network.prototype.getConnectedNodes = function (objectId) {
40097 if (this.body.nodes[objectId] !== undefined) {
40098 return this.nodesHandler.getConnectedNodes.apply(this.nodesHandler, arguments);
40099 } else {
40100 return this.edgesHandler.getConnectedNodes.apply(this.edgesHandler, arguments);
40101 }
40102 };
40103
40104 Network.prototype.getConnectedEdges = function () {
40105 return this.nodesHandler.getConnectedEdges.apply(this.nodesHandler, arguments);
40106 };
40107
40108 Network.prototype.startSimulation = function () {
40109 return this.physics.startSimulation.apply(this.physics, arguments);
40110 };
40111
40112 Network.prototype.stopSimulation = function () {
40113 return this.physics.stopSimulation.apply(this.physics, arguments);
40114 };
40115
40116 Network.prototype.stabilize = function () {
40117 return this.physics.stabilize.apply(this.physics, arguments);
40118 };
40119
40120 Network.prototype.getSelection = function () {
40121 return this.selectionHandler.getSelection.apply(this.selectionHandler, arguments);
40122 };
40123
40124 Network.prototype.setSelection = function () {
40125 return this.selectionHandler.setSelection.apply(this.selectionHandler, arguments);
40126 };
40127
40128 Network.prototype.getSelectedNodes = function () {
40129 return this.selectionHandler.getSelectedNodeIds.apply(this.selectionHandler, arguments);
40130 };
40131
40132 Network.prototype.getSelectedEdges = function () {
40133 return this.selectionHandler.getSelectedEdgeIds.apply(this.selectionHandler, arguments);
40134 };
40135
40136 Network.prototype.getNodeAt = function () {
40137 var node = this.selectionHandler.getNodeAt.apply(this.selectionHandler, arguments);
40138
40139 if (node !== undefined && node.id !== undefined) {
40140 return node.id;
40141 }
40142
40143 return node;
40144 };
40145
40146 Network.prototype.getEdgeAt = function () {
40147 var edge = this.selectionHandler.getEdgeAt.apply(this.selectionHandler, arguments);
40148
40149 if (edge !== undefined && edge.id !== undefined) {
40150 return edge.id;
40151 }
40152
40153 return edge;
40154 };
40155
40156 Network.prototype.selectNodes = function () {
40157 return this.selectionHandler.selectNodes.apply(this.selectionHandler, arguments);
40158 };
40159
40160 Network.prototype.selectEdges = function () {
40161 return this.selectionHandler.selectEdges.apply(this.selectionHandler, arguments);
40162 };
40163
40164 Network.prototype.unselectAll = function () {
40165 this.selectionHandler.unselectAll.apply(this.selectionHandler, arguments);
40166 this.selectionHandler.commitWithoutEmitting.apply(this.selectionHandler);
40167 this.redraw();
40168 };
40169
40170 Network.prototype.redraw = function () {
40171 return this.renderer.redraw.apply(this.renderer, arguments);
40172 };
40173
40174 Network.prototype.getScale = function () {
40175 return this.view.getScale.apply(this.view, arguments);
40176 };
40177
40178 Network.prototype.getViewPosition = function () {
40179 return this.view.getViewPosition.apply(this.view, arguments);
40180 };
40181
40182 Network.prototype.fit = function () {
40183 return this.view.fit.apply(this.view, arguments);
40184 };
40185
40186 Network.prototype.moveTo = function () {
40187 return this.view.moveTo.apply(this.view, arguments);
40188 };
40189
40190 Network.prototype.focus = function () {
40191 return this.view.focus.apply(this.view, arguments);
40192 };
40193
40194 Network.prototype.releaseNode = function () {
40195 return this.view.releaseNode.apply(this.view, arguments);
40196 };
40197
40198 Network.prototype.getOptionsFromConfigurator = function () {
40199 var options = {};
40200
40201 if (this.configurator) {
40202 options = this.configurator.getOptions.apply(this.configurator);
40203 }
40204
40205 return options;
40206 };
40207
40208 var parseDOTNetwork = DOTToGraph;
40209 // overflow in UMD builds. They all export vis namespace therefore reexporting
40210 // leads to loading vis to load vis to load vis…
40211
40212 exports.Network = Network;
40213 exports.NetworkImages = Images;
40214 exports.networkDOTParser = dotparser;
40215 exports.networkGephiParser = gephiParser;
40216 exports.networkOptions = options;
40217 exports.parseDOTNetwork = parseDOTNetwork;
40218 exports.parseGephiNetwork = parseGephi;
40219
40220 Object.defineProperty(exports, '__esModule', { value: true });
40221
40222})));
40223//# sourceMappingURL=vis-network.js.map