UNPKG

1.4 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.2
8 * @date 2022-03-28T20:17:35.342Z
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) :
29 typeof define === 'function' && define.amd ? define(['exports'], factory) :
30 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vis = global.vis || {}));
31})(this, (function (exports) { 'use strict';
32
33 var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
34
35 var check = function (it) {
36 return it && it.Math == Math && it;
37 }; // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
38
39
40 var global$P = // eslint-disable-next-line es/no-global-this -- safe
41 check(typeof globalThis == 'object' && globalThis) || check(typeof window == 'object' && window) || // eslint-disable-next-line no-restricted-globals -- safe
42 check(typeof self == 'object' && self) || check(typeof commonjsGlobal == 'object' && commonjsGlobal) || // eslint-disable-next-line no-new-func -- fallback
43 function () {
44 return this;
45 }() || Function('return this')();
46
47 var fails$t = function (exec) {
48 try {
49 return !!exec();
50 } catch (error) {
51 return true;
52 }
53 };
54
55 var fails$s = fails$t;
56 var functionBindNative = !fails$s(function () {
57 var test = function () {
58 /* empty */
59 }.bind(); // eslint-disable-next-line no-prototype-builtins -- safe
60
61
62 return typeof test != 'function' || test.hasOwnProperty('prototype');
63 });
64
65 var NATIVE_BIND$4 = functionBindNative;
66 var FunctionPrototype$3 = Function.prototype;
67 var apply$6 = FunctionPrototype$3.apply;
68 var call$d = FunctionPrototype$3.call; // eslint-disable-next-line es/no-reflect -- safe
69
70 var functionApply = typeof Reflect == 'object' && Reflect.apply || (NATIVE_BIND$4 ? call$d.bind(apply$6) : function () {
71 return call$d.apply(apply$6, arguments);
72 });
73
74 var NATIVE_BIND$3 = functionBindNative;
75 var FunctionPrototype$2 = Function.prototype;
76 var bind$d = FunctionPrototype$2.bind;
77 var call$c = FunctionPrototype$2.call;
78 var uncurryThis$w = NATIVE_BIND$3 && bind$d.bind(call$c, call$c);
79 var functionUncurryThis = NATIVE_BIND$3 ? function (fn) {
80 return fn && uncurryThis$w(fn);
81 } : function (fn) {
82 return fn && function () {
83 return call$c.apply(fn, arguments);
84 };
85 };
86
87 // https://tc39.es/ecma262/#sec-iscallable
88
89 var isCallable$h = function (argument) {
90 return typeof argument == 'function';
91 };
92
93 var objectGetOwnPropertyDescriptor = {};
94
95 var fails$r = fails$t; // Detect IE8's incomplete defineProperty implementation
96
97 var descriptors = !fails$r(function () {
98 // eslint-disable-next-line es/no-object-defineproperty -- required for testing
99 return Object.defineProperty({}, 1, {
100 get: function () {
101 return 7;
102 }
103 })[1] != 7;
104 });
105
106 var NATIVE_BIND$2 = functionBindNative;
107 var call$b = Function.prototype.call;
108 var functionCall = NATIVE_BIND$2 ? call$b.bind(call$b) : function () {
109 return call$b.apply(call$b, arguments);
110 };
111
112 var objectPropertyIsEnumerable = {};
113
114 var $propertyIsEnumerable$2 = {}.propertyIsEnumerable; // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
115
116 var getOwnPropertyDescriptor$8 = Object.getOwnPropertyDescriptor; // Nashorn ~ JDK8 bug
117
118 var NASHORN_BUG = getOwnPropertyDescriptor$8 && !$propertyIsEnumerable$2.call({
119 1: 2
120 }, 1); // `Object.prototype.propertyIsEnumerable` method implementation
121 // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
122
123 objectPropertyIsEnumerable.f = NASHORN_BUG ? function propertyIsEnumerable(V) {
124 var descriptor = getOwnPropertyDescriptor$8(this, V);
125 return !!descriptor && descriptor.enumerable;
126 } : $propertyIsEnumerable$2;
127
128 var createPropertyDescriptor$5 = function (bitmap, value) {
129 return {
130 enumerable: !(bitmap & 1),
131 configurable: !(bitmap & 2),
132 writable: !(bitmap & 4),
133 value: value
134 };
135 };
136
137 var uncurryThis$v = functionUncurryThis;
138 var toString$a = uncurryThis$v({}.toString);
139 var stringSlice$1 = uncurryThis$v(''.slice);
140
141 var classofRaw$1 = function (it) {
142 return stringSlice$1(toString$a(it), 8, -1);
143 };
144
145 var global$O = global$P;
146 var uncurryThis$u = functionUncurryThis;
147 var fails$q = fails$t;
148 var classof$f = classofRaw$1;
149 var Object$a = global$O.Object;
150 var split = uncurryThis$u(''.split); // fallback for non-array-like ES3 and non-enumerable old V8 strings
151
152 var indexedObject = fails$q(function () {
153 // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
154 // eslint-disable-next-line no-prototype-builtins -- safe
155 return !Object$a('z').propertyIsEnumerable(0);
156 }) ? function (it) {
157 return classof$f(it) == 'String' ? split(it, '') : Object$a(it);
158 } : Object$a;
159
160 var global$N = global$P;
161 var TypeError$j = global$N.TypeError; // `RequireObjectCoercible` abstract operation
162 // https://tc39.es/ecma262/#sec-requireobjectcoercible
163
164 var requireObjectCoercible$5 = function (it) {
165 if (it == undefined) throw TypeError$j("Can't call method on " + it);
166 return it;
167 };
168
169 var IndexedObject$3 = indexedObject;
170 var requireObjectCoercible$4 = requireObjectCoercible$5;
171
172 var toIndexedObject$b = function (it) {
173 return IndexedObject$3(requireObjectCoercible$4(it));
174 };
175
176 var isCallable$g = isCallable$h;
177
178 var isObject$j = function (it) {
179 return typeof it == 'object' ? it !== null : isCallable$g(it);
180 };
181
182 var path$y = {};
183
184 var path$x = path$y;
185 var global$M = global$P;
186 var isCallable$f = isCallable$h;
187
188 var aFunction = function (variable) {
189 return isCallable$f(variable) ? variable : undefined;
190 };
191
192 var getBuiltIn$9 = function (namespace, method) {
193 return arguments.length < 2 ? aFunction(path$x[namespace]) || aFunction(global$M[namespace]) : path$x[namespace] && path$x[namespace][method] || global$M[namespace] && global$M[namespace][method];
194 };
195
196 var uncurryThis$t = functionUncurryThis;
197 var objectIsPrototypeOf = uncurryThis$t({}.isPrototypeOf);
198
199 var getBuiltIn$8 = getBuiltIn$9;
200 var engineUserAgent = getBuiltIn$8('navigator', 'userAgent') || '';
201
202 var global$L = global$P;
203 var userAgent$3 = engineUserAgent;
204 var process = global$L.process;
205 var Deno = global$L.Deno;
206 var versions = process && process.versions || Deno && Deno.version;
207 var v8 = versions && versions.v8;
208 var match, version;
209
210 if (v8) {
211 match = v8.split('.'); // in old Chrome, versions of V8 isn't V8 = Chrome / 10
212 // but their correct versions are not interesting for us
213
214 version = match[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1]);
215 } // BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`
216 // so check `userAgent` even if `.v8` exists, but 0
217
218
219 if (!version && userAgent$3) {
220 match = userAgent$3.match(/Edge\/(\d+)/);
221
222 if (!match || match[1] >= 74) {
223 match = userAgent$3.match(/Chrome\/(\d+)/);
224 if (match) version = +match[1];
225 }
226 }
227
228 var engineV8Version = version;
229
230 /* eslint-disable es/no-symbol -- required for testing */
231 var V8_VERSION$2 = engineV8Version;
232 var fails$p = fails$t; // eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
233
234 var nativeSymbol = !!Object.getOwnPropertySymbols && !fails$p(function () {
235 var symbol = Symbol(); // Chrome 38 Symbol has incorrect toString conversion
236 // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
237
238 return !String(symbol) || !(Object(symbol) instanceof Symbol) || // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
239 !Symbol.sham && V8_VERSION$2 && V8_VERSION$2 < 41;
240 });
241
242 /* eslint-disable es/no-symbol -- required for testing */
243 var NATIVE_SYMBOL$2 = nativeSymbol;
244 var useSymbolAsUid = NATIVE_SYMBOL$2 && !Symbol.sham && typeof Symbol.iterator == 'symbol';
245
246 var global$K = global$P;
247 var getBuiltIn$7 = getBuiltIn$9;
248 var isCallable$e = isCallable$h;
249 var isPrototypeOf$n = objectIsPrototypeOf;
250 var USE_SYMBOL_AS_UID$1 = useSymbolAsUid;
251 var Object$9 = global$K.Object;
252 var isSymbol$3 = USE_SYMBOL_AS_UID$1 ? function (it) {
253 return typeof it == 'symbol';
254 } : function (it) {
255 var $Symbol = getBuiltIn$7('Symbol');
256 return isCallable$e($Symbol) && isPrototypeOf$n($Symbol.prototype, Object$9(it));
257 };
258
259 var global$J = global$P;
260 var String$4 = global$J.String;
261
262 var tryToString$4 = function (argument) {
263 try {
264 return String$4(argument);
265 } catch (error) {
266 return 'Object';
267 }
268 };
269
270 var global$I = global$P;
271 var isCallable$d = isCallable$h;
272 var tryToString$3 = tryToString$4;
273 var TypeError$i = global$I.TypeError; // `Assert: IsCallable(argument) is true`
274
275 var aCallable$7 = function (argument) {
276 if (isCallable$d(argument)) return argument;
277 throw TypeError$i(tryToString$3(argument) + ' is not a function');
278 };
279
280 var aCallable$6 = aCallable$7; // `GetMethod` abstract operation
281 // https://tc39.es/ecma262/#sec-getmethod
282
283 var getMethod$3 = function (V, P) {
284 var func = V[P];
285 return func == null ? undefined : aCallable$6(func);
286 };
287
288 var global$H = global$P;
289 var call$a = functionCall;
290 var isCallable$c = isCallable$h;
291 var isObject$i = isObject$j;
292 var TypeError$h = global$H.TypeError; // `OrdinaryToPrimitive` abstract operation
293 // https://tc39.es/ecma262/#sec-ordinarytoprimitive
294
295 var ordinaryToPrimitive$1 = function (input, pref) {
296 var fn, val;
297 if (pref === 'string' && isCallable$c(fn = input.toString) && !isObject$i(val = call$a(fn, input))) return val;
298 if (isCallable$c(fn = input.valueOf) && !isObject$i(val = call$a(fn, input))) return val;
299 if (pref !== 'string' && isCallable$c(fn = input.toString) && !isObject$i(val = call$a(fn, input))) return val;
300 throw TypeError$h("Can't convert object to primitive value");
301 };
302
303 var shared$4 = {exports: {}};
304
305 var global$G = global$P; // eslint-disable-next-line es/no-object-defineproperty -- safe
306
307 var defineProperty$e = Object.defineProperty;
308
309 var setGlobal$1 = function (key, value) {
310 try {
311 defineProperty$e(global$G, key, {
312 value: value,
313 configurable: true,
314 writable: true
315 });
316 } catch (error) {
317 global$G[key] = value;
318 }
319
320 return value;
321 };
322
323 var global$F = global$P;
324 var setGlobal = setGlobal$1;
325 var SHARED = '__core-js_shared__';
326 var store$3 = global$F[SHARED] || setGlobal(SHARED, {});
327 var sharedStore = store$3;
328
329 var store$2 = sharedStore;
330 (shared$4.exports = function (key, value) {
331 return store$2[key] || (store$2[key] = value !== undefined ? value : {});
332 })('versions', []).push({
333 version: '3.21.1',
334 mode: 'pure' ,
335 copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)',
336 license: 'https://github.com/zloirock/core-js/blob/v3.21.1/LICENSE',
337 source: 'https://github.com/zloirock/core-js'
338 });
339
340 var global$E = global$P;
341 var requireObjectCoercible$3 = requireObjectCoercible$5;
342 var Object$8 = global$E.Object; // `ToObject` abstract operation
343 // https://tc39.es/ecma262/#sec-toobject
344
345 var toObject$e = function (argument) {
346 return Object$8(requireObjectCoercible$3(argument));
347 };
348
349 var uncurryThis$s = functionUncurryThis;
350 var toObject$d = toObject$e;
351 var hasOwnProperty = uncurryThis$s({}.hasOwnProperty); // `HasOwnProperty` abstract operation
352 // https://tc39.es/ecma262/#sec-hasownproperty
353
354 var hasOwnProperty_1 = Object.hasOwn || function hasOwn(it, key) {
355 return hasOwnProperty(toObject$d(it), key);
356 };
357
358 var uncurryThis$r = functionUncurryThis;
359 var id$2 = 0;
360 var postfix = Math.random();
361 var toString$9 = uncurryThis$r(1.0.toString);
362
363 var uid$4 = function (key) {
364 return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString$9(++id$2 + postfix, 36);
365 };
366
367 var global$D = global$P;
368 var shared$3 = shared$4.exports;
369 var hasOwn$h = hasOwnProperty_1;
370 var uid$3 = uid$4;
371 var NATIVE_SYMBOL$1 = nativeSymbol;
372 var USE_SYMBOL_AS_UID = useSymbolAsUid;
373 var WellKnownSymbolsStore$1 = shared$3('wks');
374 var Symbol$3 = global$D.Symbol;
375 var symbolFor = Symbol$3 && Symbol$3['for'];
376 var createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol$3 : Symbol$3 && Symbol$3.withoutSetter || uid$3;
377
378 var wellKnownSymbol$j = function (name) {
379 if (!hasOwn$h(WellKnownSymbolsStore$1, name) || !(NATIVE_SYMBOL$1 || typeof WellKnownSymbolsStore$1[name] == 'string')) {
380 var description = 'Symbol.' + name;
381
382 if (NATIVE_SYMBOL$1 && hasOwn$h(Symbol$3, name)) {
383 WellKnownSymbolsStore$1[name] = Symbol$3[name];
384 } else if (USE_SYMBOL_AS_UID && symbolFor) {
385 WellKnownSymbolsStore$1[name] = symbolFor(description);
386 } else {
387 WellKnownSymbolsStore$1[name] = createWellKnownSymbol(description);
388 }
389 }
390
391 return WellKnownSymbolsStore$1[name];
392 };
393
394 var global$C = global$P;
395 var call$9 = functionCall;
396 var isObject$h = isObject$j;
397 var isSymbol$2 = isSymbol$3;
398 var getMethod$2 = getMethod$3;
399 var ordinaryToPrimitive = ordinaryToPrimitive$1;
400 var wellKnownSymbol$i = wellKnownSymbol$j;
401 var TypeError$g = global$C.TypeError;
402 var TO_PRIMITIVE$1 = wellKnownSymbol$i('toPrimitive'); // `ToPrimitive` abstract operation
403 // https://tc39.es/ecma262/#sec-toprimitive
404
405 var toPrimitive$1 = function (input, pref) {
406 if (!isObject$h(input) || isSymbol$2(input)) return input;
407 var exoticToPrim = getMethod$2(input, TO_PRIMITIVE$1);
408 var result;
409
410 if (exoticToPrim) {
411 if (pref === undefined) pref = 'default';
412 result = call$9(exoticToPrim, input, pref);
413 if (!isObject$h(result) || isSymbol$2(result)) return result;
414 throw TypeError$g("Can't convert object to primitive value");
415 }
416
417 if (pref === undefined) pref = 'number';
418 return ordinaryToPrimitive(input, pref);
419 };
420
421 var toPrimitive = toPrimitive$1;
422 var isSymbol$1 = isSymbol$3; // `ToPropertyKey` abstract operation
423 // https://tc39.es/ecma262/#sec-topropertykey
424
425 var toPropertyKey$4 = function (argument) {
426 var key = toPrimitive(argument, 'string');
427 return isSymbol$1(key) ? key : key + '';
428 };
429
430 var global$B = global$P;
431 var isObject$g = isObject$j;
432 var document$1 = global$B.document; // typeof document.createElement is 'object' in old IE
433
434 var EXISTS$1 = isObject$g(document$1) && isObject$g(document$1.createElement);
435
436 var documentCreateElement$1 = function (it) {
437 return EXISTS$1 ? document$1.createElement(it) : {};
438 };
439
440 var DESCRIPTORS$h = descriptors;
441 var fails$o = fails$t;
442 var createElement = documentCreateElement$1; // Thanks to IE8 for its funny defineProperty
443
444 var ie8DomDefine = !DESCRIPTORS$h && !fails$o(function () {
445 // eslint-disable-next-line es/no-object-defineproperty -- required for testing
446 return Object.defineProperty(createElement('div'), 'a', {
447 get: function () {
448 return 7;
449 }
450 }).a != 7;
451 });
452
453 var DESCRIPTORS$g = descriptors;
454 var call$8 = functionCall;
455 var propertyIsEnumerableModule$2 = objectPropertyIsEnumerable;
456 var createPropertyDescriptor$4 = createPropertyDescriptor$5;
457 var toIndexedObject$a = toIndexedObject$b;
458 var toPropertyKey$3 = toPropertyKey$4;
459 var hasOwn$g = hasOwnProperty_1;
460 var IE8_DOM_DEFINE$1 = ie8DomDefine; // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
461
462 var $getOwnPropertyDescriptor$2 = Object.getOwnPropertyDescriptor; // `Object.getOwnPropertyDescriptor` method
463 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
464
465 objectGetOwnPropertyDescriptor.f = DESCRIPTORS$g ? $getOwnPropertyDescriptor$2 : function getOwnPropertyDescriptor(O, P) {
466 O = toIndexedObject$a(O);
467 P = toPropertyKey$3(P);
468 if (IE8_DOM_DEFINE$1) try {
469 return $getOwnPropertyDescriptor$2(O, P);
470 } catch (error) {
471 /* empty */
472 }
473 if (hasOwn$g(O, P)) return createPropertyDescriptor$4(!call$8(propertyIsEnumerableModule$2.f, O, P), O[P]);
474 };
475
476 var fails$n = fails$t;
477 var isCallable$b = isCallable$h;
478 var replacement = /#|\.prototype\./;
479
480 var isForced$1 = function (feature, detection) {
481 var value = data[normalize(feature)];
482 return value == POLYFILL ? true : value == NATIVE ? false : isCallable$b(detection) ? fails$n(detection) : !!detection;
483 };
484
485 var normalize = isForced$1.normalize = function (string) {
486 return String(string).replace(replacement, '.').toLowerCase();
487 };
488
489 var data = isForced$1.data = {};
490 var NATIVE = isForced$1.NATIVE = 'N';
491 var POLYFILL = isForced$1.POLYFILL = 'P';
492 var isForced_1 = isForced$1;
493
494 var uncurryThis$q = functionUncurryThis;
495 var aCallable$5 = aCallable$7;
496 var NATIVE_BIND$1 = functionBindNative;
497 var bind$c = uncurryThis$q(uncurryThis$q.bind); // optional / simple context binding
498
499 var functionBindContext = function (fn, that) {
500 aCallable$5(fn);
501 return that === undefined ? fn : NATIVE_BIND$1 ? bind$c(fn, that) : function
502 /* ...args */
503 () {
504 return fn.apply(that, arguments);
505 };
506 };
507
508 var objectDefineProperty = {};
509
510 var DESCRIPTORS$f = descriptors;
511 var fails$m = fails$t; // V8 ~ Chrome 36-
512 // https://bugs.chromium.org/p/v8/issues/detail?id=3334
513
514 var v8PrototypeDefineBug = DESCRIPTORS$f && fails$m(function () {
515 // eslint-disable-next-line es/no-object-defineproperty -- required for testing
516 return Object.defineProperty(function () {
517 /* empty */
518 }, 'prototype', {
519 value: 42,
520 writable: false
521 }).prototype != 42;
522 });
523
524 var global$A = global$P;
525 var isObject$f = isObject$j;
526 var String$3 = global$A.String;
527 var TypeError$f = global$A.TypeError; // `Assert: Type(argument) is Object`
528
529 var anObject$d = function (argument) {
530 if (isObject$f(argument)) return argument;
531 throw TypeError$f(String$3(argument) + ' is not an object');
532 };
533
534 var global$z = global$P;
535 var DESCRIPTORS$e = descriptors;
536 var IE8_DOM_DEFINE = ie8DomDefine;
537 var V8_PROTOTYPE_DEFINE_BUG$1 = v8PrototypeDefineBug;
538 var anObject$c = anObject$d;
539 var toPropertyKey$2 = toPropertyKey$4;
540 var TypeError$e = global$z.TypeError; // eslint-disable-next-line es/no-object-defineproperty -- safe
541
542 var $defineProperty$1 = Object.defineProperty; // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
543
544 var $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
545 var ENUMERABLE = 'enumerable';
546 var CONFIGURABLE$1 = 'configurable';
547 var WRITABLE = 'writable'; // `Object.defineProperty` method
548 // https://tc39.es/ecma262/#sec-object.defineproperty
549
550 objectDefineProperty.f = DESCRIPTORS$e ? V8_PROTOTYPE_DEFINE_BUG$1 ? function defineProperty(O, P, Attributes) {
551 anObject$c(O);
552 P = toPropertyKey$2(P);
553 anObject$c(Attributes);
554
555 if (typeof O === 'function' && P === 'prototype' && 'value' in Attributes && WRITABLE in Attributes && !Attributes[WRITABLE]) {
556 var current = $getOwnPropertyDescriptor$1(O, P);
557
558 if (current && current[WRITABLE]) {
559 O[P] = Attributes.value;
560 Attributes = {
561 configurable: CONFIGURABLE$1 in Attributes ? Attributes[CONFIGURABLE$1] : current[CONFIGURABLE$1],
562 enumerable: ENUMERABLE in Attributes ? Attributes[ENUMERABLE] : current[ENUMERABLE],
563 writable: false
564 };
565 }
566 }
567
568 return $defineProperty$1(O, P, Attributes);
569 } : $defineProperty$1 : function defineProperty(O, P, Attributes) {
570 anObject$c(O);
571 P = toPropertyKey$2(P);
572 anObject$c(Attributes);
573 if (IE8_DOM_DEFINE) try {
574 return $defineProperty$1(O, P, Attributes);
575 } catch (error) {
576 /* empty */
577 }
578 if ('get' in Attributes || 'set' in Attributes) throw TypeError$e('Accessors not supported');
579 if ('value' in Attributes) O[P] = Attributes.value;
580 return O;
581 };
582
583 var DESCRIPTORS$d = descriptors;
584 var definePropertyModule$4 = objectDefineProperty;
585 var createPropertyDescriptor$3 = createPropertyDescriptor$5;
586 var createNonEnumerableProperty$6 = DESCRIPTORS$d ? function (object, key, value) {
587 return definePropertyModule$4.f(object, key, createPropertyDescriptor$3(1, value));
588 } : function (object, key, value) {
589 object[key] = value;
590 return object;
591 };
592
593 var global$y = global$P;
594 var apply$5 = functionApply;
595 var uncurryThis$p = functionUncurryThis;
596 var isCallable$a = isCallable$h;
597 var getOwnPropertyDescriptor$7 = objectGetOwnPropertyDescriptor.f;
598 var isForced = isForced_1;
599 var path$w = path$y;
600 var bind$b = functionBindContext;
601 var createNonEnumerableProperty$5 = createNonEnumerableProperty$6;
602 var hasOwn$f = hasOwnProperty_1;
603
604 var wrapConstructor = function (NativeConstructor) {
605 var Wrapper = function (a, b, c) {
606 if (this instanceof Wrapper) {
607 switch (arguments.length) {
608 case 0:
609 return new NativeConstructor();
610
611 case 1:
612 return new NativeConstructor(a);
613
614 case 2:
615 return new NativeConstructor(a, b);
616 }
617
618 return new NativeConstructor(a, b, c);
619 }
620
621 return apply$5(NativeConstructor, this, arguments);
622 };
623
624 Wrapper.prototype = NativeConstructor.prototype;
625 return Wrapper;
626 };
627 /*
628 options.target - name of the target object
629 options.global - target is the global object
630 options.stat - export as static methods of target
631 options.proto - export as prototype methods of target
632 options.real - real prototype method for the `pure` version
633 options.forced - export even if the native feature is available
634 options.bind - bind methods to the target, required for the `pure` version
635 options.wrap - wrap constructors to preventing global pollution, required for the `pure` version
636 options.unsafe - use the simple assignment of property instead of delete + defineProperty
637 options.sham - add a flag to not completely full polyfills
638 options.enumerable - export as enumerable property
639 options.noTargetGet - prevent calling a getter on target
640 options.name - the .name of the function if it does not match the key
641 */
642
643
644 var _export = function (options, source) {
645 var TARGET = options.target;
646 var GLOBAL = options.global;
647 var STATIC = options.stat;
648 var PROTO = options.proto;
649 var nativeSource = GLOBAL ? global$y : STATIC ? global$y[TARGET] : (global$y[TARGET] || {}).prototype;
650 var target = GLOBAL ? path$w : path$w[TARGET] || createNonEnumerableProperty$5(path$w, TARGET, {})[TARGET];
651 var targetPrototype = target.prototype;
652 var FORCED, USE_NATIVE, VIRTUAL_PROTOTYPE;
653 var key, sourceProperty, targetProperty, nativeProperty, resultProperty, descriptor;
654
655 for (key in source) {
656 FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced); // contains in native
657
658 USE_NATIVE = !FORCED && nativeSource && hasOwn$f(nativeSource, key);
659 targetProperty = target[key];
660 if (USE_NATIVE) if (options.noTargetGet) {
661 descriptor = getOwnPropertyDescriptor$7(nativeSource, key);
662 nativeProperty = descriptor && descriptor.value;
663 } else nativeProperty = nativeSource[key]; // export native or implementation
664
665 sourceProperty = USE_NATIVE && nativeProperty ? nativeProperty : source[key];
666 if (USE_NATIVE && typeof targetProperty == typeof sourceProperty) continue; // bind timers to global for call from export context
667
668 if (options.bind && USE_NATIVE) resultProperty = bind$b(sourceProperty, global$y); // wrap global constructors for prevent changs in this version
669 else if (options.wrap && USE_NATIVE) resultProperty = wrapConstructor(sourceProperty); // make static versions for prototype methods
670 else if (PROTO && isCallable$a(sourceProperty)) resultProperty = uncurryThis$p(sourceProperty); // default case
671 else resultProperty = sourceProperty; // add a flag to not completely full polyfills
672
673 if (options.sham || sourceProperty && sourceProperty.sham || targetProperty && targetProperty.sham) {
674 createNonEnumerableProperty$5(resultProperty, 'sham', true);
675 }
676
677 createNonEnumerableProperty$5(target, key, resultProperty);
678
679 if (PROTO) {
680 VIRTUAL_PROTOTYPE = TARGET + 'Prototype';
681
682 if (!hasOwn$f(path$w, VIRTUAL_PROTOTYPE)) {
683 createNonEnumerableProperty$5(path$w, VIRTUAL_PROTOTYPE, {});
684 } // export virtual prototype methods
685
686
687 createNonEnumerableProperty$5(path$w[VIRTUAL_PROTOTYPE], key, sourceProperty); // export real prototype methods
688
689 if (options.real && targetPrototype && !targetPrototype[key]) {
690 createNonEnumerableProperty$5(targetPrototype, key, sourceProperty);
691 }
692 }
693 }
694 };
695
696 var ceil = Math.ceil;
697 var floor$1 = Math.floor; // `ToIntegerOrInfinity` abstract operation
698 // https://tc39.es/ecma262/#sec-tointegerorinfinity
699
700 var toIntegerOrInfinity$4 = function (argument) {
701 var number = +argument; // eslint-disable-next-line no-self-compare -- safe
702
703 return number !== number || number === 0 ? 0 : (number > 0 ? floor$1 : ceil)(number);
704 };
705
706 var toIntegerOrInfinity$3 = toIntegerOrInfinity$4;
707 var max$3 = Math.max;
708 var min$2 = Math.min; // Helper for a popular repeating case of the spec:
709 // Let integer be ? ToInteger(index).
710 // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
711
712 var toAbsoluteIndex$5 = function (index, length) {
713 var integer = toIntegerOrInfinity$3(index);
714 return integer < 0 ? max$3(integer + length, 0) : min$2(integer, length);
715 };
716
717 var toIntegerOrInfinity$2 = toIntegerOrInfinity$4;
718 var min$1 = Math.min; // `ToLength` abstract operation
719 // https://tc39.es/ecma262/#sec-tolength
720
721 var toLength$1 = function (argument) {
722 return argument > 0 ? min$1(toIntegerOrInfinity$2(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
723 };
724
725 var toLength = toLength$1; // `LengthOfArrayLike` abstract operation
726 // https://tc39.es/ecma262/#sec-lengthofarraylike
727
728 var lengthOfArrayLike$d = function (obj) {
729 return toLength(obj.length);
730 };
731
732 var toIndexedObject$9 = toIndexedObject$b;
733 var toAbsoluteIndex$4 = toAbsoluteIndex$5;
734 var lengthOfArrayLike$c = lengthOfArrayLike$d; // `Array.prototype.{ indexOf, includes }` methods implementation
735
736 var createMethod$5 = function (IS_INCLUDES) {
737 return function ($this, el, fromIndex) {
738 var O = toIndexedObject$9($this);
739 var length = lengthOfArrayLike$c(O);
740 var index = toAbsoluteIndex$4(fromIndex, length);
741 var value; // Array#includes uses SameValueZero equality algorithm
742 // eslint-disable-next-line no-self-compare -- NaN check
743
744 if (IS_INCLUDES && el != el) while (length > index) {
745 value = O[index++]; // eslint-disable-next-line no-self-compare -- NaN check
746
747 if (value != value) return true; // Array#indexOf ignores holes, Array#includes - not
748 } else for (; length > index; index++) {
749 if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
750 }
751 return !IS_INCLUDES && -1;
752 };
753 };
754
755 var arrayIncludes = {
756 // `Array.prototype.includes` method
757 // https://tc39.es/ecma262/#sec-array.prototype.includes
758 includes: createMethod$5(true),
759 // `Array.prototype.indexOf` method
760 // https://tc39.es/ecma262/#sec-array.prototype.indexof
761 indexOf: createMethod$5(false)
762 };
763
764 var hiddenKeys$6 = {};
765
766 var uncurryThis$o = functionUncurryThis;
767 var hasOwn$e = hasOwnProperty_1;
768 var toIndexedObject$8 = toIndexedObject$b;
769 var indexOf$4 = arrayIncludes.indexOf;
770 var hiddenKeys$5 = hiddenKeys$6;
771 var push$5 = uncurryThis$o([].push);
772
773 var objectKeysInternal = function (object, names) {
774 var O = toIndexedObject$8(object);
775 var i = 0;
776 var result = [];
777 var key;
778
779 for (key in O) !hasOwn$e(hiddenKeys$5, key) && hasOwn$e(O, key) && push$5(result, key); // Don't enum bug & hidden keys
780
781
782 while (names.length > i) if (hasOwn$e(O, key = names[i++])) {
783 ~indexOf$4(result, key) || push$5(result, key);
784 }
785
786 return result;
787 };
788
789 var enumBugKeys$3 = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'];
790
791 var internalObjectKeys$1 = objectKeysInternal;
792 var enumBugKeys$2 = enumBugKeys$3; // `Object.keys` method
793 // https://tc39.es/ecma262/#sec-object.keys
794 // eslint-disable-next-line es/no-object-keys -- safe
795
796 var objectKeys$4 = Object.keys || function keys(O) {
797 return internalObjectKeys$1(O, enumBugKeys$2);
798 };
799
800 var objectGetOwnPropertySymbols = {};
801
802 objectGetOwnPropertySymbols.f = Object.getOwnPropertySymbols;
803
804 var DESCRIPTORS$c = descriptors;
805 var uncurryThis$n = functionUncurryThis;
806 var call$7 = functionCall;
807 var fails$l = fails$t;
808 var objectKeys$3 = objectKeys$4;
809 var getOwnPropertySymbolsModule$2 = objectGetOwnPropertySymbols;
810 var propertyIsEnumerableModule$1 = objectPropertyIsEnumerable;
811 var toObject$c = toObject$e;
812 var IndexedObject$2 = indexedObject; // eslint-disable-next-line es/no-object-assign -- safe
813
814 var $assign = Object.assign; // eslint-disable-next-line es/no-object-defineproperty -- required for testing
815
816 var defineProperty$d = Object.defineProperty;
817 var concat$6 = uncurryThis$n([].concat); // `Object.assign` method
818 // https://tc39.es/ecma262/#sec-object.assign
819
820 var objectAssign = !$assign || fails$l(function () {
821 // should have correct order of operations (Edge bug)
822 if (DESCRIPTORS$c && $assign({
823 b: 1
824 }, $assign(defineProperty$d({}, 'a', {
825 enumerable: true,
826 get: function () {
827 defineProperty$d(this, 'b', {
828 value: 3,
829 enumerable: false
830 });
831 }
832 }), {
833 b: 2
834 })).b !== 1) return true; // should work with symbols and should have deterministic property order (V8 bug)
835
836 var A = {};
837 var B = {}; // eslint-disable-next-line es/no-symbol -- safe
838
839 var symbol = Symbol();
840 var alphabet = 'abcdefghijklmnopqrst';
841 A[symbol] = 7;
842 alphabet.split('').forEach(function (chr) {
843 B[chr] = chr;
844 });
845 return $assign({}, A)[symbol] != 7 || objectKeys$3($assign({}, B)).join('') != alphabet;
846 }) ? function assign(target, source) {
847 // eslint-disable-line no-unused-vars -- required for `.length`
848 var T = toObject$c(target);
849 var argumentsLength = arguments.length;
850 var index = 1;
851 var getOwnPropertySymbols = getOwnPropertySymbolsModule$2.f;
852 var propertyIsEnumerable = propertyIsEnumerableModule$1.f;
853
854 while (argumentsLength > index) {
855 var S = IndexedObject$2(arguments[index++]);
856 var keys = getOwnPropertySymbols ? concat$6(objectKeys$3(S), getOwnPropertySymbols(S)) : objectKeys$3(S);
857 var length = keys.length;
858 var j = 0;
859 var key;
860
861 while (length > j) {
862 key = keys[j++];
863 if (!DESCRIPTORS$c || call$7(propertyIsEnumerable, S, key)) T[key] = S[key];
864 }
865 }
866
867 return T;
868 } : $assign;
869
870 var $$J = _export;
871 var assign$5 = objectAssign; // `Object.assign` method
872 // https://tc39.es/ecma262/#sec-object.assign
873 // eslint-disable-next-line es/no-object-assign -- required for testing
874
875 $$J({
876 target: 'Object',
877 stat: true,
878 forced: Object.assign !== assign$5
879 }, {
880 assign: assign$5
881 });
882
883 var path$v = path$y;
884 var assign$4 = path$v.Object.assign;
885
886 var parent$1c = assign$4;
887 var assign$3 = parent$1c;
888
889 var assign$2 = assign$3;
890
891 var uncurryThis$m = functionUncurryThis;
892 var arraySlice$5 = uncurryThis$m([].slice);
893
894 var global$x = global$P;
895 var uncurryThis$l = functionUncurryThis;
896 var aCallable$4 = aCallable$7;
897 var isObject$e = isObject$j;
898 var hasOwn$d = hasOwnProperty_1;
899 var arraySlice$4 = arraySlice$5;
900 var NATIVE_BIND = functionBindNative;
901 var Function$2 = global$x.Function;
902 var concat$5 = uncurryThis$l([].concat);
903 var join = uncurryThis$l([].join);
904 var factories = {};
905
906 var construct$4 = function (C, argsLength, args) {
907 if (!hasOwn$d(factories, argsLength)) {
908 for (var list = [], i = 0; i < argsLength; i++) list[i] = 'a[' + i + ']';
909
910 factories[argsLength] = Function$2('C,a', 'return new C(' + join(list, ',') + ')');
911 }
912
913 return factories[argsLength](C, args);
914 }; // `Function.prototype.bind` method implementation
915 // https://tc39.es/ecma262/#sec-function.prototype.bind
916
917
918 var functionBind = NATIVE_BIND ? Function$2.bind : function bind(that
919 /* , ...args */
920 ) {
921 var F = aCallable$4(this);
922 var Prototype = F.prototype;
923 var partArgs = arraySlice$4(arguments, 1);
924
925 var boundFunction = function
926 /* args... */
927 bound() {
928 var args = concat$5(partArgs, arraySlice$4(arguments));
929 return this instanceof boundFunction ? construct$4(F, args.length, args) : F.apply(that, args);
930 };
931
932 if (isObject$e(Prototype)) boundFunction.prototype = Prototype;
933 return boundFunction;
934 };
935
936 var $$I = _export;
937 var bind$a = functionBind; // `Function.prototype.bind` method
938 // https://tc39.es/ecma262/#sec-function.prototype.bind
939
940 $$I({
941 target: 'Function',
942 proto: true,
943 forced: Function.bind !== bind$a
944 }, {
945 bind: bind$a
946 });
947
948 var path$u = path$y;
949
950 var entryVirtual$l = function (CONSTRUCTOR) {
951 return path$u[CONSTRUCTOR + 'Prototype'];
952 };
953
954 var entryVirtual$k = entryVirtual$l;
955 var bind$9 = entryVirtual$k('Function').bind;
956
957 var isPrototypeOf$m = objectIsPrototypeOf;
958 var method$i = bind$9;
959 var FunctionPrototype$1 = Function.prototype;
960
961 var bind$8 = function (it) {
962 var own = it.bind;
963 return it === FunctionPrototype$1 || isPrototypeOf$m(FunctionPrototype$1, it) && own === FunctionPrototype$1.bind ? method$i : own;
964 };
965
966 var parent$1b = bind$8;
967 var bind$7 = parent$1b;
968
969 var bind$6 = bind$7;
970
971 /**
972 * Draw a circle.
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 r - The radius of the circle.
978 */
979 function drawCircle(ctx, x, y, r) {
980 ctx.beginPath();
981 ctx.arc(x, y, r, 0, 2 * Math.PI, false);
982 ctx.closePath();
983 }
984 /**
985 * Draw a square.
986 *
987 * @param ctx - The context this shape will be rendered to.
988 * @param x - The position of the center on the x axis.
989 * @param y - The position of the center on the y axis.
990 * @param r - Half of the width and height of the square.
991 */
992
993 function drawSquare(ctx, x, y, r) {
994 ctx.beginPath();
995 ctx.rect(x - r, y - r, r * 2, r * 2);
996 ctx.closePath();
997 }
998 /**
999 * Draw an equilateral triangle standing on a side.
1000 *
1001 * @param ctx - The context this shape will be rendered to.
1002 * @param x - The position of the center on the x axis.
1003 * @param y - The position of the center on the y axis.
1004 * @param r - Half of the length of the sides.
1005 * @remarks
1006 * http://en.wikipedia.org/wiki/Equilateral_triangle
1007 */
1008
1009 function drawTriangle(ctx, x, y, r) {
1010 ctx.beginPath(); // the change in radius and the offset is here to center the shape
1011
1012 r *= 1.15;
1013 y += 0.275 * r;
1014 var s = r * 2;
1015 var s2 = s / 2;
1016 var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
1017
1018 var h = Math.sqrt(s * s - s2 * s2); // height
1019
1020 ctx.moveTo(x, y - (h - ir));
1021 ctx.lineTo(x + s2, y + ir);
1022 ctx.lineTo(x - s2, y + ir);
1023 ctx.lineTo(x, y - (h - ir));
1024 ctx.closePath();
1025 }
1026 /**
1027 * Draw an equilateral triangle standing on a vertex.
1028 *
1029 * @param ctx - The context this shape will be rendered to.
1030 * @param x - The position of the center on the x axis.
1031 * @param y - The position of the center on the y axis.
1032 * @param r - Half of the length of the sides.
1033 * @remarks
1034 * http://en.wikipedia.org/wiki/Equilateral_triangle
1035 */
1036
1037 function drawTriangleDown(ctx, x, y, r) {
1038 ctx.beginPath(); // the change in radius and the offset is here to center the shape
1039
1040 r *= 1.15;
1041 y -= 0.275 * r;
1042 var s = r * 2;
1043 var s2 = s / 2;
1044 var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
1045
1046 var h = Math.sqrt(s * s - s2 * s2); // height
1047
1048 ctx.moveTo(x, y + (h - ir));
1049 ctx.lineTo(x + s2, y - ir);
1050 ctx.lineTo(x - s2, y - ir);
1051 ctx.lineTo(x, y + (h - ir));
1052 ctx.closePath();
1053 }
1054 /**
1055 * Draw a star.
1056 *
1057 * @param ctx - The context this shape will be rendered to.
1058 * @param x - The position of the center on the x axis.
1059 * @param y - The position of the center on the y axis.
1060 * @param r - The outer radius of the star.
1061 */
1062
1063 function drawStar(ctx, x, y, r) {
1064 // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
1065 ctx.beginPath(); // the change in radius and the offset is here to center the shape
1066
1067 r *= 0.82;
1068 y += 0.1 * r;
1069
1070 for (var n = 0; n < 10; n++) {
1071 var radius = n % 2 === 0 ? r * 1.3 : r * 0.5;
1072 ctx.lineTo(x + radius * Math.sin(n * 2 * Math.PI / 10), y - radius * Math.cos(n * 2 * Math.PI / 10));
1073 }
1074
1075 ctx.closePath();
1076 }
1077 /**
1078 * Draw a diamond.
1079 *
1080 * @param ctx - The context this shape will be rendered to.
1081 * @param x - The position of the center on the x axis.
1082 * @param y - The position of the center on the y axis.
1083 * @param r - Half of the width and height of the diamond.
1084 * @remarks
1085 * http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
1086 */
1087
1088 function drawDiamond(ctx, x, y, r) {
1089 ctx.beginPath();
1090 ctx.lineTo(x, y + r);
1091 ctx.lineTo(x + r, y);
1092 ctx.lineTo(x, y - r);
1093 ctx.lineTo(x - r, y);
1094 ctx.closePath();
1095 }
1096 /**
1097 * Draw a rectangle with rounded corners.
1098 *
1099 * @param ctx - The context this shape will be rendered to.
1100 * @param x - The position of the center on the x axis.
1101 * @param y - The position of the center on the y axis.
1102 * @param w - The width of the rectangle.
1103 * @param h - The height of the rectangle.
1104 * @param r - The radius of the corners.
1105 * @remarks
1106 * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas
1107 */
1108
1109 function drawRoundRect(ctx, x, y, w, h, r) {
1110 var r2d = Math.PI / 180;
1111
1112 if (w - 2 * r < 0) {
1113 r = w / 2;
1114 } //ensure that the radius isn't too large for x
1115
1116
1117 if (h - 2 * r < 0) {
1118 r = h / 2;
1119 } //ensure that the radius isn't too large for y
1120
1121
1122 ctx.beginPath();
1123 ctx.moveTo(x + r, y);
1124 ctx.lineTo(x + w - r, y);
1125 ctx.arc(x + w - r, y + r, r, r2d * 270, r2d * 360, false);
1126 ctx.lineTo(x + w, y + h - r);
1127 ctx.arc(x + w - r, y + h - r, r, 0, r2d * 90, false);
1128 ctx.lineTo(x + r, y + h);
1129 ctx.arc(x + r, y + h - r, r, r2d * 90, r2d * 180, false);
1130 ctx.lineTo(x, y + r);
1131 ctx.arc(x + r, y + r, r, r2d * 180, r2d * 270, false);
1132 ctx.closePath();
1133 }
1134 /**
1135 * Draw an ellipse.
1136 *
1137 * @param ctx - The context this shape will be rendered to.
1138 * @param x - The position of the center on the x axis.
1139 * @param y - The position of the center on the y axis.
1140 * @param w - The width of the ellipse.
1141 * @param h - The height of the ellipse.
1142 * @remarks
1143 * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
1144 *
1145 * Postfix '_vis' added to discern it from standard method ellipse().
1146 */
1147
1148 function drawEllipse(ctx, x, y, w, h) {
1149 var kappa = 0.5522848,
1150 ox = w / 2 * kappa,
1151 // control point offset horizontal
1152 oy = h / 2 * kappa,
1153 // control point offset vertical
1154 xe = x + w,
1155 // x-end
1156 ye = y + h,
1157 // y-end
1158 xm = x + w / 2,
1159 // x-middle
1160 ym = y + h / 2; // y-middle
1161
1162 ctx.beginPath();
1163 ctx.moveTo(x, ym);
1164 ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
1165 ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
1166 ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
1167 ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
1168 ctx.closePath();
1169 }
1170 /**
1171 * Draw an isometric cylinder.
1172 *
1173 * @param ctx - The context this shape will be rendered to.
1174 * @param x - The position of the center on the x axis.
1175 * @param y - The position of the center on the y axis.
1176 * @param w - The width of the database.
1177 * @param h - The height of the database.
1178 * @remarks
1179 * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
1180 */
1181
1182 function drawDatabase(ctx, x, y, w, h) {
1183 var f = 1 / 3;
1184 var wEllipse = w;
1185 var hEllipse = h * f;
1186 var kappa = 0.5522848,
1187 ox = wEllipse / 2 * kappa,
1188 // control point offset horizontal
1189 oy = hEllipse / 2 * kappa,
1190 // control point offset vertical
1191 xe = x + wEllipse,
1192 // x-end
1193 ye = y + hEllipse,
1194 // y-end
1195 xm = x + wEllipse / 2,
1196 // x-middle
1197 ym = y + hEllipse / 2,
1198 // y-middle
1199 ymb = y + (h - hEllipse / 2),
1200 // y-midlle, bottom ellipse
1201 yeb = y + h; // y-end, bottom ellipse
1202
1203 ctx.beginPath();
1204 ctx.moveTo(xe, ym);
1205 ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
1206 ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
1207 ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
1208 ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
1209 ctx.lineTo(xe, ymb);
1210 ctx.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb);
1211 ctx.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb);
1212 ctx.lineTo(x, ym);
1213 }
1214 /**
1215 * Draw a dashed line.
1216 *
1217 * @param ctx - The context this shape will be rendered to.
1218 * @param x - The start position on the x axis.
1219 * @param y - The start position on the y axis.
1220 * @param x2 - The end position on the x axis.
1221 * @param y2 - The end position on the y axis.
1222 * @param pattern - List of lengths starting with line and then alternating between space and line.
1223 * @author David Jordan
1224 * @remarks
1225 * date 2012-08-08
1226 * http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas
1227 */
1228
1229 function drawDashedLine(ctx, x, y, x2, y2, pattern) {
1230 ctx.beginPath();
1231 ctx.moveTo(x, y);
1232 var patternLength = pattern.length;
1233 var dx = x2 - x;
1234 var dy = y2 - y;
1235 var slope = dy / dx;
1236 var distRemaining = Math.sqrt(dx * dx + dy * dy);
1237 var patternIndex = 0;
1238 var draw = true;
1239 var xStep = 0;
1240 var dashLength = +pattern[0];
1241
1242 while (distRemaining >= 0.1) {
1243 dashLength = +pattern[patternIndex++ % patternLength];
1244
1245 if (dashLength > distRemaining) {
1246 dashLength = distRemaining;
1247 }
1248
1249 xStep = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
1250 xStep = dx < 0 ? -xStep : xStep;
1251 x += xStep;
1252 y += slope * xStep;
1253
1254 if (draw === true) {
1255 ctx.lineTo(x, y);
1256 } else {
1257 ctx.moveTo(x, y);
1258 }
1259
1260 distRemaining -= dashLength;
1261 draw = !draw;
1262 }
1263 }
1264 /**
1265 * Draw a hexagon.
1266 *
1267 * @param ctx - The context this shape will be rendered to.
1268 * @param x - The position of the center on the x axis.
1269 * @param y - The position of the center on the y axis.
1270 * @param r - The radius of the hexagon.
1271 */
1272
1273 function drawHexagon(ctx, x, y, r) {
1274 ctx.beginPath();
1275 var sides = 6;
1276 var a = Math.PI * 2 / sides;
1277 ctx.moveTo(x + r, y);
1278
1279 for (var i = 1; i < sides; i++) {
1280 ctx.lineTo(x + r * Math.cos(a * i), y + r * Math.sin(a * i));
1281 }
1282
1283 ctx.closePath();
1284 }
1285 var shapeMap = {
1286 circle: drawCircle,
1287 dashedLine: drawDashedLine,
1288 database: drawDatabase,
1289 diamond: drawDiamond,
1290 ellipse: drawEllipse,
1291 ellipse_vis: drawEllipse,
1292 hexagon: drawHexagon,
1293 roundRect: drawRoundRect,
1294 square: drawSquare,
1295 star: drawStar,
1296 triangle: drawTriangle,
1297 triangleDown: drawTriangleDown
1298 };
1299 /**
1300 * Returns either custom or native drawing function base on supplied name.
1301 *
1302 * @param name - The name of the function. Either the name of a
1303 * CanvasRenderingContext2D property or an export from shapes.ts without the
1304 * draw prefix.
1305 * @returns The function that can be used for rendering. In case of native
1306 * CanvasRenderingContext2D function the API is normalized to
1307 * `(ctx: CanvasRenderingContext2D, ...originalArgs) => void`.
1308 */
1309
1310 function getShape(name) {
1311 if (Object.prototype.hasOwnProperty.call(shapeMap, name)) {
1312 return shapeMap[name];
1313 } else {
1314 return function (ctx) {
1315 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
1316 args[_key - 1] = arguments[_key];
1317 }
1318
1319 CanvasRenderingContext2D.prototype[name].call(ctx, args);
1320 };
1321 }
1322 }
1323
1324 var componentEmitter = {exports: {}};
1325
1326 (function (module) {
1327 /**
1328 * Expose `Emitter`.
1329 */
1330 {
1331 module.exports = Emitter;
1332 }
1333 /**
1334 * Initialize a new `Emitter`.
1335 *
1336 * @api public
1337 */
1338
1339
1340 function Emitter(obj) {
1341 if (obj) return mixin(obj);
1342 }
1343 /**
1344 * Mixin the emitter properties.
1345 *
1346 * @param {Object} obj
1347 * @return {Object}
1348 * @api private
1349 */
1350
1351 function mixin(obj) {
1352 for (var key in Emitter.prototype) {
1353 obj[key] = Emitter.prototype[key];
1354 }
1355
1356 return obj;
1357 }
1358 /**
1359 * Listen on the given `event` with `fn`.
1360 *
1361 * @param {String} event
1362 * @param {Function} fn
1363 * @return {Emitter}
1364 * @api public
1365 */
1366
1367
1368 Emitter.prototype.on = Emitter.prototype.addEventListener = function (event, fn) {
1369 this._callbacks = this._callbacks || {};
1370 (this._callbacks['$' + event] = this._callbacks['$' + event] || []).push(fn);
1371 return this;
1372 };
1373 /**
1374 * Adds an `event` listener that will be invoked a single
1375 * time then automatically removed.
1376 *
1377 * @param {String} event
1378 * @param {Function} fn
1379 * @return {Emitter}
1380 * @api public
1381 */
1382
1383
1384 Emitter.prototype.once = function (event, fn) {
1385 function on() {
1386 this.off(event, on);
1387 fn.apply(this, arguments);
1388 }
1389
1390 on.fn = fn;
1391 this.on(event, on);
1392 return this;
1393 };
1394 /**
1395 * Remove the given callback for `event` or all
1396 * registered callbacks.
1397 *
1398 * @param {String} event
1399 * @param {Function} fn
1400 * @return {Emitter}
1401 * @api public
1402 */
1403
1404
1405 Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function (event, fn) {
1406 this._callbacks = this._callbacks || {}; // all
1407
1408 if (0 == arguments.length) {
1409 this._callbacks = {};
1410 return this;
1411 } // specific event
1412
1413
1414 var callbacks = this._callbacks['$' + event];
1415 if (!callbacks) return this; // remove all handlers
1416
1417 if (1 == arguments.length) {
1418 delete this._callbacks['$' + event];
1419 return this;
1420 } // remove specific handler
1421
1422
1423 var cb;
1424
1425 for (var i = 0; i < callbacks.length; i++) {
1426 cb = callbacks[i];
1427
1428 if (cb === fn || cb.fn === fn) {
1429 callbacks.splice(i, 1);
1430 break;
1431 }
1432 } // Remove event specific arrays for event types that no
1433 // one is subscribed for to avoid memory leak.
1434
1435
1436 if (callbacks.length === 0) {
1437 delete this._callbacks['$' + event];
1438 }
1439
1440 return this;
1441 };
1442 /**
1443 * Emit `event` with the given args.
1444 *
1445 * @param {String} event
1446 * @param {Mixed} ...
1447 * @return {Emitter}
1448 */
1449
1450
1451 Emitter.prototype.emit = function (event) {
1452 this._callbacks = this._callbacks || {};
1453 var args = new Array(arguments.length - 1),
1454 callbacks = this._callbacks['$' + event];
1455
1456 for (var i = 1; i < arguments.length; i++) {
1457 args[i - 1] = arguments[i];
1458 }
1459
1460 if (callbacks) {
1461 callbacks = callbacks.slice(0);
1462
1463 for (var i = 0, len = callbacks.length; i < len; ++i) {
1464 callbacks[i].apply(this, args);
1465 }
1466 }
1467
1468 return this;
1469 };
1470 /**
1471 * Return array of callbacks for `event`.
1472 *
1473 * @param {String} event
1474 * @return {Array}
1475 * @api public
1476 */
1477
1478
1479 Emitter.prototype.listeners = function (event) {
1480 this._callbacks = this._callbacks || {};
1481 return this._callbacks['$' + event] || [];
1482 };
1483 /**
1484 * Check if this emitter has `event` handlers.
1485 *
1486 * @param {String} event
1487 * @return {Boolean}
1488 * @api public
1489 */
1490
1491
1492 Emitter.prototype.hasListeners = function (event) {
1493 return !!this.listeners(event).length;
1494 };
1495 })(componentEmitter);
1496
1497 var Emitter = componentEmitter.exports;
1498
1499 var wellKnownSymbol$h = wellKnownSymbol$j;
1500 var TO_STRING_TAG$3 = wellKnownSymbol$h('toStringTag');
1501 var test$2 = {};
1502 test$2[TO_STRING_TAG$3] = 'z';
1503 var toStringTagSupport = String(test$2) === '[object z]';
1504
1505 var global$w = global$P;
1506 var TO_STRING_TAG_SUPPORT$2 = toStringTagSupport;
1507 var isCallable$9 = isCallable$h;
1508 var classofRaw = classofRaw$1;
1509 var wellKnownSymbol$g = wellKnownSymbol$j;
1510 var TO_STRING_TAG$2 = wellKnownSymbol$g('toStringTag');
1511 var Object$7 = global$w.Object; // ES3 wrong here
1512
1513 var CORRECT_ARGUMENTS = classofRaw(function () {
1514 return arguments;
1515 }()) == 'Arguments'; // fallback for IE11 Script Access Denied error
1516
1517 var tryGet = function (it, key) {
1518 try {
1519 return it[key];
1520 } catch (error) {
1521 /* empty */
1522 }
1523 }; // getting tag from ES6+ `Object.prototype.toString`
1524
1525
1526 var classof$e = TO_STRING_TAG_SUPPORT$2 ? classofRaw : function (it) {
1527 var O, tag, result;
1528 return it === undefined ? 'Undefined' : it === null ? 'Null' // @@toStringTag case
1529 : typeof (tag = tryGet(O = Object$7(it), TO_STRING_TAG$2)) == 'string' ? tag // builtinTag case
1530 : CORRECT_ARGUMENTS ? classofRaw(O) // ES3 arguments fallback
1531 : (result = classofRaw(O)) == 'Object' && isCallable$9(O.callee) ? 'Arguments' : result;
1532 };
1533
1534 var global$v = global$P;
1535 var classof$d = classof$e;
1536 var String$2 = global$v.String;
1537
1538 var toString$8 = function (argument) {
1539 if (classof$d(argument) === 'Symbol') throw TypeError('Cannot convert a Symbol value to a string');
1540 return String$2(argument);
1541 };
1542
1543 var uncurryThis$k = functionUncurryThis;
1544 var toIntegerOrInfinity$1 = toIntegerOrInfinity$4;
1545 var toString$7 = toString$8;
1546 var requireObjectCoercible$2 = requireObjectCoercible$5;
1547 var charAt$3 = uncurryThis$k(''.charAt);
1548 var charCodeAt$1 = uncurryThis$k(''.charCodeAt);
1549 var stringSlice = uncurryThis$k(''.slice);
1550
1551 var createMethod$4 = function (CONVERT_TO_STRING) {
1552 return function ($this, pos) {
1553 var S = toString$7(requireObjectCoercible$2($this));
1554 var position = toIntegerOrInfinity$1(pos);
1555 var size = S.length;
1556 var first, second;
1557 if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
1558 first = charCodeAt$1(S, position);
1559 return first < 0xD800 || first > 0xDBFF || position + 1 === size || (second = charCodeAt$1(S, position + 1)) < 0xDC00 || second > 0xDFFF ? CONVERT_TO_STRING ? charAt$3(S, position) : first : CONVERT_TO_STRING ? stringSlice(S, position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
1560 };
1561 };
1562
1563 var stringMultibyte = {
1564 // `String.prototype.codePointAt` method
1565 // https://tc39.es/ecma262/#sec-string.prototype.codepointat
1566 codeAt: createMethod$4(false),
1567 // `String.prototype.at` method
1568 // https://github.com/mathiasbynens/String.prototype.at
1569 charAt: createMethod$4(true)
1570 };
1571
1572 var uncurryThis$j = functionUncurryThis;
1573 var isCallable$8 = isCallable$h;
1574 var store$1 = sharedStore;
1575 var functionToString = uncurryThis$j(Function.toString); // this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper
1576
1577 if (!isCallable$8(store$1.inspectSource)) {
1578 store$1.inspectSource = function (it) {
1579 return functionToString(it);
1580 };
1581 }
1582
1583 var inspectSource$2 = store$1.inspectSource;
1584
1585 var global$u = global$P;
1586 var isCallable$7 = isCallable$h;
1587 var inspectSource$1 = inspectSource$2;
1588 var WeakMap$1 = global$u.WeakMap;
1589 var nativeWeakMap = isCallable$7(WeakMap$1) && /native code/.test(inspectSource$1(WeakMap$1));
1590
1591 var shared$2 = shared$4.exports;
1592 var uid$2 = uid$4;
1593 var keys$7 = shared$2('keys');
1594
1595 var sharedKey$4 = function (key) {
1596 return keys$7[key] || (keys$7[key] = uid$2(key));
1597 };
1598
1599 var NATIVE_WEAK_MAP$1 = nativeWeakMap;
1600 var global$t = global$P;
1601 var uncurryThis$i = functionUncurryThis;
1602 var isObject$d = isObject$j;
1603 var createNonEnumerableProperty$4 = createNonEnumerableProperty$6;
1604 var hasOwn$c = hasOwnProperty_1;
1605 var shared$1 = sharedStore;
1606 var sharedKey$3 = sharedKey$4;
1607 var hiddenKeys$4 = hiddenKeys$6;
1608 var OBJECT_ALREADY_INITIALIZED = 'Object already initialized';
1609 var TypeError$d = global$t.TypeError;
1610 var WeakMap = global$t.WeakMap;
1611 var set$3, get$6, has;
1612
1613 var enforce = function (it) {
1614 return has(it) ? get$6(it) : set$3(it, {});
1615 };
1616
1617 var getterFor = function (TYPE) {
1618 return function (it) {
1619 var state;
1620
1621 if (!isObject$d(it) || (state = get$6(it)).type !== TYPE) {
1622 throw TypeError$d('Incompatible receiver, ' + TYPE + ' required');
1623 }
1624
1625 return state;
1626 };
1627 };
1628
1629 if (NATIVE_WEAK_MAP$1 || shared$1.state) {
1630 var store = shared$1.state || (shared$1.state = new WeakMap());
1631 var wmget = uncurryThis$i(store.get);
1632 var wmhas = uncurryThis$i(store.has);
1633 var wmset = uncurryThis$i(store.set);
1634
1635 set$3 = function (it, metadata) {
1636 if (wmhas(store, it)) throw new TypeError$d(OBJECT_ALREADY_INITIALIZED);
1637 metadata.facade = it;
1638 wmset(store, it, metadata);
1639 return metadata;
1640 };
1641
1642 get$6 = function (it) {
1643 return wmget(store, it) || {};
1644 };
1645
1646 has = function (it) {
1647 return wmhas(store, it);
1648 };
1649 } else {
1650 var STATE = sharedKey$3('state');
1651 hiddenKeys$4[STATE] = true;
1652
1653 set$3 = function (it, metadata) {
1654 if (hasOwn$c(it, STATE)) throw new TypeError$d(OBJECT_ALREADY_INITIALIZED);
1655 metadata.facade = it;
1656 createNonEnumerableProperty$4(it, STATE, metadata);
1657 return metadata;
1658 };
1659
1660 get$6 = function (it) {
1661 return hasOwn$c(it, STATE) ? it[STATE] : {};
1662 };
1663
1664 has = function (it) {
1665 return hasOwn$c(it, STATE);
1666 };
1667 }
1668
1669 var internalState = {
1670 set: set$3,
1671 get: get$6,
1672 has: has,
1673 enforce: enforce,
1674 getterFor: getterFor
1675 };
1676
1677 var DESCRIPTORS$b = descriptors;
1678 var hasOwn$b = hasOwnProperty_1;
1679 var FunctionPrototype = Function.prototype; // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
1680
1681 var getDescriptor = DESCRIPTORS$b && Object.getOwnPropertyDescriptor;
1682 var EXISTS = hasOwn$b(FunctionPrototype, 'name'); // additional protection from minified / mangled / dropped function names
1683
1684 var PROPER = EXISTS && function something() {
1685 /* empty */
1686 }.name === 'something';
1687
1688 var CONFIGURABLE = EXISTS && (!DESCRIPTORS$b || DESCRIPTORS$b && getDescriptor(FunctionPrototype, 'name').configurable);
1689 var functionName = {
1690 EXISTS: EXISTS,
1691 PROPER: PROPER,
1692 CONFIGURABLE: CONFIGURABLE
1693 };
1694
1695 var objectDefineProperties = {};
1696
1697 var DESCRIPTORS$a = descriptors;
1698 var V8_PROTOTYPE_DEFINE_BUG = v8PrototypeDefineBug;
1699 var definePropertyModule$3 = objectDefineProperty;
1700 var anObject$b = anObject$d;
1701 var toIndexedObject$7 = toIndexedObject$b;
1702 var objectKeys$2 = objectKeys$4; // `Object.defineProperties` method
1703 // https://tc39.es/ecma262/#sec-object.defineproperties
1704 // eslint-disable-next-line es/no-object-defineproperties -- safe
1705
1706 objectDefineProperties.f = DESCRIPTORS$a && !V8_PROTOTYPE_DEFINE_BUG ? Object.defineProperties : function defineProperties(O, Properties) {
1707 anObject$b(O);
1708 var props = toIndexedObject$7(Properties);
1709 var keys = objectKeys$2(Properties);
1710 var length = keys.length;
1711 var index = 0;
1712 var key;
1713
1714 while (length > index) definePropertyModule$3.f(O, key = keys[index++], props[key]);
1715
1716 return O;
1717 };
1718
1719 var getBuiltIn$6 = getBuiltIn$9;
1720 var html$1 = getBuiltIn$6('document', 'documentElement');
1721
1722 /* global ActiveXObject -- old IE, WSH */
1723 var anObject$a = anObject$d;
1724 var definePropertiesModule$1 = objectDefineProperties;
1725 var enumBugKeys$1 = enumBugKeys$3;
1726 var hiddenKeys$3 = hiddenKeys$6;
1727 var html = html$1;
1728 var documentCreateElement = documentCreateElement$1;
1729 var sharedKey$2 = sharedKey$4;
1730 var GT = '>';
1731 var LT = '<';
1732 var PROTOTYPE$1 = 'prototype';
1733 var SCRIPT = 'script';
1734 var IE_PROTO$1 = sharedKey$2('IE_PROTO');
1735
1736 var EmptyConstructor = function () {
1737 /* empty */
1738 };
1739
1740 var scriptTag = function (content) {
1741 return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
1742 }; // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
1743
1744
1745 var NullProtoObjectViaActiveX = function (activeXDocument) {
1746 activeXDocument.write(scriptTag(''));
1747 activeXDocument.close();
1748 var temp = activeXDocument.parentWindow.Object;
1749 activeXDocument = null; // avoid memory leak
1750
1751 return temp;
1752 }; // Create object with fake `null` prototype: use iframe Object with cleared prototype
1753
1754
1755 var NullProtoObjectViaIFrame = function () {
1756 // Thrash, waste and sodomy: IE GC bug
1757 var iframe = documentCreateElement('iframe');
1758 var JS = 'java' + SCRIPT + ':';
1759 var iframeDocument;
1760 iframe.style.display = 'none';
1761 html.appendChild(iframe); // https://github.com/zloirock/core-js/issues/475
1762
1763 iframe.src = String(JS);
1764 iframeDocument = iframe.contentWindow.document;
1765 iframeDocument.open();
1766 iframeDocument.write(scriptTag('document.F=Object'));
1767 iframeDocument.close();
1768 return iframeDocument.F;
1769 }; // Check for document.domain and active x support
1770 // No need to use active x approach when document.domain is not set
1771 // see https://github.com/es-shims/es5-shim/issues/150
1772 // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
1773 // avoid IE GC bug
1774
1775
1776 var activeXDocument;
1777
1778 var NullProtoObject = function () {
1779 try {
1780 activeXDocument = new ActiveXObject('htmlfile');
1781 } catch (error) {
1782 /* ignore */
1783 }
1784
1785 NullProtoObject = typeof document != 'undefined' ? document.domain && activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) // old IE
1786 : NullProtoObjectViaIFrame() : NullProtoObjectViaActiveX(activeXDocument); // WSH
1787
1788 var length = enumBugKeys$1.length;
1789
1790 while (length--) delete NullProtoObject[PROTOTYPE$1][enumBugKeys$1[length]];
1791
1792 return NullProtoObject();
1793 };
1794
1795 hiddenKeys$3[IE_PROTO$1] = true; // `Object.create` method
1796 // https://tc39.es/ecma262/#sec-object.create
1797
1798 var objectCreate = Object.create || function create(O, Properties) {
1799 var result;
1800
1801 if (O !== null) {
1802 EmptyConstructor[PROTOTYPE$1] = anObject$a(O);
1803 result = new EmptyConstructor();
1804 EmptyConstructor[PROTOTYPE$1] = null; // add "__proto__" for Object.getPrototypeOf polyfill
1805
1806 result[IE_PROTO$1] = O;
1807 } else result = NullProtoObject();
1808
1809 return Properties === undefined ? result : definePropertiesModule$1.f(result, Properties);
1810 };
1811
1812 var fails$k = fails$t;
1813 var correctPrototypeGetter = !fails$k(function () {
1814 function F() {
1815 /* empty */
1816 }
1817
1818 F.prototype.constructor = null; // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
1819
1820 return Object.getPrototypeOf(new F()) !== F.prototype;
1821 });
1822
1823 var global$s = global$P;
1824 var hasOwn$a = hasOwnProperty_1;
1825 var isCallable$6 = isCallable$h;
1826 var toObject$b = toObject$e;
1827 var sharedKey$1 = sharedKey$4;
1828 var CORRECT_PROTOTYPE_GETTER$1 = correctPrototypeGetter;
1829 var IE_PROTO = sharedKey$1('IE_PROTO');
1830 var Object$6 = global$s.Object;
1831 var ObjectPrototype$2 = Object$6.prototype; // `Object.getPrototypeOf` method
1832 // https://tc39.es/ecma262/#sec-object.getprototypeof
1833
1834 var objectGetPrototypeOf = CORRECT_PROTOTYPE_GETTER$1 ? Object$6.getPrototypeOf : function (O) {
1835 var object = toObject$b(O);
1836 if (hasOwn$a(object, IE_PROTO)) return object[IE_PROTO];
1837 var constructor = object.constructor;
1838
1839 if (isCallable$6(constructor) && object instanceof constructor) {
1840 return constructor.prototype;
1841 }
1842
1843 return object instanceof Object$6 ? ObjectPrototype$2 : null;
1844 };
1845
1846 var createNonEnumerableProperty$3 = createNonEnumerableProperty$6;
1847
1848 var redefine$4 = function (target, key, value, options) {
1849 if (options && options.enumerable) target[key] = value;else createNonEnumerableProperty$3(target, key, value);
1850 };
1851
1852 var fails$j = fails$t;
1853 var isCallable$5 = isCallable$h;
1854 var create$a = objectCreate;
1855 var getPrototypeOf$8 = objectGetPrototypeOf;
1856 var redefine$3 = redefine$4;
1857 var wellKnownSymbol$f = wellKnownSymbol$j;
1858 var ITERATOR$6 = wellKnownSymbol$f('iterator');
1859 var BUGGY_SAFARI_ITERATORS$1 = false; // `%IteratorPrototype%` object
1860 // https://tc39.es/ecma262/#sec-%iteratorprototype%-object
1861
1862 var IteratorPrototype$1, PrototypeOfArrayIteratorPrototype, arrayIterator;
1863 /* eslint-disable es/no-array-prototype-keys -- safe */
1864
1865 if ([].keys) {
1866 arrayIterator = [].keys(); // Safari 8 has buggy iterators w/o `next`
1867
1868 if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS$1 = true;else {
1869 PrototypeOfArrayIteratorPrototype = getPrototypeOf$8(getPrototypeOf$8(arrayIterator));
1870 if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype$1 = PrototypeOfArrayIteratorPrototype;
1871 }
1872 }
1873
1874 var NEW_ITERATOR_PROTOTYPE = IteratorPrototype$1 == undefined || fails$j(function () {
1875 var test = {}; // FF44- legacy iterators case
1876
1877 return IteratorPrototype$1[ITERATOR$6].call(test) !== test;
1878 });
1879 if (NEW_ITERATOR_PROTOTYPE) IteratorPrototype$1 = {};else IteratorPrototype$1 = create$a(IteratorPrototype$1); // `%IteratorPrototype%[@@iterator]()` method
1880 // https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator
1881
1882 if (!isCallable$5(IteratorPrototype$1[ITERATOR$6])) {
1883 redefine$3(IteratorPrototype$1, ITERATOR$6, function () {
1884 return this;
1885 });
1886 }
1887
1888 var iteratorsCore = {
1889 IteratorPrototype: IteratorPrototype$1,
1890 BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS$1
1891 };
1892
1893 var TO_STRING_TAG_SUPPORT$1 = toStringTagSupport;
1894 var classof$c = classof$e; // `Object.prototype.toString` method implementation
1895 // https://tc39.es/ecma262/#sec-object.prototype.tostring
1896
1897 var objectToString = TO_STRING_TAG_SUPPORT$1 ? {}.toString : function toString() {
1898 return '[object ' + classof$c(this) + ']';
1899 };
1900
1901 var TO_STRING_TAG_SUPPORT = toStringTagSupport;
1902 var defineProperty$c = objectDefineProperty.f;
1903 var createNonEnumerableProperty$2 = createNonEnumerableProperty$6;
1904 var hasOwn$9 = hasOwnProperty_1;
1905 var toString$6 = objectToString;
1906 var wellKnownSymbol$e = wellKnownSymbol$j;
1907 var TO_STRING_TAG$1 = wellKnownSymbol$e('toStringTag');
1908
1909 var setToStringTag$5 = function (it, TAG, STATIC, SET_METHOD) {
1910 if (it) {
1911 var target = STATIC ? it : it.prototype;
1912
1913 if (!hasOwn$9(target, TO_STRING_TAG$1)) {
1914 defineProperty$c(target, TO_STRING_TAG$1, {
1915 configurable: true,
1916 value: TAG
1917 });
1918 }
1919
1920 if (SET_METHOD && !TO_STRING_TAG_SUPPORT) {
1921 createNonEnumerableProperty$2(target, 'toString', toString$6);
1922 }
1923 }
1924 };
1925
1926 var iterators = {};
1927
1928 var IteratorPrototype = iteratorsCore.IteratorPrototype;
1929 var create$9 = objectCreate;
1930 var createPropertyDescriptor$2 = createPropertyDescriptor$5;
1931 var setToStringTag$4 = setToStringTag$5;
1932 var Iterators$5 = iterators;
1933
1934 var returnThis$1 = function () {
1935 return this;
1936 };
1937
1938 var createIteratorConstructor$1 = function (IteratorConstructor, NAME, next, ENUMERABLE_NEXT) {
1939 var TO_STRING_TAG = NAME + ' Iterator';
1940 IteratorConstructor.prototype = create$9(IteratorPrototype, {
1941 next: createPropertyDescriptor$2(+!ENUMERABLE_NEXT, next)
1942 });
1943 setToStringTag$4(IteratorConstructor, TO_STRING_TAG, false, true);
1944 Iterators$5[TO_STRING_TAG] = returnThis$1;
1945 return IteratorConstructor;
1946 };
1947
1948 var global$r = global$P;
1949 var isCallable$4 = isCallable$h;
1950 var String$1 = global$r.String;
1951 var TypeError$c = global$r.TypeError;
1952
1953 var aPossiblePrototype$1 = function (argument) {
1954 if (typeof argument == 'object' || isCallable$4(argument)) return argument;
1955 throw TypeError$c("Can't set " + String$1(argument) + ' as a prototype');
1956 };
1957
1958 /* eslint-disable no-proto -- safe */
1959 var uncurryThis$h = functionUncurryThis;
1960 var anObject$9 = anObject$d;
1961 var aPossiblePrototype = aPossiblePrototype$1; // `Object.setPrototypeOf` method
1962 // https://tc39.es/ecma262/#sec-object.setprototypeof
1963 // Works with __proto__ only. Old v8 can't work with null proto objects.
1964 // eslint-disable-next-line es/no-object-setprototypeof -- safe
1965
1966 var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
1967 var CORRECT_SETTER = false;
1968 var test = {};
1969 var setter;
1970
1971 try {
1972 // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
1973 setter = uncurryThis$h(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set);
1974 setter(test, []);
1975 CORRECT_SETTER = test instanceof Array;
1976 } catch (error) {
1977 /* empty */
1978 }
1979
1980 return function setPrototypeOf(O, proto) {
1981 anObject$9(O);
1982 aPossiblePrototype(proto);
1983 if (CORRECT_SETTER) setter(O, proto);else O.__proto__ = proto;
1984 return O;
1985 };
1986 }() : undefined);
1987
1988 var $$H = _export;
1989 var call$6 = functionCall;
1990 var FunctionName = functionName;
1991 var createIteratorConstructor = createIteratorConstructor$1;
1992 var getPrototypeOf$7 = objectGetPrototypeOf;
1993 var setToStringTag$3 = setToStringTag$5;
1994 var redefine$2 = redefine$4;
1995 var wellKnownSymbol$d = wellKnownSymbol$j;
1996 var Iterators$4 = iterators;
1997 var IteratorsCore = iteratorsCore;
1998 var PROPER_FUNCTION_NAME$1 = FunctionName.PROPER;
1999 var BUGGY_SAFARI_ITERATORS = IteratorsCore.BUGGY_SAFARI_ITERATORS;
2000 var ITERATOR$5 = wellKnownSymbol$d('iterator');
2001 var KEYS = 'keys';
2002 var VALUES = 'values';
2003 var ENTRIES = 'entries';
2004
2005 var returnThis = function () {
2006 return this;
2007 };
2008
2009 var defineIterator$3 = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
2010 createIteratorConstructor(IteratorConstructor, NAME, next);
2011
2012 var getIterationMethod = function (KIND) {
2013 if (KIND === DEFAULT && defaultIterator) return defaultIterator;
2014 if (!BUGGY_SAFARI_ITERATORS && KIND in IterablePrototype) return IterablePrototype[KIND];
2015
2016 switch (KIND) {
2017 case KEYS:
2018 return function keys() {
2019 return new IteratorConstructor(this, KIND);
2020 };
2021
2022 case VALUES:
2023 return function values() {
2024 return new IteratorConstructor(this, KIND);
2025 };
2026
2027 case ENTRIES:
2028 return function entries() {
2029 return new IteratorConstructor(this, KIND);
2030 };
2031 }
2032
2033 return function () {
2034 return new IteratorConstructor(this);
2035 };
2036 };
2037
2038 var TO_STRING_TAG = NAME + ' Iterator';
2039 var INCORRECT_VALUES_NAME = false;
2040 var IterablePrototype = Iterable.prototype;
2041 var nativeIterator = IterablePrototype[ITERATOR$5] || IterablePrototype['@@iterator'] || DEFAULT && IterablePrototype[DEFAULT];
2042 var defaultIterator = !BUGGY_SAFARI_ITERATORS && nativeIterator || getIterationMethod(DEFAULT);
2043 var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
2044 var CurrentIteratorPrototype, methods, KEY; // fix native
2045
2046 if (anyNativeIterator) {
2047 CurrentIteratorPrototype = getPrototypeOf$7(anyNativeIterator.call(new Iterable()));
2048
2049 if (CurrentIteratorPrototype !== Object.prototype && CurrentIteratorPrototype.next) {
2050
2051
2052 setToStringTag$3(CurrentIteratorPrototype, TO_STRING_TAG, true, true);
2053 Iterators$4[TO_STRING_TAG] = returnThis;
2054 }
2055 } // fix Array.prototype.{ values, @@iterator }.name in V8 / FF
2056
2057
2058 if (PROPER_FUNCTION_NAME$1 && DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
2059 {
2060 INCORRECT_VALUES_NAME = true;
2061
2062 defaultIterator = function values() {
2063 return call$6(nativeIterator, this);
2064 };
2065 }
2066 } // export additional methods
2067
2068
2069 if (DEFAULT) {
2070 methods = {
2071 values: getIterationMethod(VALUES),
2072 keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
2073 entries: getIterationMethod(ENTRIES)
2074 };
2075 if (FORCED) for (KEY in methods) {
2076 if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
2077 redefine$2(IterablePrototype, KEY, methods[KEY]);
2078 }
2079 } else $$H({
2080 target: NAME,
2081 proto: true,
2082 forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME
2083 }, methods);
2084 } // define iterator
2085
2086
2087 if ((FORCED) && IterablePrototype[ITERATOR$5] !== defaultIterator) {
2088 redefine$2(IterablePrototype, ITERATOR$5, defaultIterator, {
2089 name: DEFAULT
2090 });
2091 }
2092
2093 Iterators$4[NAME] = defaultIterator;
2094 return methods;
2095 };
2096
2097 var charAt$2 = stringMultibyte.charAt;
2098 var toString$5 = toString$8;
2099 var InternalStateModule$5 = internalState;
2100 var defineIterator$2 = defineIterator$3;
2101 var STRING_ITERATOR = 'String Iterator';
2102 var setInternalState$5 = InternalStateModule$5.set;
2103 var getInternalState$2 = InternalStateModule$5.getterFor(STRING_ITERATOR); // `String.prototype[@@iterator]` method
2104 // https://tc39.es/ecma262/#sec-string.prototype-@@iterator
2105
2106 defineIterator$2(String, 'String', function (iterated) {
2107 setInternalState$5(this, {
2108 type: STRING_ITERATOR,
2109 string: toString$5(iterated),
2110 index: 0
2111 }); // `%StringIteratorPrototype%.next` method
2112 // https://tc39.es/ecma262/#sec-%stringiteratorprototype%.next
2113 }, function next() {
2114 var state = getInternalState$2(this);
2115 var string = state.string;
2116 var index = state.index;
2117 var point;
2118 if (index >= string.length) return {
2119 value: undefined,
2120 done: true
2121 };
2122 point = charAt$2(string, index);
2123 state.index += point.length;
2124 return {
2125 value: point,
2126 done: false
2127 };
2128 });
2129
2130 var call$5 = functionCall;
2131 var anObject$8 = anObject$d;
2132 var getMethod$1 = getMethod$3;
2133
2134 var iteratorClose$2 = function (iterator, kind, value) {
2135 var innerResult, innerError;
2136 anObject$8(iterator);
2137
2138 try {
2139 innerResult = getMethod$1(iterator, 'return');
2140
2141 if (!innerResult) {
2142 if (kind === 'throw') throw value;
2143 return value;
2144 }
2145
2146 innerResult = call$5(innerResult, iterator);
2147 } catch (error) {
2148 innerError = true;
2149 innerResult = error;
2150 }
2151
2152 if (kind === 'throw') throw value;
2153 if (innerError) throw innerResult;
2154 anObject$8(innerResult);
2155 return value;
2156 };
2157
2158 var anObject$7 = anObject$d;
2159 var iteratorClose$1 = iteratorClose$2; // call something on iterator step with safe closing on error
2160
2161 var callWithSafeIterationClosing$1 = function (iterator, fn, value, ENTRIES) {
2162 try {
2163 return ENTRIES ? fn(anObject$7(value)[0], value[1]) : fn(value);
2164 } catch (error) {
2165 iteratorClose$1(iterator, 'throw', error);
2166 }
2167 };
2168
2169 var wellKnownSymbol$c = wellKnownSymbol$j;
2170 var Iterators$3 = iterators;
2171 var ITERATOR$4 = wellKnownSymbol$c('iterator');
2172 var ArrayPrototype$i = Array.prototype; // check on default Array iterator
2173
2174 var isArrayIteratorMethod$2 = function (it) {
2175 return it !== undefined && (Iterators$3.Array === it || ArrayPrototype$i[ITERATOR$4] === it);
2176 };
2177
2178 var uncurryThis$g = functionUncurryThis;
2179 var fails$i = fails$t;
2180 var isCallable$3 = isCallable$h;
2181 var classof$b = classof$e;
2182 var getBuiltIn$5 = getBuiltIn$9;
2183 var inspectSource = inspectSource$2;
2184
2185 var noop = function () {
2186 /* empty */
2187 };
2188
2189 var empty = [];
2190 var construct$3 = getBuiltIn$5('Reflect', 'construct');
2191 var constructorRegExp = /^\s*(?:class|function)\b/;
2192 var exec$2 = uncurryThis$g(constructorRegExp.exec);
2193 var INCORRECT_TO_STRING = !constructorRegExp.exec(noop);
2194
2195 var isConstructorModern = function isConstructor(argument) {
2196 if (!isCallable$3(argument)) return false;
2197
2198 try {
2199 construct$3(noop, empty, argument);
2200 return true;
2201 } catch (error) {
2202 return false;
2203 }
2204 };
2205
2206 var isConstructorLegacy = function isConstructor(argument) {
2207 if (!isCallable$3(argument)) return false;
2208
2209 switch (classof$b(argument)) {
2210 case 'AsyncFunction':
2211 case 'GeneratorFunction':
2212 case 'AsyncGeneratorFunction':
2213 return false;
2214 }
2215
2216 try {
2217 // we can't check .prototype since constructors produced by .bind haven't it
2218 // `Function#toString` throws on some built-it function in some legacy engines
2219 // (for example, `DOMQuad` and similar in FF41-)
2220 return INCORRECT_TO_STRING || !!exec$2(constructorRegExp, inspectSource(argument));
2221 } catch (error) {
2222 return true;
2223 }
2224 };
2225
2226 isConstructorLegacy.sham = true; // `IsConstructor` abstract operation
2227 // https://tc39.es/ecma262/#sec-isconstructor
2228
2229 var isConstructor$4 = !construct$3 || fails$i(function () {
2230 var called;
2231 return isConstructorModern(isConstructorModern.call) || !isConstructorModern(Object) || !isConstructorModern(function () {
2232 called = true;
2233 }) || called;
2234 }) ? isConstructorLegacy : isConstructorModern;
2235
2236 var toPropertyKey$1 = toPropertyKey$4;
2237 var definePropertyModule$2 = objectDefineProperty;
2238 var createPropertyDescriptor$1 = createPropertyDescriptor$5;
2239
2240 var createProperty$6 = function (object, key, value) {
2241 var propertyKey = toPropertyKey$1(key);
2242 if (propertyKey in object) definePropertyModule$2.f(object, propertyKey, createPropertyDescriptor$1(0, value));else object[propertyKey] = value;
2243 };
2244
2245 var classof$a = classof$e;
2246 var getMethod = getMethod$3;
2247 var Iterators$2 = iterators;
2248 var wellKnownSymbol$b = wellKnownSymbol$j;
2249 var ITERATOR$3 = wellKnownSymbol$b('iterator');
2250
2251 var getIteratorMethod$8 = function (it) {
2252 if (it != undefined) return getMethod(it, ITERATOR$3) || getMethod(it, '@@iterator') || Iterators$2[classof$a(it)];
2253 };
2254
2255 var global$q = global$P;
2256 var call$4 = functionCall;
2257 var aCallable$3 = aCallable$7;
2258 var anObject$6 = anObject$d;
2259 var tryToString$2 = tryToString$4;
2260 var getIteratorMethod$7 = getIteratorMethod$8;
2261 var TypeError$b = global$q.TypeError;
2262
2263 var getIterator$7 = function (argument, usingIterator) {
2264 var iteratorMethod = arguments.length < 2 ? getIteratorMethod$7(argument) : usingIterator;
2265 if (aCallable$3(iteratorMethod)) return anObject$6(call$4(iteratorMethod, argument));
2266 throw TypeError$b(tryToString$2(argument) + ' is not iterable');
2267 };
2268
2269 var global$p = global$P;
2270 var bind$5 = functionBindContext;
2271 var call$3 = functionCall;
2272 var toObject$a = toObject$e;
2273 var callWithSafeIterationClosing = callWithSafeIterationClosing$1;
2274 var isArrayIteratorMethod$1 = isArrayIteratorMethod$2;
2275 var isConstructor$3 = isConstructor$4;
2276 var lengthOfArrayLike$b = lengthOfArrayLike$d;
2277 var createProperty$5 = createProperty$6;
2278 var getIterator$6 = getIterator$7;
2279 var getIteratorMethod$6 = getIteratorMethod$8;
2280 var Array$5 = global$p.Array; // `Array.from` method implementation
2281 // https://tc39.es/ecma262/#sec-array.from
2282
2283 var arrayFrom = function from(arrayLike
2284 /* , mapfn = undefined, thisArg = undefined */
2285 ) {
2286 var O = toObject$a(arrayLike);
2287 var IS_CONSTRUCTOR = isConstructor$3(this);
2288 var argumentsLength = arguments.length;
2289 var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
2290 var mapping = mapfn !== undefined;
2291 if (mapping) mapfn = bind$5(mapfn, argumentsLength > 2 ? arguments[2] : undefined);
2292 var iteratorMethod = getIteratorMethod$6(O);
2293 var index = 0;
2294 var length, result, step, iterator, next, value; // if the target is not iterable or it's an array with the default iterator - use a simple case
2295
2296 if (iteratorMethod && !(this == Array$5 && isArrayIteratorMethod$1(iteratorMethod))) {
2297 iterator = getIterator$6(O, iteratorMethod);
2298 next = iterator.next;
2299 result = IS_CONSTRUCTOR ? new this() : [];
2300
2301 for (; !(step = call$3(next, iterator)).done; index++) {
2302 value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
2303 createProperty$5(result, index, value);
2304 }
2305 } else {
2306 length = lengthOfArrayLike$b(O);
2307 result = IS_CONSTRUCTOR ? new this(length) : Array$5(length);
2308
2309 for (; length > index; index++) {
2310 value = mapping ? mapfn(O[index], index) : O[index];
2311 createProperty$5(result, index, value);
2312 }
2313 }
2314
2315 result.length = index;
2316 return result;
2317 };
2318
2319 var wellKnownSymbol$a = wellKnownSymbol$j;
2320 var ITERATOR$2 = wellKnownSymbol$a('iterator');
2321 var SAFE_CLOSING = false;
2322
2323 try {
2324 var called = 0;
2325 var iteratorWithReturn = {
2326 next: function () {
2327 return {
2328 done: !!called++
2329 };
2330 },
2331 'return': function () {
2332 SAFE_CLOSING = true;
2333 }
2334 };
2335
2336 iteratorWithReturn[ITERATOR$2] = function () {
2337 return this;
2338 }; // eslint-disable-next-line es/no-array-from, no-throw-literal -- required for testing
2339
2340
2341 Array.from(iteratorWithReturn, function () {
2342 throw 2;
2343 });
2344 } catch (error) {
2345 /* empty */
2346 }
2347
2348 var checkCorrectnessOfIteration$1 = function (exec, SKIP_CLOSING) {
2349 if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
2350 var ITERATION_SUPPORT = false;
2351
2352 try {
2353 var object = {};
2354
2355 object[ITERATOR$2] = function () {
2356 return {
2357 next: function () {
2358 return {
2359 done: ITERATION_SUPPORT = true
2360 };
2361 }
2362 };
2363 };
2364
2365 exec(object);
2366 } catch (error) {
2367 /* empty */
2368 }
2369
2370 return ITERATION_SUPPORT;
2371 };
2372
2373 var $$G = _export;
2374 var from$6 = arrayFrom;
2375 var checkCorrectnessOfIteration = checkCorrectnessOfIteration$1;
2376 var INCORRECT_ITERATION = !checkCorrectnessOfIteration(function (iterable) {
2377 // eslint-disable-next-line es/no-array-from -- required for testing
2378 Array.from(iterable);
2379 }); // `Array.from` method
2380 // https://tc39.es/ecma262/#sec-array.from
2381
2382 $$G({
2383 target: 'Array',
2384 stat: true,
2385 forced: INCORRECT_ITERATION
2386 }, {
2387 from: from$6
2388 });
2389
2390 var path$t = path$y;
2391 var from$5 = path$t.Array.from;
2392
2393 var parent$1a = from$5;
2394 var from$4 = parent$1a;
2395
2396 var from$3 = from$4;
2397
2398 var toIndexedObject$6 = toIndexedObject$b;
2399 var Iterators$1 = iterators;
2400 var InternalStateModule$4 = internalState;
2401 objectDefineProperty.f;
2402 var defineIterator$1 = defineIterator$3;
2403 var ARRAY_ITERATOR = 'Array Iterator';
2404 var setInternalState$4 = InternalStateModule$4.set;
2405 var getInternalState$1 = InternalStateModule$4.getterFor(ARRAY_ITERATOR); // `Array.prototype.entries` method
2406 // https://tc39.es/ecma262/#sec-array.prototype.entries
2407 // `Array.prototype.keys` method
2408 // https://tc39.es/ecma262/#sec-array.prototype.keys
2409 // `Array.prototype.values` method
2410 // https://tc39.es/ecma262/#sec-array.prototype.values
2411 // `Array.prototype[@@iterator]` method
2412 // https://tc39.es/ecma262/#sec-array.prototype-@@iterator
2413 // `CreateArrayIterator` internal method
2414 // https://tc39.es/ecma262/#sec-createarrayiterator
2415
2416 defineIterator$1(Array, 'Array', function (iterated, kind) {
2417 setInternalState$4(this, {
2418 type: ARRAY_ITERATOR,
2419 target: toIndexedObject$6(iterated),
2420 // target
2421 index: 0,
2422 // next index
2423 kind: kind // kind
2424
2425 }); // `%ArrayIteratorPrototype%.next` method
2426 // https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
2427 }, function () {
2428 var state = getInternalState$1(this);
2429 var target = state.target;
2430 var kind = state.kind;
2431 var index = state.index++;
2432
2433 if (!target || index >= target.length) {
2434 state.target = undefined;
2435 return {
2436 value: undefined,
2437 done: true
2438 };
2439 }
2440
2441 if (kind == 'keys') return {
2442 value: index,
2443 done: false
2444 };
2445 if (kind == 'values') return {
2446 value: target[index],
2447 done: false
2448 };
2449 return {
2450 value: [index, target[index]],
2451 done: false
2452 };
2453 }, 'values'); // argumentsList[@@iterator] is %ArrayProto_values%
2454 // https://tc39.es/ecma262/#sec-createunmappedargumentsobject
2455 // https://tc39.es/ecma262/#sec-createmappedargumentsobject
2456
2457 Iterators$1.Arguments = Iterators$1.Array; // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
2458
2459 var getIteratorMethod$5 = getIteratorMethod$8;
2460 var getIteratorMethod_1 = getIteratorMethod$5;
2461
2462 // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
2463
2464 var domIterables = {
2465 CSSRuleList: 0,
2466 CSSStyleDeclaration: 0,
2467 CSSValueList: 0,
2468 ClientRectList: 0,
2469 DOMRectList: 0,
2470 DOMStringList: 0,
2471 DOMTokenList: 1,
2472 DataTransferItemList: 0,
2473 FileList: 0,
2474 HTMLAllCollection: 0,
2475 HTMLCollection: 0,
2476 HTMLFormElement: 0,
2477 HTMLSelectElement: 0,
2478 MediaList: 0,
2479 MimeTypeArray: 0,
2480 NamedNodeMap: 0,
2481 NodeList: 1,
2482 PaintRequestList: 0,
2483 Plugin: 0,
2484 PluginArray: 0,
2485 SVGLengthList: 0,
2486 SVGNumberList: 0,
2487 SVGPathSegList: 0,
2488 SVGPointList: 0,
2489 SVGStringList: 0,
2490 SVGTransformList: 0,
2491 SourceBufferList: 0,
2492 StyleSheetList: 0,
2493 TextTrackCueList: 0,
2494 TextTrackList: 0,
2495 TouchList: 0
2496 };
2497
2498 var DOMIterables$4 = domIterables;
2499 var global$o = global$P;
2500 var classof$9 = classof$e;
2501 var createNonEnumerableProperty$1 = createNonEnumerableProperty$6;
2502 var Iterators = iterators;
2503 var wellKnownSymbol$9 = wellKnownSymbol$j;
2504 var TO_STRING_TAG = wellKnownSymbol$9('toStringTag');
2505
2506 for (var COLLECTION_NAME in DOMIterables$4) {
2507 var Collection = global$o[COLLECTION_NAME];
2508 var CollectionPrototype = Collection && Collection.prototype;
2509
2510 if (CollectionPrototype && classof$9(CollectionPrototype) !== TO_STRING_TAG) {
2511 createNonEnumerableProperty$1(CollectionPrototype, TO_STRING_TAG, COLLECTION_NAME);
2512 }
2513
2514 Iterators[COLLECTION_NAME] = Iterators.Array;
2515 }
2516
2517 var parent$19 = getIteratorMethod_1;
2518 var getIteratorMethod$4 = parent$19;
2519
2520 var parent$18 = getIteratorMethod$4;
2521 var getIteratorMethod$3 = parent$18;
2522
2523 var parent$17 = getIteratorMethod$3;
2524 var getIteratorMethod$2 = parent$17;
2525
2526 var getIteratorMethod$1 = getIteratorMethod$2;
2527
2528 var classof$8 = classofRaw$1; // `IsArray` abstract operation
2529 // https://tc39.es/ecma262/#sec-isarray
2530 // eslint-disable-next-line es/no-array-isarray -- safe
2531
2532 var isArray$d = Array.isArray || function isArray(argument) {
2533 return classof$8(argument) == 'Array';
2534 };
2535
2536 var objectGetOwnPropertyNames = {};
2537
2538 var internalObjectKeys = objectKeysInternal;
2539 var enumBugKeys = enumBugKeys$3;
2540 var hiddenKeys$2 = enumBugKeys.concat('length', 'prototype'); // `Object.getOwnPropertyNames` method
2541 // https://tc39.es/ecma262/#sec-object.getownpropertynames
2542 // eslint-disable-next-line es/no-object-getownpropertynames -- safe
2543
2544 objectGetOwnPropertyNames.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
2545 return internalObjectKeys(O, hiddenKeys$2);
2546 };
2547
2548 var objectGetOwnPropertyNamesExternal = {};
2549
2550 var global$n = global$P;
2551 var toAbsoluteIndex$3 = toAbsoluteIndex$5;
2552 var lengthOfArrayLike$a = lengthOfArrayLike$d;
2553 var createProperty$4 = createProperty$6;
2554 var Array$4 = global$n.Array;
2555 var max$2 = Math.max;
2556
2557 var arraySliceSimple = function (O, start, end) {
2558 var length = lengthOfArrayLike$a(O);
2559 var k = toAbsoluteIndex$3(start, length);
2560 var fin = toAbsoluteIndex$3(end === undefined ? length : end, length);
2561 var result = Array$4(max$2(fin - k, 0));
2562
2563 for (var n = 0; k < fin; k++, n++) createProperty$4(result, n, O[k]);
2564
2565 result.length = n;
2566 return result;
2567 };
2568
2569 /* eslint-disable es/no-object-getownpropertynames -- safe */
2570 var classof$7 = classofRaw$1;
2571 var toIndexedObject$5 = toIndexedObject$b;
2572 var $getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
2573 var arraySlice$3 = arraySliceSimple;
2574 var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : [];
2575
2576 var getWindowNames = function (it) {
2577 try {
2578 return $getOwnPropertyNames$1(it);
2579 } catch (error) {
2580 return arraySlice$3(windowNames);
2581 }
2582 }; // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
2583
2584
2585 objectGetOwnPropertyNamesExternal.f = function getOwnPropertyNames(it) {
2586 return windowNames && classof$7(it) == 'Window' ? getWindowNames(it) : $getOwnPropertyNames$1(toIndexedObject$5(it));
2587 };
2588
2589 var wellKnownSymbolWrapped = {};
2590
2591 var wellKnownSymbol$8 = wellKnownSymbol$j;
2592 wellKnownSymbolWrapped.f = wellKnownSymbol$8;
2593
2594 var path$s = path$y;
2595 var hasOwn$8 = hasOwnProperty_1;
2596 var wrappedWellKnownSymbolModule$1 = wellKnownSymbolWrapped;
2597 var defineProperty$b = objectDefineProperty.f;
2598
2599 var defineWellKnownSymbol$l = function (NAME) {
2600 var Symbol = path$s.Symbol || (path$s.Symbol = {});
2601 if (!hasOwn$8(Symbol, NAME)) defineProperty$b(Symbol, NAME, {
2602 value: wrappedWellKnownSymbolModule$1.f(NAME)
2603 });
2604 };
2605
2606 var global$m = global$P;
2607 var isArray$c = isArray$d;
2608 var isConstructor$2 = isConstructor$4;
2609 var isObject$c = isObject$j;
2610 var wellKnownSymbol$7 = wellKnownSymbol$j;
2611 var SPECIES$3 = wellKnownSymbol$7('species');
2612 var Array$3 = global$m.Array; // a part of `ArraySpeciesCreate` abstract operation
2613 // https://tc39.es/ecma262/#sec-arrayspeciescreate
2614
2615 var arraySpeciesConstructor$1 = function (originalArray) {
2616 var C;
2617
2618 if (isArray$c(originalArray)) {
2619 C = originalArray.constructor; // cross-realm fallback
2620
2621 if (isConstructor$2(C) && (C === Array$3 || isArray$c(C.prototype))) C = undefined;else if (isObject$c(C)) {
2622 C = C[SPECIES$3];
2623 if (C === null) C = undefined;
2624 }
2625 }
2626
2627 return C === undefined ? Array$3 : C;
2628 };
2629
2630 var arraySpeciesConstructor = arraySpeciesConstructor$1; // `ArraySpeciesCreate` abstract operation
2631 // https://tc39.es/ecma262/#sec-arrayspeciescreate
2632
2633 var arraySpeciesCreate$4 = function (originalArray, length) {
2634 return new (arraySpeciesConstructor(originalArray))(length === 0 ? 0 : length);
2635 };
2636
2637 var bind$4 = functionBindContext;
2638 var uncurryThis$f = functionUncurryThis;
2639 var IndexedObject$1 = indexedObject;
2640 var toObject$9 = toObject$e;
2641 var lengthOfArrayLike$9 = lengthOfArrayLike$d;
2642 var arraySpeciesCreate$3 = arraySpeciesCreate$4;
2643 var push$4 = uncurryThis$f([].push); // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterReject }` methods implementation
2644
2645 var createMethod$3 = function (TYPE) {
2646 var IS_MAP = TYPE == 1;
2647 var IS_FILTER = TYPE == 2;
2648 var IS_SOME = TYPE == 3;
2649 var IS_EVERY = TYPE == 4;
2650 var IS_FIND_INDEX = TYPE == 6;
2651 var IS_FILTER_REJECT = TYPE == 7;
2652 var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
2653 return function ($this, callbackfn, that, specificCreate) {
2654 var O = toObject$9($this);
2655 var self = IndexedObject$1(O);
2656 var boundFunction = bind$4(callbackfn, that);
2657 var length = lengthOfArrayLike$9(self);
2658 var index = 0;
2659 var create = specificCreate || arraySpeciesCreate$3;
2660 var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_REJECT ? create($this, 0) : undefined;
2661 var value, result;
2662
2663 for (; length > index; index++) if (NO_HOLES || index in self) {
2664 value = self[index];
2665 result = boundFunction(value, index, O);
2666
2667 if (TYPE) {
2668 if (IS_MAP) target[index] = result; // map
2669 else if (result) switch (TYPE) {
2670 case 3:
2671 return true;
2672 // some
2673
2674 case 5:
2675 return value;
2676 // find
2677
2678 case 6:
2679 return index;
2680 // findIndex
2681
2682 case 2:
2683 push$4(target, value);
2684 // filter
2685 } else switch (TYPE) {
2686 case 4:
2687 return false;
2688 // every
2689
2690 case 7:
2691 push$4(target, value);
2692 // filterReject
2693 }
2694 }
2695 }
2696
2697 return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
2698 };
2699 };
2700
2701 var arrayIteration = {
2702 // `Array.prototype.forEach` method
2703 // https://tc39.es/ecma262/#sec-array.prototype.foreach
2704 forEach: createMethod$3(0),
2705 // `Array.prototype.map` method
2706 // https://tc39.es/ecma262/#sec-array.prototype.map
2707 map: createMethod$3(1),
2708 // `Array.prototype.filter` method
2709 // https://tc39.es/ecma262/#sec-array.prototype.filter
2710 filter: createMethod$3(2),
2711 // `Array.prototype.some` method
2712 // https://tc39.es/ecma262/#sec-array.prototype.some
2713 some: createMethod$3(3),
2714 // `Array.prototype.every` method
2715 // https://tc39.es/ecma262/#sec-array.prototype.every
2716 every: createMethod$3(4),
2717 // `Array.prototype.find` method
2718 // https://tc39.es/ecma262/#sec-array.prototype.find
2719 find: createMethod$3(5),
2720 // `Array.prototype.findIndex` method
2721 // https://tc39.es/ecma262/#sec-array.prototype.findIndex
2722 findIndex: createMethod$3(6),
2723 // `Array.prototype.filterReject` method
2724 // https://github.com/tc39/proposal-array-filtering
2725 filterReject: createMethod$3(7)
2726 };
2727
2728 var $$F = _export;
2729 var global$l = global$P;
2730 var getBuiltIn$4 = getBuiltIn$9;
2731 var apply$4 = functionApply;
2732 var call$2 = functionCall;
2733 var uncurryThis$e = functionUncurryThis;
2734 var DESCRIPTORS$9 = descriptors;
2735 var NATIVE_SYMBOL = nativeSymbol;
2736 var fails$h = fails$t;
2737 var hasOwn$7 = hasOwnProperty_1;
2738 var isArray$b = isArray$d;
2739 var isCallable$2 = isCallable$h;
2740 var isObject$b = isObject$j;
2741 var isPrototypeOf$l = objectIsPrototypeOf;
2742 var isSymbol = isSymbol$3;
2743 var anObject$5 = anObject$d;
2744 var toObject$8 = toObject$e;
2745 var toIndexedObject$4 = toIndexedObject$b;
2746 var toPropertyKey = toPropertyKey$4;
2747 var $toString = toString$8;
2748 var createPropertyDescriptor = createPropertyDescriptor$5;
2749 var nativeObjectCreate = objectCreate;
2750 var objectKeys$1 = objectKeys$4;
2751 var getOwnPropertyNamesModule$2 = objectGetOwnPropertyNames;
2752 var getOwnPropertyNamesExternal = objectGetOwnPropertyNamesExternal;
2753 var getOwnPropertySymbolsModule$1 = objectGetOwnPropertySymbols;
2754 var getOwnPropertyDescriptorModule$2 = objectGetOwnPropertyDescriptor;
2755 var definePropertyModule$1 = objectDefineProperty;
2756 var definePropertiesModule = objectDefineProperties;
2757 var propertyIsEnumerableModule = objectPropertyIsEnumerable;
2758 var arraySlice$2 = arraySlice$5;
2759 var redefine$1 = redefine$4;
2760 var shared = shared$4.exports;
2761 var sharedKey = sharedKey$4;
2762 var hiddenKeys$1 = hiddenKeys$6;
2763 var uid$1 = uid$4;
2764 var wellKnownSymbol$6 = wellKnownSymbol$j;
2765 var wrappedWellKnownSymbolModule = wellKnownSymbolWrapped;
2766 var defineWellKnownSymbol$k = defineWellKnownSymbol$l;
2767 var setToStringTag$2 = setToStringTag$5;
2768 var InternalStateModule$3 = internalState;
2769 var $forEach$1 = arrayIteration.forEach;
2770 var HIDDEN = sharedKey('hidden');
2771 var SYMBOL = 'Symbol';
2772 var PROTOTYPE = 'prototype';
2773 var TO_PRIMITIVE = wellKnownSymbol$6('toPrimitive');
2774 var setInternalState$3 = InternalStateModule$3.set;
2775 var getInternalState = InternalStateModule$3.getterFor(SYMBOL);
2776 var ObjectPrototype$1 = Object[PROTOTYPE];
2777 var $Symbol = global$l.Symbol;
2778 var SymbolPrototype = $Symbol && $Symbol[PROTOTYPE];
2779 var TypeError$a = global$l.TypeError;
2780 var QObject = global$l.QObject;
2781 var $stringify$1 = getBuiltIn$4('JSON', 'stringify');
2782 var nativeGetOwnPropertyDescriptor$1 = getOwnPropertyDescriptorModule$2.f;
2783 var nativeDefineProperty = definePropertyModule$1.f;
2784 var nativeGetOwnPropertyNames = getOwnPropertyNamesExternal.f;
2785 var nativePropertyIsEnumerable = propertyIsEnumerableModule.f;
2786 var push$3 = uncurryThis$e([].push);
2787 var AllSymbols = shared('symbols');
2788 var ObjectPrototypeSymbols = shared('op-symbols');
2789 var StringToSymbolRegistry = shared('string-to-symbol-registry');
2790 var SymbolToStringRegistry = shared('symbol-to-string-registry');
2791 var WellKnownSymbolsStore = shared('wks'); // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
2792
2793 var USE_SETTER = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild; // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
2794
2795 var setSymbolDescriptor = DESCRIPTORS$9 && fails$h(function () {
2796 return nativeObjectCreate(nativeDefineProperty({}, 'a', {
2797 get: function () {
2798 return nativeDefineProperty(this, 'a', {
2799 value: 7
2800 }).a;
2801 }
2802 })).a != 7;
2803 }) ? function (O, P, Attributes) {
2804 var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype$1, P);
2805 if (ObjectPrototypeDescriptor) delete ObjectPrototype$1[P];
2806 nativeDefineProperty(O, P, Attributes);
2807
2808 if (ObjectPrototypeDescriptor && O !== ObjectPrototype$1) {
2809 nativeDefineProperty(ObjectPrototype$1, P, ObjectPrototypeDescriptor);
2810 }
2811 } : nativeDefineProperty;
2812
2813 var wrap$1 = function (tag, description) {
2814 var symbol = AllSymbols[tag] = nativeObjectCreate(SymbolPrototype);
2815 setInternalState$3(symbol, {
2816 type: SYMBOL,
2817 tag: tag,
2818 description: description
2819 });
2820 if (!DESCRIPTORS$9) symbol.description = description;
2821 return symbol;
2822 };
2823
2824 var $defineProperty = function defineProperty(O, P, Attributes) {
2825 if (O === ObjectPrototype$1) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
2826 anObject$5(O);
2827 var key = toPropertyKey(P);
2828 anObject$5(Attributes);
2829
2830 if (hasOwn$7(AllSymbols, key)) {
2831 if (!Attributes.enumerable) {
2832 if (!hasOwn$7(O, HIDDEN)) nativeDefineProperty(O, HIDDEN, createPropertyDescriptor(1, {}));
2833 O[HIDDEN][key] = true;
2834 } else {
2835 if (hasOwn$7(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
2836 Attributes = nativeObjectCreate(Attributes, {
2837 enumerable: createPropertyDescriptor(0, false)
2838 });
2839 }
2840
2841 return setSymbolDescriptor(O, key, Attributes);
2842 }
2843
2844 return nativeDefineProperty(O, key, Attributes);
2845 };
2846
2847 var $defineProperties = function defineProperties(O, Properties) {
2848 anObject$5(O);
2849 var properties = toIndexedObject$4(Properties);
2850 var keys = objectKeys$1(properties).concat($getOwnPropertySymbols(properties));
2851 $forEach$1(keys, function (key) {
2852 if (!DESCRIPTORS$9 || call$2($propertyIsEnumerable$1, properties, key)) $defineProperty(O, key, properties[key]);
2853 });
2854 return O;
2855 };
2856
2857 var $create = function create(O, Properties) {
2858 return Properties === undefined ? nativeObjectCreate(O) : $defineProperties(nativeObjectCreate(O), Properties);
2859 };
2860
2861 var $propertyIsEnumerable$1 = function propertyIsEnumerable(V) {
2862 var P = toPropertyKey(V);
2863 var enumerable = call$2(nativePropertyIsEnumerable, this, P);
2864 if (this === ObjectPrototype$1 && hasOwn$7(AllSymbols, P) && !hasOwn$7(ObjectPrototypeSymbols, P)) return false;
2865 return enumerable || !hasOwn$7(this, P) || !hasOwn$7(AllSymbols, P) || hasOwn$7(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
2866 };
2867
2868 var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
2869 var it = toIndexedObject$4(O);
2870 var key = toPropertyKey(P);
2871 if (it === ObjectPrototype$1 && hasOwn$7(AllSymbols, key) && !hasOwn$7(ObjectPrototypeSymbols, key)) return;
2872 var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);
2873
2874 if (descriptor && hasOwn$7(AllSymbols, key) && !(hasOwn$7(it, HIDDEN) && it[HIDDEN][key])) {
2875 descriptor.enumerable = true;
2876 }
2877
2878 return descriptor;
2879 };
2880
2881 var $getOwnPropertyNames = function getOwnPropertyNames(O) {
2882 var names = nativeGetOwnPropertyNames(toIndexedObject$4(O));
2883 var result = [];
2884 $forEach$1(names, function (key) {
2885 if (!hasOwn$7(AllSymbols, key) && !hasOwn$7(hiddenKeys$1, key)) push$3(result, key);
2886 });
2887 return result;
2888 };
2889
2890 var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
2891 var IS_OBJECT_PROTOTYPE = O === ObjectPrototype$1;
2892 var names = nativeGetOwnPropertyNames(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject$4(O));
2893 var result = [];
2894 $forEach$1(names, function (key) {
2895 if (hasOwn$7(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || hasOwn$7(ObjectPrototype$1, key))) {
2896 push$3(result, AllSymbols[key]);
2897 }
2898 });
2899 return result;
2900 }; // `Symbol` constructor
2901 // https://tc39.es/ecma262/#sec-symbol-constructor
2902
2903
2904 if (!NATIVE_SYMBOL) {
2905 $Symbol = function Symbol() {
2906 if (isPrototypeOf$l(SymbolPrototype, this)) throw TypeError$a('Symbol is not a constructor');
2907 var description = !arguments.length || arguments[0] === undefined ? undefined : $toString(arguments[0]);
2908 var tag = uid$1(description);
2909
2910 var setter = function (value) {
2911 if (this === ObjectPrototype$1) call$2(setter, ObjectPrototypeSymbols, value);
2912 if (hasOwn$7(this, HIDDEN) && hasOwn$7(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
2913 setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
2914 };
2915
2916 if (DESCRIPTORS$9 && USE_SETTER) setSymbolDescriptor(ObjectPrototype$1, tag, {
2917 configurable: true,
2918 set: setter
2919 });
2920 return wrap$1(tag, description);
2921 };
2922
2923 SymbolPrototype = $Symbol[PROTOTYPE];
2924 redefine$1(SymbolPrototype, 'toString', function toString() {
2925 return getInternalState(this).tag;
2926 });
2927 redefine$1($Symbol, 'withoutSetter', function (description) {
2928 return wrap$1(uid$1(description), description);
2929 });
2930 propertyIsEnumerableModule.f = $propertyIsEnumerable$1;
2931 definePropertyModule$1.f = $defineProperty;
2932 definePropertiesModule.f = $defineProperties;
2933 getOwnPropertyDescriptorModule$2.f = $getOwnPropertyDescriptor;
2934 getOwnPropertyNamesModule$2.f = getOwnPropertyNamesExternal.f = $getOwnPropertyNames;
2935 getOwnPropertySymbolsModule$1.f = $getOwnPropertySymbols;
2936
2937 wrappedWellKnownSymbolModule.f = function (name) {
2938 return wrap$1(wellKnownSymbol$6(name), name);
2939 };
2940
2941 if (DESCRIPTORS$9) {
2942 // https://github.com/tc39/proposal-Symbol-description
2943 nativeDefineProperty(SymbolPrototype, 'description', {
2944 configurable: true,
2945 get: function description() {
2946 return getInternalState(this).description;
2947 }
2948 });
2949 }
2950 }
2951
2952 $$F({
2953 global: true,
2954 wrap: true,
2955 forced: !NATIVE_SYMBOL,
2956 sham: !NATIVE_SYMBOL
2957 }, {
2958 Symbol: $Symbol
2959 });
2960 $forEach$1(objectKeys$1(WellKnownSymbolsStore), function (name) {
2961 defineWellKnownSymbol$k(name);
2962 });
2963 $$F({
2964 target: SYMBOL,
2965 stat: true,
2966 forced: !NATIVE_SYMBOL
2967 }, {
2968 // `Symbol.for` method
2969 // https://tc39.es/ecma262/#sec-symbol.for
2970 'for': function (key) {
2971 var string = $toString(key);
2972 if (hasOwn$7(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
2973 var symbol = $Symbol(string);
2974 StringToSymbolRegistry[string] = symbol;
2975 SymbolToStringRegistry[symbol] = string;
2976 return symbol;
2977 },
2978 // `Symbol.keyFor` method
2979 // https://tc39.es/ecma262/#sec-symbol.keyfor
2980 keyFor: function keyFor(sym) {
2981 if (!isSymbol(sym)) throw TypeError$a(sym + ' is not a symbol');
2982 if (hasOwn$7(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
2983 },
2984 useSetter: function () {
2985 USE_SETTER = true;
2986 },
2987 useSimple: function () {
2988 USE_SETTER = false;
2989 }
2990 });
2991 $$F({
2992 target: 'Object',
2993 stat: true,
2994 forced: !NATIVE_SYMBOL,
2995 sham: !DESCRIPTORS$9
2996 }, {
2997 // `Object.create` method
2998 // https://tc39.es/ecma262/#sec-object.create
2999 create: $create,
3000 // `Object.defineProperty` method
3001 // https://tc39.es/ecma262/#sec-object.defineproperty
3002 defineProperty: $defineProperty,
3003 // `Object.defineProperties` method
3004 // https://tc39.es/ecma262/#sec-object.defineproperties
3005 defineProperties: $defineProperties,
3006 // `Object.getOwnPropertyDescriptor` method
3007 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
3008 getOwnPropertyDescriptor: $getOwnPropertyDescriptor
3009 });
3010 $$F({
3011 target: 'Object',
3012 stat: true,
3013 forced: !NATIVE_SYMBOL
3014 }, {
3015 // `Object.getOwnPropertyNames` method
3016 // https://tc39.es/ecma262/#sec-object.getownpropertynames
3017 getOwnPropertyNames: $getOwnPropertyNames,
3018 // `Object.getOwnPropertySymbols` method
3019 // https://tc39.es/ecma262/#sec-object.getownpropertysymbols
3020 getOwnPropertySymbols: $getOwnPropertySymbols
3021 }); // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
3022 // https://bugs.chromium.org/p/v8/issues/detail?id=3443
3023
3024 $$F({
3025 target: 'Object',
3026 stat: true,
3027 forced: fails$h(function () {
3028 getOwnPropertySymbolsModule$1.f(1);
3029 })
3030 }, {
3031 getOwnPropertySymbols: function getOwnPropertySymbols(it) {
3032 return getOwnPropertySymbolsModule$1.f(toObject$8(it));
3033 }
3034 }); // `JSON.stringify` method behavior with symbols
3035 // https://tc39.es/ecma262/#sec-json.stringify
3036
3037 if ($stringify$1) {
3038 var FORCED_JSON_STRINGIFY = !NATIVE_SYMBOL || fails$h(function () {
3039 var symbol = $Symbol(); // MS Edge converts symbol values to JSON as {}
3040
3041 return $stringify$1([symbol]) != '[null]' // WebKit converts symbol values to JSON as null
3042 || $stringify$1({
3043 a: symbol
3044 }) != '{}' // V8 throws on boxed symbols
3045 || $stringify$1(Object(symbol)) != '{}';
3046 });
3047 $$F({
3048 target: 'JSON',
3049 stat: true,
3050 forced: FORCED_JSON_STRINGIFY
3051 }, {
3052 // eslint-disable-next-line no-unused-vars -- required for `.length`
3053 stringify: function stringify(it, replacer, space) {
3054 var args = arraySlice$2(arguments);
3055 var $replacer = replacer;
3056 if (!isObject$b(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined
3057
3058 if (!isArray$b(replacer)) replacer = function (key, value) {
3059 if (isCallable$2($replacer)) value = call$2($replacer, this, key, value);
3060 if (!isSymbol(value)) return value;
3061 };
3062 args[1] = replacer;
3063 return apply$4($stringify$1, null, args);
3064 }
3065 });
3066 } // `Symbol.prototype[@@toPrimitive]` method
3067 // https://tc39.es/ecma262/#sec-symbol.prototype-@@toprimitive
3068
3069
3070 if (!SymbolPrototype[TO_PRIMITIVE]) {
3071 var valueOf = SymbolPrototype.valueOf; // eslint-disable-next-line no-unused-vars -- required for .length
3072
3073 redefine$1(SymbolPrototype, TO_PRIMITIVE, function (hint) {
3074 // TODO: improve hint logic
3075 return call$2(valueOf, this);
3076 });
3077 } // `Symbol.prototype[@@toStringTag]` property
3078 // https://tc39.es/ecma262/#sec-symbol.prototype-@@tostringtag
3079
3080
3081 setToStringTag$2($Symbol, SYMBOL);
3082 hiddenKeys$1[HIDDEN] = true;
3083
3084 var path$r = path$y;
3085 var getOwnPropertySymbols$2 = path$r.Object.getOwnPropertySymbols;
3086
3087 var parent$16 = getOwnPropertySymbols$2;
3088 var getOwnPropertySymbols$1 = parent$16;
3089
3090 var getOwnPropertySymbols = getOwnPropertySymbols$1;
3091
3092 var getOwnPropertyDescriptor$6 = {exports: {}};
3093
3094 var $$E = _export;
3095 var fails$g = fails$t;
3096 var toIndexedObject$3 = toIndexedObject$b;
3097 var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
3098 var DESCRIPTORS$8 = descriptors;
3099 var FAILS_ON_PRIMITIVES$4 = fails$g(function () {
3100 nativeGetOwnPropertyDescriptor(1);
3101 });
3102 var FORCED$6 = !DESCRIPTORS$8 || FAILS_ON_PRIMITIVES$4; // `Object.getOwnPropertyDescriptor` method
3103 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
3104
3105 $$E({
3106 target: 'Object',
3107 stat: true,
3108 forced: FORCED$6,
3109 sham: !DESCRIPTORS$8
3110 }, {
3111 getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
3112 return nativeGetOwnPropertyDescriptor(toIndexedObject$3(it), key);
3113 }
3114 });
3115
3116 var path$q = path$y;
3117 var Object$5 = path$q.Object;
3118
3119 var getOwnPropertyDescriptor$5 = getOwnPropertyDescriptor$6.exports = function getOwnPropertyDescriptor(it, key) {
3120 return Object$5.getOwnPropertyDescriptor(it, key);
3121 };
3122
3123 if (Object$5.getOwnPropertyDescriptor.sham) getOwnPropertyDescriptor$5.sham = true;
3124
3125 var parent$15 = getOwnPropertyDescriptor$6.exports;
3126 var getOwnPropertyDescriptor$4 = parent$15;
3127
3128 var getOwnPropertyDescriptor$3 = getOwnPropertyDescriptor$4;
3129
3130 var getBuiltIn$3 = getBuiltIn$9;
3131 var uncurryThis$d = functionUncurryThis;
3132 var getOwnPropertyNamesModule$1 = objectGetOwnPropertyNames;
3133 var getOwnPropertySymbolsModule = objectGetOwnPropertySymbols;
3134 var anObject$4 = anObject$d;
3135 var concat$4 = uncurryThis$d([].concat); // all object keys, includes non-enumerable and symbols
3136
3137 var ownKeys$b = getBuiltIn$3('Reflect', 'ownKeys') || function ownKeys(it) {
3138 var keys = getOwnPropertyNamesModule$1.f(anObject$4(it));
3139 var getOwnPropertySymbols = getOwnPropertySymbolsModule.f;
3140 return getOwnPropertySymbols ? concat$4(keys, getOwnPropertySymbols(it)) : keys;
3141 };
3142
3143 var $$D = _export;
3144 var DESCRIPTORS$7 = descriptors;
3145 var ownKeys$a = ownKeys$b;
3146 var toIndexedObject$2 = toIndexedObject$b;
3147 var getOwnPropertyDescriptorModule$1 = objectGetOwnPropertyDescriptor;
3148 var createProperty$3 = createProperty$6; // `Object.getOwnPropertyDescriptors` method
3149 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
3150
3151 $$D({
3152 target: 'Object',
3153 stat: true,
3154 sham: !DESCRIPTORS$7
3155 }, {
3156 getOwnPropertyDescriptors: function getOwnPropertyDescriptors(object) {
3157 var O = toIndexedObject$2(object);
3158 var getOwnPropertyDescriptor = getOwnPropertyDescriptorModule$1.f;
3159 var keys = ownKeys$a(O);
3160 var result = {};
3161 var index = 0;
3162 var key, descriptor;
3163
3164 while (keys.length > index) {
3165 descriptor = getOwnPropertyDescriptor(O, key = keys[index++]);
3166 if (descriptor !== undefined) createProperty$3(result, key, descriptor);
3167 }
3168
3169 return result;
3170 }
3171 });
3172
3173 var path$p = path$y;
3174 var getOwnPropertyDescriptors$2 = path$p.Object.getOwnPropertyDescriptors;
3175
3176 var parent$14 = getOwnPropertyDescriptors$2;
3177 var getOwnPropertyDescriptors$1 = parent$14;
3178
3179 var getOwnPropertyDescriptors = getOwnPropertyDescriptors$1;
3180
3181 var defineProperties$4 = {exports: {}};
3182
3183 var $$C = _export;
3184 var DESCRIPTORS$6 = descriptors;
3185 var defineProperties$3 = objectDefineProperties.f; // `Object.defineProperties` method
3186 // https://tc39.es/ecma262/#sec-object.defineproperties
3187 // eslint-disable-next-line es/no-object-defineproperties -- safe
3188
3189 $$C({
3190 target: 'Object',
3191 stat: true,
3192 forced: Object.defineProperties !== defineProperties$3,
3193 sham: !DESCRIPTORS$6
3194 }, {
3195 defineProperties: defineProperties$3
3196 });
3197
3198 var path$o = path$y;
3199 var Object$4 = path$o.Object;
3200
3201 var defineProperties$2 = defineProperties$4.exports = function defineProperties(T, D) {
3202 return Object$4.defineProperties(T, D);
3203 };
3204
3205 if (Object$4.defineProperties.sham) defineProperties$2.sham = true;
3206
3207 var parent$13 = defineProperties$4.exports;
3208 var defineProperties$1 = parent$13;
3209
3210 var defineProperties = defineProperties$1;
3211
3212 var defineProperty$a = {exports: {}};
3213
3214 var $$B = _export;
3215 var DESCRIPTORS$5 = descriptors;
3216 var defineProperty$9 = objectDefineProperty.f; // `Object.defineProperty` method
3217 // https://tc39.es/ecma262/#sec-object.defineproperty
3218 // eslint-disable-next-line es/no-object-defineproperty -- safe
3219
3220 $$B({
3221 target: 'Object',
3222 stat: true,
3223 forced: Object.defineProperty !== defineProperty$9,
3224 sham: !DESCRIPTORS$5
3225 }, {
3226 defineProperty: defineProperty$9
3227 });
3228
3229 var path$n = path$y;
3230 var Object$3 = path$n.Object;
3231
3232 var defineProperty$8 = defineProperty$a.exports = function defineProperty(it, key, desc) {
3233 return Object$3.defineProperty(it, key, desc);
3234 };
3235
3236 if (Object$3.defineProperty.sham) defineProperty$8.sham = true;
3237
3238 var parent$12 = defineProperty$a.exports;
3239 var defineProperty$7 = parent$12;
3240
3241 var defineProperty$6 = defineProperty$7;
3242
3243 function _classCallCheck(instance, Constructor) {
3244 if (!(instance instanceof Constructor)) {
3245 throw new TypeError("Cannot call a class as a function");
3246 }
3247 }
3248
3249 var parent$11 = defineProperty$7;
3250 var defineProperty$5 = parent$11;
3251
3252 var parent$10 = defineProperty$5;
3253 var defineProperty$4 = parent$10;
3254
3255 var defineProperty$3 = defineProperty$4;
3256
3257 function _defineProperties(target, props) {
3258 for (var i = 0; i < props.length; i++) {
3259 var descriptor = props[i];
3260 descriptor.enumerable = descriptor.enumerable || false;
3261 descriptor.configurable = true;
3262 if ("value" in descriptor) descriptor.writable = true;
3263
3264 defineProperty$3(target, descriptor.key, descriptor);
3265 }
3266 }
3267
3268 function _createClass(Constructor, protoProps, staticProps) {
3269 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
3270 if (staticProps) _defineProperties(Constructor, staticProps);
3271
3272 defineProperty$3(Constructor, "prototype", {
3273 writable: false
3274 });
3275
3276 return Constructor;
3277 }
3278
3279 function _defineProperty(obj, key, value) {
3280 if (key in obj) {
3281 defineProperty$3(obj, key, {
3282 value: value,
3283 enumerable: true,
3284 configurable: true,
3285 writable: true
3286 });
3287 } else {
3288 obj[key] = value;
3289 }
3290
3291 return obj;
3292 }
3293
3294 var $$A = _export;
3295 var isArray$a = isArray$d; // `Array.isArray` method
3296 // https://tc39.es/ecma262/#sec-array.isarray
3297
3298 $$A({
3299 target: 'Array',
3300 stat: true
3301 }, {
3302 isArray: isArray$a
3303 });
3304
3305 var path$m = path$y;
3306 var isArray$9 = path$m.Array.isArray;
3307
3308 var parent$$ = isArray$9;
3309 var isArray$8 = parent$$;
3310
3311 var parent$_ = isArray$8;
3312 var isArray$7 = parent$_;
3313
3314 var parent$Z = isArray$7;
3315 var isArray$6 = parent$Z;
3316
3317 var isArray$5 = isArray$6;
3318
3319 function _arrayWithHoles(arr) {
3320 if (isArray$5(arr)) return arr;
3321 }
3322
3323 var fails$f = fails$t;
3324 var wellKnownSymbol$5 = wellKnownSymbol$j;
3325 var V8_VERSION$1 = engineV8Version;
3326 var SPECIES$2 = wellKnownSymbol$5('species');
3327
3328 var arrayMethodHasSpeciesSupport$5 = function (METHOD_NAME) {
3329 // We can't use this feature detection in V8 since it causes
3330 // deoptimization and serious performance degradation
3331 // https://github.com/zloirock/core-js/issues/677
3332 return V8_VERSION$1 >= 51 || !fails$f(function () {
3333 var array = [];
3334 var constructor = array.constructor = {};
3335
3336 constructor[SPECIES$2] = function () {
3337 return {
3338 foo: 1
3339 };
3340 };
3341
3342 return array[METHOD_NAME](Boolean).foo !== 1;
3343 });
3344 };
3345
3346 var $$z = _export;
3347 var global$k = global$P;
3348 var fails$e = fails$t;
3349 var isArray$4 = isArray$d;
3350 var isObject$a = isObject$j;
3351 var toObject$7 = toObject$e;
3352 var lengthOfArrayLike$8 = lengthOfArrayLike$d;
3353 var createProperty$2 = createProperty$6;
3354 var arraySpeciesCreate$2 = arraySpeciesCreate$4;
3355 var arrayMethodHasSpeciesSupport$4 = arrayMethodHasSpeciesSupport$5;
3356 var wellKnownSymbol$4 = wellKnownSymbol$j;
3357 var V8_VERSION = engineV8Version;
3358 var IS_CONCAT_SPREADABLE = wellKnownSymbol$4('isConcatSpreadable');
3359 var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
3360 var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';
3361 var TypeError$9 = global$k.TypeError; // We can't use this feature detection in V8 since it causes
3362 // deoptimization and serious performance degradation
3363 // https://github.com/zloirock/core-js/issues/679
3364
3365 var IS_CONCAT_SPREADABLE_SUPPORT = V8_VERSION >= 51 || !fails$e(function () {
3366 var array = [];
3367 array[IS_CONCAT_SPREADABLE] = false;
3368 return array.concat()[0] !== array;
3369 });
3370 var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport$4('concat');
3371
3372 var isConcatSpreadable = function (O) {
3373 if (!isObject$a(O)) return false;
3374 var spreadable = O[IS_CONCAT_SPREADABLE];
3375 return spreadable !== undefined ? !!spreadable : isArray$4(O);
3376 };
3377
3378 var FORCED$5 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT; // `Array.prototype.concat` method
3379 // https://tc39.es/ecma262/#sec-array.prototype.concat
3380 // with adding support of @@isConcatSpreadable and @@species
3381
3382 $$z({
3383 target: 'Array',
3384 proto: true,
3385 forced: FORCED$5
3386 }, {
3387 // eslint-disable-next-line no-unused-vars -- required for `.length`
3388 concat: function concat(arg) {
3389 var O = toObject$7(this);
3390 var A = arraySpeciesCreate$2(O, 0);
3391 var n = 0;
3392 var i, k, length, len, E;
3393
3394 for (i = -1, length = arguments.length; i < length; i++) {
3395 E = i === -1 ? O : arguments[i];
3396
3397 if (isConcatSpreadable(E)) {
3398 len = lengthOfArrayLike$8(E);
3399 if (n + len > MAX_SAFE_INTEGER$1) throw TypeError$9(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
3400
3401 for (k = 0; k < len; k++, n++) if (k in E) createProperty$2(A, n, E[k]);
3402 } else {
3403 if (n >= MAX_SAFE_INTEGER$1) throw TypeError$9(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
3404 createProperty$2(A, n++, E);
3405 }
3406 }
3407
3408 A.length = n;
3409 return A;
3410 }
3411 });
3412
3413 var defineWellKnownSymbol$j = defineWellKnownSymbol$l; // `Symbol.asyncIterator` well-known symbol
3414 // https://tc39.es/ecma262/#sec-symbol.asynciterator
3415
3416 defineWellKnownSymbol$j('asyncIterator');
3417
3418 var defineWellKnownSymbol$i = defineWellKnownSymbol$l; // `Symbol.hasInstance` well-known symbol
3419 // https://tc39.es/ecma262/#sec-symbol.hasinstance
3420
3421 defineWellKnownSymbol$i('hasInstance');
3422
3423 var defineWellKnownSymbol$h = defineWellKnownSymbol$l; // `Symbol.isConcatSpreadable` well-known symbol
3424 // https://tc39.es/ecma262/#sec-symbol.isconcatspreadable
3425
3426 defineWellKnownSymbol$h('isConcatSpreadable');
3427
3428 var defineWellKnownSymbol$g = defineWellKnownSymbol$l; // `Symbol.iterator` well-known symbol
3429 // https://tc39.es/ecma262/#sec-symbol.iterator
3430
3431 defineWellKnownSymbol$g('iterator');
3432
3433 var defineWellKnownSymbol$f = defineWellKnownSymbol$l; // `Symbol.match` well-known symbol
3434 // https://tc39.es/ecma262/#sec-symbol.match
3435
3436 defineWellKnownSymbol$f('match');
3437
3438 var defineWellKnownSymbol$e = defineWellKnownSymbol$l; // `Symbol.matchAll` well-known symbol
3439 // https://tc39.es/ecma262/#sec-symbol.matchall
3440
3441 defineWellKnownSymbol$e('matchAll');
3442
3443 var defineWellKnownSymbol$d = defineWellKnownSymbol$l; // `Symbol.replace` well-known symbol
3444 // https://tc39.es/ecma262/#sec-symbol.replace
3445
3446 defineWellKnownSymbol$d('replace');
3447
3448 var defineWellKnownSymbol$c = defineWellKnownSymbol$l; // `Symbol.search` well-known symbol
3449 // https://tc39.es/ecma262/#sec-symbol.search
3450
3451 defineWellKnownSymbol$c('search');
3452
3453 var defineWellKnownSymbol$b = defineWellKnownSymbol$l; // `Symbol.species` well-known symbol
3454 // https://tc39.es/ecma262/#sec-symbol.species
3455
3456 defineWellKnownSymbol$b('species');
3457
3458 var defineWellKnownSymbol$a = defineWellKnownSymbol$l; // `Symbol.split` well-known symbol
3459 // https://tc39.es/ecma262/#sec-symbol.split
3460
3461 defineWellKnownSymbol$a('split');
3462
3463 var defineWellKnownSymbol$9 = defineWellKnownSymbol$l; // `Symbol.toPrimitive` well-known symbol
3464 // https://tc39.es/ecma262/#sec-symbol.toprimitive
3465
3466 defineWellKnownSymbol$9('toPrimitive');
3467
3468 var defineWellKnownSymbol$8 = defineWellKnownSymbol$l; // `Symbol.toStringTag` well-known symbol
3469 // https://tc39.es/ecma262/#sec-symbol.tostringtag
3470
3471 defineWellKnownSymbol$8('toStringTag');
3472
3473 var defineWellKnownSymbol$7 = defineWellKnownSymbol$l; // `Symbol.unscopables` well-known symbol
3474 // https://tc39.es/ecma262/#sec-symbol.unscopables
3475
3476 defineWellKnownSymbol$7('unscopables');
3477
3478 var global$j = global$P;
3479 var setToStringTag$1 = setToStringTag$5; // JSON[@@toStringTag] property
3480 // https://tc39.es/ecma262/#sec-json-@@tostringtag
3481
3482 setToStringTag$1(global$j.JSON, 'JSON', true);
3483
3484 var path$l = path$y;
3485 var symbol$5 = path$l.Symbol;
3486
3487 var parent$Y = symbol$5;
3488 var symbol$4 = parent$Y;
3489
3490 var parent$X = symbol$4;
3491 var symbol$3 = parent$X;
3492
3493 var defineWellKnownSymbol$6 = defineWellKnownSymbol$l; // `Symbol.asyncDispose` well-known symbol
3494 // https://github.com/tc39/proposal-using-statement
3495
3496 defineWellKnownSymbol$6('asyncDispose');
3497
3498 var defineWellKnownSymbol$5 = defineWellKnownSymbol$l; // `Symbol.dispose` well-known symbol
3499 // https://github.com/tc39/proposal-using-statement
3500
3501 defineWellKnownSymbol$5('dispose');
3502
3503 var defineWellKnownSymbol$4 = defineWellKnownSymbol$l; // `Symbol.matcher` well-known symbol
3504 // https://github.com/tc39/proposal-pattern-matching
3505
3506 defineWellKnownSymbol$4('matcher');
3507
3508 var defineWellKnownSymbol$3 = defineWellKnownSymbol$l; // `Symbol.metadata` well-known symbol
3509 // https://github.com/tc39/proposal-decorators
3510
3511 defineWellKnownSymbol$3('metadata');
3512
3513 var defineWellKnownSymbol$2 = defineWellKnownSymbol$l; // `Symbol.observable` well-known symbol
3514 // https://github.com/tc39/proposal-observable
3515
3516 defineWellKnownSymbol$2('observable');
3517
3518 var defineWellKnownSymbol$1 = defineWellKnownSymbol$l; // `Symbol.patternMatch` well-known symbol
3519 // https://github.com/tc39/proposal-pattern-matching
3520
3521 defineWellKnownSymbol$1('patternMatch');
3522
3523 var defineWellKnownSymbol = defineWellKnownSymbol$l;
3524 defineWellKnownSymbol('replaceAll');
3525
3526 var parent$W = symbol$3; // TODO: Remove from `core-js@4`
3527 // TODO: Remove from `core-js@4`
3528
3529 var symbol$2 = parent$W;
3530
3531 var symbol$1 = symbol$2;
3532
3533 function _iterableToArrayLimit(arr, i) {
3534 var _i = arr == null ? null : typeof symbol$1 !== "undefined" && getIteratorMethod$1(arr) || arr["@@iterator"];
3535
3536 if (_i == null) return;
3537 var _arr = [];
3538 var _n = true;
3539 var _d = false;
3540
3541 var _s, _e;
3542
3543 try {
3544 for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
3545 _arr.push(_s.value);
3546
3547 if (i && _arr.length === i) break;
3548 }
3549 } catch (err) {
3550 _d = true;
3551 _e = err;
3552 } finally {
3553 try {
3554 if (!_n && _i["return"] != null) _i["return"]();
3555 } finally {
3556 if (_d) throw _e;
3557 }
3558 }
3559
3560 return _arr;
3561 }
3562
3563 var $$y = _export;
3564 var global$i = global$P;
3565 var isArray$3 = isArray$d;
3566 var isConstructor$1 = isConstructor$4;
3567 var isObject$9 = isObject$j;
3568 var toAbsoluteIndex$2 = toAbsoluteIndex$5;
3569 var lengthOfArrayLike$7 = lengthOfArrayLike$d;
3570 var toIndexedObject$1 = toIndexedObject$b;
3571 var createProperty$1 = createProperty$6;
3572 var wellKnownSymbol$3 = wellKnownSymbol$j;
3573 var arrayMethodHasSpeciesSupport$3 = arrayMethodHasSpeciesSupport$5;
3574 var un$Slice = arraySlice$5;
3575 var HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport$3('slice');
3576 var SPECIES$1 = wellKnownSymbol$3('species');
3577 var Array$2 = global$i.Array;
3578 var max$1 = Math.max; // `Array.prototype.slice` method
3579 // https://tc39.es/ecma262/#sec-array.prototype.slice
3580 // fallback for not array-like ES3 strings and DOM objects
3581
3582 $$y({
3583 target: 'Array',
3584 proto: true,
3585 forced: !HAS_SPECIES_SUPPORT$3
3586 }, {
3587 slice: function slice(start, end) {
3588 var O = toIndexedObject$1(this);
3589 var length = lengthOfArrayLike$7(O);
3590 var k = toAbsoluteIndex$2(start, length);
3591 var fin = toAbsoluteIndex$2(end === undefined ? length : end, length); // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
3592
3593 var Constructor, result, n;
3594
3595 if (isArray$3(O)) {
3596 Constructor = O.constructor; // cross-realm fallback
3597
3598 if (isConstructor$1(Constructor) && (Constructor === Array$2 || isArray$3(Constructor.prototype))) {
3599 Constructor = undefined;
3600 } else if (isObject$9(Constructor)) {
3601 Constructor = Constructor[SPECIES$1];
3602 if (Constructor === null) Constructor = undefined;
3603 }
3604
3605 if (Constructor === Array$2 || Constructor === undefined) {
3606 return un$Slice(O, k, fin);
3607 }
3608 }
3609
3610 result = new (Constructor === undefined ? Array$2 : Constructor)(max$1(fin - k, 0));
3611
3612 for (n = 0; k < fin; k++, n++) if (k in O) createProperty$1(result, n, O[k]);
3613
3614 result.length = n;
3615 return result;
3616 }
3617 });
3618
3619 var entryVirtual$j = entryVirtual$l;
3620 var slice$6 = entryVirtual$j('Array').slice;
3621
3622 var isPrototypeOf$k = objectIsPrototypeOf;
3623 var method$h = slice$6;
3624 var ArrayPrototype$h = Array.prototype;
3625
3626 var slice$5 = function (it) {
3627 var own = it.slice;
3628 return it === ArrayPrototype$h || isPrototypeOf$k(ArrayPrototype$h, it) && own === ArrayPrototype$h.slice ? method$h : own;
3629 };
3630
3631 var parent$V = slice$5;
3632 var slice$4 = parent$V;
3633
3634 var parent$U = slice$4;
3635 var slice$3 = parent$U;
3636
3637 var parent$T = slice$3;
3638 var slice$2 = parent$T;
3639
3640 var slice$1 = slice$2;
3641
3642 var parent$S = from$4;
3643 var from$2 = parent$S;
3644
3645 var parent$R = from$2;
3646 var from$1 = parent$R;
3647
3648 var from = from$1;
3649
3650 function _arrayLikeToArray$9(arr, len) {
3651 if (len == null || len > arr.length) len = arr.length;
3652
3653 for (var i = 0, arr2 = new Array(len); i < len; i++) {
3654 arr2[i] = arr[i];
3655 }
3656
3657 return arr2;
3658 }
3659
3660 function _unsupportedIterableToArray$9(o, minLen) {
3661 var _context;
3662
3663 if (!o) return;
3664 if (typeof o === "string") return _arrayLikeToArray$9(o, minLen);
3665
3666 var n = slice$1(_context = Object.prototype.toString.call(o)).call(_context, 8, -1);
3667
3668 if (n === "Object" && o.constructor) n = o.constructor.name;
3669 if (n === "Map" || n === "Set") return from(o);
3670 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$9(o, minLen);
3671 }
3672
3673 function _nonIterableRest() {
3674 throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
3675 }
3676
3677 function _slicedToArray(arr, i) {
3678 return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray$9(arr, i) || _nonIterableRest();
3679 }
3680
3681 var WrappedWellKnownSymbolModule = wellKnownSymbolWrapped;
3682 var iterator$5 = WrappedWellKnownSymbolModule.f('iterator');
3683
3684 var parent$Q = iterator$5;
3685 var iterator$4 = parent$Q;
3686
3687 var parent$P = iterator$4;
3688 var iterator$3 = parent$P;
3689
3690 var parent$O = iterator$3;
3691 var iterator$2 = parent$O;
3692
3693 var iterator$1 = iterator$2;
3694
3695 function _typeof(obj) {
3696 "@babel/helpers - typeof";
3697
3698 return _typeof = "function" == typeof symbol$1 && "symbol" == typeof iterator$1 ? function (obj) {
3699 return typeof obj;
3700 } : function (obj) {
3701 return obj && "function" == typeof symbol$1 && obj.constructor === symbol$1 && obj !== symbol$1.prototype ? "symbol" : typeof obj;
3702 }, _typeof(obj);
3703 }
3704
3705 function _arrayWithoutHoles(arr) {
3706 if (isArray$5(arr)) return _arrayLikeToArray$9(arr);
3707 }
3708
3709 function _iterableToArray(iter) {
3710 if (typeof symbol$1 !== "undefined" && getIteratorMethod$1(iter) != null || iter["@@iterator"] != null) return from(iter);
3711 }
3712
3713 function _nonIterableSpread() {
3714 throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
3715 }
3716
3717 function _toConsumableArray(arr) {
3718 return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray$9(arr) || _nonIterableSpread();
3719 }
3720
3721 var symbol = symbol$4;
3722
3723 var entryVirtual$i = entryVirtual$l;
3724 var concat$3 = entryVirtual$i('Array').concat;
3725
3726 var isPrototypeOf$j = objectIsPrototypeOf;
3727 var method$g = concat$3;
3728 var ArrayPrototype$g = Array.prototype;
3729
3730 var concat$2 = function (it) {
3731 var own = it.concat;
3732 return it === ArrayPrototype$g || isPrototypeOf$j(ArrayPrototype$g, it) && own === ArrayPrototype$g.concat ? method$g : own;
3733 };
3734
3735 var parent$N = concat$2;
3736 var concat$1 = parent$N;
3737
3738 var concat = concat$1;
3739
3740 var slice = slice$4;
3741
3742 var $$x = _export;
3743 var ownKeys$9 = ownKeys$b; // `Reflect.ownKeys` method
3744 // https://tc39.es/ecma262/#sec-reflect.ownkeys
3745
3746 $$x({
3747 target: 'Reflect',
3748 stat: true
3749 }, {
3750 ownKeys: ownKeys$9
3751 });
3752
3753 var path$k = path$y;
3754 var ownKeys$8 = path$k.Reflect.ownKeys;
3755
3756 var parent$M = ownKeys$8;
3757 var ownKeys$7 = parent$M;
3758
3759 var ownKeys$6 = ownKeys$7;
3760
3761 var isArray$2 = isArray$8;
3762
3763 var $$w = _export;
3764 var $map = arrayIteration.map;
3765 var arrayMethodHasSpeciesSupport$2 = arrayMethodHasSpeciesSupport$5;
3766 var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport$2('map'); // `Array.prototype.map` method
3767 // https://tc39.es/ecma262/#sec-array.prototype.map
3768 // with adding support of @@species
3769
3770 $$w({
3771 target: 'Array',
3772 proto: true,
3773 forced: !HAS_SPECIES_SUPPORT$2
3774 }, {
3775 map: function map(callbackfn
3776 /* , thisArg */
3777 ) {
3778 return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3779 }
3780 });
3781
3782 var entryVirtual$h = entryVirtual$l;
3783 var map$6 = entryVirtual$h('Array').map;
3784
3785 var isPrototypeOf$i = objectIsPrototypeOf;
3786 var method$f = map$6;
3787 var ArrayPrototype$f = Array.prototype;
3788
3789 var map$5 = function (it) {
3790 var own = it.map;
3791 return it === ArrayPrototype$f || isPrototypeOf$i(ArrayPrototype$f, it) && own === ArrayPrototype$f.map ? method$f : own;
3792 };
3793
3794 var parent$L = map$5;
3795 var map$4 = parent$L;
3796
3797 var map$3 = map$4;
3798
3799 var $$v = _export;
3800 var toObject$6 = toObject$e;
3801 var nativeKeys = objectKeys$4;
3802 var fails$d = fails$t;
3803 var FAILS_ON_PRIMITIVES$3 = fails$d(function () {
3804 nativeKeys(1);
3805 }); // `Object.keys` method
3806 // https://tc39.es/ecma262/#sec-object.keys
3807
3808 $$v({
3809 target: 'Object',
3810 stat: true,
3811 forced: FAILS_ON_PRIMITIVES$3
3812 }, {
3813 keys: function keys(it) {
3814 return nativeKeys(toObject$6(it));
3815 }
3816 });
3817
3818 var path$j = path$y;
3819 var keys$6 = path$j.Object.keys;
3820
3821 var parent$K = keys$6;
3822 var keys$5 = parent$K;
3823
3824 var keys$4 = keys$5;
3825
3826 var $$u = _export;
3827 var global$h = global$P;
3828 var uncurryThis$c = functionUncurryThis;
3829 var Date$1 = global$h.Date;
3830 var getTime = uncurryThis$c(Date$1.prototype.getTime); // `Date.now` method
3831 // https://tc39.es/ecma262/#sec-date.now
3832
3833 $$u({
3834 target: 'Date',
3835 stat: true
3836 }, {
3837 now: function now() {
3838 return getTime(new Date$1());
3839 }
3840 });
3841
3842 var path$i = path$y;
3843 var now$3 = path$i.Date.now;
3844
3845 var parent$J = now$3;
3846 var now$2 = parent$J;
3847
3848 var now$1 = now$2;
3849
3850 var fails$c = fails$t;
3851
3852 var arrayMethodIsStrict$6 = function (METHOD_NAME, argument) {
3853 var method = [][METHOD_NAME];
3854 return !!method && fails$c(function () {
3855 // eslint-disable-next-line no-useless-call -- required for testing
3856 method.call(null, argument || function () {
3857 return 1;
3858 }, 1);
3859 });
3860 };
3861
3862 var $forEach = arrayIteration.forEach;
3863 var arrayMethodIsStrict$5 = arrayMethodIsStrict$6;
3864 var STRICT_METHOD$5 = arrayMethodIsStrict$5('forEach'); // `Array.prototype.forEach` method implementation
3865 // https://tc39.es/ecma262/#sec-array.prototype.foreach
3866
3867 var arrayForEach = !STRICT_METHOD$5 ? function forEach(callbackfn
3868 /* , thisArg */
3869 ) {
3870 return $forEach(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); // eslint-disable-next-line es/no-array-prototype-foreach -- safe
3871 } : [].forEach;
3872
3873 var $$t = _export;
3874 var forEach$6 = arrayForEach; // `Array.prototype.forEach` method
3875 // https://tc39.es/ecma262/#sec-array.prototype.foreach
3876 // eslint-disable-next-line es/no-array-prototype-foreach -- safe
3877
3878 $$t({
3879 target: 'Array',
3880 proto: true,
3881 forced: [].forEach != forEach$6
3882 }, {
3883 forEach: forEach$6
3884 });
3885
3886 var entryVirtual$g = entryVirtual$l;
3887 var forEach$5 = entryVirtual$g('Array').forEach;
3888
3889 var parent$I = forEach$5;
3890 var forEach$4 = parent$I;
3891
3892 var classof$6 = classof$e;
3893 var hasOwn$6 = hasOwnProperty_1;
3894 var isPrototypeOf$h = objectIsPrototypeOf;
3895 var method$e = forEach$4;
3896 var ArrayPrototype$e = Array.prototype;
3897 var DOMIterables$3 = {
3898 DOMTokenList: true,
3899 NodeList: true
3900 };
3901
3902 var forEach$3 = function (it) {
3903 var own = it.forEach;
3904 return it === ArrayPrototype$e || isPrototypeOf$h(ArrayPrototype$e, it) && own === ArrayPrototype$e.forEach || hasOwn$6(DOMIterables$3, classof$6(it)) ? method$e : own;
3905 };
3906
3907 var forEach$2 = forEach$3;
3908
3909 var $$s = _export;
3910 var uncurryThis$b = functionUncurryThis;
3911 var isArray$1 = isArray$d;
3912 var un$Reverse = uncurryThis$b([].reverse);
3913 var test$1 = [1, 2]; // `Array.prototype.reverse` method
3914 // https://tc39.es/ecma262/#sec-array.prototype.reverse
3915 // fix for Safari 12.0 bug
3916 // https://bugs.webkit.org/show_bug.cgi?id=188794
3917
3918 $$s({
3919 target: 'Array',
3920 proto: true,
3921 forced: String(test$1) === String(test$1.reverse())
3922 }, {
3923 reverse: function reverse() {
3924 // eslint-disable-next-line no-self-assign -- dirty hack
3925 if (isArray$1(this)) this.length = this.length;
3926 return un$Reverse(this);
3927 }
3928 });
3929
3930 var entryVirtual$f = entryVirtual$l;
3931 var reverse$3 = entryVirtual$f('Array').reverse;
3932
3933 var isPrototypeOf$g = objectIsPrototypeOf;
3934 var method$d = reverse$3;
3935 var ArrayPrototype$d = Array.prototype;
3936
3937 var reverse$2 = function (it) {
3938 var own = it.reverse;
3939 return it === ArrayPrototype$d || isPrototypeOf$g(ArrayPrototype$d, it) && own === ArrayPrototype$d.reverse ? method$d : own;
3940 };
3941
3942 var parent$H = reverse$2;
3943 var reverse$1 = parent$H;
3944
3945 var reverse = reverse$1;
3946
3947 var $$r = _export;
3948 var global$g = global$P;
3949 var toAbsoluteIndex$1 = toAbsoluteIndex$5;
3950 var toIntegerOrInfinity = toIntegerOrInfinity$4;
3951 var lengthOfArrayLike$6 = lengthOfArrayLike$d;
3952 var toObject$5 = toObject$e;
3953 var arraySpeciesCreate$1 = arraySpeciesCreate$4;
3954 var createProperty = createProperty$6;
3955 var arrayMethodHasSpeciesSupport$1 = arrayMethodHasSpeciesSupport$5;
3956 var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport$1('splice');
3957 var TypeError$8 = global$g.TypeError;
3958 var max = Math.max;
3959 var min = Math.min;
3960 var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
3961 var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded'; // `Array.prototype.splice` method
3962 // https://tc39.es/ecma262/#sec-array.prototype.splice
3963 // with adding support of @@species
3964
3965 $$r({
3966 target: 'Array',
3967 proto: true,
3968 forced: !HAS_SPECIES_SUPPORT$1
3969 }, {
3970 splice: function splice(start, deleteCount
3971 /* , ...items */
3972 ) {
3973 var O = toObject$5(this);
3974 var len = lengthOfArrayLike$6(O);
3975 var actualStart = toAbsoluteIndex$1(start, len);
3976 var argumentsLength = arguments.length;
3977 var insertCount, actualDeleteCount, A, k, from, to;
3978
3979 if (argumentsLength === 0) {
3980 insertCount = actualDeleteCount = 0;
3981 } else if (argumentsLength === 1) {
3982 insertCount = 0;
3983 actualDeleteCount = len - actualStart;
3984 } else {
3985 insertCount = argumentsLength - 2;
3986 actualDeleteCount = min(max(toIntegerOrInfinity(deleteCount), 0), len - actualStart);
3987 }
3988
3989 if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER) {
3990 throw TypeError$8(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
3991 }
3992
3993 A = arraySpeciesCreate$1(O, actualDeleteCount);
3994
3995 for (k = 0; k < actualDeleteCount; k++) {
3996 from = actualStart + k;
3997 if (from in O) createProperty(A, k, O[from]);
3998 }
3999
4000 A.length = actualDeleteCount;
4001
4002 if (insertCount < actualDeleteCount) {
4003 for (k = actualStart; k < len - actualDeleteCount; k++) {
4004 from = k + actualDeleteCount;
4005 to = k + insertCount;
4006 if (from in O) O[to] = O[from];else delete O[to];
4007 }
4008
4009 for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
4010 } else if (insertCount > actualDeleteCount) {
4011 for (k = len - actualDeleteCount; k > actualStart; k--) {
4012 from = k + actualDeleteCount - 1;
4013 to = k + insertCount - 1;
4014 if (from in O) O[to] = O[from];else delete O[to];
4015 }
4016 }
4017
4018 for (k = 0; k < insertCount; k++) {
4019 O[k + actualStart] = arguments[k + 2];
4020 }
4021
4022 O.length = len - actualDeleteCount + insertCount;
4023 return A;
4024 }
4025 });
4026
4027 var entryVirtual$e = entryVirtual$l;
4028 var splice$4 = entryVirtual$e('Array').splice;
4029
4030 var isPrototypeOf$f = objectIsPrototypeOf;
4031 var method$c = splice$4;
4032 var ArrayPrototype$c = Array.prototype;
4033
4034 var splice$3 = function (it) {
4035 var own = it.splice;
4036 return it === ArrayPrototype$c || isPrototypeOf$f(ArrayPrototype$c, it) && own === ArrayPrototype$c.splice ? method$c : own;
4037 };
4038
4039 var parent$G = splice$3;
4040 var splice$2 = parent$G;
4041
4042 var splice$1 = splice$2;
4043
4044 var $$q = _export;
4045 var $includes = arrayIncludes.includes;
4046 // https://tc39.es/ecma262/#sec-array.prototype.includes
4047
4048 $$q({
4049 target: 'Array',
4050 proto: true
4051 }, {
4052 includes: function includes(el
4053 /* , fromIndex = 0 */
4054 ) {
4055 return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
4056 }
4057 }); // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
4058
4059 var entryVirtual$d = entryVirtual$l;
4060 var includes$4 = entryVirtual$d('Array').includes;
4061
4062 var isObject$8 = isObject$j;
4063 var classof$5 = classofRaw$1;
4064 var wellKnownSymbol$2 = wellKnownSymbol$j;
4065 var MATCH$1 = wellKnownSymbol$2('match'); // `IsRegExp` abstract operation
4066 // https://tc39.es/ecma262/#sec-isregexp
4067
4068 var isRegexp = function (it) {
4069 var isRegExp;
4070 return isObject$8(it) && ((isRegExp = it[MATCH$1]) !== undefined ? !!isRegExp : classof$5(it) == 'RegExp');
4071 };
4072
4073 var global$f = global$P;
4074 var isRegExp = isRegexp;
4075 var TypeError$7 = global$f.TypeError;
4076
4077 var notARegexp = function (it) {
4078 if (isRegExp(it)) {
4079 throw TypeError$7("The method doesn't accept regular expressions");
4080 }
4081
4082 return it;
4083 };
4084
4085 var wellKnownSymbol$1 = wellKnownSymbol$j;
4086 var MATCH = wellKnownSymbol$1('match');
4087
4088 var correctIsRegexpLogic = function (METHOD_NAME) {
4089 var regexp = /./;
4090
4091 try {
4092 '/./'[METHOD_NAME](regexp);
4093 } catch (error1) {
4094 try {
4095 regexp[MATCH] = false;
4096 return '/./'[METHOD_NAME](regexp);
4097 } catch (error2) {
4098 /* empty */
4099 }
4100 }
4101
4102 return false;
4103 };
4104
4105 var $$p = _export;
4106 var uncurryThis$a = functionUncurryThis;
4107 var notARegExp = notARegexp;
4108 var requireObjectCoercible$1 = requireObjectCoercible$5;
4109 var toString$4 = toString$8;
4110 var correctIsRegExpLogic = correctIsRegexpLogic;
4111 var stringIndexOf = uncurryThis$a(''.indexOf); // `String.prototype.includes` method
4112 // https://tc39.es/ecma262/#sec-string.prototype.includes
4113
4114 $$p({
4115 target: 'String',
4116 proto: true,
4117 forced: !correctIsRegExpLogic('includes')
4118 }, {
4119 includes: function includes(searchString
4120 /* , position = 0 */
4121 ) {
4122 return !!~stringIndexOf(toString$4(requireObjectCoercible$1(this)), toString$4(notARegExp(searchString)), arguments.length > 1 ? arguments[1] : undefined);
4123 }
4124 });
4125
4126 var entryVirtual$c = entryVirtual$l;
4127 var includes$3 = entryVirtual$c('String').includes;
4128
4129 var isPrototypeOf$e = objectIsPrototypeOf;
4130 var arrayMethod = includes$4;
4131 var stringMethod = includes$3;
4132 var ArrayPrototype$b = Array.prototype;
4133 var StringPrototype$1 = String.prototype;
4134
4135 var includes$2 = function (it) {
4136 var own = it.includes;
4137 if (it === ArrayPrototype$b || isPrototypeOf$e(ArrayPrototype$b, it) && own === ArrayPrototype$b.includes) return arrayMethod;
4138
4139 if (typeof it == 'string' || it === StringPrototype$1 || isPrototypeOf$e(StringPrototype$1, it) && own === StringPrototype$1.includes) {
4140 return stringMethod;
4141 }
4142
4143 return own;
4144 };
4145
4146 var parent$F = includes$2;
4147 var includes$1 = parent$F;
4148
4149 var includes = includes$1;
4150
4151 var $$o = _export;
4152 var fails$b = fails$t;
4153 var toObject$4 = toObject$e;
4154 var nativeGetPrototypeOf = objectGetPrototypeOf;
4155 var CORRECT_PROTOTYPE_GETTER = correctPrototypeGetter;
4156 var FAILS_ON_PRIMITIVES$2 = fails$b(function () {
4157 nativeGetPrototypeOf(1);
4158 }); // `Object.getPrototypeOf` method
4159 // https://tc39.es/ecma262/#sec-object.getprototypeof
4160
4161 $$o({
4162 target: 'Object',
4163 stat: true,
4164 forced: FAILS_ON_PRIMITIVES$2,
4165 sham: !CORRECT_PROTOTYPE_GETTER
4166 }, {
4167 getPrototypeOf: function getPrototypeOf(it) {
4168 return nativeGetPrototypeOf(toObject$4(it));
4169 }
4170 });
4171
4172 var path$h = path$y;
4173 var getPrototypeOf$6 = path$h.Object.getPrototypeOf;
4174
4175 var parent$E = getPrototypeOf$6;
4176 var getPrototypeOf$5 = parent$E;
4177
4178 var getPrototypeOf$4 = getPrototypeOf$5;
4179
4180 var $$n = _export;
4181 var $filter = arrayIteration.filter;
4182 var arrayMethodHasSpeciesSupport = arrayMethodHasSpeciesSupport$5;
4183 var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('filter'); // `Array.prototype.filter` method
4184 // https://tc39.es/ecma262/#sec-array.prototype.filter
4185 // with adding support of @@species
4186
4187 $$n({
4188 target: 'Array',
4189 proto: true,
4190 forced: !HAS_SPECIES_SUPPORT
4191 }, {
4192 filter: function filter(callbackfn
4193 /* , thisArg */
4194 ) {
4195 return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4196 }
4197 });
4198
4199 var entryVirtual$b = entryVirtual$l;
4200 var filter$3 = entryVirtual$b('Array').filter;
4201
4202 var isPrototypeOf$d = objectIsPrototypeOf;
4203 var method$b = filter$3;
4204 var ArrayPrototype$a = Array.prototype;
4205
4206 var filter$2 = function (it) {
4207 var own = it.filter;
4208 return it === ArrayPrototype$a || isPrototypeOf$d(ArrayPrototype$a, it) && own === ArrayPrototype$a.filter ? method$b : own;
4209 };
4210
4211 var parent$D = filter$2;
4212 var filter$1 = parent$D;
4213
4214 var filter = filter$1;
4215
4216 var DESCRIPTORS$4 = descriptors;
4217 var uncurryThis$9 = functionUncurryThis;
4218 var objectKeys = objectKeys$4;
4219 var toIndexedObject = toIndexedObject$b;
4220 var $propertyIsEnumerable = objectPropertyIsEnumerable.f;
4221 var propertyIsEnumerable = uncurryThis$9($propertyIsEnumerable);
4222 var push$2 = uncurryThis$9([].push); // `Object.{ entries, values }` methods implementation
4223
4224 var createMethod$2 = function (TO_ENTRIES) {
4225 return function (it) {
4226 var O = toIndexedObject(it);
4227 var keys = objectKeys(O);
4228 var length = keys.length;
4229 var i = 0;
4230 var result = [];
4231 var key;
4232
4233 while (length > i) {
4234 key = keys[i++];
4235
4236 if (!DESCRIPTORS$4 || propertyIsEnumerable(O, key)) {
4237 push$2(result, TO_ENTRIES ? [key, O[key]] : O[key]);
4238 }
4239 }
4240
4241 return result;
4242 };
4243 };
4244
4245 var objectToArray = {
4246 // `Object.entries` method
4247 // https://tc39.es/ecma262/#sec-object.entries
4248 entries: createMethod$2(true),
4249 // `Object.values` method
4250 // https://tc39.es/ecma262/#sec-object.values
4251 values: createMethod$2(false)
4252 };
4253
4254 var $$m = _export;
4255 var $values = objectToArray.values; // `Object.values` method
4256 // https://tc39.es/ecma262/#sec-object.values
4257
4258 $$m({
4259 target: 'Object',
4260 stat: true
4261 }, {
4262 values: function values(O) {
4263 return $values(O);
4264 }
4265 });
4266
4267 var path$g = path$y;
4268 var values$6 = path$g.Object.values;
4269
4270 var parent$C = values$6;
4271 var values$5 = parent$C;
4272
4273 var values$4 = values$5;
4274
4275 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';
4276
4277 var uncurryThis$8 = functionUncurryThis;
4278 var requireObjectCoercible = requireObjectCoercible$5;
4279 var toString$3 = toString$8;
4280 var whitespaces$3 = whitespaces$4;
4281 var replace$1 = uncurryThis$8(''.replace);
4282 var whitespace = '[' + whitespaces$3 + ']';
4283 var ltrim = RegExp('^' + whitespace + whitespace + '*');
4284 var rtrim = RegExp(whitespace + whitespace + '*$'); // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
4285
4286 var createMethod$1 = function (TYPE) {
4287 return function ($this) {
4288 var string = toString$3(requireObjectCoercible($this));
4289 if (TYPE & 1) string = replace$1(string, ltrim, '');
4290 if (TYPE & 2) string = replace$1(string, rtrim, '');
4291 return string;
4292 };
4293 };
4294
4295 var stringTrim = {
4296 // `String.prototype.{ trimLeft, trimStart }` methods
4297 // https://tc39.es/ecma262/#sec-string.prototype.trimstart
4298 start: createMethod$1(1),
4299 // `String.prototype.{ trimRight, trimEnd }` methods
4300 // https://tc39.es/ecma262/#sec-string.prototype.trimend
4301 end: createMethod$1(2),
4302 // `String.prototype.trim` method
4303 // https://tc39.es/ecma262/#sec-string.prototype.trim
4304 trim: createMethod$1(3)
4305 };
4306
4307 var global$e = global$P;
4308 var fails$a = fails$t;
4309 var uncurryThis$7 = functionUncurryThis;
4310 var toString$2 = toString$8;
4311 var trim$5 = stringTrim.trim;
4312 var whitespaces$2 = whitespaces$4;
4313 var $parseInt$1 = global$e.parseInt;
4314 var Symbol$2 = global$e.Symbol;
4315 var ITERATOR$1 = Symbol$2 && Symbol$2.iterator;
4316 var hex = /^[+-]?0x/i;
4317 var exec$1 = uncurryThis$7(hex.exec);
4318 var FORCED$4 = $parseInt$1(whitespaces$2 + '08') !== 8 || $parseInt$1(whitespaces$2 + '0x16') !== 22 // MS Edge 18- broken with boxed symbols
4319 || ITERATOR$1 && !fails$a(function () {
4320 $parseInt$1(Object(ITERATOR$1));
4321 }); // `parseInt` method
4322 // https://tc39.es/ecma262/#sec-parseint-string-radix
4323
4324 var numberParseInt = FORCED$4 ? function parseInt(string, radix) {
4325 var S = trim$5(toString$2(string));
4326 return $parseInt$1(S, radix >>> 0 || (exec$1(hex, S) ? 16 : 10));
4327 } : $parseInt$1;
4328
4329 var $$l = _export;
4330 var $parseInt = numberParseInt; // `parseInt` method
4331 // https://tc39.es/ecma262/#sec-parseint-string-radix
4332
4333 $$l({
4334 global: true,
4335 forced: parseInt != $parseInt
4336 }, {
4337 parseInt: $parseInt
4338 });
4339
4340 var path$f = path$y;
4341 var _parseInt$2 = path$f.parseInt;
4342
4343 var parent$B = _parseInt$2;
4344 var _parseInt$1 = parent$B;
4345
4346 var _parseInt = _parseInt$1;
4347
4348 /* eslint-disable es/no-array-prototype-indexof -- required for testing */
4349
4350
4351 var $$k = _export;
4352 var uncurryThis$6 = functionUncurryThis;
4353 var $IndexOf = arrayIncludes.indexOf;
4354 var arrayMethodIsStrict$4 = arrayMethodIsStrict$6;
4355 var un$IndexOf = uncurryThis$6([].indexOf);
4356 var NEGATIVE_ZERO = !!un$IndexOf && 1 / un$IndexOf([1], 1, -0) < 0;
4357 var STRICT_METHOD$4 = arrayMethodIsStrict$4('indexOf'); // `Array.prototype.indexOf` method
4358 // https://tc39.es/ecma262/#sec-array.prototype.indexof
4359
4360 $$k({
4361 target: 'Array',
4362 proto: true,
4363 forced: NEGATIVE_ZERO || !STRICT_METHOD$4
4364 }, {
4365 indexOf: function indexOf(searchElement
4366 /* , fromIndex = 0 */
4367 ) {
4368 var fromIndex = arguments.length > 1 ? arguments[1] : undefined;
4369 return NEGATIVE_ZERO // convert -0 to +0
4370 ? un$IndexOf(this, searchElement, fromIndex) || 0 : $IndexOf(this, searchElement, fromIndex);
4371 }
4372 });
4373
4374 var entryVirtual$a = entryVirtual$l;
4375 var indexOf$3 = entryVirtual$a('Array').indexOf;
4376
4377 var isPrototypeOf$c = objectIsPrototypeOf;
4378 var method$a = indexOf$3;
4379 var ArrayPrototype$9 = Array.prototype;
4380
4381 var indexOf$2 = function (it) {
4382 var own = it.indexOf;
4383 return it === ArrayPrototype$9 || isPrototypeOf$c(ArrayPrototype$9, it) && own === ArrayPrototype$9.indexOf ? method$a : own;
4384 };
4385
4386 var parent$A = indexOf$2;
4387 var indexOf$1 = parent$A;
4388
4389 var indexOf = indexOf$1;
4390
4391 var PROPER_FUNCTION_NAME = functionName.PROPER;
4392 var fails$9 = fails$t;
4393 var whitespaces$1 = whitespaces$4;
4394 var non = '\u200B\u0085\u180E'; // check that a method works with the correct list
4395 // of whitespaces and has a correct name
4396
4397 var stringTrimForced = function (METHOD_NAME) {
4398 return fails$9(function () {
4399 return !!whitespaces$1[METHOD_NAME]() || non[METHOD_NAME]() !== non || PROPER_FUNCTION_NAME && whitespaces$1[METHOD_NAME].name !== METHOD_NAME;
4400 });
4401 };
4402
4403 var $$j = _export;
4404 var $trim = stringTrim.trim;
4405 var forcedStringTrimMethod = stringTrimForced; // `String.prototype.trim` method
4406 // https://tc39.es/ecma262/#sec-string.prototype.trim
4407
4408 $$j({
4409 target: 'String',
4410 proto: true,
4411 forced: forcedStringTrimMethod('trim')
4412 }, {
4413 trim: function trim() {
4414 return $trim(this);
4415 }
4416 });
4417
4418 var entryVirtual$9 = entryVirtual$l;
4419 var trim$4 = entryVirtual$9('String').trim;
4420
4421 var isPrototypeOf$b = objectIsPrototypeOf;
4422 var method$9 = trim$4;
4423 var StringPrototype = String.prototype;
4424
4425 var trim$3 = function (it) {
4426 var own = it.trim;
4427 return typeof it == 'string' || it === StringPrototype || isPrototypeOf$b(StringPrototype, it) && own === StringPrototype.trim ? method$9 : own;
4428 };
4429
4430 var parent$z = trim$3;
4431 var trim$2 = parent$z;
4432
4433 var trim$1 = trim$2;
4434
4435 var $$i = _export;
4436 var DESCRIPTORS$3 = descriptors;
4437 var create$8 = objectCreate; // `Object.create` method
4438 // https://tc39.es/ecma262/#sec-object.create
4439
4440 $$i({
4441 target: 'Object',
4442 stat: true,
4443 sham: !DESCRIPTORS$3
4444 }, {
4445 create: create$8
4446 });
4447
4448 var path$e = path$y;
4449 var Object$2 = path$e.Object;
4450
4451 var create$7 = function create(P, D) {
4452 return Object$2.create(P, D);
4453 };
4454
4455 var parent$y = create$7;
4456 var create$6 = parent$y;
4457
4458 var create$5 = create$6;
4459
4460 var $$h = _export;
4461 var global$d = global$P;
4462 var getBuiltIn$2 = getBuiltIn$9;
4463 var apply$3 = functionApply;
4464 var uncurryThis$5 = functionUncurryThis;
4465 var fails$8 = fails$t;
4466 var Array$1 = global$d.Array;
4467 var $stringify = getBuiltIn$2('JSON', 'stringify');
4468 var exec = uncurryThis$5(/./.exec);
4469 var charAt$1 = uncurryThis$5(''.charAt);
4470 var charCodeAt = uncurryThis$5(''.charCodeAt);
4471 var replace = uncurryThis$5(''.replace);
4472 var numberToString = uncurryThis$5(1.0.toString);
4473 var tester = /[\uD800-\uDFFF]/g;
4474 var low = /^[\uD800-\uDBFF]$/;
4475 var hi = /^[\uDC00-\uDFFF]$/;
4476
4477 var fix = function (match, offset, string) {
4478 var prev = charAt$1(string, offset - 1);
4479 var next = charAt$1(string, offset + 1);
4480
4481 if (exec(low, match) && !exec(hi, next) || exec(hi, match) && !exec(low, prev)) {
4482 return '\\u' + numberToString(charCodeAt(match, 0), 16);
4483 }
4484
4485 return match;
4486 };
4487
4488 var FORCED$3 = fails$8(function () {
4489 return $stringify('\uDF06\uD834') !== '"\\udf06\\ud834"' || $stringify('\uDEAD') !== '"\\udead"';
4490 });
4491
4492 if ($stringify) {
4493 // `JSON.stringify` method
4494 // https://tc39.es/ecma262/#sec-json.stringify
4495 // https://github.com/tc39/proposal-well-formed-stringify
4496 $$h({
4497 target: 'JSON',
4498 stat: true,
4499 forced: FORCED$3
4500 }, {
4501 // eslint-disable-next-line no-unused-vars -- required for `.length`
4502 stringify: function stringify(it, replacer, space) {
4503 for (var i = 0, l = arguments.length, args = Array$1(l); i < l; i++) args[i] = arguments[i];
4504
4505 var result = apply$3($stringify, null, args);
4506 return typeof result == 'string' ? replace(result, tester, fix) : result;
4507 }
4508 });
4509 }
4510
4511 var path$d = path$y;
4512 var apply$2 = functionApply; // eslint-disable-next-line es/no-json -- safe
4513
4514 if (!path$d.JSON) path$d.JSON = {
4515 stringify: JSON.stringify
4516 }; // eslint-disable-next-line no-unused-vars -- required for `.length`
4517
4518 var stringify$3 = function stringify(it, replacer, space) {
4519 return apply$2(path$d.JSON.stringify, null, arguments);
4520 };
4521
4522 var parent$x = stringify$3;
4523 var stringify$2 = parent$x;
4524
4525 var stringify$1 = stringify$2;
4526
4527 var global$c = global$P;
4528 var TypeError$6 = global$c.TypeError;
4529
4530 var validateArgumentsLength$1 = function (passed, required) {
4531 if (passed < required) throw TypeError$6('Not enough arguments');
4532 return passed;
4533 };
4534
4535 var $$g = _export;
4536 var global$b = global$P;
4537 var apply$1 = functionApply;
4538 var isCallable$1 = isCallable$h;
4539 var userAgent$2 = engineUserAgent;
4540 var arraySlice$1 = arraySlice$5;
4541 var validateArgumentsLength = validateArgumentsLength$1;
4542 var MSIE = /MSIE .\./.test(userAgent$2); // <- dirty ie9- check
4543
4544 var Function$1 = global$b.Function;
4545
4546 var wrap = function (scheduler) {
4547 return function (handler, timeout
4548 /* , ...arguments */
4549 ) {
4550 var boundArgs = validateArgumentsLength(arguments.length, 1) > 2;
4551 var fn = isCallable$1(handler) ? handler : Function$1(handler);
4552 var args = boundArgs ? arraySlice$1(arguments, 2) : undefined;
4553 return scheduler(boundArgs ? function () {
4554 apply$1(fn, this, args);
4555 } : fn, timeout);
4556 };
4557 }; // ie9- setTimeout & setInterval additional parameters fix
4558 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
4559
4560
4561 $$g({
4562 global: true,
4563 bind: true,
4564 forced: MSIE
4565 }, {
4566 // `setTimeout` method
4567 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout
4568 setTimeout: wrap(global$b.setTimeout),
4569 // `setInterval` method
4570 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
4571 setInterval: wrap(global$b.setInterval)
4572 });
4573
4574 var path$c = path$y;
4575 var setTimeout$2 = path$c.setTimeout;
4576
4577 var setTimeout$1 = setTimeout$2;
4578
4579 var toObject$3 = toObject$e;
4580 var toAbsoluteIndex = toAbsoluteIndex$5;
4581 var lengthOfArrayLike$5 = lengthOfArrayLike$d; // `Array.prototype.fill` method implementation
4582 // https://tc39.es/ecma262/#sec-array.prototype.fill
4583
4584 var arrayFill = function fill(value
4585 /* , start = 0, end = @length */
4586 ) {
4587 var O = toObject$3(this);
4588 var length = lengthOfArrayLike$5(O);
4589 var argumentsLength = arguments.length;
4590 var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);
4591 var end = argumentsLength > 2 ? arguments[2] : undefined;
4592 var endPos = end === undefined ? length : toAbsoluteIndex(end, length);
4593
4594 while (endPos > index) O[index++] = value;
4595
4596 return O;
4597 };
4598
4599 var $$f = _export;
4600 var fill$4 = arrayFill;
4601 // https://tc39.es/ecma262/#sec-array.prototype.fill
4602
4603 $$f({
4604 target: 'Array',
4605 proto: true
4606 }, {
4607 fill: fill$4
4608 }); // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
4609
4610 var entryVirtual$8 = entryVirtual$l;
4611 var fill$3 = entryVirtual$8('Array').fill;
4612
4613 var isPrototypeOf$a = objectIsPrototypeOf;
4614 var method$8 = fill$3;
4615 var ArrayPrototype$8 = Array.prototype;
4616
4617 var fill$2 = function (it) {
4618 var own = it.fill;
4619 return it === ArrayPrototype$8 || isPrototypeOf$a(ArrayPrototype$8, it) && own === ArrayPrototype$8.fill ? method$8 : own;
4620 };
4621
4622 var parent$w = fill$2;
4623 var fill$1 = parent$w;
4624
4625 var fill = fill$1;
4626
4627 /*! Hammer.JS - v2.0.17-rc - 2019-12-16
4628 * http://naver.github.io/egjs
4629 *
4630 * Forked By Naver egjs
4631 * Copyright (c) hammerjs
4632 * Licensed under the MIT license */
4633 function _extends() {
4634 _extends = Object.assign || function (target) {
4635 for (var i = 1; i < arguments.length; i++) {
4636 var source = arguments[i];
4637
4638 for (var key in source) {
4639 if (Object.prototype.hasOwnProperty.call(source, key)) {
4640 target[key] = source[key];
4641 }
4642 }
4643 }
4644
4645 return target;
4646 };
4647
4648 return _extends.apply(this, arguments);
4649 }
4650
4651 function _inheritsLoose(subClass, superClass) {
4652 subClass.prototype = Object.create(superClass.prototype);
4653 subClass.prototype.constructor = subClass;
4654 subClass.__proto__ = superClass;
4655 }
4656
4657 function _assertThisInitialized$1(self) {
4658 if (self === void 0) {
4659 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
4660 }
4661
4662 return self;
4663 }
4664 /**
4665 * @private
4666 * extend object.
4667 * means that properties in dest will be overwritten by the ones in src.
4668 * @param {Object} target
4669 * @param {...Object} objects_to_assign
4670 * @returns {Object} target
4671 */
4672
4673
4674 var assign;
4675
4676 if (typeof Object.assign !== 'function') {
4677 assign = function assign(target) {
4678 if (target === undefined || target === null) {
4679 throw new TypeError('Cannot convert undefined or null to object');
4680 }
4681
4682 var output = Object(target);
4683
4684 for (var index = 1; index < arguments.length; index++) {
4685 var source = arguments[index];
4686
4687 if (source !== undefined && source !== null) {
4688 for (var nextKey in source) {
4689 if (source.hasOwnProperty(nextKey)) {
4690 output[nextKey] = source[nextKey];
4691 }
4692 }
4693 }
4694 }
4695
4696 return output;
4697 };
4698 } else {
4699 assign = Object.assign;
4700 }
4701
4702 var assign$1 = assign;
4703 var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
4704 var TEST_ELEMENT = typeof document === "undefined" ? {
4705 style: {}
4706 } : document.createElement('div');
4707 var TYPE_FUNCTION = 'function';
4708 var round = Math.round,
4709 abs$1 = Math.abs;
4710 var now = Date.now;
4711 /**
4712 * @private
4713 * get the prefixed property
4714 * @param {Object} obj
4715 * @param {String} property
4716 * @returns {String|Undefined} prefixed
4717 */
4718
4719 function prefixed(obj, property) {
4720 var prefix;
4721 var prop;
4722 var camelProp = property[0].toUpperCase() + property.slice(1);
4723 var i = 0;
4724
4725 while (i < VENDOR_PREFIXES.length) {
4726 prefix = VENDOR_PREFIXES[i];
4727 prop = prefix ? prefix + camelProp : property;
4728
4729 if (prop in obj) {
4730 return prop;
4731 }
4732
4733 i++;
4734 }
4735
4736 return undefined;
4737 }
4738 /* eslint-disable no-new-func, no-nested-ternary */
4739
4740
4741 var win;
4742
4743 if (typeof window === "undefined") {
4744 // window is undefined in node.js
4745 win = {};
4746 } else {
4747 win = window;
4748 }
4749
4750 var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
4751 var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
4752
4753 function getTouchActionProps() {
4754 if (!NATIVE_TOUCH_ACTION) {
4755 return false;
4756 }
4757
4758 var touchMap = {};
4759 var cssSupports = win.CSS && win.CSS.supports;
4760 ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function (val) {
4761 // If css.supports is not supported but there is native touch-action assume it supports
4762 // all values. This is the case for IE 10 and 11.
4763 return touchMap[val] = cssSupports ? win.CSS.supports('touch-action', val) : true;
4764 });
4765 return touchMap;
4766 }
4767
4768 var TOUCH_ACTION_COMPUTE = 'compute';
4769 var TOUCH_ACTION_AUTO = 'auto';
4770 var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
4771
4772 var TOUCH_ACTION_NONE = 'none';
4773 var TOUCH_ACTION_PAN_X = 'pan-x';
4774 var TOUCH_ACTION_PAN_Y = 'pan-y';
4775 var TOUCH_ACTION_MAP = getTouchActionProps();
4776 var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
4777 var SUPPORT_TOUCH = ('ontouchstart' in win);
4778 var SUPPORT_POINTER_EVENTS = prefixed(win, 'PointerEvent') !== undefined;
4779 var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
4780 var INPUT_TYPE_TOUCH = 'touch';
4781 var INPUT_TYPE_PEN = 'pen';
4782 var INPUT_TYPE_MOUSE = 'mouse';
4783 var INPUT_TYPE_KINECT = 'kinect';
4784 var COMPUTE_INTERVAL = 25;
4785 var INPUT_START = 1;
4786 var INPUT_MOVE = 2;
4787 var INPUT_END = 4;
4788 var INPUT_CANCEL = 8;
4789 var DIRECTION_NONE = 1;
4790 var DIRECTION_LEFT = 2;
4791 var DIRECTION_RIGHT = 4;
4792 var DIRECTION_UP = 8;
4793 var DIRECTION_DOWN = 16;
4794 var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
4795 var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
4796 var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
4797 var PROPS_XY = ['x', 'y'];
4798 var PROPS_CLIENT_XY = ['clientX', 'clientY'];
4799 /**
4800 * @private
4801 * walk objects and arrays
4802 * @param {Object} obj
4803 * @param {Function} iterator
4804 * @param {Object} context
4805 */
4806
4807 function each(obj, iterator, context) {
4808 var i;
4809
4810 if (!obj) {
4811 return;
4812 }
4813
4814 if (obj.forEach) {
4815 obj.forEach(iterator, context);
4816 } else if (obj.length !== undefined) {
4817 i = 0;
4818
4819 while (i < obj.length) {
4820 iterator.call(context, obj[i], i, obj);
4821 i++;
4822 }
4823 } else {
4824 for (i in obj) {
4825 obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
4826 }
4827 }
4828 }
4829 /**
4830 * @private
4831 * let a boolean value also be a function that must return a boolean
4832 * this first item in args will be used as the context
4833 * @param {Boolean|Function} val
4834 * @param {Array} [args]
4835 * @returns {Boolean}
4836 */
4837
4838
4839 function boolOrFn(val, args) {
4840 if (typeof val === TYPE_FUNCTION) {
4841 return val.apply(args ? args[0] || undefined : undefined, args);
4842 }
4843
4844 return val;
4845 }
4846 /**
4847 * @private
4848 * small indexOf wrapper
4849 * @param {String} str
4850 * @param {String} find
4851 * @returns {Boolean} found
4852 */
4853
4854
4855 function inStr(str, find) {
4856 return str.indexOf(find) > -1;
4857 }
4858 /**
4859 * @private
4860 * when the touchActions are collected they are not a valid value, so we need to clean things up. *
4861 * @param {String} actions
4862 * @returns {*}
4863 */
4864
4865
4866 function cleanTouchActions(actions) {
4867 // none
4868 if (inStr(actions, TOUCH_ACTION_NONE)) {
4869 return TOUCH_ACTION_NONE;
4870 }
4871
4872 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
4873 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); // if both pan-x and pan-y are set (different recognizers
4874 // for different directions, e.g. horizontal pan but vertical swipe?)
4875 // we need none (as otherwise with pan-x pan-y combined none of these
4876 // recognizers will work, since the browser would handle all panning
4877
4878 if (hasPanX && hasPanY) {
4879 return TOUCH_ACTION_NONE;
4880 } // pan-x OR pan-y
4881
4882
4883 if (hasPanX || hasPanY) {
4884 return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
4885 } // manipulation
4886
4887
4888 if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
4889 return TOUCH_ACTION_MANIPULATION;
4890 }
4891
4892 return TOUCH_ACTION_AUTO;
4893 }
4894 /**
4895 * @private
4896 * Touch Action
4897 * sets the touchAction property or uses the js alternative
4898 * @param {Manager} manager
4899 * @param {String} value
4900 * @constructor
4901 */
4902
4903
4904 var TouchAction = /*#__PURE__*/function () {
4905 function TouchAction(manager, value) {
4906 this.manager = manager;
4907 this.set(value);
4908 }
4909 /**
4910 * @private
4911 * set the touchAction value on the element or enable the polyfill
4912 * @param {String} value
4913 */
4914
4915
4916 var _proto = TouchAction.prototype;
4917
4918 _proto.set = function set(value) {
4919 // find out the touch-action by the event handlers
4920 if (value === TOUCH_ACTION_COMPUTE) {
4921 value = this.compute();
4922 }
4923
4924 if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
4925 this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
4926 }
4927
4928 this.actions = value.toLowerCase().trim();
4929 };
4930 /**
4931 * @private
4932 * just re-set the touchAction value
4933 */
4934
4935
4936 _proto.update = function update() {
4937 this.set(this.manager.options.touchAction);
4938 };
4939 /**
4940 * @private
4941 * compute the value for the touchAction property based on the recognizer's settings
4942 * @returns {String} value
4943 */
4944
4945
4946 _proto.compute = function compute() {
4947 var actions = [];
4948 each(this.manager.recognizers, function (recognizer) {
4949 if (boolOrFn(recognizer.options.enable, [recognizer])) {
4950 actions = actions.concat(recognizer.getTouchAction());
4951 }
4952 });
4953 return cleanTouchActions(actions.join(' '));
4954 };
4955 /**
4956 * @private
4957 * this method is called on each input cycle and provides the preventing of the browser behavior
4958 * @param {Object} input
4959 */
4960
4961
4962 _proto.preventDefaults = function preventDefaults(input) {
4963 var srcEvent = input.srcEvent;
4964 var direction = input.offsetDirection; // if the touch action did prevented once this session
4965
4966 if (this.manager.session.prevented) {
4967 srcEvent.preventDefault();
4968 return;
4969 }
4970
4971 var actions = this.actions;
4972 var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
4973 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
4974 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
4975
4976 if (hasNone) {
4977 // do not prevent defaults if this is a tap gesture
4978 var isTapPointer = input.pointers.length === 1;
4979 var isTapMovement = input.distance < 2;
4980 var isTapTouchTime = input.deltaTime < 250;
4981
4982 if (isTapPointer && isTapMovement && isTapTouchTime) {
4983 return;
4984 }
4985 }
4986
4987 if (hasPanX && hasPanY) {
4988 // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
4989 return;
4990 }
4991
4992 if (hasNone || hasPanY && direction & DIRECTION_HORIZONTAL || hasPanX && direction & DIRECTION_VERTICAL) {
4993 return this.preventSrc(srcEvent);
4994 }
4995 };
4996 /**
4997 * @private
4998 * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
4999 * @param {Object} srcEvent
5000 */
5001
5002
5003 _proto.preventSrc = function preventSrc(srcEvent) {
5004 this.manager.session.prevented = true;
5005 srcEvent.preventDefault();
5006 };
5007
5008 return TouchAction;
5009 }();
5010 /**
5011 * @private
5012 * find if a node is in the given parent
5013 * @method hasParent
5014 * @param {HTMLElement} node
5015 * @param {HTMLElement} parent
5016 * @return {Boolean} found
5017 */
5018
5019
5020 function hasParent$1(node, parent) {
5021 while (node) {
5022 if (node === parent) {
5023 return true;
5024 }
5025
5026 node = node.parentNode;
5027 }
5028
5029 return false;
5030 }
5031 /**
5032 * @private
5033 * get the center of all the pointers
5034 * @param {Array} pointers
5035 * @return {Object} center contains `x` and `y` properties
5036 */
5037
5038
5039 function getCenter(pointers) {
5040 var pointersLength = pointers.length; // no need to loop when only one touch
5041
5042 if (pointersLength === 1) {
5043 return {
5044 x: round(pointers[0].clientX),
5045 y: round(pointers[0].clientY)
5046 };
5047 }
5048
5049 var x = 0;
5050 var y = 0;
5051 var i = 0;
5052
5053 while (i < pointersLength) {
5054 x += pointers[i].clientX;
5055 y += pointers[i].clientY;
5056 i++;
5057 }
5058
5059 return {
5060 x: round(x / pointersLength),
5061 y: round(y / pointersLength)
5062 };
5063 }
5064 /**
5065 * @private
5066 * create a simple clone from the input used for storage of firstInput and firstMultiple
5067 * @param {Object} input
5068 * @returns {Object} clonedInputData
5069 */
5070
5071
5072 function simpleCloneInputData(input) {
5073 // make a simple copy of the pointers because we will get a reference if we don't
5074 // we only need clientXY for the calculations
5075 var pointers = [];
5076 var i = 0;
5077
5078 while (i < input.pointers.length) {
5079 pointers[i] = {
5080 clientX: round(input.pointers[i].clientX),
5081 clientY: round(input.pointers[i].clientY)
5082 };
5083 i++;
5084 }
5085
5086 return {
5087 timeStamp: now(),
5088 pointers: pointers,
5089 center: getCenter(pointers),
5090 deltaX: input.deltaX,
5091 deltaY: input.deltaY
5092 };
5093 }
5094 /**
5095 * @private
5096 * calculate the absolute distance between two points
5097 * @param {Object} p1 {x, y}
5098 * @param {Object} p2 {x, y}
5099 * @param {Array} [props] containing x and y keys
5100 * @return {Number} distance
5101 */
5102
5103
5104 function getDistance(p1, p2, props) {
5105 if (!props) {
5106 props = PROPS_XY;
5107 }
5108
5109 var x = p2[props[0]] - p1[props[0]];
5110 var y = p2[props[1]] - p1[props[1]];
5111 return Math.sqrt(x * x + y * y);
5112 }
5113 /**
5114 * @private
5115 * calculate the angle between two coordinates
5116 * @param {Object} p1
5117 * @param {Object} p2
5118 * @param {Array} [props] containing x and y keys
5119 * @return {Number} angle
5120 */
5121
5122
5123 function getAngle(p1, p2, props) {
5124 if (!props) {
5125 props = PROPS_XY;
5126 }
5127
5128 var x = p2[props[0]] - p1[props[0]];
5129 var y = p2[props[1]] - p1[props[1]];
5130 return Math.atan2(y, x) * 180 / Math.PI;
5131 }
5132 /**
5133 * @private
5134 * get the direction between two points
5135 * @param {Number} x
5136 * @param {Number} y
5137 * @return {Number} direction
5138 */
5139
5140
5141 function getDirection(x, y) {
5142 if (x === y) {
5143 return DIRECTION_NONE;
5144 }
5145
5146 if (abs$1(x) >= abs$1(y)) {
5147 return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
5148 }
5149
5150 return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
5151 }
5152
5153 function computeDeltaXY(session, input) {
5154 var center = input.center; // let { offsetDelta:offset = {}, prevDelta = {}, prevInput = {} } = session;
5155 // jscs throwing error on defalut destructured values and without defaults tests fail
5156
5157 var offset = session.offsetDelta || {};
5158 var prevDelta = session.prevDelta || {};
5159 var prevInput = session.prevInput || {};
5160
5161 if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
5162 prevDelta = session.prevDelta = {
5163 x: prevInput.deltaX || 0,
5164 y: prevInput.deltaY || 0
5165 };
5166 offset = session.offsetDelta = {
5167 x: center.x,
5168 y: center.y
5169 };
5170 }
5171
5172 input.deltaX = prevDelta.x + (center.x - offset.x);
5173 input.deltaY = prevDelta.y + (center.y - offset.y);
5174 }
5175 /**
5176 * @private
5177 * calculate the velocity between two points. unit is in px per ms.
5178 * @param {Number} deltaTime
5179 * @param {Number} x
5180 * @param {Number} y
5181 * @return {Object} velocity `x` and `y`
5182 */
5183
5184
5185 function getVelocity(deltaTime, x, y) {
5186 return {
5187 x: x / deltaTime || 0,
5188 y: y / deltaTime || 0
5189 };
5190 }
5191 /**
5192 * @private
5193 * calculate the scale factor between two pointersets
5194 * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
5195 * @param {Array} start array of pointers
5196 * @param {Array} end array of pointers
5197 * @return {Number} scale
5198 */
5199
5200
5201 function getScale(start, end) {
5202 return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
5203 }
5204 /**
5205 * @private
5206 * calculate the rotation degrees between two pointersets
5207 * @param {Array} start array of pointers
5208 * @param {Array} end array of pointers
5209 * @return {Number} rotation
5210 */
5211
5212
5213 function getRotation(start, end) {
5214 return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
5215 }
5216 /**
5217 * @private
5218 * velocity is calculated every x ms
5219 * @param {Object} session
5220 * @param {Object} input
5221 */
5222
5223
5224 function computeIntervalInputData(session, input) {
5225 var last = session.lastInterval || input;
5226 var deltaTime = input.timeStamp - last.timeStamp;
5227 var velocity;
5228 var velocityX;
5229 var velocityY;
5230 var direction;
5231
5232 if (input.eventType !== INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
5233 var deltaX = input.deltaX - last.deltaX;
5234 var deltaY = input.deltaY - last.deltaY;
5235 var v = getVelocity(deltaTime, deltaX, deltaY);
5236 velocityX = v.x;
5237 velocityY = v.y;
5238 velocity = abs$1(v.x) > abs$1(v.y) ? v.x : v.y;
5239 direction = getDirection(deltaX, deltaY);
5240 session.lastInterval = input;
5241 } else {
5242 // use latest velocity info if it doesn't overtake a minimum period
5243 velocity = last.velocity;
5244 velocityX = last.velocityX;
5245 velocityY = last.velocityY;
5246 direction = last.direction;
5247 }
5248
5249 input.velocity = velocity;
5250 input.velocityX = velocityX;
5251 input.velocityY = velocityY;
5252 input.direction = direction;
5253 }
5254 /**
5255 * @private
5256 * extend the data with some usable properties like scale, rotate, velocity etc
5257 * @param {Object} manager
5258 * @param {Object} input
5259 */
5260
5261
5262 function computeInputData(manager, input) {
5263 var session = manager.session;
5264 var pointers = input.pointers;
5265 var pointersLength = pointers.length; // store the first input to calculate the distance and direction
5266
5267 if (!session.firstInput) {
5268 session.firstInput = simpleCloneInputData(input);
5269 } // to compute scale and rotation we need to store the multiple touches
5270
5271
5272 if (pointersLength > 1 && !session.firstMultiple) {
5273 session.firstMultiple = simpleCloneInputData(input);
5274 } else if (pointersLength === 1) {
5275 session.firstMultiple = false;
5276 }
5277
5278 var firstInput = session.firstInput,
5279 firstMultiple = session.firstMultiple;
5280 var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
5281 var center = input.center = getCenter(pointers);
5282 input.timeStamp = now();
5283 input.deltaTime = input.timeStamp - firstInput.timeStamp;
5284 input.angle = getAngle(offsetCenter, center);
5285 input.distance = getDistance(offsetCenter, center);
5286 computeDeltaXY(session, input);
5287 input.offsetDirection = getDirection(input.deltaX, input.deltaY);
5288 var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
5289 input.overallVelocityX = overallVelocity.x;
5290 input.overallVelocityY = overallVelocity.y;
5291 input.overallVelocity = abs$1(overallVelocity.x) > abs$1(overallVelocity.y) ? overallVelocity.x : overallVelocity.y;
5292 input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
5293 input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
5294 input.maxPointers = !session.prevInput ? input.pointers.length : input.pointers.length > session.prevInput.maxPointers ? input.pointers.length : session.prevInput.maxPointers;
5295 computeIntervalInputData(session, input); // find the correct target
5296
5297 var target = manager.element;
5298 var srcEvent = input.srcEvent;
5299 var srcEventTarget;
5300
5301 if (srcEvent.composedPath) {
5302 srcEventTarget = srcEvent.composedPath()[0];
5303 } else if (srcEvent.path) {
5304 srcEventTarget = srcEvent.path[0];
5305 } else {
5306 srcEventTarget = srcEvent.target;
5307 }
5308
5309 if (hasParent$1(srcEventTarget, target)) {
5310 target = srcEventTarget;
5311 }
5312
5313 input.target = target;
5314 }
5315 /**
5316 * @private
5317 * handle input events
5318 * @param {Manager} manager
5319 * @param {String} eventType
5320 * @param {Object} input
5321 */
5322
5323
5324 function inputHandler(manager, eventType, input) {
5325 var pointersLen = input.pointers.length;
5326 var changedPointersLen = input.changedPointers.length;
5327 var isFirst = eventType & INPUT_START && pointersLen - changedPointersLen === 0;
5328 var isFinal = eventType & (INPUT_END | INPUT_CANCEL) && pointersLen - changedPointersLen === 0;
5329 input.isFirst = !!isFirst;
5330 input.isFinal = !!isFinal;
5331
5332 if (isFirst) {
5333 manager.session = {};
5334 } // source event is the normalized value of the domEvents
5335 // like 'touchstart, mouseup, pointerdown'
5336
5337
5338 input.eventType = eventType; // compute scale, rotation etc
5339
5340 computeInputData(manager, input); // emit secret event
5341
5342 manager.emit('hammer.input', input);
5343 manager.recognize(input);
5344 manager.session.prevInput = input;
5345 }
5346 /**
5347 * @private
5348 * split string on whitespace
5349 * @param {String} str
5350 * @returns {Array} words
5351 */
5352
5353
5354 function splitStr(str) {
5355 return str.trim().split(/\s+/g);
5356 }
5357 /**
5358 * @private
5359 * addEventListener with multiple events at once
5360 * @param {EventTarget} target
5361 * @param {String} types
5362 * @param {Function} handler
5363 */
5364
5365
5366 function addEventListeners(target, types, handler) {
5367 each(splitStr(types), function (type) {
5368 target.addEventListener(type, handler, false);
5369 });
5370 }
5371 /**
5372 * @private
5373 * removeEventListener with multiple events at once
5374 * @param {EventTarget} target
5375 * @param {String} types
5376 * @param {Function} handler
5377 */
5378
5379
5380 function removeEventListeners(target, types, handler) {
5381 each(splitStr(types), function (type) {
5382 target.removeEventListener(type, handler, false);
5383 });
5384 }
5385 /**
5386 * @private
5387 * get the window object of an element
5388 * @param {HTMLElement} element
5389 * @returns {DocumentView|Window}
5390 */
5391
5392
5393 function getWindowForElement(element) {
5394 var doc = element.ownerDocument || element;
5395 return doc.defaultView || doc.parentWindow || window;
5396 }
5397 /**
5398 * @private
5399 * create new input type manager
5400 * @param {Manager} manager
5401 * @param {Function} callback
5402 * @returns {Input}
5403 * @constructor
5404 */
5405
5406
5407 var Input = /*#__PURE__*/function () {
5408 function Input(manager, callback) {
5409 var self = this;
5410 this.manager = manager;
5411 this.callback = callback;
5412 this.element = manager.element;
5413 this.target = manager.options.inputTarget; // smaller wrapper around the handler, for the scope and the enabled state of the manager,
5414 // so when disabled the input events are completely bypassed.
5415
5416 this.domHandler = function (ev) {
5417 if (boolOrFn(manager.options.enable, [manager])) {
5418 self.handler(ev);
5419 }
5420 };
5421
5422 this.init();
5423 }
5424 /**
5425 * @private
5426 * should handle the inputEvent data and trigger the callback
5427 * @virtual
5428 */
5429
5430
5431 var _proto = Input.prototype;
5432
5433 _proto.handler = function handler() {};
5434 /**
5435 * @private
5436 * bind the events
5437 */
5438
5439
5440 _proto.init = function init() {
5441 this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
5442 this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
5443 this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
5444 };
5445 /**
5446 * @private
5447 * unbind the events
5448 */
5449
5450
5451 _proto.destroy = function destroy() {
5452 this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
5453 this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
5454 this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
5455 };
5456
5457 return Input;
5458 }();
5459 /**
5460 * @private
5461 * find if a array contains the object using indexOf or a simple polyFill
5462 * @param {Array} src
5463 * @param {String} find
5464 * @param {String} [findByKey]
5465 * @return {Boolean|Number} false when not found, or the index
5466 */
5467
5468
5469 function inArray(src, find, findByKey) {
5470 if (src.indexOf && !findByKey) {
5471 return src.indexOf(find);
5472 } else {
5473 var i = 0;
5474
5475 while (i < src.length) {
5476 if (findByKey && src[i][findByKey] == find || !findByKey && src[i] === find) {
5477 // do not use === here, test fails
5478 return i;
5479 }
5480
5481 i++;
5482 }
5483
5484 return -1;
5485 }
5486 }
5487
5488 var POINTER_INPUT_MAP = {
5489 pointerdown: INPUT_START,
5490 pointermove: INPUT_MOVE,
5491 pointerup: INPUT_END,
5492 pointercancel: INPUT_CANCEL,
5493 pointerout: INPUT_CANCEL
5494 }; // in IE10 the pointer types is defined as an enum
5495
5496 var IE10_POINTER_TYPE_ENUM = {
5497 2: INPUT_TYPE_TOUCH,
5498 3: INPUT_TYPE_PEN,
5499 4: INPUT_TYPE_MOUSE,
5500 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
5501
5502 };
5503 var POINTER_ELEMENT_EVENTS = 'pointerdown';
5504 var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; // IE10 has prefixed support, and case-sensitive
5505
5506 if (win.MSPointerEvent && !win.PointerEvent) {
5507 POINTER_ELEMENT_EVENTS = 'MSPointerDown';
5508 POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
5509 }
5510 /**
5511 * @private
5512 * Pointer events input
5513 * @constructor
5514 * @extends Input
5515 */
5516
5517
5518 var PointerEventInput = /*#__PURE__*/function (_Input) {
5519 _inheritsLoose(PointerEventInput, _Input);
5520
5521 function PointerEventInput() {
5522 var _this;
5523
5524 var proto = PointerEventInput.prototype;
5525 proto.evEl = POINTER_ELEMENT_EVENTS;
5526 proto.evWin = POINTER_WINDOW_EVENTS;
5527 _this = _Input.apply(this, arguments) || this;
5528 _this.store = _this.manager.session.pointerEvents = [];
5529 return _this;
5530 }
5531 /**
5532 * @private
5533 * handle mouse events
5534 * @param {Object} ev
5535 */
5536
5537
5538 var _proto = PointerEventInput.prototype;
5539
5540 _proto.handler = function handler(ev) {
5541 var store = this.store;
5542 var removePointer = false;
5543 var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
5544 var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
5545 var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
5546 var isTouch = pointerType === INPUT_TYPE_TOUCH; // get index of the event in the store
5547
5548 var storeIndex = inArray(store, ev.pointerId, 'pointerId'); // start and mouse must be down
5549
5550 if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
5551 if (storeIndex < 0) {
5552 store.push(ev);
5553 storeIndex = store.length - 1;
5554 }
5555 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
5556 removePointer = true;
5557 } // it not found, so the pointer hasn't been down (so it's probably a hover)
5558
5559
5560 if (storeIndex < 0) {
5561 return;
5562 } // update the event in the store
5563
5564
5565 store[storeIndex] = ev;
5566 this.callback(this.manager, eventType, {
5567 pointers: store,
5568 changedPointers: [ev],
5569 pointerType: pointerType,
5570 srcEvent: ev
5571 });
5572
5573 if (removePointer) {
5574 // remove from the store
5575 store.splice(storeIndex, 1);
5576 }
5577 };
5578
5579 return PointerEventInput;
5580 }(Input);
5581 /**
5582 * @private
5583 * convert array-like objects to real arrays
5584 * @param {Object} obj
5585 * @returns {Array}
5586 */
5587
5588
5589 function toArray$1(obj) {
5590 return Array.prototype.slice.call(obj, 0);
5591 }
5592 /**
5593 * @private
5594 * unique array with objects based on a key (like 'id') or just by the array's value
5595 * @param {Array} src [{id:1},{id:2},{id:1}]
5596 * @param {String} [key]
5597 * @param {Boolean} [sort=False]
5598 * @returns {Array} [{id:1},{id:2}]
5599 */
5600
5601
5602 function uniqueArray(src, key, sort) {
5603 var results = [];
5604 var values = [];
5605 var i = 0;
5606
5607 while (i < src.length) {
5608 var val = key ? src[i][key] : src[i];
5609
5610 if (inArray(values, val) < 0) {
5611 results.push(src[i]);
5612 }
5613
5614 values[i] = val;
5615 i++;
5616 }
5617
5618 if (sort) {
5619 if (!key) {
5620 results = results.sort();
5621 } else {
5622 results = results.sort(function (a, b) {
5623 return a[key] > b[key];
5624 });
5625 }
5626 }
5627
5628 return results;
5629 }
5630
5631 var TOUCH_INPUT_MAP = {
5632 touchstart: INPUT_START,
5633 touchmove: INPUT_MOVE,
5634 touchend: INPUT_END,
5635 touchcancel: INPUT_CANCEL
5636 };
5637 var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
5638 /**
5639 * @private
5640 * Multi-user touch events input
5641 * @constructor
5642 * @extends Input
5643 */
5644
5645 var TouchInput = /*#__PURE__*/function (_Input) {
5646 _inheritsLoose(TouchInput, _Input);
5647
5648 function TouchInput() {
5649 var _this;
5650
5651 TouchInput.prototype.evTarget = TOUCH_TARGET_EVENTS;
5652 _this = _Input.apply(this, arguments) || this;
5653 _this.targetIds = {}; // this.evTarget = TOUCH_TARGET_EVENTS;
5654
5655 return _this;
5656 }
5657
5658 var _proto = TouchInput.prototype;
5659
5660 _proto.handler = function handler(ev) {
5661 var type = TOUCH_INPUT_MAP[ev.type];
5662 var touches = getTouches.call(this, ev, type);
5663
5664 if (!touches) {
5665 return;
5666 }
5667
5668 this.callback(this.manager, type, {
5669 pointers: touches[0],
5670 changedPointers: touches[1],
5671 pointerType: INPUT_TYPE_TOUCH,
5672 srcEvent: ev
5673 });
5674 };
5675
5676 return TouchInput;
5677 }(Input);
5678
5679 function getTouches(ev, type) {
5680 var allTouches = toArray$1(ev.touches);
5681 var targetIds = this.targetIds; // when there is only one touch, the process can be simplified
5682
5683 if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
5684 targetIds[allTouches[0].identifier] = true;
5685 return [allTouches, allTouches];
5686 }
5687
5688 var i;
5689 var targetTouches;
5690 var changedTouches = toArray$1(ev.changedTouches);
5691 var changedTargetTouches = [];
5692 var target = this.target; // get target touches from touches
5693
5694 targetTouches = allTouches.filter(function (touch) {
5695 return hasParent$1(touch.target, target);
5696 }); // collect touches
5697
5698 if (type === INPUT_START) {
5699 i = 0;
5700
5701 while (i < targetTouches.length) {
5702 targetIds[targetTouches[i].identifier] = true;
5703 i++;
5704 }
5705 } // filter changed touches to only contain touches that exist in the collected target ids
5706
5707
5708 i = 0;
5709
5710 while (i < changedTouches.length) {
5711 if (targetIds[changedTouches[i].identifier]) {
5712 changedTargetTouches.push(changedTouches[i]);
5713 } // cleanup removed touches
5714
5715
5716 if (type & (INPUT_END | INPUT_CANCEL)) {
5717 delete targetIds[changedTouches[i].identifier];
5718 }
5719
5720 i++;
5721 }
5722
5723 if (!changedTargetTouches.length) {
5724 return;
5725 }
5726
5727 return [// merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
5728 uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), changedTargetTouches];
5729 }
5730
5731 var MOUSE_INPUT_MAP = {
5732 mousedown: INPUT_START,
5733 mousemove: INPUT_MOVE,
5734 mouseup: INPUT_END
5735 };
5736 var MOUSE_ELEMENT_EVENTS = 'mousedown';
5737 var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
5738 /**
5739 * @private
5740 * Mouse events input
5741 * @constructor
5742 * @extends Input
5743 */
5744
5745 var MouseInput = /*#__PURE__*/function (_Input) {
5746 _inheritsLoose(MouseInput, _Input);
5747
5748 function MouseInput() {
5749 var _this;
5750
5751 var proto = MouseInput.prototype;
5752 proto.evEl = MOUSE_ELEMENT_EVENTS;
5753 proto.evWin = MOUSE_WINDOW_EVENTS;
5754 _this = _Input.apply(this, arguments) || this;
5755 _this.pressed = false; // mousedown state
5756
5757 return _this;
5758 }
5759 /**
5760 * @private
5761 * handle mouse events
5762 * @param {Object} ev
5763 */
5764
5765
5766 var _proto = MouseInput.prototype;
5767
5768 _proto.handler = function handler(ev) {
5769 var eventType = MOUSE_INPUT_MAP[ev.type]; // on start we want to have the left mouse button down
5770
5771 if (eventType & INPUT_START && ev.button === 0) {
5772 this.pressed = true;
5773 }
5774
5775 if (eventType & INPUT_MOVE && ev.which !== 1) {
5776 eventType = INPUT_END;
5777 } // mouse must be down
5778
5779
5780 if (!this.pressed) {
5781 return;
5782 }
5783
5784 if (eventType & INPUT_END) {
5785 this.pressed = false;
5786 }
5787
5788 this.callback(this.manager, eventType, {
5789 pointers: [ev],
5790 changedPointers: [ev],
5791 pointerType: INPUT_TYPE_MOUSE,
5792 srcEvent: ev
5793 });
5794 };
5795
5796 return MouseInput;
5797 }(Input);
5798 /**
5799 * @private
5800 * Combined touch and mouse input
5801 *
5802 * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
5803 * This because touch devices also emit mouse events while doing a touch.
5804 *
5805 * @constructor
5806 * @extends Input
5807 */
5808
5809
5810 var DEDUP_TIMEOUT = 2500;
5811 var DEDUP_DISTANCE = 25;
5812
5813 function setLastTouch(eventData) {
5814 var _eventData$changedPoi = eventData.changedPointers,
5815 touch = _eventData$changedPoi[0];
5816
5817 if (touch.identifier === this.primaryTouch) {
5818 var lastTouch = {
5819 x: touch.clientX,
5820 y: touch.clientY
5821 };
5822 var lts = this.lastTouches;
5823 this.lastTouches.push(lastTouch);
5824
5825 var removeLastTouch = function removeLastTouch() {
5826 var i = lts.indexOf(lastTouch);
5827
5828 if (i > -1) {
5829 lts.splice(i, 1);
5830 }
5831 };
5832
5833 setTimeout(removeLastTouch, DEDUP_TIMEOUT);
5834 }
5835 }
5836
5837 function recordTouches(eventType, eventData) {
5838 if (eventType & INPUT_START) {
5839 this.primaryTouch = eventData.changedPointers[0].identifier;
5840 setLastTouch.call(this, eventData);
5841 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
5842 setLastTouch.call(this, eventData);
5843 }
5844 }
5845
5846 function isSyntheticEvent(eventData) {
5847 var x = eventData.srcEvent.clientX;
5848 var y = eventData.srcEvent.clientY;
5849
5850 for (var i = 0; i < this.lastTouches.length; i++) {
5851 var t = this.lastTouches[i];
5852 var dx = Math.abs(x - t.x);
5853 var dy = Math.abs(y - t.y);
5854
5855 if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
5856 return true;
5857 }
5858 }
5859
5860 return false;
5861 }
5862
5863 var TouchMouseInput = /*#__PURE__*/function () {
5864 var TouchMouseInput = /*#__PURE__*/function (_Input) {
5865 _inheritsLoose(TouchMouseInput, _Input);
5866
5867 function TouchMouseInput(_manager, callback) {
5868 var _this;
5869
5870 _this = _Input.call(this, _manager, callback) || this;
5871
5872 _this.handler = function (manager, inputEvent, inputData) {
5873 var isTouch = inputData.pointerType === INPUT_TYPE_TOUCH;
5874 var isMouse = inputData.pointerType === INPUT_TYPE_MOUSE;
5875
5876 if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
5877 return;
5878 } // when we're in a touch event, record touches to de-dupe synthetic mouse event
5879
5880
5881 if (isTouch) {
5882 recordTouches.call(_assertThisInitialized$1(_assertThisInitialized$1(_this)), inputEvent, inputData);
5883 } else if (isMouse && isSyntheticEvent.call(_assertThisInitialized$1(_assertThisInitialized$1(_this)), inputData)) {
5884 return;
5885 }
5886
5887 _this.callback(manager, inputEvent, inputData);
5888 };
5889
5890 _this.touch = new TouchInput(_this.manager, _this.handler);
5891 _this.mouse = new MouseInput(_this.manager, _this.handler);
5892 _this.primaryTouch = null;
5893 _this.lastTouches = [];
5894 return _this;
5895 }
5896 /**
5897 * @private
5898 * handle mouse and touch events
5899 * @param {Hammer} manager
5900 * @param {String} inputEvent
5901 * @param {Object} inputData
5902 */
5903
5904
5905 var _proto = TouchMouseInput.prototype;
5906 /**
5907 * @private
5908 * remove the event listeners
5909 */
5910
5911 _proto.destroy = function destroy() {
5912 this.touch.destroy();
5913 this.mouse.destroy();
5914 };
5915
5916 return TouchMouseInput;
5917 }(Input);
5918
5919 return TouchMouseInput;
5920 }();
5921 /**
5922 * @private
5923 * create new input type manager
5924 * called by the Manager constructor
5925 * @param {Hammer} manager
5926 * @returns {Input}
5927 */
5928
5929
5930 function createInputInstance(manager) {
5931 var Type; // let inputClass = manager.options.inputClass;
5932
5933 var inputClass = manager.options.inputClass;
5934
5935 if (inputClass) {
5936 Type = inputClass;
5937 } else if (SUPPORT_POINTER_EVENTS) {
5938 Type = PointerEventInput;
5939 } else if (SUPPORT_ONLY_TOUCH) {
5940 Type = TouchInput;
5941 } else if (!SUPPORT_TOUCH) {
5942 Type = MouseInput;
5943 } else {
5944 Type = TouchMouseInput;
5945 }
5946
5947 return new Type(manager, inputHandler);
5948 }
5949 /**
5950 * @private
5951 * if the argument is an array, we want to execute the fn on each entry
5952 * if it aint an array we don't want to do a thing.
5953 * this is used by all the methods that accept a single and array argument.
5954 * @param {*|Array} arg
5955 * @param {String} fn
5956 * @param {Object} [context]
5957 * @returns {Boolean}
5958 */
5959
5960
5961 function invokeArrayArg(arg, fn, context) {
5962 if (Array.isArray(arg)) {
5963 each(arg, context[fn], context);
5964 return true;
5965 }
5966
5967 return false;
5968 }
5969
5970 var STATE_POSSIBLE = 1;
5971 var STATE_BEGAN = 2;
5972 var STATE_CHANGED = 4;
5973 var STATE_ENDED = 8;
5974 var STATE_RECOGNIZED = STATE_ENDED;
5975 var STATE_CANCELLED = 16;
5976 var STATE_FAILED = 32;
5977 /**
5978 * @private
5979 * get a unique id
5980 * @returns {number} uniqueId
5981 */
5982
5983 var _uniqueId = 1;
5984
5985 function uniqueId() {
5986 return _uniqueId++;
5987 }
5988 /**
5989 * @private
5990 * get a recognizer by name if it is bound to a manager
5991 * @param {Recognizer|String} otherRecognizer
5992 * @param {Recognizer} recognizer
5993 * @returns {Recognizer}
5994 */
5995
5996
5997 function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
5998 var manager = recognizer.manager;
5999
6000 if (manager) {
6001 return manager.get(otherRecognizer);
6002 }
6003
6004 return otherRecognizer;
6005 }
6006 /**
6007 * @private
6008 * get a usable string, used as event postfix
6009 * @param {constant} state
6010 * @returns {String} state
6011 */
6012
6013
6014 function stateStr(state) {
6015 if (state & STATE_CANCELLED) {
6016 return 'cancel';
6017 } else if (state & STATE_ENDED) {
6018 return 'end';
6019 } else if (state & STATE_CHANGED) {
6020 return 'move';
6021 } else if (state & STATE_BEGAN) {
6022 return 'start';
6023 }
6024
6025 return '';
6026 }
6027 /**
6028 * @private
6029 * Recognizer flow explained; *
6030 * All recognizers have the initial state of POSSIBLE when a input session starts.
6031 * The definition of a input session is from the first input until the last input, with all it's movement in it. *
6032 * Example session for mouse-input: mousedown -> mousemove -> mouseup
6033 *
6034 * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
6035 * which determines with state it should be.
6036 *
6037 * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
6038 * POSSIBLE to give it another change on the next cycle.
6039 *
6040 * Possible
6041 * |
6042 * +-----+---------------+
6043 * | |
6044 * +-----+-----+ |
6045 * | | |
6046 * Failed Cancelled |
6047 * +-------+------+
6048 * | |
6049 * Recognized Began
6050 * |
6051 * Changed
6052 * |
6053 * Ended/Recognized
6054 */
6055
6056 /**
6057 * @private
6058 * Recognizer
6059 * Every recognizer needs to extend from this class.
6060 * @constructor
6061 * @param {Object} options
6062 */
6063
6064
6065 var Recognizer = /*#__PURE__*/function () {
6066 function Recognizer(options) {
6067 if (options === void 0) {
6068 options = {};
6069 }
6070
6071 this.options = _extends({
6072 enable: true
6073 }, options);
6074 this.id = uniqueId();
6075 this.manager = null; // default is enable true
6076
6077 this.state = STATE_POSSIBLE;
6078 this.simultaneous = {};
6079 this.requireFail = [];
6080 }
6081 /**
6082 * @private
6083 * set options
6084 * @param {Object} options
6085 * @return {Recognizer}
6086 */
6087
6088
6089 var _proto = Recognizer.prototype;
6090
6091 _proto.set = function set(options) {
6092 assign$1(this.options, options); // also update the touchAction, in case something changed about the directions/enabled state
6093
6094 this.manager && this.manager.touchAction.update();
6095 return this;
6096 };
6097 /**
6098 * @private
6099 * recognize simultaneous with an other recognizer.
6100 * @param {Recognizer} otherRecognizer
6101 * @returns {Recognizer} this
6102 */
6103
6104
6105 _proto.recognizeWith = function recognizeWith(otherRecognizer) {
6106 if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
6107 return this;
6108 }
6109
6110 var simultaneous = this.simultaneous;
6111 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
6112
6113 if (!simultaneous[otherRecognizer.id]) {
6114 simultaneous[otherRecognizer.id] = otherRecognizer;
6115 otherRecognizer.recognizeWith(this);
6116 }
6117
6118 return this;
6119 };
6120 /**
6121 * @private
6122 * drop the simultaneous link. it doesnt remove the link on the other recognizer.
6123 * @param {Recognizer} otherRecognizer
6124 * @returns {Recognizer} this
6125 */
6126
6127
6128 _proto.dropRecognizeWith = function dropRecognizeWith(otherRecognizer) {
6129 if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
6130 return this;
6131 }
6132
6133 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
6134 delete this.simultaneous[otherRecognizer.id];
6135 return this;
6136 };
6137 /**
6138 * @private
6139 * recognizer can only run when an other is failing
6140 * @param {Recognizer} otherRecognizer
6141 * @returns {Recognizer} this
6142 */
6143
6144
6145 _proto.requireFailure = function requireFailure(otherRecognizer) {
6146 if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
6147 return this;
6148 }
6149
6150 var requireFail = this.requireFail;
6151 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
6152
6153 if (inArray(requireFail, otherRecognizer) === -1) {
6154 requireFail.push(otherRecognizer);
6155 otherRecognizer.requireFailure(this);
6156 }
6157
6158 return this;
6159 };
6160 /**
6161 * @private
6162 * drop the requireFailure link. it does not remove the link on the other recognizer.
6163 * @param {Recognizer} otherRecognizer
6164 * @returns {Recognizer} this
6165 */
6166
6167
6168 _proto.dropRequireFailure = function dropRequireFailure(otherRecognizer) {
6169 if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
6170 return this;
6171 }
6172
6173 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
6174 var index = inArray(this.requireFail, otherRecognizer);
6175
6176 if (index > -1) {
6177 this.requireFail.splice(index, 1);
6178 }
6179
6180 return this;
6181 };
6182 /**
6183 * @private
6184 * has require failures boolean
6185 * @returns {boolean}
6186 */
6187
6188
6189 _proto.hasRequireFailures = function hasRequireFailures() {
6190 return this.requireFail.length > 0;
6191 };
6192 /**
6193 * @private
6194 * if the recognizer can recognize simultaneous with an other recognizer
6195 * @param {Recognizer} otherRecognizer
6196 * @returns {Boolean}
6197 */
6198
6199
6200 _proto.canRecognizeWith = function canRecognizeWith(otherRecognizer) {
6201 return !!this.simultaneous[otherRecognizer.id];
6202 };
6203 /**
6204 * @private
6205 * You should use `tryEmit` instead of `emit` directly to check
6206 * that all the needed recognizers has failed before emitting.
6207 * @param {Object} input
6208 */
6209
6210
6211 _proto.emit = function emit(input) {
6212 var self = this;
6213 var state = this.state;
6214
6215 function emit(event) {
6216 self.manager.emit(event, input);
6217 } // 'panstart' and 'panmove'
6218
6219
6220 if (state < STATE_ENDED) {
6221 emit(self.options.event + stateStr(state));
6222 }
6223
6224 emit(self.options.event); // simple 'eventName' events
6225
6226 if (input.additionalEvent) {
6227 // additional event(panleft, panright, pinchin, pinchout...)
6228 emit(input.additionalEvent);
6229 } // panend and pancancel
6230
6231
6232 if (state >= STATE_ENDED) {
6233 emit(self.options.event + stateStr(state));
6234 }
6235 };
6236 /**
6237 * @private
6238 * Check that all the require failure recognizers has failed,
6239 * if true, it emits a gesture event,
6240 * otherwise, setup the state to FAILED.
6241 * @param {Object} input
6242 */
6243
6244
6245 _proto.tryEmit = function tryEmit(input) {
6246 if (this.canEmit()) {
6247 return this.emit(input);
6248 } // it's failing anyway
6249
6250
6251 this.state = STATE_FAILED;
6252 };
6253 /**
6254 * @private
6255 * can we emit?
6256 * @returns {boolean}
6257 */
6258
6259
6260 _proto.canEmit = function canEmit() {
6261 var i = 0;
6262
6263 while (i < this.requireFail.length) {
6264 if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
6265 return false;
6266 }
6267
6268 i++;
6269 }
6270
6271 return true;
6272 };
6273 /**
6274 * @private
6275 * update the recognizer
6276 * @param {Object} inputData
6277 */
6278
6279
6280 _proto.recognize = function recognize(inputData) {
6281 // make a new copy of the inputData
6282 // so we can change the inputData without messing up the other recognizers
6283 var inputDataClone = assign$1({}, inputData); // is is enabled and allow recognizing?
6284
6285 if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
6286 this.reset();
6287 this.state = STATE_FAILED;
6288 return;
6289 } // reset when we've reached the end
6290
6291
6292 if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
6293 this.state = STATE_POSSIBLE;
6294 }
6295
6296 this.state = this.process(inputDataClone); // the recognizer has recognized a gesture
6297 // so trigger an event
6298
6299 if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
6300 this.tryEmit(inputDataClone);
6301 }
6302 };
6303 /**
6304 * @private
6305 * return the state of the recognizer
6306 * the actual recognizing happens in this method
6307 * @virtual
6308 * @param {Object} inputData
6309 * @returns {constant} STATE
6310 */
6311
6312 /* jshint ignore:start */
6313
6314
6315 _proto.process = function process(inputData) {};
6316 /* jshint ignore:end */
6317
6318 /**
6319 * @private
6320 * return the preferred touch-action
6321 * @virtual
6322 * @returns {Array}
6323 */
6324
6325
6326 _proto.getTouchAction = function getTouchAction() {};
6327 /**
6328 * @private
6329 * called when the gesture isn't allowed to recognize
6330 * like when another is being recognized or it is disabled
6331 * @virtual
6332 */
6333
6334
6335 _proto.reset = function reset() {};
6336
6337 return Recognizer;
6338 }();
6339 /**
6340 * @private
6341 * A tap is recognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
6342 * between the given interval and position. The delay option can be used to recognize multi-taps without firing
6343 * a single tap.
6344 *
6345 * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
6346 * multi-taps being recognized.
6347 * @constructor
6348 * @extends Recognizer
6349 */
6350
6351
6352 var TapRecognizer = /*#__PURE__*/function (_Recognizer) {
6353 _inheritsLoose(TapRecognizer, _Recognizer);
6354
6355 function TapRecognizer(options) {
6356 var _this;
6357
6358 if (options === void 0) {
6359 options = {};
6360 }
6361
6362 _this = _Recognizer.call(this, _extends({
6363 event: 'tap',
6364 pointers: 1,
6365 taps: 1,
6366 interval: 300,
6367 // max time between the multi-tap taps
6368 time: 250,
6369 // max time of the pointer to be down (like finger on the screen)
6370 threshold: 9,
6371 // a minimal movement is ok, but keep it low
6372 posThreshold: 10
6373 }, options)) || this; // previous time and center,
6374 // used for tap counting
6375
6376 _this.pTime = false;
6377 _this.pCenter = false;
6378 _this._timer = null;
6379 _this._input = null;
6380 _this.count = 0;
6381 return _this;
6382 }
6383
6384 var _proto = TapRecognizer.prototype;
6385
6386 _proto.getTouchAction = function getTouchAction() {
6387 return [TOUCH_ACTION_MANIPULATION];
6388 };
6389
6390 _proto.process = function process(input) {
6391 var _this2 = this;
6392
6393 var options = this.options;
6394 var validPointers = input.pointers.length === options.pointers;
6395 var validMovement = input.distance < options.threshold;
6396 var validTouchTime = input.deltaTime < options.time;
6397 this.reset();
6398
6399 if (input.eventType & INPUT_START && this.count === 0) {
6400 return this.failTimeout();
6401 } // we only allow little movement
6402 // and we've reached an end event, so a tap is possible
6403
6404
6405 if (validMovement && validTouchTime && validPointers) {
6406 if (input.eventType !== INPUT_END) {
6407 return this.failTimeout();
6408 }
6409
6410 var validInterval = this.pTime ? input.timeStamp - this.pTime < options.interval : true;
6411 var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
6412 this.pTime = input.timeStamp;
6413 this.pCenter = input.center;
6414
6415 if (!validMultiTap || !validInterval) {
6416 this.count = 1;
6417 } else {
6418 this.count += 1;
6419 }
6420
6421 this._input = input; // if tap count matches we have recognized it,
6422 // else it has began recognizing...
6423
6424 var tapCount = this.count % options.taps;
6425
6426 if (tapCount === 0) {
6427 // no failing requirements, immediately trigger the tap event
6428 // or wait as long as the multitap interval to trigger
6429 if (!this.hasRequireFailures()) {
6430 return STATE_RECOGNIZED;
6431 } else {
6432 this._timer = setTimeout(function () {
6433 _this2.state = STATE_RECOGNIZED;
6434
6435 _this2.tryEmit();
6436 }, options.interval);
6437 return STATE_BEGAN;
6438 }
6439 }
6440 }
6441
6442 return STATE_FAILED;
6443 };
6444
6445 _proto.failTimeout = function failTimeout() {
6446 var _this3 = this;
6447
6448 this._timer = setTimeout(function () {
6449 _this3.state = STATE_FAILED;
6450 }, this.options.interval);
6451 return STATE_FAILED;
6452 };
6453
6454 _proto.reset = function reset() {
6455 clearTimeout(this._timer);
6456 };
6457
6458 _proto.emit = function emit() {
6459 if (this.state === STATE_RECOGNIZED) {
6460 this._input.tapCount = this.count;
6461 this.manager.emit(this.options.event, this._input);
6462 }
6463 };
6464
6465 return TapRecognizer;
6466 }(Recognizer);
6467 /**
6468 * @private
6469 * This recognizer is just used as a base for the simple attribute recognizers.
6470 * @constructor
6471 * @extends Recognizer
6472 */
6473
6474
6475 var AttrRecognizer = /*#__PURE__*/function (_Recognizer) {
6476 _inheritsLoose(AttrRecognizer, _Recognizer);
6477
6478 function AttrRecognizer(options) {
6479 if (options === void 0) {
6480 options = {};
6481 }
6482
6483 return _Recognizer.call(this, _extends({
6484 pointers: 1
6485 }, options)) || this;
6486 }
6487 /**
6488 * @private
6489 * Used to check if it the recognizer receives valid input, like input.distance > 10.
6490 * @memberof AttrRecognizer
6491 * @param {Object} input
6492 * @returns {Boolean} recognized
6493 */
6494
6495
6496 var _proto = AttrRecognizer.prototype;
6497
6498 _proto.attrTest = function attrTest(input) {
6499 var optionPointers = this.options.pointers;
6500 return optionPointers === 0 || input.pointers.length === optionPointers;
6501 };
6502 /**
6503 * @private
6504 * Process the input and return the state for the recognizer
6505 * @memberof AttrRecognizer
6506 * @param {Object} input
6507 * @returns {*} State
6508 */
6509
6510
6511 _proto.process = function process(input) {
6512 var state = this.state;
6513 var eventType = input.eventType;
6514 var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
6515 var isValid = this.attrTest(input); // on cancel input and we've recognized before, return STATE_CANCELLED
6516
6517 if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
6518 return state | STATE_CANCELLED;
6519 } else if (isRecognized || isValid) {
6520 if (eventType & INPUT_END) {
6521 return state | STATE_ENDED;
6522 } else if (!(state & STATE_BEGAN)) {
6523 return STATE_BEGAN;
6524 }
6525
6526 return state | STATE_CHANGED;
6527 }
6528
6529 return STATE_FAILED;
6530 };
6531
6532 return AttrRecognizer;
6533 }(Recognizer);
6534 /**
6535 * @private
6536 * direction cons to string
6537 * @param {constant} direction
6538 * @returns {String}
6539 */
6540
6541
6542 function directionStr(direction) {
6543 if (direction === DIRECTION_DOWN) {
6544 return 'down';
6545 } else if (direction === DIRECTION_UP) {
6546 return 'up';
6547 } else if (direction === DIRECTION_LEFT) {
6548 return 'left';
6549 } else if (direction === DIRECTION_RIGHT) {
6550 return 'right';
6551 }
6552
6553 return '';
6554 }
6555 /**
6556 * @private
6557 * Pan
6558 * Recognized when the pointer is down and moved in the allowed direction.
6559 * @constructor
6560 * @extends AttrRecognizer
6561 */
6562
6563
6564 var PanRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
6565 _inheritsLoose(PanRecognizer, _AttrRecognizer);
6566
6567 function PanRecognizer(options) {
6568 var _this;
6569
6570 if (options === void 0) {
6571 options = {};
6572 }
6573
6574 _this = _AttrRecognizer.call(this, _extends({
6575 event: 'pan',
6576 threshold: 10,
6577 pointers: 1,
6578 direction: DIRECTION_ALL
6579 }, options)) || this;
6580 _this.pX = null;
6581 _this.pY = null;
6582 return _this;
6583 }
6584
6585 var _proto = PanRecognizer.prototype;
6586
6587 _proto.getTouchAction = function getTouchAction() {
6588 var direction = this.options.direction;
6589 var actions = [];
6590
6591 if (direction & DIRECTION_HORIZONTAL) {
6592 actions.push(TOUCH_ACTION_PAN_Y);
6593 }
6594
6595 if (direction & DIRECTION_VERTICAL) {
6596 actions.push(TOUCH_ACTION_PAN_X);
6597 }
6598
6599 return actions;
6600 };
6601
6602 _proto.directionTest = function directionTest(input) {
6603 var options = this.options;
6604 var hasMoved = true;
6605 var distance = input.distance;
6606 var direction = input.direction;
6607 var x = input.deltaX;
6608 var y = input.deltaY; // lock to axis?
6609
6610 if (!(direction & options.direction)) {
6611 if (options.direction & DIRECTION_HORIZONTAL) {
6612 direction = x === 0 ? DIRECTION_NONE : x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
6613 hasMoved = x !== this.pX;
6614 distance = Math.abs(input.deltaX);
6615 } else {
6616 direction = y === 0 ? DIRECTION_NONE : y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
6617 hasMoved = y !== this.pY;
6618 distance = Math.abs(input.deltaY);
6619 }
6620 }
6621
6622 input.direction = direction;
6623 return hasMoved && distance > options.threshold && direction & options.direction;
6624 };
6625
6626 _proto.attrTest = function attrTest(input) {
6627 return AttrRecognizer.prototype.attrTest.call(this, input) && ( // replace with a super call
6628 this.state & STATE_BEGAN || !(this.state & STATE_BEGAN) && this.directionTest(input));
6629 };
6630
6631 _proto.emit = function emit(input) {
6632 this.pX = input.deltaX;
6633 this.pY = input.deltaY;
6634 var direction = directionStr(input.direction);
6635
6636 if (direction) {
6637 input.additionalEvent = this.options.event + direction;
6638 }
6639
6640 _AttrRecognizer.prototype.emit.call(this, input);
6641 };
6642
6643 return PanRecognizer;
6644 }(AttrRecognizer);
6645 /**
6646 * @private
6647 * Swipe
6648 * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
6649 * @constructor
6650 * @extends AttrRecognizer
6651 */
6652
6653
6654 var SwipeRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
6655 _inheritsLoose(SwipeRecognizer, _AttrRecognizer);
6656
6657 function SwipeRecognizer(options) {
6658 if (options === void 0) {
6659 options = {};
6660 }
6661
6662 return _AttrRecognizer.call(this, _extends({
6663 event: 'swipe',
6664 threshold: 10,
6665 velocity: 0.3,
6666 direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
6667 pointers: 1
6668 }, options)) || this;
6669 }
6670
6671 var _proto = SwipeRecognizer.prototype;
6672
6673 _proto.getTouchAction = function getTouchAction() {
6674 return PanRecognizer.prototype.getTouchAction.call(this);
6675 };
6676
6677 _proto.attrTest = function attrTest(input) {
6678 var direction = this.options.direction;
6679 var velocity;
6680
6681 if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
6682 velocity = input.overallVelocity;
6683 } else if (direction & DIRECTION_HORIZONTAL) {
6684 velocity = input.overallVelocityX;
6685 } else if (direction & DIRECTION_VERTICAL) {
6686 velocity = input.overallVelocityY;
6687 }
6688
6689 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;
6690 };
6691
6692 _proto.emit = function emit(input) {
6693 var direction = directionStr(input.offsetDirection);
6694
6695 if (direction) {
6696 this.manager.emit(this.options.event + direction, input);
6697 }
6698
6699 this.manager.emit(this.options.event, input);
6700 };
6701
6702 return SwipeRecognizer;
6703 }(AttrRecognizer);
6704 /**
6705 * @private
6706 * Pinch
6707 * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
6708 * @constructor
6709 * @extends AttrRecognizer
6710 */
6711
6712
6713 var PinchRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
6714 _inheritsLoose(PinchRecognizer, _AttrRecognizer);
6715
6716 function PinchRecognizer(options) {
6717 if (options === void 0) {
6718 options = {};
6719 }
6720
6721 return _AttrRecognizer.call(this, _extends({
6722 event: 'pinch',
6723 threshold: 0,
6724 pointers: 2
6725 }, options)) || this;
6726 }
6727
6728 var _proto = PinchRecognizer.prototype;
6729
6730 _proto.getTouchAction = function getTouchAction() {
6731 return [TOUCH_ACTION_NONE];
6732 };
6733
6734 _proto.attrTest = function attrTest(input) {
6735 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
6736 };
6737
6738 _proto.emit = function emit(input) {
6739 if (input.scale !== 1) {
6740 var inOut = input.scale < 1 ? 'in' : 'out';
6741 input.additionalEvent = this.options.event + inOut;
6742 }
6743
6744 _AttrRecognizer.prototype.emit.call(this, input);
6745 };
6746
6747 return PinchRecognizer;
6748 }(AttrRecognizer);
6749 /**
6750 * @private
6751 * Rotate
6752 * Recognized when two or more pointer are moving in a circular motion.
6753 * @constructor
6754 * @extends AttrRecognizer
6755 */
6756
6757
6758 var RotateRecognizer = /*#__PURE__*/function (_AttrRecognizer) {
6759 _inheritsLoose(RotateRecognizer, _AttrRecognizer);
6760
6761 function RotateRecognizer(options) {
6762 if (options === void 0) {
6763 options = {};
6764 }
6765
6766 return _AttrRecognizer.call(this, _extends({
6767 event: 'rotate',
6768 threshold: 0,
6769 pointers: 2
6770 }, options)) || this;
6771 }
6772
6773 var _proto = RotateRecognizer.prototype;
6774
6775 _proto.getTouchAction = function getTouchAction() {
6776 return [TOUCH_ACTION_NONE];
6777 };
6778
6779 _proto.attrTest = function attrTest(input) {
6780 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
6781 };
6782
6783 return RotateRecognizer;
6784 }(AttrRecognizer);
6785 /**
6786 * @private
6787 * Press
6788 * Recognized when the pointer is down for x ms without any movement.
6789 * @constructor
6790 * @extends Recognizer
6791 */
6792
6793
6794 var PressRecognizer = /*#__PURE__*/function (_Recognizer) {
6795 _inheritsLoose(PressRecognizer, _Recognizer);
6796
6797 function PressRecognizer(options) {
6798 var _this;
6799
6800 if (options === void 0) {
6801 options = {};
6802 }
6803
6804 _this = _Recognizer.call(this, _extends({
6805 event: 'press',
6806 pointers: 1,
6807 time: 251,
6808 // minimal time of the pointer to be pressed
6809 threshold: 9
6810 }, options)) || this;
6811 _this._timer = null;
6812 _this._input = null;
6813 return _this;
6814 }
6815
6816 var _proto = PressRecognizer.prototype;
6817
6818 _proto.getTouchAction = function getTouchAction() {
6819 return [TOUCH_ACTION_AUTO];
6820 };
6821
6822 _proto.process = function process(input) {
6823 var _this2 = this;
6824
6825 var options = this.options;
6826 var validPointers = input.pointers.length === options.pointers;
6827 var validMovement = input.distance < options.threshold;
6828 var validTime = input.deltaTime > options.time;
6829 this._input = input; // we only allow little movement
6830 // and we've reached an end event, so a tap is possible
6831
6832 if (!validMovement || !validPointers || input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime) {
6833 this.reset();
6834 } else if (input.eventType & INPUT_START) {
6835 this.reset();
6836 this._timer = setTimeout(function () {
6837 _this2.state = STATE_RECOGNIZED;
6838
6839 _this2.tryEmit();
6840 }, options.time);
6841 } else if (input.eventType & INPUT_END) {
6842 return STATE_RECOGNIZED;
6843 }
6844
6845 return STATE_FAILED;
6846 };
6847
6848 _proto.reset = function reset() {
6849 clearTimeout(this._timer);
6850 };
6851
6852 _proto.emit = function emit(input) {
6853 if (this.state !== STATE_RECOGNIZED) {
6854 return;
6855 }
6856
6857 if (input && input.eventType & INPUT_END) {
6858 this.manager.emit(this.options.event + "up", input);
6859 } else {
6860 this._input.timeStamp = now();
6861 this.manager.emit(this.options.event, this._input);
6862 }
6863 };
6864
6865 return PressRecognizer;
6866 }(Recognizer);
6867
6868 var defaults = {
6869 /**
6870 * @private
6871 * set if DOM events are being triggered.
6872 * But this is slower and unused by simple implementations, so disabled by default.
6873 * @type {Boolean}
6874 * @default false
6875 */
6876 domEvents: false,
6877
6878 /**
6879 * @private
6880 * The value for the touchAction property/fallback.
6881 * When set to `compute` it will magically set the correct value based on the added recognizers.
6882 * @type {String}
6883 * @default compute
6884 */
6885 touchAction: TOUCH_ACTION_COMPUTE,
6886
6887 /**
6888 * @private
6889 * @type {Boolean}
6890 * @default true
6891 */
6892 enable: true,
6893
6894 /**
6895 * @private
6896 * EXPERIMENTAL FEATURE -- can be removed/changed
6897 * Change the parent input target element.
6898 * If Null, then it is being set the to main element.
6899 * @type {Null|EventTarget}
6900 * @default null
6901 */
6902 inputTarget: null,
6903
6904 /**
6905 * @private
6906 * force an input class
6907 * @type {Null|Function}
6908 * @default null
6909 */
6910 inputClass: null,
6911
6912 /**
6913 * @private
6914 * Some CSS properties can be used to improve the working of Hammer.
6915 * Add them to this method and they will be set when creating a new Manager.
6916 * @namespace
6917 */
6918 cssProps: {
6919 /**
6920 * @private
6921 * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
6922 * @type {String}
6923 * @default 'none'
6924 */
6925 userSelect: "none",
6926
6927 /**
6928 * @private
6929 * Disable the Windows Phone grippers when pressing an element.
6930 * @type {String}
6931 * @default 'none'
6932 */
6933 touchSelect: "none",
6934
6935 /**
6936 * @private
6937 * Disables the default callout shown when you touch and hold a touch target.
6938 * On iOS, when you touch and hold a touch target such as a link, Safari displays
6939 * a callout containing information about the link. This property allows you to disable that callout.
6940 * @type {String}
6941 * @default 'none'
6942 */
6943 touchCallout: "none",
6944
6945 /**
6946 * @private
6947 * Specifies whether zooming is enabled. Used by IE10>
6948 * @type {String}
6949 * @default 'none'
6950 */
6951 contentZooming: "none",
6952
6953 /**
6954 * @private
6955 * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
6956 * @type {String}
6957 * @default 'none'
6958 */
6959 userDrag: "none",
6960
6961 /**
6962 * @private
6963 * Overrides the highlight color shown when the user taps a link or a JavaScript
6964 * clickable element in iOS. This property obeys the alpha value, if specified.
6965 * @type {String}
6966 * @default 'rgba(0,0,0,0)'
6967 */
6968 tapHighlightColor: "rgba(0,0,0,0)"
6969 }
6970 };
6971 /**
6972 * @private
6973 * Default recognizer setup when calling `Hammer()`
6974 * When creating a new Manager these will be skipped.
6975 * This is separated with other defaults because of tree-shaking.
6976 * @type {Array}
6977 */
6978
6979 var preset = [[RotateRecognizer, {
6980 enable: false
6981 }], [PinchRecognizer, {
6982 enable: false
6983 }, ['rotate']], [SwipeRecognizer, {
6984 direction: DIRECTION_HORIZONTAL
6985 }], [PanRecognizer, {
6986 direction: DIRECTION_HORIZONTAL
6987 }, ['swipe']], [TapRecognizer], [TapRecognizer, {
6988 event: 'doubletap',
6989 taps: 2
6990 }, ['tap']], [PressRecognizer]];
6991 var STOP = 1;
6992 var FORCED_STOP = 2;
6993 /**
6994 * @private
6995 * add/remove the css properties as defined in manager.options.cssProps
6996 * @param {Manager} manager
6997 * @param {Boolean} add
6998 */
6999
7000 function toggleCssProps(manager, add) {
7001 var element = manager.element;
7002
7003 if (!element.style) {
7004 return;
7005 }
7006
7007 var prop;
7008 each(manager.options.cssProps, function (value, name) {
7009 prop = prefixed(element.style, name);
7010
7011 if (add) {
7012 manager.oldCssProps[prop] = element.style[prop];
7013 element.style[prop] = value;
7014 } else {
7015 element.style[prop] = manager.oldCssProps[prop] || "";
7016 }
7017 });
7018
7019 if (!add) {
7020 manager.oldCssProps = {};
7021 }
7022 }
7023 /**
7024 * @private
7025 * trigger dom event
7026 * @param {String} event
7027 * @param {Object} data
7028 */
7029
7030
7031 function triggerDomEvent(event, data) {
7032 var gestureEvent = document.createEvent("Event");
7033 gestureEvent.initEvent(event, true, true);
7034 gestureEvent.gesture = data;
7035 data.target.dispatchEvent(gestureEvent);
7036 }
7037 /**
7038 * @private
7039 * Manager
7040 * @param {HTMLElement} element
7041 * @param {Object} [options]
7042 * @constructor
7043 */
7044
7045
7046 var Manager = /*#__PURE__*/function () {
7047 function Manager(element, options) {
7048 var _this = this;
7049
7050 this.options = assign$1({}, defaults, options || {});
7051 this.options.inputTarget = this.options.inputTarget || element;
7052 this.handlers = {};
7053 this.session = {};
7054 this.recognizers = [];
7055 this.oldCssProps = {};
7056 this.element = element;
7057 this.input = createInputInstance(this);
7058 this.touchAction = new TouchAction(this, this.options.touchAction);
7059 toggleCssProps(this, true);
7060 each(this.options.recognizers, function (item) {
7061 var recognizer = _this.add(new item[0](item[1]));
7062
7063 item[2] && recognizer.recognizeWith(item[2]);
7064 item[3] && recognizer.requireFailure(item[3]);
7065 }, this);
7066 }
7067 /**
7068 * @private
7069 * set options
7070 * @param {Object} options
7071 * @returns {Manager}
7072 */
7073
7074
7075 var _proto = Manager.prototype;
7076
7077 _proto.set = function set(options) {
7078 assign$1(this.options, options); // Options that need a little more setup
7079
7080 if (options.touchAction) {
7081 this.touchAction.update();
7082 }
7083
7084 if (options.inputTarget) {
7085 // Clean up existing event listeners and reinitialize
7086 this.input.destroy();
7087 this.input.target = options.inputTarget;
7088 this.input.init();
7089 }
7090
7091 return this;
7092 };
7093 /**
7094 * @private
7095 * stop recognizing for this session.
7096 * This session will be discarded, when a new [input]start event is fired.
7097 * When forced, the recognizer cycle is stopped immediately.
7098 * @param {Boolean} [force]
7099 */
7100
7101
7102 _proto.stop = function stop(force) {
7103 this.session.stopped = force ? FORCED_STOP : STOP;
7104 };
7105 /**
7106 * @private
7107 * run the recognizers!
7108 * called by the inputHandler function on every movement of the pointers (touches)
7109 * it walks through all the recognizers and tries to detect the gesture that is being made
7110 * @param {Object} inputData
7111 */
7112
7113
7114 _proto.recognize = function recognize(inputData) {
7115 var session = this.session;
7116
7117 if (session.stopped) {
7118 return;
7119 } // run the touch-action polyfill
7120
7121
7122 this.touchAction.preventDefaults(inputData);
7123 var recognizer;
7124 var recognizers = this.recognizers; // this holds the recognizer that is being recognized.
7125 // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
7126 // if no recognizer is detecting a thing, it is set to `null`
7127
7128 var curRecognizer = session.curRecognizer; // reset when the last recognizer is recognized
7129 // or when we're in a new session
7130
7131 if (!curRecognizer || curRecognizer && curRecognizer.state & STATE_RECOGNIZED) {
7132 session.curRecognizer = null;
7133 curRecognizer = null;
7134 }
7135
7136 var i = 0;
7137
7138 while (i < recognizers.length) {
7139 recognizer = recognizers[i]; // find out if we are allowed try to recognize the input for this one.
7140 // 1. allow if the session is NOT forced stopped (see the .stop() method)
7141 // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
7142 // that is being recognized.
7143 // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
7144 // this can be setup with the `recognizeWith()` method on the recognizer.
7145
7146 if (session.stopped !== FORCED_STOP && ( // 1
7147 !curRecognizer || recognizer === curRecognizer || // 2
7148 recognizer.canRecognizeWith(curRecognizer))) {
7149 // 3
7150 recognizer.recognize(inputData);
7151 } else {
7152 recognizer.reset();
7153 } // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
7154 // current active recognizer. but only if we don't already have an active recognizer
7155
7156
7157 if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
7158 session.curRecognizer = recognizer;
7159 curRecognizer = recognizer;
7160 }
7161
7162 i++;
7163 }
7164 };
7165 /**
7166 * @private
7167 * get a recognizer by its event name.
7168 * @param {Recognizer|String} recognizer
7169 * @returns {Recognizer|Null}
7170 */
7171
7172
7173 _proto.get = function get(recognizer) {
7174 if (recognizer instanceof Recognizer) {
7175 return recognizer;
7176 }
7177
7178 var recognizers = this.recognizers;
7179
7180 for (var i = 0; i < recognizers.length; i++) {
7181 if (recognizers[i].options.event === recognizer) {
7182 return recognizers[i];
7183 }
7184 }
7185
7186 return null;
7187 };
7188 /**
7189 * @private add a recognizer to the manager
7190 * existing recognizers with the same event name will be removed
7191 * @param {Recognizer} recognizer
7192 * @returns {Recognizer|Manager}
7193 */
7194
7195
7196 _proto.add = function add(recognizer) {
7197 if (invokeArrayArg(recognizer, "add", this)) {
7198 return this;
7199 } // remove existing
7200
7201
7202 var existing = this.get(recognizer.options.event);
7203
7204 if (existing) {
7205 this.remove(existing);
7206 }
7207
7208 this.recognizers.push(recognizer);
7209 recognizer.manager = this;
7210 this.touchAction.update();
7211 return recognizer;
7212 };
7213 /**
7214 * @private
7215 * remove a recognizer by name or instance
7216 * @param {Recognizer|String} recognizer
7217 * @returns {Manager}
7218 */
7219
7220
7221 _proto.remove = function remove(recognizer) {
7222 if (invokeArrayArg(recognizer, "remove", this)) {
7223 return this;
7224 }
7225
7226 var targetRecognizer = this.get(recognizer); // let's make sure this recognizer exists
7227
7228 if (recognizer) {
7229 var recognizers = this.recognizers;
7230 var index = inArray(recognizers, targetRecognizer);
7231
7232 if (index !== -1) {
7233 recognizers.splice(index, 1);
7234 this.touchAction.update();
7235 }
7236 }
7237
7238 return this;
7239 };
7240 /**
7241 * @private
7242 * bind event
7243 * @param {String} events
7244 * @param {Function} handler
7245 * @returns {EventEmitter} this
7246 */
7247
7248
7249 _proto.on = function on(events, handler) {
7250 if (events === undefined || handler === undefined) {
7251 return this;
7252 }
7253
7254 var handlers = this.handlers;
7255 each(splitStr(events), function (event) {
7256 handlers[event] = handlers[event] || [];
7257 handlers[event].push(handler);
7258 });
7259 return this;
7260 };
7261 /**
7262 * @private unbind event, leave emit blank to remove all handlers
7263 * @param {String} events
7264 * @param {Function} [handler]
7265 * @returns {EventEmitter} this
7266 */
7267
7268
7269 _proto.off = function off(events, handler) {
7270 if (events === undefined) {
7271 return this;
7272 }
7273
7274 var handlers = this.handlers;
7275 each(splitStr(events), function (event) {
7276 if (!handler) {
7277 delete handlers[event];
7278 } else {
7279 handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
7280 }
7281 });
7282 return this;
7283 };
7284 /**
7285 * @private emit event to the listeners
7286 * @param {String} event
7287 * @param {Object} data
7288 */
7289
7290
7291 _proto.emit = function emit(event, data) {
7292 // we also want to trigger dom events
7293 if (this.options.domEvents) {
7294 triggerDomEvent(event, data);
7295 } // no handlers, so skip it all
7296
7297
7298 var handlers = this.handlers[event] && this.handlers[event].slice();
7299
7300 if (!handlers || !handlers.length) {
7301 return;
7302 }
7303
7304 data.type = event;
7305
7306 data.preventDefault = function () {
7307 data.srcEvent.preventDefault();
7308 };
7309
7310 var i = 0;
7311
7312 while (i < handlers.length) {
7313 handlers[i](data);
7314 i++;
7315 }
7316 };
7317 /**
7318 * @private
7319 * destroy the manager and unbinds all events
7320 * it doesn't unbind dom events, that is the user own responsibility
7321 */
7322
7323
7324 _proto.destroy = function destroy() {
7325 this.element && toggleCssProps(this, false);
7326 this.handlers = {};
7327 this.session = {};
7328 this.input.destroy();
7329 this.element = null;
7330 };
7331
7332 return Manager;
7333 }();
7334
7335 var SINGLE_TOUCH_INPUT_MAP = {
7336 touchstart: INPUT_START,
7337 touchmove: INPUT_MOVE,
7338 touchend: INPUT_END,
7339 touchcancel: INPUT_CANCEL
7340 };
7341 var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
7342 var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
7343 /**
7344 * @private
7345 * Touch events input
7346 * @constructor
7347 * @extends Input
7348 */
7349
7350 var SingleTouchInput = /*#__PURE__*/function (_Input) {
7351 _inheritsLoose(SingleTouchInput, _Input);
7352
7353 function SingleTouchInput() {
7354 var _this;
7355
7356 var proto = SingleTouchInput.prototype;
7357 proto.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
7358 proto.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
7359 _this = _Input.apply(this, arguments) || this;
7360 _this.started = false;
7361 return _this;
7362 }
7363
7364 var _proto = SingleTouchInput.prototype;
7365
7366 _proto.handler = function handler(ev) {
7367 var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; // should we handle the touch events?
7368
7369 if (type === INPUT_START) {
7370 this.started = true;
7371 }
7372
7373 if (!this.started) {
7374 return;
7375 }
7376
7377 var touches = normalizeSingleTouches.call(this, ev, type); // when done, reset the started state
7378
7379 if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
7380 this.started = false;
7381 }
7382
7383 this.callback(this.manager, type, {
7384 pointers: touches[0],
7385 changedPointers: touches[1],
7386 pointerType: INPUT_TYPE_TOUCH,
7387 srcEvent: ev
7388 });
7389 };
7390
7391 return SingleTouchInput;
7392 }(Input);
7393
7394 function normalizeSingleTouches(ev, type) {
7395 var all = toArray$1(ev.touches);
7396 var changed = toArray$1(ev.changedTouches);
7397
7398 if (type & (INPUT_END | INPUT_CANCEL)) {
7399 all = uniqueArray(all.concat(changed), 'identifier', true);
7400 }
7401
7402 return [all, changed];
7403 }
7404 /**
7405 * @private
7406 * wrap a method with a deprecation warning and stack trace
7407 * @param {Function} method
7408 * @param {String} name
7409 * @param {String} message
7410 * @returns {Function} A new function wrapping the supplied method.
7411 */
7412
7413
7414 function deprecate(method, name, message) {
7415 var deprecationMessage = "DEPRECATED METHOD: " + name + "\n" + message + " AT \n";
7416 return function () {
7417 var e = new Error('get-stack-trace');
7418 var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '').replace(/^\s+at\s+/gm, '').replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
7419 var log = window.console && (window.console.warn || window.console.log);
7420
7421 if (log) {
7422 log.call(window.console, deprecationMessage, stack);
7423 }
7424
7425 return method.apply(this, arguments);
7426 };
7427 }
7428 /**
7429 * @private
7430 * extend object.
7431 * means that properties in dest will be overwritten by the ones in src.
7432 * @param {Object} dest
7433 * @param {Object} src
7434 * @param {Boolean} [merge=false]
7435 * @returns {Object} dest
7436 */
7437
7438
7439 var extend$1 = deprecate(function (dest, src, merge) {
7440 var keys = Object.keys(src);
7441 var i = 0;
7442
7443 while (i < keys.length) {
7444 if (!merge || merge && dest[keys[i]] === undefined) {
7445 dest[keys[i]] = src[keys[i]];
7446 }
7447
7448 i++;
7449 }
7450
7451 return dest;
7452 }, 'extend', 'Use `assign`.');
7453 /**
7454 * @private
7455 * merge the values from src in the dest.
7456 * means that properties that exist in dest will not be overwritten by src
7457 * @param {Object} dest
7458 * @param {Object} src
7459 * @returns {Object} dest
7460 */
7461
7462 var merge$2 = deprecate(function (dest, src) {
7463 return extend$1(dest, src, true);
7464 }, 'merge', 'Use `assign`.');
7465 /**
7466 * @private
7467 * simple class inheritance
7468 * @param {Function} child
7469 * @param {Function} base
7470 * @param {Object} [properties]
7471 */
7472
7473 function inherit(child, base, properties) {
7474 var baseP = base.prototype;
7475 var childP;
7476 childP = child.prototype = Object.create(baseP);
7477 childP.constructor = child;
7478 childP._super = baseP;
7479
7480 if (properties) {
7481 assign$1(childP, properties);
7482 }
7483 }
7484 /**
7485 * @private
7486 * simple function bind
7487 * @param {Function} fn
7488 * @param {Object} context
7489 * @returns {Function}
7490 */
7491
7492
7493 function bindFn(fn, context) {
7494 return function boundFn() {
7495 return fn.apply(context, arguments);
7496 };
7497 }
7498 /**
7499 * @private
7500 * Simple way to create a manager with a default set of recognizers.
7501 * @param {HTMLElement} element
7502 * @param {Object} [options]
7503 * @constructor
7504 */
7505
7506
7507 var Hammer$2 = /*#__PURE__*/function () {
7508 var Hammer =
7509 /**
7510 * @private
7511 * @const {string}
7512 */
7513 function Hammer(element, options) {
7514 if (options === void 0) {
7515 options = {};
7516 }
7517
7518 return new Manager(element, _extends({
7519 recognizers: preset.concat()
7520 }, options));
7521 };
7522
7523 Hammer.VERSION = "2.0.17-rc";
7524 Hammer.DIRECTION_ALL = DIRECTION_ALL;
7525 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
7526 Hammer.DIRECTION_LEFT = DIRECTION_LEFT;
7527 Hammer.DIRECTION_RIGHT = DIRECTION_RIGHT;
7528 Hammer.DIRECTION_UP = DIRECTION_UP;
7529 Hammer.DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL;
7530 Hammer.DIRECTION_VERTICAL = DIRECTION_VERTICAL;
7531 Hammer.DIRECTION_NONE = DIRECTION_NONE;
7532 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
7533 Hammer.INPUT_START = INPUT_START;
7534 Hammer.INPUT_MOVE = INPUT_MOVE;
7535 Hammer.INPUT_END = INPUT_END;
7536 Hammer.INPUT_CANCEL = INPUT_CANCEL;
7537 Hammer.STATE_POSSIBLE = STATE_POSSIBLE;
7538 Hammer.STATE_BEGAN = STATE_BEGAN;
7539 Hammer.STATE_CHANGED = STATE_CHANGED;
7540 Hammer.STATE_ENDED = STATE_ENDED;
7541 Hammer.STATE_RECOGNIZED = STATE_RECOGNIZED;
7542 Hammer.STATE_CANCELLED = STATE_CANCELLED;
7543 Hammer.STATE_FAILED = STATE_FAILED;
7544 Hammer.Manager = Manager;
7545 Hammer.Input = Input;
7546 Hammer.TouchAction = TouchAction;
7547 Hammer.TouchInput = TouchInput;
7548 Hammer.MouseInput = MouseInput;
7549 Hammer.PointerEventInput = PointerEventInput;
7550 Hammer.TouchMouseInput = TouchMouseInput;
7551 Hammer.SingleTouchInput = SingleTouchInput;
7552 Hammer.Recognizer = Recognizer;
7553 Hammer.AttrRecognizer = AttrRecognizer;
7554 Hammer.Tap = TapRecognizer;
7555 Hammer.Pan = PanRecognizer;
7556 Hammer.Swipe = SwipeRecognizer;
7557 Hammer.Pinch = PinchRecognizer;
7558 Hammer.Rotate = RotateRecognizer;
7559 Hammer.Press = PressRecognizer;
7560 Hammer.on = addEventListeners;
7561 Hammer.off = removeEventListeners;
7562 Hammer.each = each;
7563 Hammer.merge = merge$2;
7564 Hammer.extend = extend$1;
7565 Hammer.bindFn = bindFn;
7566 Hammer.assign = assign$1;
7567 Hammer.inherit = inherit;
7568 Hammer.bindFn = bindFn;
7569 Hammer.prefixed = prefixed;
7570 Hammer.toArray = toArray$1;
7571 Hammer.inArray = inArray;
7572 Hammer.uniqueArray = uniqueArray;
7573 Hammer.splitStr = splitStr;
7574 Hammer.boolOrFn = boolOrFn;
7575 Hammer.hasParent = hasParent$1;
7576 Hammer.addEventListeners = addEventListeners;
7577 Hammer.removeEventListeners = removeEventListeners;
7578 Hammer.defaults = assign$1({}, defaults, {
7579 preset: preset
7580 });
7581 return Hammer;
7582 }(); // style loader but by script tag, not by the loader.
7583 var RealHammer = Hammer$2;
7584
7585 function ownKeys$5(object, enumerableOnly) { var keys = keys$4(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); enumerableOnly && (symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$3(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
7586
7587 function _objectSpread$5(target) { for (var i = 1; i < arguments.length; i++) { var _context22, _context23; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? forEach$2(_context22 = ownKeys$5(Object(source), !0)).call(_context22, function (key) { _defineProperty(target, key, source[key]); }) : getOwnPropertyDescriptors ? defineProperties(target, getOwnPropertyDescriptors(source)) : forEach$2(_context23 = ownKeys$5(Object(source))).call(_context23, function (key) { defineProperty$6(target, key, getOwnPropertyDescriptor$3(source, key)); }); } return target; }
7588
7589 function _createForOfIteratorHelper$8(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$2(o) || (it = _unsupportedIterableToArray$8(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
7590
7591 function _unsupportedIterableToArray$8(o, minLen) { var _context21; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$8(o, minLen); var n = slice(_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$3(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$8(o, minLen); }
7592
7593 function _arrayLikeToArray$8(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
7594 /**
7595 * Use this symbol to delete properies in deepObjectAssign.
7596 */
7597
7598 var DELETE = symbol("DELETE");
7599 /**
7600 * Pure version of deepObjectAssign, it doesn't modify any of it's arguments.
7601 *
7602 * @param base - The base object that fullfils the whole interface T.
7603 * @param updates - Updates that may change or delete props.
7604 * @returns A brand new instance with all the supplied objects deeply merged.
7605 */
7606
7607
7608 function pureDeepObjectAssign(base) {
7609 var _context;
7610
7611 for (var _len = arguments.length, updates = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
7612 updates[_key - 1] = arguments[_key];
7613 }
7614
7615 return deepObjectAssign.apply(void 0, concat(_context = [{}, base]).call(_context, updates));
7616 }
7617 /**
7618 * Deep version of object assign with additional deleting by the DELETE symbol.
7619 *
7620 * @param values - Objects to be deeply merged.
7621 * @returns The first object from values.
7622 */
7623
7624
7625 function deepObjectAssign() {
7626 var merged = deepObjectAssignNonentry.apply(void 0, arguments);
7627 stripDelete(merged);
7628 return merged;
7629 }
7630 /**
7631 * Deep version of object assign with additional deleting by the DELETE symbol.
7632 *
7633 * @remarks
7634 * This doesn't strip the DELETE symbols so they may end up in the final object.
7635 * @param values - Objects to be deeply merged.
7636 * @returns The first object from values.
7637 */
7638
7639
7640 function deepObjectAssignNonentry() {
7641 for (var _len2 = arguments.length, values = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
7642 values[_key2] = arguments[_key2];
7643 }
7644
7645 if (values.length < 2) {
7646 return values[0];
7647 } else if (values.length > 2) {
7648 var _context2;
7649
7650 return deepObjectAssignNonentry.apply(void 0, concat(_context2 = [deepObjectAssign(values[0], values[1])]).call(_context2, _toConsumableArray(slice(values).call(values, 2))));
7651 }
7652
7653 var a = values[0];
7654 var b = values[1];
7655
7656 var _iterator = _createForOfIteratorHelper$8(ownKeys$6(b)),
7657 _step;
7658
7659 try {
7660 for (_iterator.s(); !(_step = _iterator.n()).done;) {
7661 var prop = _step.value;
7662 if (!Object.prototype.propertyIsEnumerable.call(b, prop)) ;else if (b[prop] === DELETE) {
7663 delete a[prop];
7664 } else if (a[prop] !== null && b[prop] !== null && _typeof(a[prop]) === "object" && _typeof(b[prop]) === "object" && !isArray$2(a[prop]) && !isArray$2(b[prop])) {
7665 a[prop] = deepObjectAssignNonentry(a[prop], b[prop]);
7666 } else {
7667 a[prop] = clone(b[prop]);
7668 }
7669 }
7670 } catch (err) {
7671 _iterator.e(err);
7672 } finally {
7673 _iterator.f();
7674 }
7675
7676 return a;
7677 }
7678 /**
7679 * Deep clone given object or array. In case of primitive simply return.
7680 *
7681 * @param a - Anything.
7682 * @returns Deep cloned object/array or unchanged a.
7683 */
7684
7685
7686 function clone(a) {
7687 if (isArray$2(a)) {
7688 return map$3(a).call(a, function (value) {
7689 return clone(value);
7690 });
7691 } else if (_typeof(a) === "object" && a !== null) {
7692 return deepObjectAssignNonentry({}, a);
7693 } else {
7694 return a;
7695 }
7696 }
7697 /**
7698 * Strip DELETE from given object.
7699 *
7700 * @param a - Object which may contain DELETE but won't after this is executed.
7701 */
7702
7703
7704 function stripDelete(a) {
7705 for (var _i = 0, _Object$keys = keys$4(a); _i < _Object$keys.length; _i++) {
7706 var prop = _Object$keys[_i];
7707
7708 if (a[prop] === DELETE) {
7709 delete a[prop];
7710 } else if (_typeof(a[prop]) === "object" && a[prop] !== null) {
7711 stripDelete(a[prop]);
7712 }
7713 }
7714 }
7715 /**
7716 * Seedable, fast and reasonably good (not crypto but more than okay for our
7717 * needs) random number generator.
7718 *
7719 * @remarks
7720 * Adapted from {@link https://web.archive.org/web/20110429100736/http://baagoe.com:80/en/RandomMusings/javascript}.
7721 * Original algorithm created by Johannes Baagøe \<baagoe\@baagoe.com\> in 2010.
7722 */
7723
7724 /**
7725 * Create a seeded pseudo random generator based on Alea by Johannes Baagøe.
7726 *
7727 * @param seed - All supplied arguments will be used as a seed. In case nothing
7728 * is supplied the current time will be used to seed the generator.
7729 * @returns A ready to use seeded generator.
7730 */
7731
7732
7733 function Alea() {
7734 for (var _len3 = arguments.length, seed = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
7735 seed[_key3] = arguments[_key3];
7736 }
7737
7738 return AleaImplementation(seed.length ? seed : [now$1()]);
7739 }
7740 /**
7741 * An implementation of [[Alea]] without user input validation.
7742 *
7743 * @param seed - The data that will be used to seed the generator.
7744 * @returns A ready to use seeded generator.
7745 */
7746
7747
7748 function AleaImplementation(seed) {
7749 var _mashSeed = mashSeed(seed),
7750 _mashSeed2 = _slicedToArray(_mashSeed, 3),
7751 s0 = _mashSeed2[0],
7752 s1 = _mashSeed2[1],
7753 s2 = _mashSeed2[2];
7754
7755 var c = 1;
7756
7757 var random = function random() {
7758 var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
7759
7760 s0 = s1;
7761 s1 = s2;
7762 return s2 = t - (c = t | 0);
7763 };
7764
7765 random.uint32 = function () {
7766 return random() * 0x100000000;
7767 }; // 2^32
7768
7769
7770 random.fract53 = function () {
7771 return random() + (random() * 0x200000 | 0) * 1.1102230246251565e-16;
7772 }; // 2^-53
7773
7774
7775 random.algorithm = "Alea";
7776 random.seed = seed;
7777 random.version = "0.9";
7778 return random;
7779 }
7780 /**
7781 * Turn arbitrary data into values [[AleaImplementation]] can use to generate
7782 * random numbers.
7783 *
7784 * @param seed - Arbitrary data that will be used as the seed.
7785 * @returns Three numbers to use as initial values for [[AleaImplementation]].
7786 */
7787
7788
7789 function mashSeed() {
7790 var mash = Mash();
7791 var s0 = mash(" ");
7792 var s1 = mash(" ");
7793 var s2 = mash(" ");
7794
7795 for (var i = 0; i < arguments.length; i++) {
7796 s0 -= mash(i < 0 || arguments.length <= i ? undefined : arguments[i]);
7797
7798 if (s0 < 0) {
7799 s0 += 1;
7800 }
7801
7802 s1 -= mash(i < 0 || arguments.length <= i ? undefined : arguments[i]);
7803
7804 if (s1 < 0) {
7805 s1 += 1;
7806 }
7807
7808 s2 -= mash(i < 0 || arguments.length <= i ? undefined : arguments[i]);
7809
7810 if (s2 < 0) {
7811 s2 += 1;
7812 }
7813 }
7814
7815 return [s0, s1, s2];
7816 }
7817 /**
7818 * Create a new mash function.
7819 *
7820 * @returns A nonpure function that takes arbitrary [[Mashable]] data and turns
7821 * them into numbers.
7822 */
7823
7824
7825 function Mash() {
7826 var n = 0xefc8249d;
7827 return function (data) {
7828 var string = data.toString();
7829
7830 for (var i = 0; i < string.length; i++) {
7831 n += string.charCodeAt(i);
7832 var h = 0.02519603282416938 * n;
7833 n = h >>> 0;
7834 h -= n;
7835 h *= n;
7836 n = h >>> 0;
7837 h -= n;
7838 n += h * 0x100000000; // 2^32
7839 }
7840
7841 return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
7842 };
7843 }
7844 /**
7845 * Setup a mock hammer.js object, for unit testing.
7846 *
7847 * Inspiration: https://github.com/uber/deck.gl/pull/658
7848 *
7849 * @returns {{on: noop, off: noop, destroy: noop, emit: noop, get: get}}
7850 */
7851
7852
7853 function hammerMock() {
7854 var noop = function noop() {};
7855
7856 return {
7857 on: noop,
7858 off: noop,
7859 destroy: noop,
7860 emit: noop,
7861 get: function get() {
7862 return {
7863 set: noop
7864 };
7865 }
7866 };
7867 }
7868
7869 var Hammer$1 = typeof window !== "undefined" ? window.Hammer || RealHammer : function () {
7870 // hammer.js is only available in a browser, not in node.js. Replacing it with a mock object.
7871 return hammerMock();
7872 };
7873 /**
7874 * Turn an element into an clickToUse element.
7875 * When not active, the element has a transparent overlay. When the overlay is
7876 * clicked, the mode is changed to active.
7877 * When active, the element is displayed with a blue border around it, and
7878 * the interactive contents of the element can be used. When clicked outside
7879 * the element, the elements mode is changed to inactive.
7880 *
7881 * @param {Element} container
7882 * @class Activator
7883 */
7884
7885 function Activator$1(container) {
7886 var _this = this,
7887 _context3;
7888
7889 this._cleanupQueue = [];
7890 this.active = false;
7891 this._dom = {
7892 container: container,
7893 overlay: document.createElement("div")
7894 };
7895
7896 this._dom.overlay.classList.add("vis-overlay");
7897
7898 this._dom.container.appendChild(this._dom.overlay);
7899
7900 this._cleanupQueue.push(function () {
7901 _this._dom.overlay.parentNode.removeChild(_this._dom.overlay);
7902 });
7903
7904 var hammer = Hammer$1(this._dom.overlay);
7905 hammer.on("tap", bind$6(_context3 = this._onTapOverlay).call(_context3, this));
7906
7907 this._cleanupQueue.push(function () {
7908 hammer.destroy(); // FIXME: cleaning up hammer instances doesn't work (Timeline not removed
7909 // from memory)
7910 }); // block all touch events (except tap)
7911
7912
7913 var events = ["tap", "doubletap", "press", "pinch", "pan", "panstart", "panmove", "panend"];
7914
7915 forEach$2(events).call(events, function (event) {
7916 hammer.on(event, function (event) {
7917 event.srcEvent.stopPropagation();
7918 });
7919 }); // attach a click event to the window, in order to deactivate when clicking outside the timeline
7920
7921
7922 if (document && document.body) {
7923 this._onClick = function (event) {
7924 if (!_hasParent(event.target, container)) {
7925 _this.deactivate();
7926 }
7927 };
7928
7929 document.body.addEventListener("click", this._onClick);
7930
7931 this._cleanupQueue.push(function () {
7932 document.body.removeEventListener("click", _this._onClick);
7933 });
7934 } // prepare escape key listener for deactivating when active
7935
7936
7937 this._escListener = function (event) {
7938 if ("key" in event ? event.key === "Escape" : event.keyCode === 27
7939 /* the keyCode is for IE11 */
7940 ) {
7941 _this.deactivate();
7942 }
7943 };
7944 } // turn into an event emitter
7945
7946
7947 Emitter(Activator$1.prototype); // The currently active activator
7948
7949 Activator$1.current = null;
7950 /**
7951 * Destroy the activator. Cleans up all created DOM and event listeners
7952 */
7953
7954 Activator$1.prototype.destroy = function () {
7955 var _context4, _context5;
7956
7957 this.deactivate();
7958
7959 var _iterator2 = _createForOfIteratorHelper$8(reverse(_context4 = splice$1(_context5 = this._cleanupQueue).call(_context5, 0)).call(_context4)),
7960 _step2;
7961
7962 try {
7963 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
7964 var callback = _step2.value;
7965 callback();
7966 }
7967 } catch (err) {
7968 _iterator2.e(err);
7969 } finally {
7970 _iterator2.f();
7971 }
7972 };
7973 /**
7974 * Activate the element
7975 * Overlay is hidden, element is decorated with a blue shadow border
7976 */
7977
7978
7979 Activator$1.prototype.activate = function () {
7980 // we allow only one active activator at a time
7981 if (Activator$1.current) {
7982 Activator$1.current.deactivate();
7983 }
7984
7985 Activator$1.current = this;
7986 this.active = true;
7987 this._dom.overlay.style.display = "none";
7988
7989 this._dom.container.classList.add("vis-active");
7990
7991 this.emit("change");
7992 this.emit("activate"); // ugly hack: bind ESC after emitting the events, as the Network rebinds all
7993 // keyboard events on a 'change' event
7994
7995 document.body.addEventListener("keydown", this._escListener);
7996 };
7997 /**
7998 * Deactivate the element
7999 * Overlay is displayed on top of the element
8000 */
8001
8002
8003 Activator$1.prototype.deactivate = function () {
8004 this.active = false;
8005 this._dom.overlay.style.display = "block";
8006
8007 this._dom.container.classList.remove("vis-active");
8008
8009 document.body.removeEventListener("keydown", this._escListener);
8010 this.emit("change");
8011 this.emit("deactivate");
8012 };
8013 /**
8014 * Handle a tap event: activate the container
8015 *
8016 * @param {Event} event The event
8017 * @private
8018 */
8019
8020
8021 Activator$1.prototype._onTapOverlay = function (event) {
8022 // activate the container
8023 this.activate();
8024 event.srcEvent.stopPropagation();
8025 };
8026 /**
8027 * Test whether the element has the requested parent element somewhere in
8028 * its chain of parent nodes.
8029 *
8030 * @param {HTMLElement} element
8031 * @param {HTMLElement} parent
8032 * @returns {boolean} Returns true when the parent is found somewhere in the
8033 * chain of parent nodes.
8034 * @private
8035 */
8036
8037
8038 function _hasParent(element, parent) {
8039 while (element) {
8040 if (element === parent) {
8041 return true;
8042 }
8043
8044 element = element.parentNode;
8045 }
8046
8047 return false;
8048 } // utility functions
8049 // parse ASP.Net Date pattern,
8050 // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/'
8051 // code from http://momentjs.com/
8052
8053
8054 var ASPDateRegex = /^\/?Date\((-?\d+)/i; // Color REs
8055
8056 var fullHexRE = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
8057 var shortHexRE = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
8058 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;
8059 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;
8060 /**
8061 * Test whether given object is a number.
8062 *
8063 * @param value - Input value of unknown type.
8064 * @returns True if number, false otherwise.
8065 */
8066
8067 function isNumber(value) {
8068 return value instanceof Number || typeof value === "number";
8069 }
8070 /**
8071 * Remove everything in the DOM object.
8072 *
8073 * @param DOMobject - Node whose child nodes will be recursively deleted.
8074 */
8075
8076
8077 function recursiveDOMDelete(DOMobject) {
8078 if (DOMobject) {
8079 while (DOMobject.hasChildNodes() === true) {
8080 var child = DOMobject.firstChild;
8081
8082 if (child) {
8083 recursiveDOMDelete(child);
8084 DOMobject.removeChild(child);
8085 }
8086 }
8087 }
8088 }
8089 /**
8090 * Test whether given object is a string.
8091 *
8092 * @param value - Input value of unknown type.
8093 * @returns True if string, false otherwise.
8094 */
8095
8096
8097 function isString(value) {
8098 return value instanceof String || typeof value === "string";
8099 }
8100 /**
8101 * Test whether given object is a object (not primitive or null).
8102 *
8103 * @param value - Input value of unknown type.
8104 * @returns True if not null object, false otherwise.
8105 */
8106
8107
8108 function isObject$7(value) {
8109 return _typeof(value) === "object" && value !== null;
8110 }
8111 /**
8112 * Test whether given object is a Date, or a String containing a Date.
8113 *
8114 * @param value - Input value of unknown type.
8115 * @returns True if Date instance or string date representation, false otherwise.
8116 */
8117
8118
8119 function isDate(value) {
8120 if (value instanceof Date) {
8121 return true;
8122 } else if (isString(value)) {
8123 // test whether this string contains a date
8124 var match = ASPDateRegex.exec(value);
8125
8126 if (match) {
8127 return true;
8128 } else if (!isNaN(Date.parse(value))) {
8129 return true;
8130 }
8131 }
8132
8133 return false;
8134 }
8135 /**
8136 * Copy property from b to a if property present in a.
8137 * If property in b explicitly set to null, delete it if `allowDeletion` set.
8138 *
8139 * Internal helper routine, should not be exported. Not added to `exports` for that reason.
8140 *
8141 * @param a - Target object.
8142 * @param b - Source object.
8143 * @param prop - Name of property to copy from b to a.
8144 * @param allowDeletion - If true, delete property in a if explicitly set to null in b.
8145 */
8146
8147
8148 function copyOrDelete(a, b, prop, allowDeletion) {
8149 var doDeletion = false;
8150
8151 if (allowDeletion === true) {
8152 doDeletion = b[prop] === null && a[prop] !== undefined;
8153 }
8154
8155 if (doDeletion) {
8156 delete a[prop];
8157 } else {
8158 a[prop] = b[prop]; // Remember, this is a reference copy!
8159 }
8160 }
8161 /**
8162 * Fill an object with a possibly partially defined other object.
8163 *
8164 * Only copies values for the properties already present in a.
8165 * That means an object is not created on a property if only the b object has it.
8166 *
8167 * @param a - The object that will have it's properties updated.
8168 * @param b - The object with property updates.
8169 * @param allowDeletion - If true, delete properties in a that are explicitly set to null in b.
8170 */
8171
8172
8173 function fillIfDefined(a, b) {
8174 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
8175
8176 // NOTE: iteration of properties of a
8177 // NOTE: prototype properties iterated over as well
8178 for (var prop in a) {
8179 if (b[prop] !== undefined) {
8180 if (b[prop] === null || _typeof(b[prop]) !== "object") {
8181 // Note: typeof null === 'object'
8182 copyOrDelete(a, b, prop, allowDeletion);
8183 } else {
8184 var aProp = a[prop];
8185 var bProp = b[prop];
8186
8187 if (isObject$7(aProp) && isObject$7(bProp)) {
8188 fillIfDefined(aProp, bProp, allowDeletion);
8189 }
8190 }
8191 }
8192 }
8193 }
8194 /**
8195 * Copy the values of all of the enumerable own properties from one or more source objects to a
8196 * target object. Returns the target object.
8197 *
8198 * @param target - The target object to copy to.
8199 * @param source - The source object from which to copy properties.
8200 * @returns The target object.
8201 */
8202
8203
8204 var extend = assign$2;
8205 /**
8206 * Extend object a with selected properties of object b or a series of objects.
8207 *
8208 * @remarks
8209 * Only properties with defined values are copied.
8210 * @param props - Properties to be copied to a.
8211 * @param a - The target.
8212 * @param others - The sources.
8213 * @returns Argument a.
8214 */
8215
8216 function selectiveExtend(props, a) {
8217 if (!isArray$2(props)) {
8218 throw new Error("Array with property names expected as first argument");
8219 }
8220
8221 for (var _len4 = arguments.length, others = new Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) {
8222 others[_key4 - 2] = arguments[_key4];
8223 }
8224
8225 for (var _i2 = 0, _others = others; _i2 < _others.length; _i2++) {
8226 var other = _others[_i2];
8227
8228 for (var p = 0; p < props.length; p++) {
8229 var prop = props[p];
8230
8231 if (other && Object.prototype.hasOwnProperty.call(other, prop)) {
8232 a[prop] = other[prop];
8233 }
8234 }
8235 }
8236
8237 return a;
8238 }
8239 /**
8240 * Extend object a with selected properties of object b.
8241 * Only properties with defined values are copied.
8242 *
8243 * @remarks
8244 * Previous version of this routine implied that multiple source objects could
8245 * be used; however, the implementation was **wrong**. Since multiple (\>1)
8246 * sources weren't used anywhere in the `vis.js` code, this has been removed
8247 * @param props - Names of first-level properties to copy over.
8248 * @param a - Target object.
8249 * @param b - Source object.
8250 * @param allowDeletion - If true, delete property in a if explicitly set to null in b.
8251 * @returns Argument a.
8252 */
8253
8254
8255 function selectiveDeepExtend(props, a, b) {
8256 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
8257
8258 // TODO: add support for Arrays to deepExtend
8259 if (isArray$2(b)) {
8260 throw new TypeError("Arrays are not supported by deepExtend");
8261 }
8262
8263 for (var p = 0; p < props.length; p++) {
8264 var prop = props[p];
8265
8266 if (Object.prototype.hasOwnProperty.call(b, prop)) {
8267 if (b[prop] && b[prop].constructor === Object) {
8268 if (a[prop] === undefined) {
8269 a[prop] = {};
8270 }
8271
8272 if (a[prop].constructor === Object) {
8273 deepExtend(a[prop], b[prop], false, allowDeletion);
8274 } else {
8275 copyOrDelete(a, b, prop, allowDeletion);
8276 }
8277 } else if (isArray$2(b[prop])) {
8278 throw new TypeError("Arrays are not supported by deepExtend");
8279 } else {
8280 copyOrDelete(a, b, prop, allowDeletion);
8281 }
8282 }
8283 }
8284
8285 return a;
8286 }
8287 /**
8288 * Extend object `a` with properties of object `b`, ignoring properties which
8289 * are explicitly specified to be excluded.
8290 *
8291 * @remarks
8292 * The properties of `b` are considered for copying. Properties which are
8293 * themselves objects are are also extended. Only properties with defined
8294 * values are copied.
8295 * @param propsToExclude - Names of properties which should *not* be copied.
8296 * @param a - Object to extend.
8297 * @param b - Object to take properties from for extension.
8298 * @param allowDeletion - If true, delete properties in a that are explicitly
8299 * set to null in b.
8300 * @returns Argument a.
8301 */
8302
8303
8304 function selectiveNotDeepExtend(propsToExclude, a, b) {
8305 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
8306
8307 // TODO: add support for Arrays to deepExtend
8308 // NOTE: array properties have an else-below; apparently, there is a problem here.
8309 if (isArray$2(b)) {
8310 throw new TypeError("Arrays are not supported by deepExtend");
8311 }
8312
8313 for (var prop in b) {
8314 if (!Object.prototype.hasOwnProperty.call(b, prop)) {
8315 continue;
8316 } // Handle local properties only
8317
8318
8319 if (includes(propsToExclude).call(propsToExclude, prop)) {
8320 continue;
8321 } // In exclusion list, skip
8322
8323
8324 if (b[prop] && b[prop].constructor === Object) {
8325 if (a[prop] === undefined) {
8326 a[prop] = {};
8327 }
8328
8329 if (a[prop].constructor === Object) {
8330 deepExtend(a[prop], b[prop]); // NOTE: allowDeletion not propagated!
8331 } else {
8332 copyOrDelete(a, b, prop, allowDeletion);
8333 }
8334 } else if (isArray$2(b[prop])) {
8335 a[prop] = [];
8336
8337 for (var i = 0; i < b[prop].length; i++) {
8338 a[prop].push(b[prop][i]);
8339 }
8340 } else {
8341 copyOrDelete(a, b, prop, allowDeletion);
8342 }
8343 }
8344
8345 return a;
8346 }
8347 /**
8348 * Deep extend an object a with the properties of object b.
8349 *
8350 * @param a - Target object.
8351 * @param b - Source object.
8352 * @param protoExtend - If true, the prototype values will also be extended.
8353 * (That is the options objects that inherit from others will also get the
8354 * inherited options).
8355 * @param allowDeletion - If true, the values of fields that are null will be deleted.
8356 * @returns Argument a.
8357 */
8358
8359
8360 function deepExtend(a, b) {
8361 var protoExtend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
8362 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
8363
8364 for (var prop in b) {
8365 if (Object.prototype.hasOwnProperty.call(b, prop) || protoExtend === true) {
8366 if (_typeof(b[prop]) === "object" && b[prop] !== null && getPrototypeOf$4(b[prop]) === Object.prototype) {
8367 if (a[prop] === undefined) {
8368 a[prop] = deepExtend({}, b[prop], protoExtend); // NOTE: allowDeletion not propagated!
8369 } else if (_typeof(a[prop]) === "object" && a[prop] !== null && getPrototypeOf$4(a[prop]) === Object.prototype) {
8370 deepExtend(a[prop], b[prop], protoExtend); // NOTE: allowDeletion not propagated!
8371 } else {
8372 copyOrDelete(a, b, prop, allowDeletion);
8373 }
8374 } else if (isArray$2(b[prop])) {
8375 var _context6;
8376
8377 a[prop] = slice(_context6 = b[prop]).call(_context6);
8378 } else {
8379 copyOrDelete(a, b, prop, allowDeletion);
8380 }
8381 }
8382 }
8383
8384 return a;
8385 }
8386 /**
8387 * Test whether all elements in two arrays are equal.
8388 *
8389 * @param a - First array.
8390 * @param b - Second array.
8391 * @returns True if both arrays have the same length and same elements (1 = '1').
8392 */
8393
8394
8395 function equalArray(a, b) {
8396 if (a.length !== b.length) {
8397 return false;
8398 }
8399
8400 for (var i = 0, len = a.length; i < len; i++) {
8401 if (a[i] != b[i]) {
8402 return false;
8403 }
8404 }
8405
8406 return true;
8407 }
8408 /**
8409 * Get the type of an object, for example exports.getType([]) returns 'Array'.
8410 *
8411 * @param object - Input value of unknown type.
8412 * @returns Detected type.
8413 */
8414
8415
8416 function getType(object) {
8417 var type = _typeof(object);
8418
8419 if (type === "object") {
8420 if (object === null) {
8421 return "null";
8422 }
8423
8424 if (object instanceof Boolean) {
8425 return "Boolean";
8426 }
8427
8428 if (object instanceof Number) {
8429 return "Number";
8430 }
8431
8432 if (object instanceof String) {
8433 return "String";
8434 }
8435
8436 if (isArray$2(object)) {
8437 return "Array";
8438 }
8439
8440 if (object instanceof Date) {
8441 return "Date";
8442 }
8443
8444 return "Object";
8445 }
8446
8447 if (type === "number") {
8448 return "Number";
8449 }
8450
8451 if (type === "boolean") {
8452 return "Boolean";
8453 }
8454
8455 if (type === "string") {
8456 return "String";
8457 }
8458
8459 if (type === undefined) {
8460 return "undefined";
8461 }
8462
8463 return type;
8464 }
8465 /**
8466 * Used to extend an array and copy it. This is used to propagate paths recursively.
8467 *
8468 * @param arr - First part.
8469 * @param newValue - The value to be aadded into the array.
8470 * @returns A new array with all items from arr and newValue (which is last).
8471 */
8472
8473
8474 function copyAndExtendArray(arr, newValue) {
8475 var _context7;
8476
8477 return concat(_context7 = []).call(_context7, _toConsumableArray(arr), [newValue]);
8478 }
8479 /**
8480 * Used to extend an array and copy it. This is used to propagate paths recursively.
8481 *
8482 * @param arr - The array to be copied.
8483 * @returns Shallow copy of arr.
8484 */
8485
8486
8487 function copyArray(arr) {
8488 return slice(arr).call(arr);
8489 }
8490 /**
8491 * Retrieve the absolute left value of a DOM element.
8492 *
8493 * @param elem - A dom element, for example a div.
8494 * @returns The absolute left position of this element in the browser page.
8495 */
8496
8497
8498 function getAbsoluteLeft(elem) {
8499 return elem.getBoundingClientRect().left;
8500 }
8501 /**
8502 * Retrieve the absolute right value of a DOM element.
8503 *
8504 * @param elem - A dom element, for example a div.
8505 * @returns The absolute right position of this element in the browser page.
8506 */
8507
8508
8509 function getAbsoluteRight(elem) {
8510 return elem.getBoundingClientRect().right;
8511 }
8512 /**
8513 * Retrieve the absolute top value of a DOM element.
8514 *
8515 * @param elem - A dom element, for example a div.
8516 * @returns The absolute top position of this element in the browser page.
8517 */
8518
8519
8520 function getAbsoluteTop(elem) {
8521 return elem.getBoundingClientRect().top;
8522 }
8523 /**
8524 * Add a className to the given elements style.
8525 *
8526 * @param elem - The element to which the classes will be added.
8527 * @param classNames - Space separated list of classes.
8528 */
8529
8530
8531 function addClassName(elem, classNames) {
8532 var classes = elem.className.split(" ");
8533 var newClasses = classNames.split(" ");
8534 classes = concat(classes).call(classes, filter(newClasses).call(newClasses, function (className) {
8535 return !includes(classes).call(classes, className);
8536 }));
8537 elem.className = classes.join(" ");
8538 }
8539 /**
8540 * Remove a className from the given elements style.
8541 *
8542 * @param elem - The element from which the classes will be removed.
8543 * @param classNames - Space separated list of classes.
8544 */
8545
8546
8547 function removeClassName(elem, classNames) {
8548 var classes = elem.className.split(" ");
8549 var oldClasses = classNames.split(" ");
8550 classes = filter(classes).call(classes, function (className) {
8551 return !includes(oldClasses).call(oldClasses, className);
8552 });
8553 elem.className = classes.join(" ");
8554 }
8555 /**
8556 * For each method for both arrays and objects.
8557 * In case of an array, the built-in Array.forEach() is applied (**No, it's not!**).
8558 * In case of an Object, the method loops over all properties of the object.
8559 *
8560 * @param object - An Object or Array to be iterated over.
8561 * @param callback - Array.forEach-like callback.
8562 */
8563
8564
8565 function forEach$1(object, callback) {
8566 if (isArray$2(object)) {
8567 // array
8568 var len = object.length;
8569
8570 for (var i = 0; i < len; i++) {
8571 callback(object[i], i, object);
8572 }
8573 } else {
8574 // object
8575 for (var key in object) {
8576 if (Object.prototype.hasOwnProperty.call(object, key)) {
8577 callback(object[key], key, object);
8578 }
8579 }
8580 }
8581 }
8582 /**
8583 * Convert an object into an array: all objects properties are put into the array. The resulting array is unordered.
8584 *
8585 * @param o - Object that contains the properties and methods.
8586 * @returns An array of unordered values.
8587 */
8588
8589
8590 var toArray = values$4;
8591 /**
8592 * Update a property in an object.
8593 *
8594 * @param object - The object whose property will be updated.
8595 * @param key - Name of the property to be updated.
8596 * @param value - The new value to be assigned.
8597 * @returns Whether the value was updated (true) or already strictly the same in the original object (false).
8598 */
8599
8600 function updateProperty(object, key, value) {
8601 if (object[key] !== value) {
8602 object[key] = value;
8603 return true;
8604 } else {
8605 return false;
8606 }
8607 }
8608 /**
8609 * Throttle the given function to be only executed once per animation frame.
8610 *
8611 * @param fn - The original function.
8612 * @returns The throttled function.
8613 */
8614
8615
8616 function throttle(fn) {
8617 var scheduled = false;
8618 return function () {
8619 if (!scheduled) {
8620 scheduled = true;
8621 requestAnimationFrame(function () {
8622 scheduled = false;
8623 fn();
8624 });
8625 }
8626 };
8627 }
8628 /**
8629 * Add and event listener. Works for all browsers.
8630 *
8631 * @param element - The element to bind the event listener to.
8632 * @param action - Same as Element.addEventListener(action, —, —).
8633 * @param listener - Same as Element.addEventListener(—, listener, —).
8634 * @param useCapture - Same as Element.addEventListener(—, —, useCapture).
8635 */
8636
8637
8638 function addEventListener(element, action, listener, useCapture) {
8639 if (element.addEventListener) {
8640 var _context8;
8641
8642 if (useCapture === undefined) {
8643 useCapture = false;
8644 }
8645
8646 if (action === "mousewheel" && includes(_context8 = navigator.userAgent).call(_context8, "Firefox")) {
8647 action = "DOMMouseScroll"; // For Firefox
8648 }
8649
8650 element.addEventListener(action, listener, useCapture);
8651 } else {
8652 // @TODO: IE types? Does anyone care?
8653 element.attachEvent("on" + action, listener); // IE browsers
8654 }
8655 }
8656 /**
8657 * Remove an event listener from an element.
8658 *
8659 * @param element - The element to bind the event listener to.
8660 * @param action - Same as Element.removeEventListener(action, —, —).
8661 * @param listener - Same as Element.removeEventListener(—, listener, —).
8662 * @param useCapture - Same as Element.removeEventListener(—, —, useCapture).
8663 */
8664
8665
8666 function removeEventListener(element, action, listener, useCapture) {
8667 if (element.removeEventListener) {
8668 var _context9;
8669
8670 // non-IE browsers
8671 if (useCapture === undefined) {
8672 useCapture = false;
8673 }
8674
8675 if (action === "mousewheel" && includes(_context9 = navigator.userAgent).call(_context9, "Firefox")) {
8676 action = "DOMMouseScroll"; // For Firefox
8677 }
8678
8679 element.removeEventListener(action, listener, useCapture);
8680 } else {
8681 // @TODO: IE types? Does anyone care?
8682 element.detachEvent("on" + action, listener); // IE browsers
8683 }
8684 }
8685 /**
8686 * Cancels the event's default action if it is cancelable, without stopping further propagation of the event.
8687 *
8688 * @param event - The event whose default action should be prevented.
8689 */
8690
8691
8692 function preventDefault(event) {
8693 if (!event) {
8694 event = window.event;
8695 }
8696
8697 if (!event) ;else if (event.preventDefault) {
8698 event.preventDefault(); // non-IE browsers
8699 } else {
8700 // @TODO: IE types? Does anyone care?
8701 event.returnValue = false; // IE browsers
8702 }
8703 }
8704 /**
8705 * Get HTML element which is the target of the event.
8706 *
8707 * @param event - The event.
8708 * @returns The element or null if not obtainable.
8709 */
8710
8711
8712 function getTarget() {
8713 var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.event;
8714 // code from http://www.quirksmode.org/js/events_properties.html
8715 // @TODO: EventTarget can be almost anything, is it okay to return only Elements?
8716 var target = null;
8717 if (!event) ;else if (event.target) {
8718 target = event.target;
8719 } else if (event.srcElement) {
8720 target = event.srcElement;
8721 }
8722
8723 if (!(target instanceof Element)) {
8724 return null;
8725 }
8726
8727 if (target.nodeType != null && target.nodeType == 3) {
8728 // defeat Safari bug
8729 target = target.parentNode;
8730
8731 if (!(target instanceof Element)) {
8732 return null;
8733 }
8734 }
8735
8736 return target;
8737 }
8738 /**
8739 * Check if given element contains given parent somewhere in the DOM tree.
8740 *
8741 * @param element - The element to be tested.
8742 * @param parent - The ancestor (not necessarily parent) of the element.
8743 * @returns True if parent is an ancestor of the element, false otherwise.
8744 */
8745
8746
8747 function hasParent(element, parent) {
8748 var elem = element;
8749
8750 while (elem) {
8751 if (elem === parent) {
8752 return true;
8753 } else if (elem.parentNode) {
8754 elem = elem.parentNode;
8755 } else {
8756 return false;
8757 }
8758 }
8759
8760 return false;
8761 }
8762
8763 var option = {
8764 /**
8765 * Convert a value into a boolean.
8766 *
8767 * @param value - Value to be converted intoboolean, a function will be executed as `(() => unknown)`.
8768 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8769 * @returns Corresponding boolean value, if none then the default value, if none then null.
8770 */
8771 asBoolean: function asBoolean(value, defaultValue) {
8772 if (typeof value == "function") {
8773 value = value();
8774 }
8775
8776 if (value != null) {
8777 return value != false;
8778 }
8779
8780 return defaultValue || null;
8781 },
8782
8783 /**
8784 * Convert a value into a number.
8785 *
8786 * @param value - Value to be converted intonumber, a function will be executed as `(() => unknown)`.
8787 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8788 * @returns Corresponding **boxed** number value, if none then the default value, if none then null.
8789 */
8790 asNumber: function asNumber(value, defaultValue) {
8791 if (typeof value == "function") {
8792 value = value();
8793 }
8794
8795 if (value != null) {
8796 return Number(value) || defaultValue || null;
8797 }
8798
8799 return defaultValue || null;
8800 },
8801
8802 /**
8803 * Convert a value into a string.
8804 *
8805 * @param value - Value to be converted intostring, a function will be executed as `(() => unknown)`.
8806 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8807 * @returns Corresponding **boxed** string value, if none then the default value, if none then null.
8808 */
8809 asString: function asString(value, defaultValue) {
8810 if (typeof value == "function") {
8811 value = value();
8812 }
8813
8814 if (value != null) {
8815 return String(value);
8816 }
8817
8818 return defaultValue || null;
8819 },
8820
8821 /**
8822 * Convert a value into a size.
8823 *
8824 * @param value - Value to be converted intosize, a function will be executed as `(() => unknown)`.
8825 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8826 * @returns Corresponding string value (number + 'px'), if none then the default value, if none then null.
8827 */
8828 asSize: function asSize(value, defaultValue) {
8829 if (typeof value == "function") {
8830 value = value();
8831 }
8832
8833 if (isString(value)) {
8834 return value;
8835 } else if (isNumber(value)) {
8836 return value + "px";
8837 } else {
8838 return defaultValue || null;
8839 }
8840 },
8841
8842 /**
8843 * Convert a value into a DOM Element.
8844 *
8845 * @param value - Value to be converted into DOM Element, a function will be executed as `(() => unknown)`.
8846 * @param defaultValue - If the value or the return value of the function == null then this will be returned.
8847 * @returns The DOM Element, if none then the default value, if none then null.
8848 */
8849 asElement: function asElement(value, defaultValue) {
8850 if (typeof value == "function") {
8851 value = value();
8852 }
8853
8854 return value || defaultValue || null;
8855 }
8856 };
8857 /**
8858 * Convert hex color string into RGB color object.
8859 *
8860 * @remarks
8861 * {@link http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb}
8862 * @param hex - Hex color string (3 or 6 digits, with or without #).
8863 * @returns RGB color object.
8864 */
8865
8866 function hexToRGB(hex) {
8867 var result;
8868
8869 switch (hex.length) {
8870 case 3:
8871 case 4:
8872 result = shortHexRE.exec(hex);
8873 return result ? {
8874 r: _parseInt(result[1] + result[1], 16),
8875 g: _parseInt(result[2] + result[2], 16),
8876 b: _parseInt(result[3] + result[3], 16)
8877 } : null;
8878
8879 case 6:
8880 case 7:
8881 result = fullHexRE.exec(hex);
8882 return result ? {
8883 r: _parseInt(result[1], 16),
8884 g: _parseInt(result[2], 16),
8885 b: _parseInt(result[3], 16)
8886 } : null;
8887
8888 default:
8889 return null;
8890 }
8891 }
8892 /**
8893 * This function takes string color in hex or RGB format and adds the opacity, RGBA is passed through unchanged.
8894 *
8895 * @param color - The color string (hex, RGB, RGBA).
8896 * @param opacity - The new opacity.
8897 * @returns RGBA string, for example 'rgba(255, 0, 127, 0.3)'.
8898 */
8899
8900
8901 function overrideOpacity(color, opacity) {
8902 if (includes(color).call(color, "rgba")) {
8903 return color;
8904 } else if (includes(color).call(color, "rgb")) {
8905 var rgb = color.substr(indexOf(color).call(color, "(") + 1).replace(")", "").split(",");
8906 return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + opacity + ")";
8907 } else {
8908 var _rgb = hexToRGB(color);
8909
8910 if (_rgb == null) {
8911 return color;
8912 } else {
8913 return "rgba(" + _rgb.r + "," + _rgb.g + "," + _rgb.b + "," + opacity + ")";
8914 }
8915 }
8916 }
8917 /**
8918 * Convert RGB \<0, 255\> into hex color string.
8919 *
8920 * @param red - Red channel.
8921 * @param green - Green channel.
8922 * @param blue - Blue channel.
8923 * @returns Hex color string (for example: '#0acdc0').
8924 */
8925
8926
8927 function RGBToHex(red, green, blue) {
8928 var _context10;
8929
8930 return "#" + slice(_context10 = ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16)).call(_context10, 1);
8931 }
8932 /**
8933 * Parse a color property into an object with border, background, and highlight colors.
8934 *
8935 * @param inputColor - Shorthand color string or input color object.
8936 * @param defaultColor - Full color object to fill in missing values in inputColor.
8937 * @returns Color object.
8938 */
8939
8940
8941 function parseColor(inputColor, defaultColor) {
8942 if (isString(inputColor)) {
8943 var colorStr = inputColor;
8944
8945 if (isValidRGB(colorStr)) {
8946 var _context11;
8947
8948 var rgb = map$3(_context11 = colorStr.substr(4).substr(0, colorStr.length - 5).split(",")).call(_context11, function (value) {
8949 return _parseInt(value);
8950 });
8951
8952 colorStr = RGBToHex(rgb[0], rgb[1], rgb[2]);
8953 }
8954
8955 if (isValidHex(colorStr) === true) {
8956 var hsv = hexToHSV(colorStr);
8957 var lighterColorHSV = {
8958 h: hsv.h,
8959 s: hsv.s * 0.8,
8960 v: Math.min(1, hsv.v * 1.02)
8961 };
8962 var darkerColorHSV = {
8963 h: hsv.h,
8964 s: Math.min(1, hsv.s * 1.25),
8965 v: hsv.v * 0.8
8966 };
8967 var darkerColorHex = HSVToHex(darkerColorHSV.h, darkerColorHSV.s, darkerColorHSV.v);
8968 var lighterColorHex = HSVToHex(lighterColorHSV.h, lighterColorHSV.s, lighterColorHSV.v);
8969 return {
8970 background: colorStr,
8971 border: darkerColorHex,
8972 highlight: {
8973 background: lighterColorHex,
8974 border: darkerColorHex
8975 },
8976 hover: {
8977 background: lighterColorHex,
8978 border: darkerColorHex
8979 }
8980 };
8981 } else {
8982 return {
8983 background: colorStr,
8984 border: colorStr,
8985 highlight: {
8986 background: colorStr,
8987 border: colorStr
8988 },
8989 hover: {
8990 background: colorStr,
8991 border: colorStr
8992 }
8993 };
8994 }
8995 } else {
8996 if (defaultColor) {
8997 var color = {
8998 background: inputColor.background || defaultColor.background,
8999 border: inputColor.border || defaultColor.border,
9000 highlight: isString(inputColor.highlight) ? {
9001 border: inputColor.highlight,
9002 background: inputColor.highlight
9003 } : {
9004 background: inputColor.highlight && inputColor.highlight.background || defaultColor.highlight.background,
9005 border: inputColor.highlight && inputColor.highlight.border || defaultColor.highlight.border
9006 },
9007 hover: isString(inputColor.hover) ? {
9008 border: inputColor.hover,
9009 background: inputColor.hover
9010 } : {
9011 border: inputColor.hover && inputColor.hover.border || defaultColor.hover.border,
9012 background: inputColor.hover && inputColor.hover.background || defaultColor.hover.background
9013 }
9014 };
9015 return color;
9016 } else {
9017 var _color = {
9018 background: inputColor.background || undefined,
9019 border: inputColor.border || undefined,
9020 highlight: isString(inputColor.highlight) ? {
9021 border: inputColor.highlight,
9022 background: inputColor.highlight
9023 } : {
9024 background: inputColor.highlight && inputColor.highlight.background || undefined,
9025 border: inputColor.highlight && inputColor.highlight.border || undefined
9026 },
9027 hover: isString(inputColor.hover) ? {
9028 border: inputColor.hover,
9029 background: inputColor.hover
9030 } : {
9031 border: inputColor.hover && inputColor.hover.border || undefined,
9032 background: inputColor.hover && inputColor.hover.background || undefined
9033 }
9034 };
9035 return _color;
9036 }
9037 }
9038 }
9039 /**
9040 * Convert RGB \<0, 255\> into HSV object.
9041 *
9042 * @remarks
9043 * {@link http://www.javascripter.net/faq/rgb2hsv.htm}
9044 * @param red - Red channel.
9045 * @param green - Green channel.
9046 * @param blue - Blue channel.
9047 * @returns HSV color object.
9048 */
9049
9050
9051 function RGBToHSV(red, green, blue) {
9052 red = red / 255;
9053 green = green / 255;
9054 blue = blue / 255;
9055 var minRGB = Math.min(red, Math.min(green, blue));
9056 var maxRGB = Math.max(red, Math.max(green, blue)); // Black-gray-white
9057
9058 if (minRGB === maxRGB) {
9059 return {
9060 h: 0,
9061 s: 0,
9062 v: minRGB
9063 };
9064 } // Colors other than black-gray-white:
9065
9066
9067 var d = red === minRGB ? green - blue : blue === minRGB ? red - green : blue - red;
9068 var h = red === minRGB ? 3 : blue === minRGB ? 1 : 5;
9069 var hue = 60 * (h - d / (maxRGB - minRGB)) / 360;
9070 var saturation = (maxRGB - minRGB) / maxRGB;
9071 var value = maxRGB;
9072 return {
9073 h: hue,
9074 s: saturation,
9075 v: value
9076 };
9077 }
9078
9079 var cssUtil = {
9080 // split a string with css styles into an object with key/values
9081 split: function split(cssText) {
9082 var _context12;
9083
9084 var styles = {};
9085
9086 forEach$2(_context12 = cssText.split(";")).call(_context12, function (style) {
9087 if (trim$1(style).call(style) != "") {
9088 var _context13, _context14;
9089
9090 var parts = style.split(":");
9091
9092 var key = trim$1(_context13 = parts[0]).call(_context13);
9093
9094 var value = trim$1(_context14 = parts[1]).call(_context14);
9095
9096 styles[key] = value;
9097 }
9098 });
9099
9100 return styles;
9101 },
9102 // build a css text string from an object with key/values
9103 join: function join(styles) {
9104 var _context15;
9105
9106 return map$3(_context15 = keys$4(styles)).call(_context15, function (key) {
9107 return key + ": " + styles[key];
9108 }).join("; ");
9109 }
9110 };
9111 /**
9112 * Append a string with css styles to an element.
9113 *
9114 * @param element - The element that will receive new styles.
9115 * @param cssText - The styles to be appended.
9116 */
9117
9118 function addCssText(element, cssText) {
9119 var currentStyles = cssUtil.split(element.style.cssText);
9120 var newStyles = cssUtil.split(cssText);
9121
9122 var styles = _objectSpread$5(_objectSpread$5({}, currentStyles), newStyles);
9123
9124 element.style.cssText = cssUtil.join(styles);
9125 }
9126 /**
9127 * Remove a string with css styles from an element.
9128 *
9129 * @param element - The element from which styles should be removed.
9130 * @param cssText - The styles to be removed.
9131 */
9132
9133
9134 function removeCssText(element, cssText) {
9135 var styles = cssUtil.split(element.style.cssText);
9136 var removeStyles = cssUtil.split(cssText);
9137
9138 for (var key in removeStyles) {
9139 if (Object.prototype.hasOwnProperty.call(removeStyles, key)) {
9140 delete styles[key];
9141 }
9142 }
9143
9144 element.style.cssText = cssUtil.join(styles);
9145 }
9146 /**
9147 * Convert HSV \<0, 1\> into RGB color object.
9148 *
9149 * @remarks
9150 * {@link https://gist.github.com/mjijackson/5311256}
9151 * @param h - Hue.
9152 * @param s - Saturation.
9153 * @param v - Value.
9154 * @returns RGB color object.
9155 */
9156
9157
9158 function HSVToRGB(h, s, v) {
9159 var r;
9160 var g;
9161 var b;
9162 var i = Math.floor(h * 6);
9163 var f = h * 6 - i;
9164 var p = v * (1 - s);
9165 var q = v * (1 - f * s);
9166 var t = v * (1 - (1 - f) * s);
9167
9168 switch (i % 6) {
9169 case 0:
9170 r = v, g = t, b = p;
9171 break;
9172
9173 case 1:
9174 r = q, g = v, b = p;
9175 break;
9176
9177 case 2:
9178 r = p, g = v, b = t;
9179 break;
9180
9181 case 3:
9182 r = p, g = q, b = v;
9183 break;
9184
9185 case 4:
9186 r = t, g = p, b = v;
9187 break;
9188
9189 case 5:
9190 r = v, g = p, b = q;
9191 break;
9192 }
9193
9194 return {
9195 r: Math.floor(r * 255),
9196 g: Math.floor(g * 255),
9197 b: Math.floor(b * 255)
9198 };
9199 }
9200 /**
9201 * Convert HSV \<0, 1\> into hex color string.
9202 *
9203 * @param h - Hue.
9204 * @param s - Saturation.
9205 * @param v - Value.
9206 * @returns Hex color string.
9207 */
9208
9209
9210 function HSVToHex(h, s, v) {
9211 var rgb = HSVToRGB(h, s, v);
9212 return RGBToHex(rgb.r, rgb.g, rgb.b);
9213 }
9214 /**
9215 * Convert hex color string into HSV \<0, 1\>.
9216 *
9217 * @param hex - Hex color string.
9218 * @returns HSV color object.
9219 */
9220
9221
9222 function hexToHSV(hex) {
9223 var rgb = hexToRGB(hex);
9224
9225 if (!rgb) {
9226 throw new TypeError("'".concat(hex, "' is not a valid color."));
9227 }
9228
9229 return RGBToHSV(rgb.r, rgb.g, rgb.b);
9230 }
9231 /**
9232 * Validate hex color string.
9233 *
9234 * @param hex - Unknown string that may contain a color.
9235 * @returns True if the string is valid, false otherwise.
9236 */
9237
9238
9239 function isValidHex(hex) {
9240 var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex);
9241 return isOk;
9242 }
9243 /**
9244 * Validate RGB color string.
9245 *
9246 * @param rgb - Unknown string that may contain a color.
9247 * @returns True if the string is valid, false otherwise.
9248 */
9249
9250
9251 function isValidRGB(rgb) {
9252 return rgbRE.test(rgb);
9253 }
9254 /**
9255 * Validate RGBA color string.
9256 *
9257 * @param rgba - Unknown string that may contain a color.
9258 * @returns True if the string is valid, false otherwise.
9259 */
9260
9261
9262 function isValidRGBA(rgba) {
9263 return rgbaRE.test(rgba);
9264 }
9265 /**
9266 * This recursively redirects the prototype of JSON objects to the referenceObject.
9267 * This is used for default options.
9268 *
9269 * @param fields - Names of properties to be bridged.
9270 * @param referenceObject - The original object.
9271 * @returns A new object inheriting from the referenceObject.
9272 */
9273
9274
9275 function selectiveBridgeObject(fields, referenceObject) {
9276 if (referenceObject !== null && _typeof(referenceObject) === "object") {
9277 // !!! typeof null === 'object'
9278 var objectTo = create$5(referenceObject);
9279
9280 for (var i = 0; i < fields.length; i++) {
9281 if (Object.prototype.hasOwnProperty.call(referenceObject, fields[i])) {
9282 if (_typeof(referenceObject[fields[i]]) == "object") {
9283 objectTo[fields[i]] = bridgeObject(referenceObject[fields[i]]);
9284 }
9285 }
9286 }
9287
9288 return objectTo;
9289 } else {
9290 return null;
9291 }
9292 }
9293 /**
9294 * This recursively redirects the prototype of JSON objects to the referenceObject.
9295 * This is used for default options.
9296 *
9297 * @param referenceObject - The original object.
9298 * @returns The Element if the referenceObject is an Element, or a new object inheriting from the referenceObject.
9299 */
9300
9301
9302 function bridgeObject(referenceObject) {
9303 if (referenceObject === null || _typeof(referenceObject) !== "object") {
9304 return null;
9305 }
9306
9307 if (referenceObject instanceof Element) {
9308 // Avoid bridging DOM objects
9309 return referenceObject;
9310 }
9311
9312 var objectTo = create$5(referenceObject);
9313
9314 for (var i in referenceObject) {
9315 if (Object.prototype.hasOwnProperty.call(referenceObject, i)) {
9316 if (_typeof(referenceObject[i]) == "object") {
9317 objectTo[i] = bridgeObject(referenceObject[i]);
9318 }
9319 }
9320 }
9321
9322 return objectTo;
9323 }
9324 /**
9325 * This method provides a stable sort implementation, very fast for presorted data.
9326 *
9327 * @param a - The array to be sorted (in-place).
9328 * @param compare - An order comparator.
9329 * @returns The argument a.
9330 */
9331
9332
9333 function insertSort(a, compare) {
9334 for (var i = 0; i < a.length; i++) {
9335 var k = a[i];
9336 var j = void 0;
9337
9338 for (j = i; j > 0 && compare(k, a[j - 1]) < 0; j--) {
9339 a[j] = a[j - 1];
9340 }
9341
9342 a[j] = k;
9343 }
9344
9345 return a;
9346 }
9347 /**
9348 * This is used to set the options of subobjects in the options object.
9349 *
9350 * A requirement of these subobjects is that they have an 'enabled' element
9351 * which is optional for the user but mandatory for the program.
9352 *
9353 * The added value here of the merge is that option 'enabled' is set as required.
9354 *
9355 * @param mergeTarget - Either this.options or the options used for the groups.
9356 * @param options - Options.
9357 * @param option - Option key in the options argument.
9358 * @param globalOptions - Global options, passed in to determine value of option 'enabled'.
9359 */
9360
9361
9362 function mergeOptions(mergeTarget, options, option) {
9363 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
9364
9365 // Local helpers
9366 var isPresent = function isPresent(obj) {
9367 return obj !== null && obj !== undefined;
9368 };
9369
9370 var isObject = function isObject(obj) {
9371 return obj !== null && _typeof(obj) === "object";
9372 }; // https://stackoverflow.com/a/34491287/1223531
9373
9374
9375 var isEmpty = function isEmpty(obj) {
9376 for (var x in obj) {
9377 if (Object.prototype.hasOwnProperty.call(obj, x)) {
9378 return false;
9379 }
9380 }
9381
9382 return true;
9383 }; // Guards
9384
9385
9386 if (!isObject(mergeTarget)) {
9387 throw new Error("Parameter mergeTarget must be an object");
9388 }
9389
9390 if (!isObject(options)) {
9391 throw new Error("Parameter options must be an object");
9392 }
9393
9394 if (!isPresent(option)) {
9395 throw new Error("Parameter option must have a value");
9396 }
9397
9398 if (!isObject(globalOptions)) {
9399 throw new Error("Parameter globalOptions must be an object");
9400 } //
9401 // Actual merge routine, separated from main logic
9402 // Only a single level of options is merged. Deeper levels are ref'd. This may actually be an issue.
9403 //
9404
9405
9406 var doMerge = function doMerge(target, options, option) {
9407 if (!isObject(target[option])) {
9408 target[option] = {};
9409 }
9410
9411 var src = options[option];
9412 var dst = target[option];
9413
9414 for (var prop in src) {
9415 if (Object.prototype.hasOwnProperty.call(src, prop)) {
9416 dst[prop] = src[prop];
9417 }
9418 }
9419 }; // Local initialization
9420
9421
9422 var srcOption = options[option];
9423 var globalPassed = isObject(globalOptions) && !isEmpty(globalOptions);
9424 var globalOption = globalPassed ? globalOptions[option] : undefined;
9425 var globalEnabled = globalOption ? globalOption.enabled : undefined; /////////////////////////////////////////
9426 // Main routine
9427 /////////////////////////////////////////
9428
9429 if (srcOption === undefined) {
9430 return; // Nothing to do
9431 }
9432
9433 if (typeof srcOption === "boolean") {
9434 if (!isObject(mergeTarget[option])) {
9435 mergeTarget[option] = {};
9436 }
9437
9438 mergeTarget[option].enabled = srcOption;
9439 return;
9440 }
9441
9442 if (srcOption === null && !isObject(mergeTarget[option])) {
9443 // If possible, explicit copy from globals
9444 if (isPresent(globalOption)) {
9445 mergeTarget[option] = create$5(globalOption);
9446 } else {
9447 return; // Nothing to do
9448 }
9449 }
9450
9451 if (!isObject(srcOption)) {
9452 return;
9453 } //
9454 // Ensure that 'enabled' is properly set. It is required internally
9455 // Note that the value from options will always overwrite the existing value
9456 //
9457
9458
9459 var enabled = true; // default value
9460
9461 if (srcOption.enabled !== undefined) {
9462 enabled = srcOption.enabled;
9463 } else {
9464 // Take from globals, if present
9465 if (globalEnabled !== undefined) {
9466 enabled = globalOption.enabled;
9467 }
9468 }
9469
9470 doMerge(mergeTarget, options, option);
9471 mergeTarget[option].enabled = enabled;
9472 }
9473 /**
9474 * This function does a binary search for a visible item in a sorted list. If we find a visible item, the code that uses
9475 * this function will then iterate in both directions over this sorted list to find all visible items.
9476 *
9477 * @param orderedItems - Items ordered by start.
9478 * @param comparator - -1 is lower, 0 is equal, 1 is higher.
9479 * @param field - Property name on an item (That is item[field]).
9480 * @param field2 - Second property name on an item (That is item[field][field2]).
9481 * @returns Index of the found item or -1 if nothing was found.
9482 */
9483
9484
9485 function binarySearchCustom(orderedItems, comparator, field, field2) {
9486 var maxIterations = 10000;
9487 var iteration = 0;
9488 var low = 0;
9489 var high = orderedItems.length - 1;
9490
9491 while (low <= high && iteration < maxIterations) {
9492 var middle = Math.floor((low + high) / 2);
9493 var item = orderedItems[middle];
9494 var value = field2 === undefined ? item[field] : item[field][field2];
9495 var searchResult = comparator(value);
9496
9497 if (searchResult == 0) {
9498 // jihaa, found a visible item!
9499 return middle;
9500 } else if (searchResult == -1) {
9501 // it is too small --> increase low
9502 low = middle + 1;
9503 } else {
9504 // it is too big --> decrease high
9505 high = middle - 1;
9506 }
9507
9508 iteration++;
9509 }
9510
9511 return -1;
9512 }
9513 /**
9514 * This function does a binary search for a specific value in a sorted array.
9515 * If it does not exist but is in between of two values, we return either the
9516 * one before or the one after, depending on user input If it is found, we
9517 * return the index, else -1.
9518 *
9519 * @param orderedItems - Sorted array.
9520 * @param target - The searched value.
9521 * @param field - Name of the property in items to be searched.
9522 * @param sidePreference - If the target is between two values, should the index of the before or the after be returned?
9523 * @param comparator - An optional comparator, returning -1, 0, 1 for \<, ===, \>.
9524 * @returns The index of found value or -1 if nothing was found.
9525 */
9526
9527
9528 function binarySearchValue(orderedItems, target, field, sidePreference, comparator) {
9529 var maxIterations = 10000;
9530 var iteration = 0;
9531 var low = 0;
9532 var high = orderedItems.length - 1;
9533 var prevValue;
9534 var value;
9535 var nextValue;
9536 var middle;
9537 comparator = comparator != undefined ? comparator : function (a, b) {
9538 return a == b ? 0 : a < b ? -1 : 1;
9539 };
9540
9541 while (low <= high && iteration < maxIterations) {
9542 // get a new guess
9543 middle = Math.floor(0.5 * (high + low));
9544 prevValue = orderedItems[Math.max(0, middle - 1)][field];
9545 value = orderedItems[middle][field];
9546 nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field];
9547
9548 if (comparator(value, target) == 0) {
9549 // we found the target
9550 return middle;
9551 } else if (comparator(prevValue, target) < 0 && comparator(value, target) > 0) {
9552 // target is in between of the previous and the current
9553 return sidePreference == "before" ? Math.max(0, middle - 1) : middle;
9554 } else if (comparator(value, target) < 0 && comparator(nextValue, target) > 0) {
9555 // target is in between of the current and the next
9556 return sidePreference == "before" ? middle : Math.min(orderedItems.length - 1, middle + 1);
9557 } else {
9558 // didnt find the target, we need to change our boundaries.
9559 if (comparator(value, target) < 0) {
9560 // it is too small --> increase low
9561 low = middle + 1;
9562 } else {
9563 // it is too big --> decrease high
9564 high = middle - 1;
9565 }
9566 }
9567
9568 iteration++;
9569 } // didnt find anything. Return -1.
9570
9571
9572 return -1;
9573 }
9574 /*
9575 * Easing Functions.
9576 * Only considering the t value for the range [0, 1] => [0, 1].
9577 *
9578 * Inspiration: from http://gizma.com/easing/
9579 * https://gist.github.com/gre/1650294
9580 */
9581
9582
9583 var easingFunctions = {
9584 /**
9585 * Provides no easing and no acceleration.
9586 *
9587 * @param t - Time.
9588 * @returns Value at time t.
9589 */
9590 linear: function linear(t) {
9591 return t;
9592 },
9593
9594 /**
9595 * Accelerate from zero velocity.
9596 *
9597 * @param t - Time.
9598 * @returns Value at time t.
9599 */
9600 easeInQuad: function easeInQuad(t) {
9601 return t * t;
9602 },
9603
9604 /**
9605 * Decelerate to zero velocity.
9606 *
9607 * @param t - Time.
9608 * @returns Value at time t.
9609 */
9610 easeOutQuad: function easeOutQuad(t) {
9611 return t * (2 - t);
9612 },
9613
9614 /**
9615 * Accelerate until halfway, then decelerate.
9616 *
9617 * @param t - Time.
9618 * @returns Value at time t.
9619 */
9620 easeInOutQuad: function easeInOutQuad(t) {
9621 return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
9622 },
9623
9624 /**
9625 * Accelerate from zero velocity.
9626 *
9627 * @param t - Time.
9628 * @returns Value at time t.
9629 */
9630 easeInCubic: function easeInCubic(t) {
9631 return t * t * t;
9632 },
9633
9634 /**
9635 * Decelerate to zero velocity.
9636 *
9637 * @param t - Time.
9638 * @returns Value at time t.
9639 */
9640 easeOutCubic: function easeOutCubic(t) {
9641 return --t * t * t + 1;
9642 },
9643
9644 /**
9645 * Accelerate until halfway, then decelerate.
9646 *
9647 * @param t - Time.
9648 * @returns Value at time t.
9649 */
9650 easeInOutCubic: function easeInOutCubic(t) {
9651 return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
9652 },
9653
9654 /**
9655 * Accelerate from zero velocity.
9656 *
9657 * @param t - Time.
9658 * @returns Value at time t.
9659 */
9660 easeInQuart: function easeInQuart(t) {
9661 return t * t * t * t;
9662 },
9663
9664 /**
9665 * Decelerate to zero velocity.
9666 *
9667 * @param t - Time.
9668 * @returns Value at time t.
9669 */
9670 easeOutQuart: function easeOutQuart(t) {
9671 return 1 - --t * t * t * t;
9672 },
9673
9674 /**
9675 * Accelerate until halfway, then decelerate.
9676 *
9677 * @param t - Time.
9678 * @returns Value at time t.
9679 */
9680 easeInOutQuart: function easeInOutQuart(t) {
9681 return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
9682 },
9683
9684 /**
9685 * Accelerate from zero velocity.
9686 *
9687 * @param t - Time.
9688 * @returns Value at time t.
9689 */
9690 easeInQuint: function easeInQuint(t) {
9691 return t * t * t * t * t;
9692 },
9693
9694 /**
9695 * Decelerate to zero velocity.
9696 *
9697 * @param t - Time.
9698 * @returns Value at time t.
9699 */
9700 easeOutQuint: function easeOutQuint(t) {
9701 return 1 + --t * t * t * t * t;
9702 },
9703
9704 /**
9705 * Accelerate until halfway, then decelerate.
9706 *
9707 * @param t - Time.
9708 * @returns Value at time t.
9709 */
9710 easeInOutQuint: function easeInOutQuint(t) {
9711 return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
9712 }
9713 };
9714 /**
9715 * Experimentaly compute the width of the scrollbar for this browser.
9716 *
9717 * @returns The width in pixels.
9718 */
9719
9720 function getScrollBarWidth() {
9721 var inner = document.createElement("p");
9722 inner.style.width = "100%";
9723 inner.style.height = "200px";
9724 var outer = document.createElement("div");
9725 outer.style.position = "absolute";
9726 outer.style.top = "0px";
9727 outer.style.left = "0px";
9728 outer.style.visibility = "hidden";
9729 outer.style.width = "200px";
9730 outer.style.height = "150px";
9731 outer.style.overflow = "hidden";
9732 outer.appendChild(inner);
9733 document.body.appendChild(outer);
9734 var w1 = inner.offsetWidth;
9735 outer.style.overflow = "scroll";
9736 var w2 = inner.offsetWidth;
9737
9738 if (w1 == w2) {
9739 w2 = outer.clientWidth;
9740 }
9741
9742 document.body.removeChild(outer);
9743 return w1 - w2;
9744 } // @TODO: This doesn't work properly.
9745 // It works only for single property objects,
9746 // otherwise it combines all of the types in a union.
9747 // export function topMost<K1 extends string, V1> (
9748 // pile: Record<K1, undefined | V1>[],
9749 // accessors: K1 | [K1]
9750 // ): undefined | V1
9751 // export function topMost<K1 extends string, K2 extends string, V1, V2> (
9752 // pile: Record<K1, undefined | V1 | Record<K2, undefined | V2>>[],
9753 // accessors: [K1, K2]
9754 // ): undefined | V1 | V2
9755 // export function topMost<K1 extends string, K2 extends string, K3 extends string, V1, V2, V3> (
9756 // pile: Record<K1, undefined | V1 | Record<K2, undefined | V2 | Record<K3, undefined | V3>>>[],
9757 // accessors: [K1, K2, K3]
9758 // ): undefined | V1 | V2 | V3
9759
9760 /**
9761 * Get the top most property value from a pile of objects.
9762 *
9763 * @param pile - Array of objects, no required format.
9764 * @param accessors - Array of property names.
9765 * For example `object['foo']['bar']` → `['foo', 'bar']`.
9766 * @returns Value of the property with given accessors path from the first pile item where it's not undefined.
9767 */
9768
9769
9770 function topMost(pile, accessors) {
9771 var candidate;
9772
9773 if (!isArray$2(accessors)) {
9774 accessors = [accessors];
9775 }
9776
9777 var _iterator3 = _createForOfIteratorHelper$8(pile),
9778 _step3;
9779
9780 try {
9781 for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
9782 var member = _step3.value;
9783
9784 if (member) {
9785 candidate = member[accessors[0]];
9786
9787 for (var i = 1; i < accessors.length; i++) {
9788 if (candidate) {
9789 candidate = candidate[accessors[i]];
9790 }
9791 }
9792
9793 if (typeof candidate !== "undefined") {
9794 break;
9795 }
9796 }
9797 }
9798 } catch (err) {
9799 _iterator3.e(err);
9800 } finally {
9801 _iterator3.f();
9802 }
9803
9804 return candidate;
9805 }
9806
9807 var htmlColors = {
9808 black: "#000000",
9809 navy: "#000080",
9810 darkblue: "#00008B",
9811 mediumblue: "#0000CD",
9812 blue: "#0000FF",
9813 darkgreen: "#006400",
9814 green: "#008000",
9815 teal: "#008080",
9816 darkcyan: "#008B8B",
9817 deepskyblue: "#00BFFF",
9818 darkturquoise: "#00CED1",
9819 mediumspringgreen: "#00FA9A",
9820 lime: "#00FF00",
9821 springgreen: "#00FF7F",
9822 aqua: "#00FFFF",
9823 cyan: "#00FFFF",
9824 midnightblue: "#191970",
9825 dodgerblue: "#1E90FF",
9826 lightseagreen: "#20B2AA",
9827 forestgreen: "#228B22",
9828 seagreen: "#2E8B57",
9829 darkslategray: "#2F4F4F",
9830 limegreen: "#32CD32",
9831 mediumseagreen: "#3CB371",
9832 turquoise: "#40E0D0",
9833 royalblue: "#4169E1",
9834 steelblue: "#4682B4",
9835 darkslateblue: "#483D8B",
9836 mediumturquoise: "#48D1CC",
9837 indigo: "#4B0082",
9838 darkolivegreen: "#556B2F",
9839 cadetblue: "#5F9EA0",
9840 cornflowerblue: "#6495ED",
9841 mediumaquamarine: "#66CDAA",
9842 dimgray: "#696969",
9843 slateblue: "#6A5ACD",
9844 olivedrab: "#6B8E23",
9845 slategray: "#708090",
9846 lightslategray: "#778899",
9847 mediumslateblue: "#7B68EE",
9848 lawngreen: "#7CFC00",
9849 chartreuse: "#7FFF00",
9850 aquamarine: "#7FFFD4",
9851 maroon: "#800000",
9852 purple: "#800080",
9853 olive: "#808000",
9854 gray: "#808080",
9855 skyblue: "#87CEEB",
9856 lightskyblue: "#87CEFA",
9857 blueviolet: "#8A2BE2",
9858 darkred: "#8B0000",
9859 darkmagenta: "#8B008B",
9860 saddlebrown: "#8B4513",
9861 darkseagreen: "#8FBC8F",
9862 lightgreen: "#90EE90",
9863 mediumpurple: "#9370D8",
9864 darkviolet: "#9400D3",
9865 palegreen: "#98FB98",
9866 darkorchid: "#9932CC",
9867 yellowgreen: "#9ACD32",
9868 sienna: "#A0522D",
9869 brown: "#A52A2A",
9870 darkgray: "#A9A9A9",
9871 lightblue: "#ADD8E6",
9872 greenyellow: "#ADFF2F",
9873 paleturquoise: "#AFEEEE",
9874 lightsteelblue: "#B0C4DE",
9875 powderblue: "#B0E0E6",
9876 firebrick: "#B22222",
9877 darkgoldenrod: "#B8860B",
9878 mediumorchid: "#BA55D3",
9879 rosybrown: "#BC8F8F",
9880 darkkhaki: "#BDB76B",
9881 silver: "#C0C0C0",
9882 mediumvioletred: "#C71585",
9883 indianred: "#CD5C5C",
9884 peru: "#CD853F",
9885 chocolate: "#D2691E",
9886 tan: "#D2B48C",
9887 lightgrey: "#D3D3D3",
9888 palevioletred: "#D87093",
9889 thistle: "#D8BFD8",
9890 orchid: "#DA70D6",
9891 goldenrod: "#DAA520",
9892 crimson: "#DC143C",
9893 gainsboro: "#DCDCDC",
9894 plum: "#DDA0DD",
9895 burlywood: "#DEB887",
9896 lightcyan: "#E0FFFF",
9897 lavender: "#E6E6FA",
9898 darksalmon: "#E9967A",
9899 violet: "#EE82EE",
9900 palegoldenrod: "#EEE8AA",
9901 lightcoral: "#F08080",
9902 khaki: "#F0E68C",
9903 aliceblue: "#F0F8FF",
9904 honeydew: "#F0FFF0",
9905 azure: "#F0FFFF",
9906 sandybrown: "#F4A460",
9907 wheat: "#F5DEB3",
9908 beige: "#F5F5DC",
9909 whitesmoke: "#F5F5F5",
9910 mintcream: "#F5FFFA",
9911 ghostwhite: "#F8F8FF",
9912 salmon: "#FA8072",
9913 antiquewhite: "#FAEBD7",
9914 linen: "#FAF0E6",
9915 lightgoldenrodyellow: "#FAFAD2",
9916 oldlace: "#FDF5E6",
9917 red: "#FF0000",
9918 fuchsia: "#FF00FF",
9919 magenta: "#FF00FF",
9920 deeppink: "#FF1493",
9921 orangered: "#FF4500",
9922 tomato: "#FF6347",
9923 hotpink: "#FF69B4",
9924 coral: "#FF7F50",
9925 darkorange: "#FF8C00",
9926 lightsalmon: "#FFA07A",
9927 orange: "#FFA500",
9928 lightpink: "#FFB6C1",
9929 pink: "#FFC0CB",
9930 gold: "#FFD700",
9931 peachpuff: "#FFDAB9",
9932 navajowhite: "#FFDEAD",
9933 moccasin: "#FFE4B5",
9934 bisque: "#FFE4C4",
9935 mistyrose: "#FFE4E1",
9936 blanchedalmond: "#FFEBCD",
9937 papayawhip: "#FFEFD5",
9938 lavenderblush: "#FFF0F5",
9939 seashell: "#FFF5EE",
9940 cornsilk: "#FFF8DC",
9941 lemonchiffon: "#FFFACD",
9942 floralwhite: "#FFFAF0",
9943 snow: "#FFFAFA",
9944 yellow: "#FFFF00",
9945 lightyellow: "#FFFFE0",
9946 ivory: "#FFFFF0",
9947 white: "#FFFFFF"
9948 };
9949 /**
9950 * @param {number} [pixelRatio=1]
9951 */
9952
9953 var ColorPicker$1 = /*#__PURE__*/function () {
9954 /**
9955 * @param {number} [pixelRatio=1]
9956 */
9957 function ColorPicker$1() {
9958 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
9959
9960 _classCallCheck(this, ColorPicker$1);
9961
9962 this.pixelRatio = pixelRatio;
9963 this.generated = false;
9964 this.centerCoordinates = {
9965 x: 289 / 2,
9966 y: 289 / 2
9967 };
9968 this.r = 289 * 0.49;
9969 this.color = {
9970 r: 255,
9971 g: 255,
9972 b: 255,
9973 a: 1.0
9974 };
9975 this.hueCircle = undefined;
9976 this.initialColor = {
9977 r: 255,
9978 g: 255,
9979 b: 255,
9980 a: 1.0
9981 };
9982 this.previousColor = undefined;
9983 this.applied = false; // bound by
9984
9985 this.updateCallback = function () {};
9986
9987 this.closeCallback = function () {}; // create all DOM elements
9988
9989
9990 this._create();
9991 }
9992 /**
9993 * this inserts the colorPicker into a div from the DOM
9994 *
9995 * @param {Element} container
9996 */
9997
9998
9999 _createClass(ColorPicker$1, [{
10000 key: "insertTo",
10001 value: function insertTo(container) {
10002 if (this.hammer !== undefined) {
10003 this.hammer.destroy();
10004 this.hammer = undefined;
10005 }
10006
10007 this.container = container;
10008 this.container.appendChild(this.frame);
10009
10010 this._bindHammer();
10011
10012 this._setSize();
10013 }
10014 /**
10015 * the callback is executed on apply and save. Bind it to the application
10016 *
10017 * @param {Function} callback
10018 */
10019
10020 }, {
10021 key: "setUpdateCallback",
10022 value: function setUpdateCallback(callback) {
10023 if (typeof callback === "function") {
10024 this.updateCallback = callback;
10025 } else {
10026 throw new Error("Function attempted to set as colorPicker update callback is not a function.");
10027 }
10028 }
10029 /**
10030 * the callback is executed on apply and save. Bind it to the application
10031 *
10032 * @param {Function} callback
10033 */
10034
10035 }, {
10036 key: "setCloseCallback",
10037 value: function setCloseCallback(callback) {
10038 if (typeof callback === "function") {
10039 this.closeCallback = callback;
10040 } else {
10041 throw new Error("Function attempted to set as colorPicker closing callback is not a function.");
10042 }
10043 }
10044 /**
10045 *
10046 * @param {string} color
10047 * @returns {string}
10048 * @private
10049 */
10050
10051 }, {
10052 key: "_isColorString",
10053 value: function _isColorString(color) {
10054 if (typeof color === "string") {
10055 return htmlColors[color];
10056 }
10057 }
10058 /**
10059 * Set the color of the colorPicker
10060 * Supported formats:
10061 * 'red' --> HTML color string
10062 * '#ffffff' --> hex string
10063 * 'rgb(255,255,255)' --> rgb string
10064 * 'rgba(255,255,255,1.0)' --> rgba string
10065 * {r:255,g:255,b:255} --> rgb object
10066 * {r:255,g:255,b:255,a:1.0} --> rgba object
10067 *
10068 * @param {string | object} color
10069 * @param {boolean} [setInitial=true]
10070 */
10071
10072 }, {
10073 key: "setColor",
10074 value: function setColor(color) {
10075 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
10076
10077 if (color === "none") {
10078 return;
10079 }
10080
10081 var rgba; // if a html color shorthand is used, convert to hex
10082
10083 var htmlColor = this._isColorString(color);
10084
10085 if (htmlColor !== undefined) {
10086 color = htmlColor;
10087 } // check format
10088
10089
10090 if (isString(color) === true) {
10091 if (isValidRGB(color) === true) {
10092 var rgbaArray = color.substr(4).substr(0, color.length - 5).split(",");
10093 rgba = {
10094 r: rgbaArray[0],
10095 g: rgbaArray[1],
10096 b: rgbaArray[2],
10097 a: 1.0
10098 };
10099 } else if (isValidRGBA(color) === true) {
10100 var _rgbaArray = color.substr(5).substr(0, color.length - 6).split(",");
10101
10102 rgba = {
10103 r: _rgbaArray[0],
10104 g: _rgbaArray[1],
10105 b: _rgbaArray[2],
10106 a: _rgbaArray[3]
10107 };
10108 } else if (isValidHex(color) === true) {
10109 var rgbObj = hexToRGB(color);
10110 rgba = {
10111 r: rgbObj.r,
10112 g: rgbObj.g,
10113 b: rgbObj.b,
10114 a: 1.0
10115 };
10116 }
10117 } else {
10118 if (color instanceof Object) {
10119 if (color.r !== undefined && color.g !== undefined && color.b !== undefined) {
10120 var alpha = color.a !== undefined ? color.a : "1.0";
10121 rgba = {
10122 r: color.r,
10123 g: color.g,
10124 b: color.b,
10125 a: alpha
10126 };
10127 }
10128 }
10129 } // set color
10130
10131
10132 if (rgba === undefined) {
10133 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));
10134 } else {
10135 this._setColor(rgba, setInitial);
10136 }
10137 }
10138 /**
10139 * this shows the color picker.
10140 * The hue circle is constructed once and stored.
10141 */
10142
10143 }, {
10144 key: "show",
10145 value: function show() {
10146 if (this.closeCallback !== undefined) {
10147 this.closeCallback();
10148 this.closeCallback = undefined;
10149 }
10150
10151 this.applied = false;
10152 this.frame.style.display = "block";
10153
10154 this._generateHueCircle();
10155 } // ------------------------------------------ PRIVATE ----------------------------- //
10156
10157 /**
10158 * Hide the picker. Is called by the cancel button.
10159 * Optional boolean to store the previous color for easy access later on.
10160 *
10161 * @param {boolean} [storePrevious=true]
10162 * @private
10163 */
10164
10165 }, {
10166 key: "_hide",
10167 value: function _hide() {
10168 var _this2 = this;
10169
10170 var storePrevious = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
10171
10172 // store the previous color for next time;
10173 if (storePrevious === true) {
10174 this.previousColor = assign$2({}, this.color);
10175 }
10176
10177 if (this.applied === true) {
10178 this.updateCallback(this.initialColor);
10179 }
10180
10181 this.frame.style.display = "none"; // call the closing callback, restoring the onclick method.
10182 // this is in a setTimeout because it will trigger the show again before the click is done.
10183
10184 setTimeout$1(function () {
10185 if (_this2.closeCallback !== undefined) {
10186 _this2.closeCallback();
10187
10188 _this2.closeCallback = undefined;
10189 }
10190 }, 0);
10191 }
10192 /**
10193 * bound to the save button. Saves and hides.
10194 *
10195 * @private
10196 */
10197
10198 }, {
10199 key: "_save",
10200 value: function _save() {
10201 this.updateCallback(this.color);
10202 this.applied = false;
10203
10204 this._hide();
10205 }
10206 /**
10207 * Bound to apply button. Saves but does not close. Is undone by the cancel button.
10208 *
10209 * @private
10210 */
10211
10212 }, {
10213 key: "_apply",
10214 value: function _apply() {
10215 this.applied = true;
10216 this.updateCallback(this.color);
10217
10218 this._updatePicker(this.color);
10219 }
10220 /**
10221 * load the color from the previous session.
10222 *
10223 * @private
10224 */
10225
10226 }, {
10227 key: "_loadLast",
10228 value: function _loadLast() {
10229 if (this.previousColor !== undefined) {
10230 this.setColor(this.previousColor, false);
10231 } else {
10232 alert("There is no last color to load...");
10233 }
10234 }
10235 /**
10236 * set the color, place the picker
10237 *
10238 * @param {object} rgba
10239 * @param {boolean} [setInitial=true]
10240 * @private
10241 */
10242
10243 }, {
10244 key: "_setColor",
10245 value: function _setColor(rgba) {
10246 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
10247
10248 // store the initial color
10249 if (setInitial === true) {
10250 this.initialColor = assign$2({}, rgba);
10251 }
10252
10253 this.color = rgba;
10254 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
10255 var angleConvert = 2 * Math.PI;
10256 var radius = this.r * hsv.s;
10257 var x = this.centerCoordinates.x + radius * Math.sin(angleConvert * hsv.h);
10258 var y = this.centerCoordinates.y + radius * Math.cos(angleConvert * hsv.h);
10259 this.colorPickerSelector.style.left = x - 0.5 * this.colorPickerSelector.clientWidth + "px";
10260 this.colorPickerSelector.style.top = y - 0.5 * this.colorPickerSelector.clientHeight + "px";
10261
10262 this._updatePicker(rgba);
10263 }
10264 /**
10265 * bound to opacity control
10266 *
10267 * @param {number} value
10268 * @private
10269 */
10270
10271 }, {
10272 key: "_setOpacity",
10273 value: function _setOpacity(value) {
10274 this.color.a = value / 100;
10275
10276 this._updatePicker(this.color);
10277 }
10278 /**
10279 * bound to brightness control
10280 *
10281 * @param {number} value
10282 * @private
10283 */
10284
10285 }, {
10286 key: "_setBrightness",
10287 value: function _setBrightness(value) {
10288 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
10289 hsv.v = value / 100;
10290 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
10291 rgba["a"] = this.color.a;
10292 this.color = rgba;
10293
10294 this._updatePicker();
10295 }
10296 /**
10297 * update the color picker. A black circle overlays the hue circle to mimic the brightness decreasing.
10298 *
10299 * @param {object} rgba
10300 * @private
10301 */
10302
10303 }, {
10304 key: "_updatePicker",
10305 value: function _updatePicker() {
10306 var rgba = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.color;
10307 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
10308 var ctx = this.colorPickerCanvas.getContext("2d");
10309
10310 if (this.pixelRation === undefined) {
10311 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
10312 }
10313
10314 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
10315
10316 var w = this.colorPickerCanvas.clientWidth;
10317 var h = this.colorPickerCanvas.clientHeight;
10318 ctx.clearRect(0, 0, w, h);
10319 ctx.putImageData(this.hueCircle, 0, 0);
10320 ctx.fillStyle = "rgba(0,0,0," + (1 - hsv.v) + ")";
10321 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
10322
10323 fill(ctx).call(ctx);
10324
10325 this.brightnessRange.value = 100 * hsv.v;
10326 this.opacityRange.value = 100 * rgba.a;
10327 this.initialColorDiv.style.backgroundColor = "rgba(" + this.initialColor.r + "," + this.initialColor.g + "," + this.initialColor.b + "," + this.initialColor.a + ")";
10328 this.newColorDiv.style.backgroundColor = "rgba(" + this.color.r + "," + this.color.g + "," + this.color.b + "," + this.color.a + ")";
10329 }
10330 /**
10331 * used by create to set the size of the canvas.
10332 *
10333 * @private
10334 */
10335
10336 }, {
10337 key: "_setSize",
10338 value: function _setSize() {
10339 this.colorPickerCanvas.style.width = "100%";
10340 this.colorPickerCanvas.style.height = "100%";
10341 this.colorPickerCanvas.width = 289 * this.pixelRatio;
10342 this.colorPickerCanvas.height = 289 * this.pixelRatio;
10343 }
10344 /**
10345 * create all dom elements
10346 * TODO: cleanup, lots of similar dom elements
10347 *
10348 * @private
10349 */
10350
10351 }, {
10352 key: "_create",
10353 value: function _create() {
10354 var _context16, _context17, _context18, _context19;
10355
10356 this.frame = document.createElement("div");
10357 this.frame.className = "vis-color-picker";
10358 this.colorPickerDiv = document.createElement("div");
10359 this.colorPickerSelector = document.createElement("div");
10360 this.colorPickerSelector.className = "vis-selector";
10361 this.colorPickerDiv.appendChild(this.colorPickerSelector);
10362 this.colorPickerCanvas = document.createElement("canvas");
10363 this.colorPickerDiv.appendChild(this.colorPickerCanvas);
10364
10365 if (!this.colorPickerCanvas.getContext) {
10366 var noCanvas = document.createElement("DIV");
10367 noCanvas.style.color = "red";
10368 noCanvas.style.fontWeight = "bold";
10369 noCanvas.style.padding = "10px";
10370 noCanvas.innerText = "Error: your browser does not support HTML canvas";
10371 this.colorPickerCanvas.appendChild(noCanvas);
10372 } else {
10373 var ctx = this.colorPickerCanvas.getContext("2d");
10374 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
10375 this.colorPickerCanvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
10376 }
10377
10378 this.colorPickerDiv.className = "vis-color";
10379 this.opacityDiv = document.createElement("div");
10380 this.opacityDiv.className = "vis-opacity";
10381 this.brightnessDiv = document.createElement("div");
10382 this.brightnessDiv.className = "vis-brightness";
10383 this.arrowDiv = document.createElement("div");
10384 this.arrowDiv.className = "vis-arrow";
10385 this.opacityRange = document.createElement("input");
10386
10387 try {
10388 this.opacityRange.type = "range"; // Not supported on IE9
10389
10390 this.opacityRange.min = "0";
10391 this.opacityRange.max = "100";
10392 } catch (err) {// TODO: Add some error handling.
10393 }
10394
10395 this.opacityRange.value = "100";
10396 this.opacityRange.className = "vis-range";
10397 this.brightnessRange = document.createElement("input");
10398
10399 try {
10400 this.brightnessRange.type = "range"; // Not supported on IE9
10401
10402 this.brightnessRange.min = "0";
10403 this.brightnessRange.max = "100";
10404 } catch (err) {// TODO: Add some error handling.
10405 }
10406
10407 this.brightnessRange.value = "100";
10408 this.brightnessRange.className = "vis-range";
10409 this.opacityDiv.appendChild(this.opacityRange);
10410 this.brightnessDiv.appendChild(this.brightnessRange);
10411 var me = this;
10412
10413 this.opacityRange.onchange = function () {
10414 me._setOpacity(this.value);
10415 };
10416
10417 this.opacityRange.oninput = function () {
10418 me._setOpacity(this.value);
10419 };
10420
10421 this.brightnessRange.onchange = function () {
10422 me._setBrightness(this.value);
10423 };
10424
10425 this.brightnessRange.oninput = function () {
10426 me._setBrightness(this.value);
10427 };
10428
10429 this.brightnessLabel = document.createElement("div");
10430 this.brightnessLabel.className = "vis-label vis-brightness";
10431 this.brightnessLabel.innerText = "brightness:";
10432 this.opacityLabel = document.createElement("div");
10433 this.opacityLabel.className = "vis-label vis-opacity";
10434 this.opacityLabel.innerText = "opacity:";
10435 this.newColorDiv = document.createElement("div");
10436 this.newColorDiv.className = "vis-new-color";
10437 this.newColorDiv.innerText = "new";
10438 this.initialColorDiv = document.createElement("div");
10439 this.initialColorDiv.className = "vis-initial-color";
10440 this.initialColorDiv.innerText = "initial";
10441 this.cancelButton = document.createElement("div");
10442 this.cancelButton.className = "vis-button vis-cancel";
10443 this.cancelButton.innerText = "cancel";
10444 this.cancelButton.onclick = bind$6(_context16 = this._hide).call(_context16, this, false);
10445 this.applyButton = document.createElement("div");
10446 this.applyButton.className = "vis-button vis-apply";
10447 this.applyButton.innerText = "apply";
10448 this.applyButton.onclick = bind$6(_context17 = this._apply).call(_context17, this);
10449 this.saveButton = document.createElement("div");
10450 this.saveButton.className = "vis-button vis-save";
10451 this.saveButton.innerText = "save";
10452 this.saveButton.onclick = bind$6(_context18 = this._save).call(_context18, this);
10453 this.loadButton = document.createElement("div");
10454 this.loadButton.className = "vis-button vis-load";
10455 this.loadButton.innerText = "load last";
10456 this.loadButton.onclick = bind$6(_context19 = this._loadLast).call(_context19, this);
10457 this.frame.appendChild(this.colorPickerDiv);
10458 this.frame.appendChild(this.arrowDiv);
10459 this.frame.appendChild(this.brightnessLabel);
10460 this.frame.appendChild(this.brightnessDiv);
10461 this.frame.appendChild(this.opacityLabel);
10462 this.frame.appendChild(this.opacityDiv);
10463 this.frame.appendChild(this.newColorDiv);
10464 this.frame.appendChild(this.initialColorDiv);
10465 this.frame.appendChild(this.cancelButton);
10466 this.frame.appendChild(this.applyButton);
10467 this.frame.appendChild(this.saveButton);
10468 this.frame.appendChild(this.loadButton);
10469 }
10470 /**
10471 * bind hammer to the color picker
10472 *
10473 * @private
10474 */
10475
10476 }, {
10477 key: "_bindHammer",
10478 value: function _bindHammer() {
10479 var _this3 = this;
10480
10481 this.drag = {};
10482 this.pinch = {};
10483 this.hammer = new Hammer$1(this.colorPickerCanvas);
10484 this.hammer.get("pinch").set({
10485 enable: true
10486 });
10487 this.hammer.on("hammer.input", function (event) {
10488 if (event.isFirst) {
10489 _this3._moveSelector(event);
10490 }
10491 });
10492 this.hammer.on("tap", function (event) {
10493 _this3._moveSelector(event);
10494 });
10495 this.hammer.on("panstart", function (event) {
10496 _this3._moveSelector(event);
10497 });
10498 this.hammer.on("panmove", function (event) {
10499 _this3._moveSelector(event);
10500 });
10501 this.hammer.on("panend", function (event) {
10502 _this3._moveSelector(event);
10503 });
10504 }
10505 /**
10506 * generate the hue circle. This is relatively heavy (200ms) and is done only once on the first time it is shown.
10507 *
10508 * @private
10509 */
10510
10511 }, {
10512 key: "_generateHueCircle",
10513 value: function _generateHueCircle() {
10514 if (this.generated === false) {
10515 var ctx = this.colorPickerCanvas.getContext("2d");
10516
10517 if (this.pixelRation === undefined) {
10518 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
10519 }
10520
10521 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
10522
10523 var w = this.colorPickerCanvas.clientWidth;
10524 var h = this.colorPickerCanvas.clientHeight;
10525 ctx.clearRect(0, 0, w, h); // draw hue circle
10526
10527 var x, y, hue, sat;
10528 this.centerCoordinates = {
10529 x: w * 0.5,
10530 y: h * 0.5
10531 };
10532 this.r = 0.49 * w;
10533 var angleConvert = 2 * Math.PI / 360;
10534 var hfac = 1 / 360;
10535 var sfac = 1 / this.r;
10536 var rgb;
10537
10538 for (hue = 0; hue < 360; hue++) {
10539 for (sat = 0; sat < this.r; sat++) {
10540 x = this.centerCoordinates.x + sat * Math.sin(angleConvert * hue);
10541 y = this.centerCoordinates.y + sat * Math.cos(angleConvert * hue);
10542 rgb = HSVToRGB(hue * hfac, sat * sfac, 1);
10543 ctx.fillStyle = "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")";
10544 ctx.fillRect(x - 0.5, y - 0.5, 2, 2);
10545 }
10546 }
10547
10548 ctx.strokeStyle = "rgba(0,0,0,1)";
10549 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
10550 ctx.stroke();
10551 this.hueCircle = ctx.getImageData(0, 0, w, h);
10552 }
10553
10554 this.generated = true;
10555 }
10556 /**
10557 * move the selector. This is called by hammer functions.
10558 *
10559 * @param {Event} event The event
10560 * @private
10561 */
10562
10563 }, {
10564 key: "_moveSelector",
10565 value: function _moveSelector(event) {
10566 var rect = this.colorPickerDiv.getBoundingClientRect();
10567 var left = event.center.x - rect.left;
10568 var top = event.center.y - rect.top;
10569 var centerY = 0.5 * this.colorPickerDiv.clientHeight;
10570 var centerX = 0.5 * this.colorPickerDiv.clientWidth;
10571 var x = left - centerX;
10572 var y = top - centerY;
10573 var angle = Math.atan2(x, y);
10574 var radius = 0.98 * Math.min(Math.sqrt(x * x + y * y), centerX);
10575 var newTop = Math.cos(angle) * radius + centerY;
10576 var newLeft = Math.sin(angle) * radius + centerX;
10577 this.colorPickerSelector.style.top = newTop - 0.5 * this.colorPickerSelector.clientHeight + "px";
10578 this.colorPickerSelector.style.left = newLeft - 0.5 * this.colorPickerSelector.clientWidth + "px"; // set color
10579
10580 var h = angle / (2 * Math.PI);
10581 h = h < 0 ? h + 1 : h;
10582 var s = radius / this.r;
10583 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
10584 hsv.h = h;
10585 hsv.s = s;
10586 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
10587 rgba["a"] = this.color.a;
10588 this.color = rgba; // update previews
10589
10590 this.initialColorDiv.style.backgroundColor = "rgba(" + this.initialColor.r + "," + this.initialColor.g + "," + this.initialColor.b + "," + this.initialColor.a + ")";
10591 this.newColorDiv.style.backgroundColor = "rgba(" + this.color.r + "," + this.color.g + "," + this.color.b + "," + this.color.a + ")";
10592 }
10593 }]);
10594
10595 return ColorPicker$1;
10596 }();
10597 /**
10598 * Wrap given text (last argument) in HTML elements (all preceding arguments).
10599 *
10600 * @param {...any} rest - List of tag names followed by inner text.
10601 * @returns An element or a text node.
10602 */
10603
10604
10605 function wrapInTag() {
10606 for (var _len5 = arguments.length, rest = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
10607 rest[_key5] = arguments[_key5];
10608 }
10609
10610 if (rest.length < 1) {
10611 throw new TypeError("Invalid arguments.");
10612 } else if (rest.length === 1) {
10613 return document.createTextNode(rest[0]);
10614 } else {
10615 var element = document.createElement(rest[0]);
10616 element.appendChild(wrapInTag.apply(void 0, _toConsumableArray(slice(rest).call(rest, 1))));
10617 return element;
10618 }
10619 }
10620 /**
10621 * 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.
10622 * Boolean options are recognised as Boolean
10623 * Number options should be written as array: [default value, min value, max value, stepsize]
10624 * Colors should be written as array: ['color', '#ffffff']
10625 * Strings with should be written as array: [option1, option2, option3, ..]
10626 *
10627 * The options are matched with their counterparts in each of the modules and the values used in the configuration are
10628 */
10629
10630
10631 var Configurator$1 = /*#__PURE__*/function () {
10632 /**
10633 * @param {object} parentModule | the location where parentModule.setOptions() can be called
10634 * @param {object} defaultContainer | the default container of the module
10635 * @param {object} configureOptions | the fully configured and predefined options set found in allOptions.js
10636 * @param {number} pixelRatio | canvas pixel ratio
10637 * @param {Function} hideOption | custom logic to dynamically hide options
10638 */
10639 function Configurator$1(parentModule, defaultContainer, configureOptions) {
10640 var pixelRatio = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
10641 var hideOption = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : function () {
10642 return false;
10643 };
10644
10645 _classCallCheck(this, Configurator$1);
10646
10647 this.parent = parentModule;
10648 this.changedOptions = [];
10649 this.container = defaultContainer;
10650 this.allowCreation = false;
10651 this.hideOption = hideOption;
10652 this.options = {};
10653 this.initialized = false;
10654 this.popupCounter = 0;
10655 this.defaultOptions = {
10656 enabled: false,
10657 filter: true,
10658 container: undefined,
10659 showButton: true
10660 };
10661
10662 assign$2(this.options, this.defaultOptions);
10663
10664 this.configureOptions = configureOptions;
10665 this.moduleOptions = {};
10666 this.domElements = [];
10667 this.popupDiv = {};
10668 this.popupLimit = 5;
10669 this.popupHistory = {};
10670 this.colorPicker = new ColorPicker$1(pixelRatio);
10671 this.wrapper = undefined;
10672 }
10673 /**
10674 * refresh all options.
10675 * Because all modules parse their options by themselves, we just use their options. We copy them here.
10676 *
10677 * @param {object} options
10678 */
10679
10680
10681 _createClass(Configurator$1, [{
10682 key: "setOptions",
10683 value: function setOptions(options) {
10684 if (options !== undefined) {
10685 // reset the popup history because the indices may have been changed.
10686 this.popupHistory = {};
10687
10688 this._removePopup();
10689
10690 var enabled = true;
10691
10692 if (typeof options === "string") {
10693 this.options.filter = options;
10694 } else if (isArray$2(options)) {
10695 this.options.filter = options.join();
10696 } else if (_typeof(options) === "object") {
10697 if (options == null) {
10698 throw new TypeError("options cannot be null");
10699 }
10700
10701 if (options.container !== undefined) {
10702 this.options.container = options.container;
10703 }
10704
10705 if (filter(options) !== undefined) {
10706 this.options.filter = filter(options);
10707 }
10708
10709 if (options.showButton !== undefined) {
10710 this.options.showButton = options.showButton;
10711 }
10712
10713 if (options.enabled !== undefined) {
10714 enabled = options.enabled;
10715 }
10716 } else if (typeof options === "boolean") {
10717 this.options.filter = true;
10718 enabled = options;
10719 } else if (typeof options === "function") {
10720 this.options.filter = options;
10721 enabled = true;
10722 }
10723
10724 if (filter(this.options) === false) {
10725 enabled = false;
10726 }
10727
10728 this.options.enabled = enabled;
10729 }
10730
10731 this._clean();
10732 }
10733 /**
10734 *
10735 * @param {object} moduleOptions
10736 */
10737
10738 }, {
10739 key: "setModuleOptions",
10740 value: function setModuleOptions(moduleOptions) {
10741 this.moduleOptions = moduleOptions;
10742
10743 if (this.options.enabled === true) {
10744 this._clean();
10745
10746 if (this.options.container !== undefined) {
10747 this.container = this.options.container;
10748 }
10749
10750 this._create();
10751 }
10752 }
10753 /**
10754 * Create all DOM elements
10755 *
10756 * @private
10757 */
10758
10759 }, {
10760 key: "_create",
10761 value: function _create() {
10762 this._clean();
10763
10764 this.changedOptions = [];
10765
10766 var filter$1 = filter(this.options);
10767
10768 var counter = 0;
10769 var show = false;
10770
10771 for (var _option in this.configureOptions) {
10772 if (Object.prototype.hasOwnProperty.call(this.configureOptions, _option)) {
10773 this.allowCreation = false;
10774 show = false;
10775
10776 if (typeof filter$1 === "function") {
10777 show = filter$1(_option, []);
10778 show = show || this._handleObject(this.configureOptions[_option], [_option], true);
10779 } else if (filter$1 === true || indexOf(filter$1).call(filter$1, _option) !== -1) {
10780 show = true;
10781 }
10782
10783 if (show !== false) {
10784 this.allowCreation = true; // linebreak between categories
10785
10786 if (counter > 0) {
10787 this._makeItem([]);
10788 } // a header for the category
10789
10790
10791 this._makeHeader(_option); // get the sub options
10792
10793
10794 this._handleObject(this.configureOptions[_option], [_option]);
10795 }
10796
10797 counter++;
10798 }
10799 }
10800
10801 this._makeButton();
10802
10803 this._push(); //~ this.colorPicker.insertTo(this.container);
10804
10805 }
10806 /**
10807 * draw all DOM elements on the screen
10808 *
10809 * @private
10810 */
10811
10812 }, {
10813 key: "_push",
10814 value: function _push() {
10815 this.wrapper = document.createElement("div");
10816 this.wrapper.className = "vis-configuration-wrapper";
10817 this.container.appendChild(this.wrapper);
10818
10819 for (var i = 0; i < this.domElements.length; i++) {
10820 this.wrapper.appendChild(this.domElements[i]);
10821 }
10822
10823 this._showPopupIfNeeded();
10824 }
10825 /**
10826 * delete all DOM elements
10827 *
10828 * @private
10829 */
10830
10831 }, {
10832 key: "_clean",
10833 value: function _clean() {
10834 for (var i = 0; i < this.domElements.length; i++) {
10835 this.wrapper.removeChild(this.domElements[i]);
10836 }
10837
10838 if (this.wrapper !== undefined) {
10839 this.container.removeChild(this.wrapper);
10840 this.wrapper = undefined;
10841 }
10842
10843 this.domElements = [];
10844
10845 this._removePopup();
10846 }
10847 /**
10848 * get the value from the actualOptions if it exists
10849 *
10850 * @param {Array} path | where to look for the actual option
10851 * @returns {*}
10852 * @private
10853 */
10854
10855 }, {
10856 key: "_getValue",
10857 value: function _getValue(path) {
10858 var base = this.moduleOptions;
10859
10860 for (var i = 0; i < path.length; i++) {
10861 if (base[path[i]] !== undefined) {
10862 base = base[path[i]];
10863 } else {
10864 base = undefined;
10865 break;
10866 }
10867 }
10868
10869 return base;
10870 }
10871 /**
10872 * all option elements are wrapped in an item
10873 *
10874 * @param {Array} path | where to look for the actual option
10875 * @param {Array.<Element>} domElements
10876 * @returns {number}
10877 * @private
10878 */
10879
10880 }, {
10881 key: "_makeItem",
10882 value: function _makeItem(path) {
10883 if (this.allowCreation === true) {
10884 var item = document.createElement("div");
10885 item.className = "vis-configuration vis-config-item vis-config-s" + path.length;
10886
10887 for (var _len6 = arguments.length, domElements = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
10888 domElements[_key6 - 1] = arguments[_key6];
10889 }
10890
10891 forEach$2(domElements).call(domElements, function (element) {
10892 item.appendChild(element);
10893 });
10894
10895 this.domElements.push(item);
10896 return this.domElements.length;
10897 }
10898
10899 return 0;
10900 }
10901 /**
10902 * header for major subjects
10903 *
10904 * @param {string} name
10905 * @private
10906 */
10907
10908 }, {
10909 key: "_makeHeader",
10910 value: function _makeHeader(name) {
10911 var div = document.createElement("div");
10912 div.className = "vis-configuration vis-config-header";
10913 div.innerText = name;
10914
10915 this._makeItem([], div);
10916 }
10917 /**
10918 * make a label, if it is an object label, it gets different styling.
10919 *
10920 * @param {string} name
10921 * @param {Array} path | where to look for the actual option
10922 * @param {string} objectLabel
10923 * @returns {HTMLElement}
10924 * @private
10925 */
10926
10927 }, {
10928 key: "_makeLabel",
10929 value: function _makeLabel(name, path) {
10930 var objectLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
10931 var div = document.createElement("div");
10932 div.className = "vis-configuration vis-config-label vis-config-s" + path.length;
10933
10934 if (objectLabel === true) {
10935 while (div.firstChild) {
10936 div.removeChild(div.firstChild);
10937 }
10938
10939 div.appendChild(wrapInTag("i", "b", name));
10940 } else {
10941 div.innerText = name + ":";
10942 }
10943
10944 return div;
10945 }
10946 /**
10947 * make a dropdown list for multiple possible string optoins
10948 *
10949 * @param {Array.<number>} arr
10950 * @param {number} value
10951 * @param {Array} path | where to look for the actual option
10952 * @private
10953 */
10954
10955 }, {
10956 key: "_makeDropdown",
10957 value: function _makeDropdown(arr, value, path) {
10958 var select = document.createElement("select");
10959 select.className = "vis-configuration vis-config-select";
10960 var selectedValue = 0;
10961
10962 if (value !== undefined) {
10963 if (indexOf(arr).call(arr, value) !== -1) {
10964 selectedValue = indexOf(arr).call(arr, value);
10965 }
10966 }
10967
10968 for (var i = 0; i < arr.length; i++) {
10969 var _option2 = document.createElement("option");
10970
10971 _option2.value = arr[i];
10972
10973 if (i === selectedValue) {
10974 _option2.selected = "selected";
10975 }
10976
10977 _option2.innerText = arr[i];
10978 select.appendChild(_option2);
10979 }
10980
10981 var me = this;
10982
10983 select.onchange = function () {
10984 me._update(this.value, path);
10985 };
10986
10987 var label = this._makeLabel(path[path.length - 1], path);
10988
10989 this._makeItem(path, label, select);
10990 }
10991 /**
10992 * make a range object for numeric options
10993 *
10994 * @param {Array.<number>} arr
10995 * @param {number} value
10996 * @param {Array} path | where to look for the actual option
10997 * @private
10998 */
10999
11000 }, {
11001 key: "_makeRange",
11002 value: function _makeRange(arr, value, path) {
11003 var defaultValue = arr[0];
11004 var min = arr[1];
11005 var max = arr[2];
11006 var step = arr[3];
11007 var range = document.createElement("input");
11008 range.className = "vis-configuration vis-config-range";
11009
11010 try {
11011 range.type = "range"; // not supported on IE9
11012
11013 range.min = min;
11014 range.max = max;
11015 } catch (err) {// TODO: Add some error handling.
11016 }
11017
11018 range.step = step; // set up the popup settings in case they are needed.
11019
11020 var popupString = "";
11021 var popupValue = 0;
11022
11023 if (value !== undefined) {
11024 var factor = 1.2;
11025
11026 if (value < 0 && value * factor < min) {
11027 range.min = Math.ceil(value * factor);
11028 popupValue = range.min;
11029 popupString = "range increased";
11030 } else if (value / factor < min) {
11031 range.min = Math.ceil(value / factor);
11032 popupValue = range.min;
11033 popupString = "range increased";
11034 }
11035
11036 if (value * factor > max && max !== 1) {
11037 range.max = Math.ceil(value * factor);
11038 popupValue = range.max;
11039 popupString = "range increased";
11040 }
11041
11042 range.value = value;
11043 } else {
11044 range.value = defaultValue;
11045 }
11046
11047 var input = document.createElement("input");
11048 input.className = "vis-configuration vis-config-rangeinput";
11049 input.value = range.value;
11050 var me = this;
11051
11052 range.onchange = function () {
11053 input.value = this.value;
11054
11055 me._update(Number(this.value), path);
11056 };
11057
11058 range.oninput = function () {
11059 input.value = this.value;
11060 };
11061
11062 var label = this._makeLabel(path[path.length - 1], path);
11063
11064 var itemIndex = this._makeItem(path, label, range, input); // if a popup is needed AND it has not been shown for this value, show it.
11065
11066
11067 if (popupString !== "" && this.popupHistory[itemIndex] !== popupValue) {
11068 this.popupHistory[itemIndex] = popupValue;
11069
11070 this._setupPopup(popupString, itemIndex);
11071 }
11072 }
11073 /**
11074 * make a button object
11075 *
11076 * @private
11077 */
11078
11079 }, {
11080 key: "_makeButton",
11081 value: function _makeButton() {
11082 var _this4 = this;
11083
11084 if (this.options.showButton === true) {
11085 var generateButton = document.createElement("div");
11086 generateButton.className = "vis-configuration vis-config-button";
11087 generateButton.innerText = "generate options";
11088
11089 generateButton.onclick = function () {
11090 _this4._printOptions();
11091 };
11092
11093 generateButton.onmouseover = function () {
11094 generateButton.className = "vis-configuration vis-config-button hover";
11095 };
11096
11097 generateButton.onmouseout = function () {
11098 generateButton.className = "vis-configuration vis-config-button";
11099 };
11100
11101 this.optionsContainer = document.createElement("div");
11102 this.optionsContainer.className = "vis-configuration vis-config-option-container";
11103 this.domElements.push(this.optionsContainer);
11104 this.domElements.push(generateButton);
11105 }
11106 }
11107 /**
11108 * prepare the popup
11109 *
11110 * @param {string} string
11111 * @param {number} index
11112 * @private
11113 */
11114
11115 }, {
11116 key: "_setupPopup",
11117 value: function _setupPopup(string, index) {
11118 var _this5 = this;
11119
11120 if (this.initialized === true && this.allowCreation === true && this.popupCounter < this.popupLimit) {
11121 var div = document.createElement("div");
11122 div.id = "vis-configuration-popup";
11123 div.className = "vis-configuration-popup";
11124 div.innerText = string;
11125
11126 div.onclick = function () {
11127 _this5._removePopup();
11128 };
11129
11130 this.popupCounter += 1;
11131 this.popupDiv = {
11132 html: div,
11133 index: index
11134 };
11135 }
11136 }
11137 /**
11138 * remove the popup from the dom
11139 *
11140 * @private
11141 */
11142
11143 }, {
11144 key: "_removePopup",
11145 value: function _removePopup() {
11146 if (this.popupDiv.html !== undefined) {
11147 this.popupDiv.html.parentNode.removeChild(this.popupDiv.html);
11148 clearTimeout(this.popupDiv.hideTimeout);
11149 clearTimeout(this.popupDiv.deleteTimeout);
11150 this.popupDiv = {};
11151 }
11152 }
11153 /**
11154 * Show the popup if it is needed.
11155 *
11156 * @private
11157 */
11158
11159 }, {
11160 key: "_showPopupIfNeeded",
11161 value: function _showPopupIfNeeded() {
11162 var _this6 = this;
11163
11164 if (this.popupDiv.html !== undefined) {
11165 var correspondingElement = this.domElements[this.popupDiv.index];
11166 var rect = correspondingElement.getBoundingClientRect();
11167 this.popupDiv.html.style.left = rect.left + "px";
11168 this.popupDiv.html.style.top = rect.top - 30 + "px"; // 30 is the height;
11169
11170 document.body.appendChild(this.popupDiv.html);
11171 this.popupDiv.hideTimeout = setTimeout$1(function () {
11172 _this6.popupDiv.html.style.opacity = 0;
11173 }, 1500);
11174 this.popupDiv.deleteTimeout = setTimeout$1(function () {
11175 _this6._removePopup();
11176 }, 1800);
11177 }
11178 }
11179 /**
11180 * make a checkbox for boolean options.
11181 *
11182 * @param {number} defaultValue
11183 * @param {number} value
11184 * @param {Array} path | where to look for the actual option
11185 * @private
11186 */
11187
11188 }, {
11189 key: "_makeCheckbox",
11190 value: function _makeCheckbox(defaultValue, value, path) {
11191 var checkbox = document.createElement("input");
11192 checkbox.type = "checkbox";
11193 checkbox.className = "vis-configuration vis-config-checkbox";
11194 checkbox.checked = defaultValue;
11195
11196 if (value !== undefined) {
11197 checkbox.checked = value;
11198
11199 if (value !== defaultValue) {
11200 if (_typeof(defaultValue) === "object") {
11201 if (value !== defaultValue.enabled) {
11202 this.changedOptions.push({
11203 path: path,
11204 value: value
11205 });
11206 }
11207 } else {
11208 this.changedOptions.push({
11209 path: path,
11210 value: value
11211 });
11212 }
11213 }
11214 }
11215
11216 var me = this;
11217
11218 checkbox.onchange = function () {
11219 me._update(this.checked, path);
11220 };
11221
11222 var label = this._makeLabel(path[path.length - 1], path);
11223
11224 this._makeItem(path, label, checkbox);
11225 }
11226 /**
11227 * make a text input field for string options.
11228 *
11229 * @param {number} defaultValue
11230 * @param {number} value
11231 * @param {Array} path | where to look for the actual option
11232 * @private
11233 */
11234
11235 }, {
11236 key: "_makeTextInput",
11237 value: function _makeTextInput(defaultValue, value, path) {
11238 var checkbox = document.createElement("input");
11239 checkbox.type = "text";
11240 checkbox.className = "vis-configuration vis-config-text";
11241 checkbox.value = value;
11242
11243 if (value !== defaultValue) {
11244 this.changedOptions.push({
11245 path: path,
11246 value: value
11247 });
11248 }
11249
11250 var me = this;
11251
11252 checkbox.onchange = function () {
11253 me._update(this.value, path);
11254 };
11255
11256 var label = this._makeLabel(path[path.length - 1], path);
11257
11258 this._makeItem(path, label, checkbox);
11259 }
11260 /**
11261 * make a color field with a color picker for color fields
11262 *
11263 * @param {Array.<number>} arr
11264 * @param {number} value
11265 * @param {Array} path | where to look for the actual option
11266 * @private
11267 */
11268
11269 }, {
11270 key: "_makeColorField",
11271 value: function _makeColorField(arr, value, path) {
11272 var _this7 = this;
11273
11274 var defaultColor = arr[1];
11275 var div = document.createElement("div");
11276 value = value === undefined ? defaultColor : value;
11277
11278 if (value !== "none") {
11279 div.className = "vis-configuration vis-config-colorBlock";
11280 div.style.backgroundColor = value;
11281 } else {
11282 div.className = "vis-configuration vis-config-colorBlock none";
11283 }
11284
11285 value = value === undefined ? defaultColor : value;
11286
11287 div.onclick = function () {
11288 _this7._showColorPicker(value, div, path);
11289 };
11290
11291 var label = this._makeLabel(path[path.length - 1], path);
11292
11293 this._makeItem(path, label, div);
11294 }
11295 /**
11296 * used by the color buttons to call the color picker.
11297 *
11298 * @param {number} value
11299 * @param {HTMLElement} div
11300 * @param {Array} path | where to look for the actual option
11301 * @private
11302 */
11303
11304 }, {
11305 key: "_showColorPicker",
11306 value: function _showColorPicker(value, div, path) {
11307 var _this8 = this;
11308
11309 // clear the callback from this div
11310 div.onclick = function () {};
11311
11312 this.colorPicker.insertTo(div);
11313 this.colorPicker.show();
11314 this.colorPicker.setColor(value);
11315 this.colorPicker.setUpdateCallback(function (color) {
11316 var colorString = "rgba(" + color.r + "," + color.g + "," + color.b + "," + color.a + ")";
11317 div.style.backgroundColor = colorString;
11318
11319 _this8._update(colorString, path);
11320 }); // on close of the colorpicker, restore the callback.
11321
11322 this.colorPicker.setCloseCallback(function () {
11323 div.onclick = function () {
11324 _this8._showColorPicker(value, div, path);
11325 };
11326 });
11327 }
11328 /**
11329 * parse an object and draw the correct items
11330 *
11331 * @param {object} obj
11332 * @param {Array} [path=[]] | where to look for the actual option
11333 * @param {boolean} [checkOnly=false]
11334 * @returns {boolean}
11335 * @private
11336 */
11337
11338 }, {
11339 key: "_handleObject",
11340 value: function _handleObject(obj) {
11341 var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
11342 var checkOnly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
11343 var show = false;
11344
11345 var filter$1 = filter(this.options);
11346
11347 var visibleInSet = false;
11348
11349 for (var subObj in obj) {
11350 if (Object.prototype.hasOwnProperty.call(obj, subObj)) {
11351 show = true;
11352 var item = obj[subObj];
11353 var newPath = copyAndExtendArray(path, subObj);
11354
11355 if (typeof filter$1 === "function") {
11356 show = filter$1(subObj, path); // if needed we must go deeper into the object.
11357
11358 if (show === false) {
11359 if (!isArray$2(item) && typeof item !== "string" && typeof item !== "boolean" && item instanceof Object) {
11360 this.allowCreation = false;
11361 show = this._handleObject(item, newPath, true);
11362 this.allowCreation = checkOnly === false;
11363 }
11364 }
11365 }
11366
11367 if (show !== false) {
11368 visibleInSet = true;
11369
11370 var value = this._getValue(newPath);
11371
11372 if (isArray$2(item)) {
11373 this._handleArray(item, value, newPath);
11374 } else if (typeof item === "string") {
11375 this._makeTextInput(item, value, newPath);
11376 } else if (typeof item === "boolean") {
11377 this._makeCheckbox(item, value, newPath);
11378 } else if (item instanceof Object) {
11379 // skip the options that are not enabled
11380 if (!this.hideOption(path, subObj, this.moduleOptions)) {
11381 // initially collapse options with an disabled enabled option.
11382 if (item.enabled !== undefined) {
11383 var enabledPath = copyAndExtendArray(newPath, "enabled");
11384
11385 var enabledValue = this._getValue(enabledPath);
11386
11387 if (enabledValue === true) {
11388 var label = this._makeLabel(subObj, newPath, true);
11389
11390 this._makeItem(newPath, label);
11391
11392 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
11393 } else {
11394 this._makeCheckbox(item, enabledValue, newPath);
11395 }
11396 } else {
11397 var _label = this._makeLabel(subObj, newPath, true);
11398
11399 this._makeItem(newPath, _label);
11400
11401 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
11402 }
11403 }
11404 } else {
11405 console.error("dont know how to handle", item, subObj, newPath);
11406 }
11407 }
11408 }
11409 }
11410
11411 return visibleInSet;
11412 }
11413 /**
11414 * handle the array type of option
11415 *
11416 * @param {Array.<number>} arr
11417 * @param {number} value
11418 * @param {Array} path | where to look for the actual option
11419 * @private
11420 */
11421
11422 }, {
11423 key: "_handleArray",
11424 value: function _handleArray(arr, value, path) {
11425 if (typeof arr[0] === "string" && arr[0] === "color") {
11426 this._makeColorField(arr, value, path);
11427
11428 if (arr[1] !== value) {
11429 this.changedOptions.push({
11430 path: path,
11431 value: value
11432 });
11433 }
11434 } else if (typeof arr[0] === "string") {
11435 this._makeDropdown(arr, value, path);
11436
11437 if (arr[0] !== value) {
11438 this.changedOptions.push({
11439 path: path,
11440 value: value
11441 });
11442 }
11443 } else if (typeof arr[0] === "number") {
11444 this._makeRange(arr, value, path);
11445
11446 if (arr[0] !== value) {
11447 this.changedOptions.push({
11448 path: path,
11449 value: Number(value)
11450 });
11451 }
11452 }
11453 }
11454 /**
11455 * called to update the network with the new settings.
11456 *
11457 * @param {number} value
11458 * @param {Array} path | where to look for the actual option
11459 * @private
11460 */
11461
11462 }, {
11463 key: "_update",
11464 value: function _update(value, path) {
11465 var options = this._constructOptions(value, path);
11466
11467 if (this.parent.body && this.parent.body.emitter && this.parent.body.emitter.emit) {
11468 this.parent.body.emitter.emit("configChange", options);
11469 }
11470
11471 this.initialized = true;
11472 this.parent.setOptions(options);
11473 }
11474 /**
11475 *
11476 * @param {string | boolean} value
11477 * @param {Array.<string>} path
11478 * @param {{}} optionsObj
11479 * @returns {{}}
11480 * @private
11481 */
11482
11483 }, {
11484 key: "_constructOptions",
11485 value: function _constructOptions(value, path) {
11486 var optionsObj = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
11487 var pointer = optionsObj; // when dropdown boxes can be string or boolean, we typecast it into correct types
11488
11489 value = value === "true" ? true : value;
11490 value = value === "false" ? false : value;
11491
11492 for (var i = 0; i < path.length; i++) {
11493 if (path[i] !== "global") {
11494 if (pointer[path[i]] === undefined) {
11495 pointer[path[i]] = {};
11496 }
11497
11498 if (i !== path.length - 1) {
11499 pointer = pointer[path[i]];
11500 } else {
11501 pointer[path[i]] = value;
11502 }
11503 }
11504 }
11505
11506 return optionsObj;
11507 }
11508 /**
11509 * @private
11510 */
11511
11512 }, {
11513 key: "_printOptions",
11514 value: function _printOptions() {
11515 var options = this.getOptions();
11516
11517 while (this.optionsContainer.firstChild) {
11518 this.optionsContainer.removeChild(this.optionsContainer.firstChild);
11519 }
11520
11521 this.optionsContainer.appendChild(wrapInTag("pre", "const options = " + stringify$1(options, null, 2)));
11522 }
11523 /**
11524 *
11525 * @returns {{}} options
11526 */
11527
11528 }, {
11529 key: "getOptions",
11530 value: function getOptions() {
11531 var options = {};
11532
11533 for (var i = 0; i < this.changedOptions.length; i++) {
11534 this._constructOptions(this.changedOptions[i].value, this.changedOptions[i].path, options);
11535 }
11536
11537 return options;
11538 }
11539 }]);
11540
11541 return Configurator$1;
11542 }();
11543 /**
11544 * Popup is a class to create a popup window with some text
11545 */
11546
11547
11548 var Popup$1 = /*#__PURE__*/function () {
11549 /**
11550 * @param {Element} container The container object.
11551 * @param {string} overflowMethod How the popup should act to overflowing ('flip' or 'cap')
11552 */
11553 function Popup$1(container, overflowMethod) {
11554 _classCallCheck(this, Popup$1);
11555
11556 this.container = container;
11557 this.overflowMethod = overflowMethod || "cap";
11558 this.x = 0;
11559 this.y = 0;
11560 this.padding = 5;
11561 this.hidden = false; // create the frame
11562
11563 this.frame = document.createElement("div");
11564 this.frame.className = "vis-tooltip";
11565 this.container.appendChild(this.frame);
11566 }
11567 /**
11568 * @param {number} x Horizontal position of the popup window
11569 * @param {number} y Vertical position of the popup window
11570 */
11571
11572
11573 _createClass(Popup$1, [{
11574 key: "setPosition",
11575 value: function setPosition(x, y) {
11576 this.x = _parseInt(x);
11577 this.y = _parseInt(y);
11578 }
11579 /**
11580 * Set the content for the popup window. This can be HTML code or text.
11581 *
11582 * @param {string | Element} content
11583 */
11584
11585 }, {
11586 key: "setText",
11587 value: function setText(content) {
11588 if (content instanceof Element) {
11589 while (this.frame.firstChild) {
11590 this.frame.removeChild(this.frame.firstChild);
11591 }
11592
11593 this.frame.appendChild(content);
11594 } else {
11595 // String containing literal text, element has to be used for HTML due to
11596 // XSS risks associated with innerHTML (i.e. prevent XSS by accident).
11597 this.frame.innerText = content;
11598 }
11599 }
11600 /**
11601 * Show the popup window
11602 *
11603 * @param {boolean} [doShow] Show or hide the window
11604 */
11605
11606 }, {
11607 key: "show",
11608 value: function show(doShow) {
11609 if (doShow === undefined) {
11610 doShow = true;
11611 }
11612
11613 if (doShow === true) {
11614 var height = this.frame.clientHeight;
11615 var width = this.frame.clientWidth;
11616 var maxHeight = this.frame.parentNode.clientHeight;
11617 var maxWidth = this.frame.parentNode.clientWidth;
11618 var left = 0,
11619 top = 0;
11620
11621 if (this.overflowMethod == "flip") {
11622 var isLeft = false,
11623 isTop = true; // Where around the position it's located
11624
11625 if (this.y - height < this.padding) {
11626 isTop = false;
11627 }
11628
11629 if (this.x + width > maxWidth - this.padding) {
11630 isLeft = true;
11631 }
11632
11633 if (isLeft) {
11634 left = this.x - width;
11635 } else {
11636 left = this.x;
11637 }
11638
11639 if (isTop) {
11640 top = this.y - height;
11641 } else {
11642 top = this.y;
11643 }
11644 } else {
11645 top = this.y - height;
11646
11647 if (top + height + this.padding > maxHeight) {
11648 top = maxHeight - height - this.padding;
11649 }
11650
11651 if (top < this.padding) {
11652 top = this.padding;
11653 }
11654
11655 left = this.x;
11656
11657 if (left + width + this.padding > maxWidth) {
11658 left = maxWidth - width - this.padding;
11659 }
11660
11661 if (left < this.padding) {
11662 left = this.padding;
11663 }
11664 }
11665
11666 this.frame.style.left = left + "px";
11667 this.frame.style.top = top + "px";
11668 this.frame.style.visibility = "visible";
11669 this.hidden = false;
11670 } else {
11671 this.hide();
11672 }
11673 }
11674 /**
11675 * Hide the popup window
11676 */
11677
11678 }, {
11679 key: "hide",
11680 value: function hide() {
11681 this.hidden = true;
11682 this.frame.style.left = "0";
11683 this.frame.style.top = "0";
11684 this.frame.style.visibility = "hidden";
11685 }
11686 /**
11687 * Remove the popup window
11688 */
11689
11690 }, {
11691 key: "destroy",
11692 value: function destroy() {
11693 this.frame.parentNode.removeChild(this.frame); // Remove element from DOM
11694 }
11695 }]);
11696
11697 return Popup$1;
11698 }();
11699
11700 var errorFound = false;
11701 var allOptions$2;
11702 var VALIDATOR_PRINT_STYLE$1 = "background: #FFeeee; color: #dd0000";
11703 /**
11704 * Used to validate options.
11705 */
11706
11707 var Validator$1 = /*#__PURE__*/function () {
11708 function Validator$1() {
11709 _classCallCheck(this, Validator$1);
11710 }
11711
11712 _createClass(Validator$1, null, [{
11713 key: "validate",
11714 value:
11715 /**
11716 * Main function to be called
11717 *
11718 * @param {object} options
11719 * @param {object} referenceOptions
11720 * @param {object} subObject
11721 * @returns {boolean}
11722 * @static
11723 */
11724 function validate(options, referenceOptions, subObject) {
11725 errorFound = false;
11726 allOptions$2 = referenceOptions;
11727 var usedOptions = referenceOptions;
11728
11729 if (subObject !== undefined) {
11730 usedOptions = referenceOptions[subObject];
11731 }
11732
11733 Validator$1.parse(options, usedOptions, []);
11734 return errorFound;
11735 }
11736 /**
11737 * Will traverse an object recursively and check every value
11738 *
11739 * @param {object} options
11740 * @param {object} referenceOptions
11741 * @param {Array} path | where to look for the actual option
11742 * @static
11743 */
11744
11745 }, {
11746 key: "parse",
11747 value: function parse(options, referenceOptions, path) {
11748 for (var _option3 in options) {
11749 if (Object.prototype.hasOwnProperty.call(options, _option3)) {
11750 Validator$1.check(_option3, options, referenceOptions, path);
11751 }
11752 }
11753 }
11754 /**
11755 * Check every value. If the value is an object, call the parse function on that object.
11756 *
11757 * @param {string} option
11758 * @param {object} options
11759 * @param {object} referenceOptions
11760 * @param {Array} path | where to look for the actual option
11761 * @static
11762 */
11763
11764 }, {
11765 key: "check",
11766 value: function check(option, options, referenceOptions, path) {
11767 if (referenceOptions[option] === undefined && referenceOptions.__any__ === undefined) {
11768 Validator$1.getSuggestion(option, referenceOptions, path);
11769 return;
11770 }
11771
11772 var referenceOption = option;
11773 var is_object = true;
11774
11775 if (referenceOptions[option] === undefined && referenceOptions.__any__ !== undefined) {
11776 // NOTE: This only triggers if the __any__ is in the top level of the options object.
11777 // THAT'S A REALLY BAD PLACE TO ALLOW IT!!!!
11778 // TODO: Examine if needed, remove if possible
11779 // __any__ is a wildcard. Any value is accepted and will be further analysed by reference.
11780 referenceOption = "__any__"; // if the any-subgroup is not a predefined object in the configurator,
11781 // we do not look deeper into the object.
11782
11783 is_object = Validator$1.getType(options[option]) === "object";
11784 }
11785
11786 var refOptionObj = referenceOptions[referenceOption];
11787
11788 if (is_object && refOptionObj.__type__ !== undefined) {
11789 refOptionObj = refOptionObj.__type__;
11790 }
11791
11792 Validator$1.checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path);
11793 }
11794 /**
11795 *
11796 * @param {string} option | the option property
11797 * @param {object} options | The supplied options object
11798 * @param {object} referenceOptions | The reference options containing all options and their allowed formats
11799 * @param {string} referenceOption | Usually this is the same as option, except when handling an __any__ tag.
11800 * @param {string} refOptionObj | This is the type object from the reference options
11801 * @param {Array} path | where in the object is the option
11802 * @static
11803 */
11804
11805 }, {
11806 key: "checkFields",
11807 value: function checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path) {
11808 var log = function log(message) {
11809 console.error("%c" + message + Validator$1.printLocation(path, option), VALIDATOR_PRINT_STYLE$1);
11810 };
11811
11812 var optionType = Validator$1.getType(options[option]);
11813 var refOptionType = refOptionObj[optionType];
11814
11815 if (refOptionType !== undefined) {
11816 // if the type is correct, we check if it is supposed to be one of a few select values
11817 if (Validator$1.getType(refOptionType) === "array" && indexOf(refOptionType).call(refOptionType, options[option]) === -1) {
11818 log('Invalid option detected in "' + option + '".' + " Allowed values are:" + Validator$1.print(refOptionType) + ' not "' + options[option] + '". ');
11819 errorFound = true;
11820 } else if (optionType === "object" && referenceOption !== "__any__") {
11821 path = copyAndExtendArray(path, option);
11822 Validator$1.parse(options[option], referenceOptions[referenceOption], path);
11823 }
11824 } else if (refOptionObj["any"] === undefined) {
11825 // type of the field is incorrect and the field cannot be any
11826 log('Invalid type received for "' + option + '". Expected: ' + Validator$1.print(keys$4(refOptionObj)) + ". Received [" + optionType + '] "' + options[option] + '"');
11827 errorFound = true;
11828 }
11829 }
11830 /**
11831 *
11832 * @param {object | boolean | number | string | Array.<number> | Date | Node | Moment | undefined | null} object
11833 * @returns {string}
11834 * @static
11835 */
11836
11837 }, {
11838 key: "getType",
11839 value: function getType(object) {
11840 var type = _typeof(object);
11841
11842 if (type === "object") {
11843 if (object === null) {
11844 return "null";
11845 }
11846
11847 if (object instanceof Boolean) {
11848 return "boolean";
11849 }
11850
11851 if (object instanceof Number) {
11852 return "number";
11853 }
11854
11855 if (object instanceof String) {
11856 return "string";
11857 }
11858
11859 if (isArray$2(object)) {
11860 return "array";
11861 }
11862
11863 if (object instanceof Date) {
11864 return "date";
11865 }
11866
11867 if (object.nodeType !== undefined) {
11868 return "dom";
11869 }
11870
11871 if (object._isAMomentObject === true) {
11872 return "moment";
11873 }
11874
11875 return "object";
11876 } else if (type === "number") {
11877 return "number";
11878 } else if (type === "boolean") {
11879 return "boolean";
11880 } else if (type === "string") {
11881 return "string";
11882 } else if (type === undefined) {
11883 return "undefined";
11884 }
11885
11886 return type;
11887 }
11888 /**
11889 * @param {string} option
11890 * @param {object} options
11891 * @param {Array.<string>} path
11892 * @static
11893 */
11894
11895 }, {
11896 key: "getSuggestion",
11897 value: function getSuggestion(option, options, path) {
11898 var localSearch = Validator$1.findInOptions(option, options, path, false);
11899 var globalSearch = Validator$1.findInOptions(option, allOptions$2, [], true);
11900 var localSearchThreshold = 8;
11901 var globalSearchThreshold = 4;
11902 var msg;
11903
11904 if (localSearch.indexMatch !== undefined) {
11905 msg = " in " + Validator$1.printLocation(localSearch.path, option, "") + 'Perhaps it was incomplete? Did you mean: "' + localSearch.indexMatch + '"?\n\n';
11906 } else if (globalSearch.distance <= globalSearchThreshold && localSearch.distance > globalSearch.distance) {
11907 msg = " in " + Validator$1.printLocation(localSearch.path, option, "") + "Perhaps it was misplaced? Matching option found at: " + Validator$1.printLocation(globalSearch.path, globalSearch.closestMatch, "");
11908 } else if (localSearch.distance <= localSearchThreshold) {
11909 msg = '. Did you mean "' + localSearch.closestMatch + '"?' + Validator$1.printLocation(localSearch.path, option);
11910 } else {
11911 msg = ". Did you mean one of these: " + Validator$1.print(keys$4(options)) + Validator$1.printLocation(path, option);
11912 }
11913
11914 console.error('%cUnknown option detected: "' + option + '"' + msg, VALIDATOR_PRINT_STYLE$1);
11915 errorFound = true;
11916 }
11917 /**
11918 * traverse the options in search for a match.
11919 *
11920 * @param {string} option
11921 * @param {object} options
11922 * @param {Array} path | where to look for the actual option
11923 * @param {boolean} [recursive=false]
11924 * @returns {{closestMatch: string, path: Array, distance: number}}
11925 * @static
11926 */
11927
11928 }, {
11929 key: "findInOptions",
11930 value: function findInOptions(option, options, path) {
11931 var recursive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
11932 var min = 1e9;
11933 var closestMatch = "";
11934 var closestMatchPath = [];
11935 var lowerCaseOption = option.toLowerCase();
11936 var indexMatch = undefined;
11937
11938 for (var op in options) {
11939 var distance = void 0;
11940
11941 if (options[op].__type__ !== undefined && recursive === true) {
11942 var result = Validator$1.findInOptions(option, options[op], copyAndExtendArray(path, op));
11943
11944 if (min > result.distance) {
11945 closestMatch = result.closestMatch;
11946 closestMatchPath = result.path;
11947 min = result.distance;
11948 indexMatch = result.indexMatch;
11949 }
11950 } else {
11951 var _context20;
11952
11953 if (indexOf(_context20 = op.toLowerCase()).call(_context20, lowerCaseOption) !== -1) {
11954 indexMatch = op;
11955 }
11956
11957 distance = Validator$1.levenshteinDistance(option, op);
11958
11959 if (min > distance) {
11960 closestMatch = op;
11961 closestMatchPath = copyArray(path);
11962 min = distance;
11963 }
11964 }
11965 }
11966
11967 return {
11968 closestMatch: closestMatch,
11969 path: closestMatchPath,
11970 distance: min,
11971 indexMatch: indexMatch
11972 };
11973 }
11974 /**
11975 * @param {Array.<string>} path
11976 * @param {object} option
11977 * @param {string} prefix
11978 * @returns {string}
11979 * @static
11980 */
11981
11982 }, {
11983 key: "printLocation",
11984 value: function printLocation(path, option) {
11985 var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "Problem value found at: \n";
11986 var str = "\n\n" + prefix + "options = {\n";
11987
11988 for (var i = 0; i < path.length; i++) {
11989 for (var j = 0; j < i + 1; j++) {
11990 str += " ";
11991 }
11992
11993 str += path[i] + ": {\n";
11994 }
11995
11996 for (var _j = 0; _j < path.length + 1; _j++) {
11997 str += " ";
11998 }
11999
12000 str += option + "\n";
12001
12002 for (var _i3 = 0; _i3 < path.length + 1; _i3++) {
12003 for (var _j2 = 0; _j2 < path.length - _i3; _j2++) {
12004 str += " ";
12005 }
12006
12007 str += "}\n";
12008 }
12009
12010 return str + "\n\n";
12011 }
12012 /**
12013 * @param {object} options
12014 * @returns {string}
12015 * @static
12016 */
12017
12018 }, {
12019 key: "print",
12020 value: function print(options) {
12021 return stringify$1(options).replace(/(")|(\[)|(\])|(,"__type__")/g, "").replace(/(,)/g, ", ");
12022 }
12023 /**
12024 * Compute the edit distance between the two given strings
12025 * http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
12026 *
12027 * Copyright (c) 2011 Andrei Mackenzie
12028 *
12029 * 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:
12030 *
12031 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12032 *
12033 * 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.
12034 *
12035 * @param {string} a
12036 * @param {string} b
12037 * @returns {Array.<Array.<number>>}}
12038 * @static
12039 */
12040
12041 }, {
12042 key: "levenshteinDistance",
12043 value: function levenshteinDistance(a, b) {
12044 if (a.length === 0) return b.length;
12045 if (b.length === 0) return a.length;
12046 var matrix = []; // increment along the first column of each row
12047
12048 var i;
12049
12050 for (i = 0; i <= b.length; i++) {
12051 matrix[i] = [i];
12052 } // increment each column in the first row
12053
12054
12055 var j;
12056
12057 for (j = 0; j <= a.length; j++) {
12058 matrix[0][j] = j;
12059 } // Fill in the rest of the matrix
12060
12061
12062 for (i = 1; i <= b.length; i++) {
12063 for (j = 1; j <= a.length; j++) {
12064 if (b.charAt(i - 1) == a.charAt(j - 1)) {
12065 matrix[i][j] = matrix[i - 1][j - 1];
12066 } else {
12067 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
12068 Math.min(matrix[i][j - 1] + 1, // insertion
12069 matrix[i - 1][j] + 1)); // deletion
12070 }
12071 }
12072 }
12073
12074 return matrix[b.length][a.length];
12075 }
12076 }]);
12077
12078 return Validator$1;
12079 }();
12080
12081 var Activator = Activator$1;
12082 var ColorPicker = ColorPicker$1;
12083 var Configurator = Configurator$1;
12084 var Hammer = Hammer$1;
12085 var Popup = Popup$1;
12086 var VALIDATOR_PRINT_STYLE = VALIDATOR_PRINT_STYLE$1;
12087 var Validator = Validator$1;
12088
12089 var index$2 = /*#__PURE__*/Object.freeze({
12090 __proto__: null,
12091 Activator: Activator,
12092 Alea: Alea,
12093 ColorPicker: ColorPicker,
12094 Configurator: Configurator,
12095 DELETE: DELETE,
12096 HSVToHex: HSVToHex,
12097 HSVToRGB: HSVToRGB,
12098 Hammer: Hammer,
12099 Popup: Popup,
12100 RGBToHSV: RGBToHSV,
12101 RGBToHex: RGBToHex,
12102 VALIDATOR_PRINT_STYLE: VALIDATOR_PRINT_STYLE,
12103 Validator: Validator,
12104 addClassName: addClassName,
12105 addCssText: addCssText,
12106 addEventListener: addEventListener,
12107 binarySearchCustom: binarySearchCustom,
12108 binarySearchValue: binarySearchValue,
12109 bridgeObject: bridgeObject,
12110 copyAndExtendArray: copyAndExtendArray,
12111 copyArray: copyArray,
12112 deepExtend: deepExtend,
12113 deepObjectAssign: deepObjectAssign,
12114 easingFunctions: easingFunctions,
12115 equalArray: equalArray,
12116 extend: extend,
12117 fillIfDefined: fillIfDefined,
12118 forEach: forEach$1,
12119 getAbsoluteLeft: getAbsoluteLeft,
12120 getAbsoluteRight: getAbsoluteRight,
12121 getAbsoluteTop: getAbsoluteTop,
12122 getScrollBarWidth: getScrollBarWidth,
12123 getTarget: getTarget,
12124 getType: getType,
12125 hasParent: hasParent,
12126 hexToHSV: hexToHSV,
12127 hexToRGB: hexToRGB,
12128 insertSort: insertSort,
12129 isDate: isDate,
12130 isNumber: isNumber,
12131 isObject: isObject$7,
12132 isString: isString,
12133 isValidHex: isValidHex,
12134 isValidRGB: isValidRGB,
12135 isValidRGBA: isValidRGBA,
12136 mergeOptions: mergeOptions,
12137 option: option,
12138 overrideOpacity: overrideOpacity,
12139 parseColor: parseColor,
12140 preventDefault: preventDefault,
12141 pureDeepObjectAssign: pureDeepObjectAssign,
12142 recursiveDOMDelete: recursiveDOMDelete,
12143 removeClassName: removeClassName,
12144 removeCssText: removeCssText,
12145 removeEventListener: removeEventListener,
12146 selectiveBridgeObject: selectiveBridgeObject,
12147 selectiveDeepExtend: selectiveDeepExtend,
12148 selectiveExtend: selectiveExtend,
12149 selectiveNotDeepExtend: selectiveNotDeepExtend,
12150 throttle: throttle,
12151 toArray: toArray,
12152 topMost: topMost,
12153 updateProperty: updateProperty
12154 });
12155
12156 /* eslint-disable no-prototype-builtins */
12157
12158 /* eslint-disable no-unused-vars */
12159
12160 /* eslint-disable no-var */
12161
12162 /**
12163 * Parse a text source containing data in DOT language into a JSON object.
12164 * The object contains two lists: one with nodes and one with edges.
12165 *
12166 * DOT language reference: http://www.graphviz.org/doc/info/lang.html
12167 *
12168 * DOT language attributes: http://graphviz.org/content/attrs
12169 *
12170 * @param {string} data Text containing a graph in DOT-notation
12171 * @returns {object} graph An object containing two parameters:
12172 * {Object[]} nodes
12173 * {Object[]} edges
12174 *
12175 * -------------------------------------------
12176 * TODO
12177 * ====
12178 *
12179 * For label handling, this is an incomplete implementation. From docs (quote #3015):
12180 *
12181 * > the escape sequences "\n", "\l" and "\r" divide the label into lines, centered,
12182 * > left-justified, and right-justified, respectively.
12183 *
12184 * Source: http://www.graphviz.org/content/attrs#kescString
12185 *
12186 * > As another aid for readability, dot allows double-quoted strings to span multiple physical
12187 * > lines using the standard C convention of a backslash immediately preceding a newline
12188 * > character
12189 * > In addition, double-quoted strings can be concatenated using a '+' operator.
12190 * > As HTML strings can contain newline characters, which are used solely for formatting,
12191 * > the language does not allow escaped newlines or concatenation operators to be used
12192 * > within them.
12193 *
12194 * - Currently, only '\\n' is handled
12195 * - Note that text explicitly says 'labels'; the dot parser currently handles escape
12196 * sequences in **all** strings.
12197 */
12198 function parseDOT(data) {
12199 dot = data;
12200 return parseGraph();
12201 } // mapping of attributes from DOT (the keys) to vis.js (the values)
12202
12203 var NODE_ATTR_MAPPING = {
12204 fontsize: "font.size",
12205 fontcolor: "font.color",
12206 labelfontcolor: "font.color",
12207 fontname: "font.face",
12208 color: ["color.border", "color.background"],
12209 fillcolor: "color.background",
12210 tooltip: "title",
12211 labeltooltip: "title"
12212 };
12213
12214 var EDGE_ATTR_MAPPING = create$5(NODE_ATTR_MAPPING);
12215
12216 EDGE_ATTR_MAPPING.color = "color.color";
12217 EDGE_ATTR_MAPPING.style = "dashes"; // token types enumeration
12218
12219 var TOKENTYPE = {
12220 NULL: 0,
12221 DELIMITER: 1,
12222 IDENTIFIER: 2,
12223 UNKNOWN: 3
12224 }; // map with all delimiters
12225
12226 var DELIMITERS = {
12227 "{": true,
12228 "}": true,
12229 "[": true,
12230 "]": true,
12231 ";": true,
12232 "=": true,
12233 ",": true,
12234 "->": true,
12235 "--": true
12236 };
12237 var dot = ""; // current dot file
12238
12239 var index$1 = 0; // current index in dot file
12240
12241 var c = ""; // current token character in expr
12242
12243 var token = ""; // current token
12244
12245 var tokenType = TOKENTYPE.NULL; // type of the token
12246
12247 /**
12248 * Get the first character from the dot file.
12249 * The character is stored into the char c. If the end of the dot file is
12250 * reached, the function puts an empty string in c.
12251 */
12252
12253 function first() {
12254 index$1 = 0;
12255 c = dot.charAt(0);
12256 }
12257 /**
12258 * Get the next character from the dot file.
12259 * The character is stored into the char c. If the end of the dot file is
12260 * reached, the function puts an empty string in c.
12261 */
12262
12263
12264 function next() {
12265 index$1++;
12266 c = dot.charAt(index$1);
12267 }
12268 /**
12269 * Preview the next character from the dot file.
12270 *
12271 * @returns {string} cNext
12272 */
12273
12274
12275 function nextPreview() {
12276 return dot.charAt(index$1 + 1);
12277 }
12278 /**
12279 * Test whether given character is alphabetic or numeric ( a-zA-Z_0-9.:# )
12280 *
12281 * @param {string} c
12282 * @returns {boolean} isAlphaNumeric
12283 */
12284
12285
12286 function isAlphaNumeric(c) {
12287 var charCode = c.charCodeAt(0);
12288
12289 if (charCode < 47) {
12290 // #.
12291 return charCode === 35 || charCode === 46;
12292 }
12293
12294 if (charCode < 59) {
12295 // 0-9 and :
12296 return charCode > 47;
12297 }
12298
12299 if (charCode < 91) {
12300 // A-Z
12301 return charCode > 64;
12302 }
12303
12304 if (charCode < 96) {
12305 // _
12306 return charCode === 95;
12307 }
12308
12309 if (charCode < 123) {
12310 // a-z
12311 return charCode > 96;
12312 }
12313
12314 return false;
12315 }
12316 /**
12317 * Merge all options of object b into object b
12318 *
12319 * @param {object} a
12320 * @param {object} b
12321 * @returns {object} a
12322 */
12323
12324
12325 function merge$1(a, b) {
12326 if (!a) {
12327 a = {};
12328 }
12329
12330 if (b) {
12331 for (var name in b) {
12332 if (b.hasOwnProperty(name)) {
12333 a[name] = b[name];
12334 }
12335 }
12336 }
12337
12338 return a;
12339 }
12340 /**
12341 * Set a value in an object, where the provided parameter name can be a
12342 * path with nested parameters. For example:
12343 *
12344 * var obj = {a: 2};
12345 * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}}
12346 *
12347 * @param {object} obj
12348 * @param {string} path A parameter name or dot-separated parameter path,
12349 * like "color.highlight.border".
12350 * @param {*} value
12351 */
12352
12353
12354 function setValue(obj, path, value) {
12355 var keys = path.split(".");
12356 var o = obj;
12357
12358 while (keys.length) {
12359 var key = keys.shift();
12360
12361 if (keys.length) {
12362 // this isn't the end point
12363 if (!o[key]) {
12364 o[key] = {};
12365 }
12366
12367 o = o[key];
12368 } else {
12369 // this is the end point
12370 o[key] = value;
12371 }
12372 }
12373 }
12374 /**
12375 * Add a node to a graph object. If there is already a node with
12376 * the same id, their attributes will be merged.
12377 *
12378 * @param {object} graph
12379 * @param {object} node
12380 */
12381
12382
12383 function addNode(graph, node) {
12384 var i, len;
12385 var current = null; // find root graph (in case of subgraph)
12386
12387 var graphs = [graph]; // list with all graphs from current graph to root graph
12388
12389 var root = graph;
12390
12391 while (root.parent) {
12392 graphs.push(root.parent);
12393 root = root.parent;
12394 } // find existing node (at root level) by its id
12395
12396
12397 if (root.nodes) {
12398 for (i = 0, len = root.nodes.length; i < len; i++) {
12399 if (node.id === root.nodes[i].id) {
12400 current = root.nodes[i];
12401 break;
12402 }
12403 }
12404 }
12405
12406 if (!current) {
12407 // this is a new node
12408 current = {
12409 id: node.id
12410 };
12411
12412 if (graph.node) {
12413 // clone default attributes
12414 current.attr = merge$1(current.attr, graph.node);
12415 }
12416 } // add node to this (sub)graph and all its parent graphs
12417
12418
12419 for (i = graphs.length - 1; i >= 0; i--) {
12420 var _context;
12421
12422 var g = graphs[i];
12423
12424 if (!g.nodes) {
12425 g.nodes = [];
12426 }
12427
12428 if (indexOf(_context = g.nodes).call(_context, current) === -1) {
12429 g.nodes.push(current);
12430 }
12431 } // merge attributes
12432
12433
12434 if (node.attr) {
12435 current.attr = merge$1(current.attr, node.attr);
12436 }
12437 }
12438 /**
12439 * Add an edge to a graph object
12440 *
12441 * @param {object} graph
12442 * @param {object} edge
12443 */
12444
12445
12446 function addEdge(graph, edge) {
12447 if (!graph.edges) {
12448 graph.edges = [];
12449 }
12450
12451 graph.edges.push(edge);
12452
12453 if (graph.edge) {
12454 var attr = merge$1({}, graph.edge); // clone default attributes
12455
12456 edge.attr = merge$1(attr, edge.attr); // merge attributes
12457 }
12458 }
12459 /**
12460 * Create an edge to a graph object
12461 *
12462 * @param {object} graph
12463 * @param {string | number | object} from
12464 * @param {string | number | object} to
12465 * @param {string} type
12466 * @param {object | null} attr
12467 * @returns {object} edge
12468 */
12469
12470
12471 function createEdge(graph, from, to, type, attr) {
12472 var edge = {
12473 from: from,
12474 to: to,
12475 type: type
12476 };
12477
12478 if (graph.edge) {
12479 edge.attr = merge$1({}, graph.edge); // clone default attributes
12480 }
12481
12482 edge.attr = merge$1(edge.attr || {}, attr); // merge attributes
12483 // Move arrows attribute from attr to edge temporally created in
12484 // parseAttributeList().
12485
12486 if (attr != null) {
12487 if (attr.hasOwnProperty("arrows") && attr["arrows"] != null) {
12488 edge["arrows"] = {
12489 to: {
12490 enabled: true,
12491 type: attr.arrows.type
12492 }
12493 };
12494 attr["arrows"] = null;
12495 }
12496 }
12497
12498 return edge;
12499 }
12500 /**
12501 * Get next token in the current dot file.
12502 * The token and token type are available as token and tokenType
12503 */
12504
12505
12506 function getToken() {
12507 tokenType = TOKENTYPE.NULL;
12508 token = ""; // skip over whitespaces
12509
12510 while (c === " " || c === "\t" || c === "\n" || c === "\r") {
12511 // space, tab, enter
12512 next();
12513 }
12514
12515 do {
12516 var isComment = false; // skip comment
12517
12518 if (c === "#") {
12519 // find the previous non-space character
12520 var i = index$1 - 1;
12521
12522 while (dot.charAt(i) === " " || dot.charAt(i) === "\t") {
12523 i--;
12524 }
12525
12526 if (dot.charAt(i) === "\n" || dot.charAt(i) === "") {
12527 // the # is at the start of a line, this is indeed a line comment
12528 while (c != "" && c != "\n") {
12529 next();
12530 }
12531
12532 isComment = true;
12533 }
12534 }
12535
12536 if (c === "/" && nextPreview() === "/") {
12537 // skip line comment
12538 while (c != "" && c != "\n") {
12539 next();
12540 }
12541
12542 isComment = true;
12543 }
12544
12545 if (c === "/" && nextPreview() === "*") {
12546 // skip block comment
12547 while (c != "") {
12548 if (c === "*" && nextPreview() === "/") {
12549 // end of block comment found. skip these last two characters
12550 next();
12551 next();
12552 break;
12553 } else {
12554 next();
12555 }
12556 }
12557
12558 isComment = true;
12559 } // skip over whitespaces
12560
12561
12562 while (c === " " || c === "\t" || c === "\n" || c === "\r") {
12563 // space, tab, enter
12564 next();
12565 }
12566 } while (isComment); // check for end of dot file
12567
12568
12569 if (c === "") {
12570 // token is still empty
12571 tokenType = TOKENTYPE.DELIMITER;
12572 return;
12573 } // check for delimiters consisting of 2 characters
12574
12575
12576 var c2 = c + nextPreview();
12577
12578 if (DELIMITERS[c2]) {
12579 tokenType = TOKENTYPE.DELIMITER;
12580 token = c2;
12581 next();
12582 next();
12583 return;
12584 } // check for delimiters consisting of 1 character
12585
12586
12587 if (DELIMITERS[c]) {
12588 tokenType = TOKENTYPE.DELIMITER;
12589 token = c;
12590 next();
12591 return;
12592 } // check for an identifier (number or string)
12593 // TODO: more precise parsing of numbers/strings (and the port separator ':')
12594
12595
12596 if (isAlphaNumeric(c) || c === "-") {
12597 token += c;
12598 next();
12599
12600 while (isAlphaNumeric(c)) {
12601 token += c;
12602 next();
12603 }
12604
12605 if (token === "false") {
12606 token = false; // convert to boolean
12607 } else if (token === "true") {
12608 token = true; // convert to boolean
12609 } else if (!isNaN(Number(token))) {
12610 token = Number(token); // convert to number
12611 }
12612
12613 tokenType = TOKENTYPE.IDENTIFIER;
12614 return;
12615 } // check for a string enclosed by double quotes
12616
12617
12618 if (c === '"') {
12619 next();
12620
12621 while (c != "" && (c != '"' || c === '"' && nextPreview() === '"')) {
12622 if (c === '"') {
12623 // skip the escape character
12624 token += c;
12625 next();
12626 } else if (c === "\\" && nextPreview() === "n") {
12627 // Honor a newline escape sequence
12628 token += "\n";
12629 next();
12630 } else {
12631 token += c;
12632 }
12633
12634 next();
12635 }
12636
12637 if (c != '"') {
12638 throw newSyntaxError('End of string " expected');
12639 }
12640
12641 next();
12642 tokenType = TOKENTYPE.IDENTIFIER;
12643 return;
12644 } // something unknown is found, wrong characters, a syntax error
12645
12646
12647 tokenType = TOKENTYPE.UNKNOWN;
12648
12649 while (c != "") {
12650 token += c;
12651 next();
12652 }
12653
12654 throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"');
12655 }
12656 /**
12657 * Parse a graph.
12658 *
12659 * @returns {object} graph
12660 */
12661
12662
12663 function parseGraph() {
12664 var graph = {};
12665 first();
12666 getToken(); // optional strict keyword
12667
12668 if (token === "strict") {
12669 graph.strict = true;
12670 getToken();
12671 } // graph or digraph keyword
12672
12673
12674 if (token === "graph" || token === "digraph") {
12675 graph.type = token;
12676 getToken();
12677 } // optional graph id
12678
12679
12680 if (tokenType === TOKENTYPE.IDENTIFIER) {
12681 graph.id = token;
12682 getToken();
12683 } // open angle bracket
12684
12685
12686 if (token != "{") {
12687 throw newSyntaxError("Angle bracket { expected");
12688 }
12689
12690 getToken(); // statements
12691
12692 parseStatements(graph); // close angle bracket
12693
12694 if (token != "}") {
12695 throw newSyntaxError("Angle bracket } expected");
12696 }
12697
12698 getToken(); // end of file
12699
12700 if (token !== "") {
12701 throw newSyntaxError("End of file expected");
12702 }
12703
12704 getToken(); // remove temporary default options
12705
12706 delete graph.node;
12707 delete graph.edge;
12708 delete graph.graph;
12709 return graph;
12710 }
12711 /**
12712 * Parse a list with statements.
12713 *
12714 * @param {object} graph
12715 */
12716
12717
12718 function parseStatements(graph) {
12719 while (token !== "" && token != "}") {
12720 parseStatement(graph);
12721
12722 if (token === ";") {
12723 getToken();
12724 }
12725 }
12726 }
12727 /**
12728 * Parse a single statement. Can be a an attribute statement, node
12729 * statement, a series of node statements and edge statements, or a
12730 * parameter.
12731 *
12732 * @param {object} graph
12733 */
12734
12735
12736 function parseStatement(graph) {
12737 // parse subgraph
12738 var subgraph = parseSubgraph(graph);
12739
12740 if (subgraph) {
12741 // edge statements
12742 parseEdge(graph, subgraph);
12743 return;
12744 } // parse an attribute statement
12745
12746
12747 var attr = parseAttributeStatement(graph);
12748
12749 if (attr) {
12750 return;
12751 } // parse node
12752
12753
12754 if (tokenType != TOKENTYPE.IDENTIFIER) {
12755 throw newSyntaxError("Identifier expected");
12756 }
12757
12758 var id = token; // id can be a string or a number
12759
12760 getToken();
12761
12762 if (token === "=") {
12763 // id statement
12764 getToken();
12765
12766 if (tokenType != TOKENTYPE.IDENTIFIER) {
12767 throw newSyntaxError("Identifier expected");
12768 }
12769
12770 graph[id] = token;
12771 getToken(); // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] "
12772 } else {
12773 parseNodeStatement(graph, id);
12774 }
12775 }
12776 /**
12777 * Parse a subgraph
12778 *
12779 * @param {object} graph parent graph object
12780 * @returns {object | null} subgraph
12781 */
12782
12783
12784 function parseSubgraph(graph) {
12785 var subgraph = null; // optional subgraph keyword
12786
12787 if (token === "subgraph") {
12788 subgraph = {};
12789 subgraph.type = "subgraph";
12790 getToken(); // optional graph id
12791
12792 if (tokenType === TOKENTYPE.IDENTIFIER) {
12793 subgraph.id = token;
12794 getToken();
12795 }
12796 } // open angle bracket
12797
12798
12799 if (token === "{") {
12800 getToken();
12801
12802 if (!subgraph) {
12803 subgraph = {};
12804 }
12805
12806 subgraph.parent = graph;
12807 subgraph.node = graph.node;
12808 subgraph.edge = graph.edge;
12809 subgraph.graph = graph.graph; // statements
12810
12811 parseStatements(subgraph); // close angle bracket
12812
12813 if (token != "}") {
12814 throw newSyntaxError("Angle bracket } expected");
12815 }
12816
12817 getToken(); // remove temporary default options
12818
12819 delete subgraph.node;
12820 delete subgraph.edge;
12821 delete subgraph.graph;
12822 delete subgraph.parent; // register at the parent graph
12823
12824 if (!graph.subgraphs) {
12825 graph.subgraphs = [];
12826 }
12827
12828 graph.subgraphs.push(subgraph);
12829 }
12830
12831 return subgraph;
12832 }
12833 /**
12834 * parse an attribute statement like "node [shape=circle fontSize=16]".
12835 * Available keywords are 'node', 'edge', 'graph'.
12836 * The previous list with default attributes will be replaced
12837 *
12838 * @param {object} graph
12839 * @returns {string | null} keyword Returns the name of the parsed attribute
12840 * (node, edge, graph), or null if nothing
12841 * is parsed.
12842 */
12843
12844
12845 function parseAttributeStatement(graph) {
12846 // attribute statements
12847 if (token === "node") {
12848 getToken(); // node attributes
12849
12850 graph.node = parseAttributeList();
12851 return "node";
12852 } else if (token === "edge") {
12853 getToken(); // edge attributes
12854
12855 graph.edge = parseAttributeList();
12856 return "edge";
12857 } else if (token === "graph") {
12858 getToken(); // graph attributes
12859
12860 graph.graph = parseAttributeList();
12861 return "graph";
12862 }
12863
12864 return null;
12865 }
12866 /**
12867 * parse a node statement
12868 *
12869 * @param {object} graph
12870 * @param {string | number} id
12871 */
12872
12873
12874 function parseNodeStatement(graph, id) {
12875 // node statement
12876 var node = {
12877 id: id
12878 };
12879 var attr = parseAttributeList();
12880
12881 if (attr) {
12882 node.attr = attr;
12883 }
12884
12885 addNode(graph, node); // edge statements
12886
12887 parseEdge(graph, id);
12888 }
12889 /**
12890 * Parse an edge or a series of edges
12891 *
12892 * @param {object} graph
12893 * @param {string | number} from Id of the from node
12894 */
12895
12896
12897 function parseEdge(graph, from) {
12898 while (token === "->" || token === "--") {
12899 var to;
12900 var type = token;
12901 getToken();
12902 var subgraph = parseSubgraph(graph);
12903
12904 if (subgraph) {
12905 to = subgraph;
12906 } else {
12907 if (tokenType != TOKENTYPE.IDENTIFIER) {
12908 throw newSyntaxError("Identifier or subgraph expected");
12909 }
12910
12911 to = token;
12912 addNode(graph, {
12913 id: to
12914 });
12915 getToken();
12916 } // parse edge attributes
12917
12918
12919 var attr = parseAttributeList(); // create edge
12920
12921 var edge = createEdge(graph, from, to, type, attr);
12922 addEdge(graph, edge);
12923 from = to;
12924 }
12925 }
12926 /**
12927 * Parse a set with attributes,
12928 * for example [label="1.000", shape=solid]
12929 *
12930 * @returns {object | null} attr
12931 */
12932
12933
12934 function parseAttributeList() {
12935 var i;
12936 var attr = null; // edge styles of dot and vis
12937
12938 var edgeStyles = {
12939 dashed: true,
12940 solid: false,
12941 dotted: [1, 5]
12942 };
12943 /**
12944 * Define arrow types.
12945 * vis currently supports types defined in 'arrowTypes'.
12946 * Details of arrow shapes are described in
12947 * http://www.graphviz.org/content/arrow-shapes
12948 */
12949
12950 var arrowTypes = {
12951 dot: "circle",
12952 box: "box",
12953 crow: "crow",
12954 curve: "curve",
12955 icurve: "inv_curve",
12956 normal: "triangle",
12957 inv: "inv_triangle",
12958 diamond: "diamond",
12959 tee: "bar",
12960 vee: "vee"
12961 };
12962 /**
12963 * 'attr_list' contains attributes for checking if some of them are affected
12964 * later. For instance, both of 'arrowhead' and 'dir' (edge style defined
12965 * in DOT) make changes to 'arrows' attribute in vis.
12966 */
12967
12968 var attr_list = new Array();
12969 var attr_names = new Array(); // used for checking the case.
12970 // parse attributes
12971
12972 while (token === "[") {
12973 getToken();
12974 attr = {};
12975
12976 while (token !== "" && token != "]") {
12977 if (tokenType != TOKENTYPE.IDENTIFIER) {
12978 throw newSyntaxError("Attribute name expected");
12979 }
12980
12981 var name = token;
12982 getToken();
12983
12984 if (token != "=") {
12985 throw newSyntaxError("Equal sign = expected");
12986 }
12987
12988 getToken();
12989
12990 if (tokenType != TOKENTYPE.IDENTIFIER) {
12991 throw newSyntaxError("Attribute value expected");
12992 }
12993
12994 var value = token; // convert from dot style to vis
12995
12996 if (name === "style") {
12997 value = edgeStyles[value];
12998 }
12999
13000 var arrowType;
13001
13002 if (name === "arrowhead") {
13003 arrowType = arrowTypes[value];
13004 name = "arrows";
13005 value = {
13006 to: {
13007 enabled: true,
13008 type: arrowType
13009 }
13010 };
13011 }
13012
13013 if (name === "arrowtail") {
13014 arrowType = arrowTypes[value];
13015 name = "arrows";
13016 value = {
13017 from: {
13018 enabled: true,
13019 type: arrowType
13020 }
13021 };
13022 }
13023
13024 attr_list.push({
13025 attr: attr,
13026 name: name,
13027 value: value
13028 });
13029 attr_names.push(name);
13030 getToken();
13031
13032 if (token == ",") {
13033 getToken();
13034 }
13035 }
13036
13037 if (token != "]") {
13038 throw newSyntaxError("Bracket ] expected");
13039 }
13040
13041 getToken();
13042 }
13043 /**
13044 * As explained in [1], graphviz has limitations for combination of
13045 * arrow[head|tail] and dir. If attribute list includes 'dir',
13046 * following cases just be supported.
13047 * 1. both or none + arrowhead, arrowtail
13048 * 2. forward + arrowhead (arrowtail is not affedted)
13049 * 3. back + arrowtail (arrowhead is not affected)
13050 * [1] https://www.graphviz.org/doc/info/attrs.html#h:undir_note
13051 */
13052
13053
13054 if (includes(attr_names).call(attr_names, "dir")) {
13055 var idx = {}; // get index of 'arrows' and 'dir'
13056
13057 idx.arrows = {};
13058
13059 for (i = 0; i < attr_list.length; i++) {
13060 if (attr_list[i].name === "arrows") {
13061 if (attr_list[i].value.to != null) {
13062 idx.arrows.to = i;
13063 } else if (attr_list[i].value.from != null) {
13064 idx.arrows.from = i;
13065 } else {
13066 throw newSyntaxError("Invalid value of arrows");
13067 }
13068 } else if (attr_list[i].name === "dir") {
13069 idx.dir = i;
13070 }
13071 } // first, add default arrow shape if it is not assigned to avoid error
13072
13073
13074 var dir_type = attr_list[idx.dir].value;
13075
13076 if (!includes(attr_names).call(attr_names, "arrows")) {
13077 if (dir_type === "both") {
13078 attr_list.push({
13079 attr: attr_list[idx.dir].attr,
13080 name: "arrows",
13081 value: {
13082 to: {
13083 enabled: true
13084 }
13085 }
13086 });
13087 idx.arrows.to = attr_list.length - 1;
13088 attr_list.push({
13089 attr: attr_list[idx.dir].attr,
13090 name: "arrows",
13091 value: {
13092 from: {
13093 enabled: true
13094 }
13095 }
13096 });
13097 idx.arrows.from = attr_list.length - 1;
13098 } else if (dir_type === "forward") {
13099 attr_list.push({
13100 attr: attr_list[idx.dir].attr,
13101 name: "arrows",
13102 value: {
13103 to: {
13104 enabled: true
13105 }
13106 }
13107 });
13108 idx.arrows.to = attr_list.length - 1;
13109 } else if (dir_type === "back") {
13110 attr_list.push({
13111 attr: attr_list[idx.dir].attr,
13112 name: "arrows",
13113 value: {
13114 from: {
13115 enabled: true
13116 }
13117 }
13118 });
13119 idx.arrows.from = attr_list.length - 1;
13120 } else if (dir_type === "none") {
13121 attr_list.push({
13122 attr: attr_list[idx.dir].attr,
13123 name: "arrows",
13124 value: ""
13125 });
13126 idx.arrows.to = attr_list.length - 1;
13127 } else {
13128 throw newSyntaxError('Invalid dir type "' + dir_type + '"');
13129 }
13130 }
13131
13132 var from_type;
13133 var to_type; // update 'arrows' attribute from 'dir'.
13134
13135 if (dir_type === "both") {
13136 // both of shapes of 'from' and 'to' are given
13137 if (idx.arrows.to && idx.arrows.from) {
13138 to_type = attr_list[idx.arrows.to].value.to.type;
13139 from_type = attr_list[idx.arrows.from].value.from.type;
13140 attr_list[idx.arrows.to] = {
13141 attr: attr_list[idx.arrows.to].attr,
13142 name: attr_list[idx.arrows.to].name,
13143 value: {
13144 to: {
13145 enabled: true,
13146 type: to_type
13147 },
13148 from: {
13149 enabled: true,
13150 type: from_type
13151 }
13152 }
13153 };
13154
13155 splice$1(attr_list).call(attr_list, idx.arrows.from, 1); // shape of 'to' is assigned and use default to 'from'
13156
13157 } else if (idx.arrows.to) {
13158 to_type = attr_list[idx.arrows.to].value.to.type;
13159 from_type = "arrow";
13160 attr_list[idx.arrows.to] = {
13161 attr: attr_list[idx.arrows.to].attr,
13162 name: attr_list[idx.arrows.to].name,
13163 value: {
13164 to: {
13165 enabled: true,
13166 type: to_type
13167 },
13168 from: {
13169 enabled: true,
13170 type: from_type
13171 }
13172 }
13173 }; // only shape of 'from' is assigned and use default for 'to'
13174 } else if (idx.arrows.from) {
13175 to_type = "arrow";
13176 from_type = attr_list[idx.arrows.from].value.from.type;
13177 attr_list[idx.arrows.from] = {
13178 attr: attr_list[idx.arrows.from].attr,
13179 name: attr_list[idx.arrows.from].name,
13180 value: {
13181 to: {
13182 enabled: true,
13183 type: to_type
13184 },
13185 from: {
13186 enabled: true,
13187 type: from_type
13188 }
13189 }
13190 };
13191 }
13192 } else if (dir_type === "back") {
13193 // given both of shapes, but use only 'from'
13194 if (idx.arrows.to && idx.arrows.from) {
13195 to_type = "";
13196 from_type = attr_list[idx.arrows.from].value.from.type;
13197 attr_list[idx.arrows.from] = {
13198 attr: attr_list[idx.arrows.from].attr,
13199 name: attr_list[idx.arrows.from].name,
13200 value: {
13201 to: {
13202 enabled: true,
13203 type: to_type
13204 },
13205 from: {
13206 enabled: true,
13207 type: from_type
13208 }
13209 }
13210 }; // given shape of 'to', but does not use it
13211 } else if (idx.arrows.to) {
13212 to_type = "";
13213 from_type = "arrow";
13214 idx.arrows.from = idx.arrows.to;
13215 attr_list[idx.arrows.from] = {
13216 attr: attr_list[idx.arrows.from].attr,
13217 name: attr_list[idx.arrows.from].name,
13218 value: {
13219 to: {
13220 enabled: true,
13221 type: to_type
13222 },
13223 from: {
13224 enabled: true,
13225 type: from_type
13226 }
13227 }
13228 }; // assign given 'from' shape
13229 } else if (idx.arrows.from) {
13230 to_type = "";
13231 from_type = attr_list[idx.arrows.from].value.from.type;
13232 attr_list[idx.arrows.to] = {
13233 attr: attr_list[idx.arrows.from].attr,
13234 name: attr_list[idx.arrows.from].name,
13235 value: {
13236 to: {
13237 enabled: true,
13238 type: to_type
13239 },
13240 from: {
13241 enabled: true,
13242 type: from_type
13243 }
13244 }
13245 };
13246 }
13247
13248 attr_list[idx.arrows.from] = {
13249 attr: attr_list[idx.arrows.from].attr,
13250 name: attr_list[idx.arrows.from].name,
13251 value: {
13252 from: {
13253 enabled: true,
13254 type: attr_list[idx.arrows.from].value.from.type
13255 }
13256 }
13257 };
13258 } else if (dir_type === "none") {
13259 var idx_arrow;
13260
13261 if (idx.arrows.to) {
13262 idx_arrow = idx.arrows.to;
13263 } else {
13264 idx_arrow = idx.arrows.from;
13265 }
13266
13267 attr_list[idx_arrow] = {
13268 attr: attr_list[idx_arrow].attr,
13269 name: attr_list[idx_arrow].name,
13270 value: ""
13271 };
13272 } else if (dir_type === "forward") {
13273 // given both of shapes, but use only 'to'
13274 if (idx.arrows.to && idx.arrows.from) {
13275 to_type = attr_list[idx.arrows.to].value.to.type;
13276 from_type = "";
13277 attr_list[idx.arrows.to] = {
13278 attr: attr_list[idx.arrows.to].attr,
13279 name: attr_list[idx.arrows.to].name,
13280 value: {
13281 to: {
13282 enabled: true,
13283 type: to_type
13284 },
13285 from: {
13286 enabled: true,
13287 type: from_type
13288 }
13289 }
13290 }; // assign given 'to' shape
13291 } else if (idx.arrows.to) {
13292 to_type = attr_list[idx.arrows.to].value.to.type;
13293 from_type = "";
13294 attr_list[idx.arrows.to] = {
13295 attr: attr_list[idx.arrows.to].attr,
13296 name: attr_list[idx.arrows.to].name,
13297 value: {
13298 to: {
13299 enabled: true,
13300 type: to_type
13301 },
13302 from: {
13303 enabled: true,
13304 type: from_type
13305 }
13306 }
13307 }; // given shape of 'from', but does not use it
13308 } else if (idx.arrows.from) {
13309 to_type = "arrow";
13310 from_type = "";
13311 idx.arrows.to = idx.arrows.from;
13312 attr_list[idx.arrows.to] = {
13313 attr: attr_list[idx.arrows.to].attr,
13314 name: attr_list[idx.arrows.to].name,
13315 value: {
13316 to: {
13317 enabled: true,
13318 type: to_type
13319 },
13320 from: {
13321 enabled: true,
13322 type: from_type
13323 }
13324 }
13325 };
13326 }
13327
13328 attr_list[idx.arrows.to] = {
13329 attr: attr_list[idx.arrows.to].attr,
13330 name: attr_list[idx.arrows.to].name,
13331 value: {
13332 to: {
13333 enabled: true,
13334 type: attr_list[idx.arrows.to].value.to.type
13335 }
13336 }
13337 };
13338 } else {
13339 throw newSyntaxError('Invalid dir type "' + dir_type + '"');
13340 } // remove 'dir' attribute no need anymore
13341
13342
13343 splice$1(attr_list).call(attr_list, idx.dir, 1);
13344 } // parse 'penwidth'
13345
13346
13347 var nof_attr_list;
13348
13349 if (includes(attr_names).call(attr_names, "penwidth")) {
13350 var tmp_attr_list = [];
13351 nof_attr_list = attr_list.length;
13352
13353 for (i = 0; i < nof_attr_list; i++) {
13354 // exclude 'width' from attr_list if 'penwidth' exists
13355 if (attr_list[i].name !== "width") {
13356 if (attr_list[i].name === "penwidth") {
13357 attr_list[i].name = "width";
13358 }
13359
13360 tmp_attr_list.push(attr_list[i]);
13361 }
13362 }
13363
13364 attr_list = tmp_attr_list;
13365 }
13366
13367 nof_attr_list = attr_list.length;
13368
13369 for (i = 0; i < nof_attr_list; i++) {
13370 setValue(attr_list[i].attr, attr_list[i].name, attr_list[i].value);
13371 }
13372
13373 return attr;
13374 }
13375 /**
13376 * Create a syntax error with extra information on current token and index.
13377 *
13378 * @param {string} message
13379 * @returns {SyntaxError} err
13380 */
13381
13382
13383 function newSyntaxError(message) {
13384 return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index$1 + ")");
13385 }
13386 /**
13387 * Chop off text after a maximum length
13388 *
13389 * @param {string} text
13390 * @param {number} maxLength
13391 * @returns {string}
13392 */
13393
13394
13395 function chop(text, maxLength) {
13396 return text.length <= maxLength ? text : text.substr(0, 27) + "...";
13397 }
13398 /**
13399 * Execute a function fn for each pair of elements in two arrays
13400 *
13401 * @param {Array | *} array1
13402 * @param {Array | *} array2
13403 * @param {Function} fn
13404 */
13405
13406
13407 function forEach2(array1, array2, fn) {
13408 if (isArray$2(array1)) {
13409 forEach$2(array1).call(array1, function (elem1) {
13410 if (isArray$2(array2)) {
13411 forEach$2(array2).call(array2, function (elem2) {
13412 fn(elem1, elem2);
13413 });
13414 } else {
13415 fn(elem1, array2);
13416 }
13417 });
13418 } else {
13419 if (isArray$2(array2)) {
13420 forEach$2(array2).call(array2, function (elem2) {
13421 fn(array1, elem2);
13422 });
13423 } else {
13424 fn(array1, array2);
13425 }
13426 }
13427 }
13428 /**
13429 * Set a nested property on an object
13430 * When nested objects are missing, they will be created.
13431 * For example setProp({}, 'font.color', 'red') will return {font: {color: 'red'}}
13432 *
13433 * @param {object} object
13434 * @param {string} path A dot separated string like 'font.color'
13435 * @param {*} value Value for the property
13436 * @returns {object} Returns the original object, allows for chaining.
13437 */
13438
13439
13440 function setProp(object, path, value) {
13441 var names = path.split(".");
13442 var prop = names.pop(); // traverse over the nested objects
13443
13444 var obj = object;
13445
13446 for (var i = 0; i < names.length; i++) {
13447 var name = names[i];
13448
13449 if (!(name in obj)) {
13450 obj[name] = {};
13451 }
13452
13453 obj = obj[name];
13454 } // set the property value
13455
13456
13457 obj[prop] = value;
13458 return object;
13459 }
13460 /**
13461 * Convert an object with DOT attributes to their vis.js equivalents.
13462 *
13463 * @param {object} attr Object with DOT attributes
13464 * @param {object} mapping
13465 * @returns {object} Returns an object with vis.js attributes
13466 */
13467
13468
13469 function convertAttr(attr, mapping) {
13470 var converted = {};
13471
13472 for (var prop in attr) {
13473 if (attr.hasOwnProperty(prop)) {
13474 var visProp = mapping[prop];
13475
13476 if (isArray$2(visProp)) {
13477 forEach$2(visProp).call(visProp, function (visPropI) {
13478 setProp(converted, visPropI, attr[prop]);
13479 });
13480 } else if (typeof visProp === "string") {
13481 setProp(converted, visProp, attr[prop]);
13482 } else {
13483 setProp(converted, prop, attr[prop]);
13484 }
13485 }
13486 }
13487
13488 return converted;
13489 }
13490 /**
13491 * Convert a string containing a graph in DOT language into a map containing
13492 * with nodes and edges in the format of graph.
13493 *
13494 * @param {string} data Text containing a graph in DOT-notation
13495 * @returns {object} graphData
13496 */
13497
13498
13499 function DOTToGraph(data) {
13500 // parse the DOT file
13501 var dotData = parseDOT(data);
13502 var graphData = {
13503 nodes: [],
13504 edges: [],
13505 options: {}
13506 }; // copy the nodes
13507
13508 if (dotData.nodes) {
13509 var _context2;
13510
13511 forEach$2(_context2 = dotData.nodes).call(_context2, function (dotNode) {
13512 var graphNode = {
13513 id: dotNode.id,
13514 label: String(dotNode.label || dotNode.id)
13515 };
13516 merge$1(graphNode, convertAttr(dotNode.attr, NODE_ATTR_MAPPING));
13517
13518 if (graphNode.image) {
13519 graphNode.shape = "image";
13520 }
13521
13522 graphData.nodes.push(graphNode);
13523 });
13524 } // copy the edges
13525
13526
13527 if (dotData.edges) {
13528 var _context3;
13529
13530 /**
13531 * Convert an edge in DOT format to an edge with VisGraph format
13532 *
13533 * @param {object} dotEdge
13534 * @returns {object} graphEdge
13535 */
13536 var convertEdge = function convertEdge(dotEdge) {
13537 var graphEdge = {
13538 from: dotEdge.from,
13539 to: dotEdge.to
13540 };
13541 merge$1(graphEdge, convertAttr(dotEdge.attr, EDGE_ATTR_MAPPING)); // Add arrows attribute to default styled arrow.
13542 // The reason why default style is not added in parseAttributeList() is
13543 // because only default is cleared before here.
13544
13545 if (graphEdge.arrows == null && dotEdge.type === "->") {
13546 graphEdge.arrows = "to";
13547 }
13548
13549 return graphEdge;
13550 };
13551
13552 forEach$2(_context3 = dotData.edges).call(_context3, function (dotEdge) {
13553 var from, to;
13554
13555 if (dotEdge.from instanceof Object) {
13556 from = dotEdge.from.nodes;
13557 } else {
13558 from = {
13559 id: dotEdge.from
13560 };
13561 }
13562
13563 if (dotEdge.to instanceof Object) {
13564 to = dotEdge.to.nodes;
13565 } else {
13566 to = {
13567 id: dotEdge.to
13568 };
13569 }
13570
13571 if (dotEdge.from instanceof Object && dotEdge.from.edges) {
13572 var _context4;
13573
13574 forEach$2(_context4 = dotEdge.from.edges).call(_context4, function (subEdge) {
13575 var graphEdge = convertEdge(subEdge);
13576 graphData.edges.push(graphEdge);
13577 });
13578 }
13579
13580 forEach2(from, to, function (from, to) {
13581 var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr);
13582 var graphEdge = convertEdge(subEdge);
13583 graphData.edges.push(graphEdge);
13584 });
13585
13586 if (dotEdge.to instanceof Object && dotEdge.to.edges) {
13587 var _context5;
13588
13589 forEach$2(_context5 = dotEdge.to.edges).call(_context5, function (subEdge) {
13590 var graphEdge = convertEdge(subEdge);
13591 graphData.edges.push(graphEdge);
13592 });
13593 }
13594 });
13595 } // copy the options
13596
13597
13598 if (dotData.attr) {
13599 graphData.options = dotData.attr;
13600 }
13601
13602 return graphData;
13603 }
13604 /* eslint-enable no-var */
13605
13606 /* eslint-enable no-unused-vars */
13607
13608 /* eslint-enable no-prototype-builtins */
13609
13610 var dotparser = /*#__PURE__*/Object.freeze({
13611 __proto__: null,
13612 parseDOT: parseDOT,
13613 DOTToGraph: DOTToGraph
13614 });
13615
13616 /**
13617 * Convert Gephi to Vis.
13618 *
13619 * @param gephiJSON - The parsed JSON data in Gephi format.
13620 * @param optionsObj - Additional options.
13621 * @returns The converted data ready to be used in Vis.
13622 */
13623 function parseGephi(gephiJSON, optionsObj) {
13624 var _context;
13625
13626 var options = {
13627 edges: {
13628 inheritColor: false
13629 },
13630 nodes: {
13631 fixed: false,
13632 parseColor: false
13633 }
13634 };
13635
13636 if (optionsObj != null) {
13637 if (optionsObj.fixed != null) {
13638 options.nodes.fixed = optionsObj.fixed;
13639 }
13640
13641 if (optionsObj.parseColor != null) {
13642 options.nodes.parseColor = optionsObj.parseColor;
13643 }
13644
13645 if (optionsObj.inheritColor != null) {
13646 options.edges.inheritColor = optionsObj.inheritColor;
13647 }
13648 }
13649
13650 var gEdges = gephiJSON.edges;
13651
13652 var vEdges = map$3(gEdges).call(gEdges, function (gEdge) {
13653 var vEdge = {
13654 from: gEdge.source,
13655 id: gEdge.id,
13656 to: gEdge.target
13657 };
13658
13659 if (gEdge.attributes != null) {
13660 vEdge.attributes = gEdge.attributes;
13661 }
13662
13663 if (gEdge.label != null) {
13664 vEdge.label = gEdge.label;
13665 }
13666
13667 if (gEdge.attributes != null && gEdge.attributes.title != null) {
13668 vEdge.title = gEdge.attributes.title;
13669 }
13670
13671 if (gEdge.type === "Directed") {
13672 vEdge.arrows = "to";
13673 } // edge['value'] = gEdge.attributes != null ? gEdge.attributes.Weight : undefined;
13674 // edge['width'] = edge['value'] != null ? undefined : edgegEdge.size;
13675
13676
13677 if (gEdge.color && options.edges.inheritColor === false) {
13678 vEdge.color = gEdge.color;
13679 }
13680
13681 return vEdge;
13682 });
13683
13684 var vNodes = map$3(_context = gephiJSON.nodes).call(_context, function (gNode) {
13685 var vNode = {
13686 id: gNode.id,
13687 fixed: options.nodes.fixed && gNode.x != null && gNode.y != null
13688 };
13689
13690 if (gNode.attributes != null) {
13691 vNode.attributes = gNode.attributes;
13692 }
13693
13694 if (gNode.label != null) {
13695 vNode.label = gNode.label;
13696 }
13697
13698 if (gNode.size != null) {
13699 vNode.size = gNode.size;
13700 }
13701
13702 if (gNode.attributes != null && gNode.attributes.title != null) {
13703 vNode.title = gNode.attributes.title;
13704 }
13705
13706 if (gNode.title != null) {
13707 vNode.title = gNode.title;
13708 }
13709
13710 if (gNode.x != null) {
13711 vNode.x = gNode.x;
13712 }
13713
13714 if (gNode.y != null) {
13715 vNode.y = gNode.y;
13716 }
13717
13718 if (gNode.color != null) {
13719 if (options.nodes.parseColor === true) {
13720 vNode.color = gNode.color;
13721 } else {
13722 vNode.color = {
13723 background: gNode.color,
13724 border: gNode.color,
13725 highlight: {
13726 background: gNode.color,
13727 border: gNode.color
13728 },
13729 hover: {
13730 background: gNode.color,
13731 border: gNode.color
13732 }
13733 };
13734 }
13735 }
13736
13737 return vNode;
13738 });
13739
13740 return {
13741 nodes: vNodes,
13742 edges: vEdges
13743 };
13744 }
13745
13746 var gephiParser = /*#__PURE__*/Object.freeze({
13747 __proto__: null,
13748 parseGephi: parseGephi
13749 });
13750
13751 // English
13752 var en = {
13753 addDescription: "Click in an empty space to place a new node.",
13754 addEdge: "Add Edge",
13755 addNode: "Add Node",
13756 back: "Back",
13757 close: "Close",
13758 createEdgeError: "Cannot link edges to a cluster.",
13759 del: "Delete selected",
13760 deleteClusterError: "Clusters cannot be deleted.",
13761 edgeDescription: "Click on a node and drag the edge to another node to connect them.",
13762 edit: "Edit",
13763 editClusterError: "Clusters cannot be edited.",
13764 editEdge: "Edit Edge",
13765 editEdgeDescription: "Click on the control points and drag them to a node to connect to it.",
13766 editNode: "Edit Node"
13767 }; // German
13768
13769 var de = {
13770 addDescription: "Klicke auf eine freie Stelle, um einen neuen Knoten zu plazieren.",
13771 addEdge: "Kante hinzuf\xFCgen",
13772 addNode: "Knoten hinzuf\xFCgen",
13773 back: "Zur\xFCck",
13774 close: "Schließen",
13775 createEdgeError: "Es ist nicht m\xF6glich, Kanten mit Clustern zu verbinden.",
13776 del: "L\xF6sche Auswahl",
13777 deleteClusterError: "Cluster k\xF6nnen nicht gel\xF6scht werden.",
13778 edgeDescription: "Klicke auf einen Knoten und ziehe die Kante zu einem anderen Knoten, um diese zu verbinden.",
13779 edit: "Editieren",
13780 editClusterError: "Cluster k\xF6nnen nicht editiert werden.",
13781 editEdge: "Kante editieren",
13782 editEdgeDescription: "Klicke auf die Verbindungspunkte und ziehe diese auf einen Knoten, um sie zu verbinden.",
13783 editNode: "Knoten editieren"
13784 }; // Spanish
13785
13786 var es = {
13787 addDescription: "Haga clic en un lugar vac\xEDo para colocar un nuevo nodo.",
13788 addEdge: "A\xF1adir arista",
13789 addNode: "A\xF1adir nodo",
13790 back: "Atr\xE1s",
13791 close: "Cerrar",
13792 createEdgeError: "No se puede conectar una arista a un grupo.",
13793 del: "Eliminar selecci\xF3n",
13794 deleteClusterError: "No es posible eliminar grupos.",
13795 edgeDescription: "Haga clic en un nodo y arrastre la arista hacia otro nodo para conectarlos.",
13796 edit: "Editar",
13797 editClusterError: "No es posible editar grupos.",
13798 editEdge: "Editar arista",
13799 editEdgeDescription: "Haga clic en un punto de control y arrastrelo a un nodo para conectarlo.",
13800 editNode: "Editar nodo"
13801 }; //Italiano
13802
13803 var it = {
13804 addDescription: "Clicca per aggiungere un nuovo nodo",
13805 addEdge: "Aggiungi un vertice",
13806 addNode: "Aggiungi un nodo",
13807 back: "Indietro",
13808 close: "Chiudere",
13809 createEdgeError: "Non si possono collegare vertici ad un cluster",
13810 del: "Cancella la selezione",
13811 deleteClusterError: "I cluster non possono essere cancellati",
13812 edgeDescription: "Clicca su un nodo e trascinalo ad un altro nodo per connetterli.",
13813 edit: "Modifica",
13814 editClusterError: "I clusters non possono essere modificati.",
13815 editEdge: "Modifica il vertice",
13816 editEdgeDescription: "Clicca sui Punti di controllo e trascinali ad un nodo per connetterli.",
13817 editNode: "Modifica il nodo"
13818 }; // Dutch
13819
13820 var nl = {
13821 addDescription: "Klik op een leeg gebied om een nieuwe node te maken.",
13822 addEdge: "Link toevoegen",
13823 addNode: "Node toevoegen",
13824 back: "Terug",
13825 close: "Sluiten",
13826 createEdgeError: "Kan geen link maken naar een cluster.",
13827 del: "Selectie verwijderen",
13828 deleteClusterError: "Clusters kunnen niet worden verwijderd.",
13829 edgeDescription: "Klik op een node en sleep de link naar een andere node om ze te verbinden.",
13830 edit: "Wijzigen",
13831 editClusterError: "Clusters kunnen niet worden aangepast.",
13832 editEdge: "Link wijzigen",
13833 editEdgeDescription: "Klik op de verbindingspunten en sleep ze naar een node om daarmee te verbinden.",
13834 editNode: "Node wijzigen"
13835 }; // Portuguese Brazil
13836
13837 var pt = {
13838 addDescription: "Clique em um espaço em branco para adicionar um novo nó",
13839 addEdge: "Adicionar aresta",
13840 addNode: "Adicionar nó",
13841 back: "Voltar",
13842 close: "Fechar",
13843 createEdgeError: "Não foi possível linkar arestas a um cluster.",
13844 del: "Remover selecionado",
13845 deleteClusterError: "Clusters não puderam ser removidos.",
13846 edgeDescription: "Clique em um nó e arraste a aresta até outro nó para conectá-los",
13847 edit: "Editar",
13848 editClusterError: "Clusters não puderam ser editados.",
13849 editEdge: "Editar aresta",
13850 editEdgeDescription: "Clique nos pontos de controle e os arraste para um nó para conectá-los",
13851 editNode: "Editar nó"
13852 }; // Russian
13853
13854 var ru = {
13855 addDescription: "Кликните в свободное место, чтобы добавить новый узел.",
13856 addEdge: "Добавить ребро",
13857 addNode: "Добавить узел",
13858 back: "Назад",
13859 close: "Закрывать",
13860 createEdgeError: "Невозможно соединить ребра в кластер.",
13861 del: "Удалить выбранное",
13862 deleteClusterError: "Кластеры не могут быть удалены",
13863 edgeDescription: "Кликните на узел и протяните ребро к другому узлу, чтобы соединить их.",
13864 edit: "Редактировать",
13865 editClusterError: "Кластеры недоступны для редактирования.",
13866 editEdge: "Редактировать ребро",
13867 editEdgeDescription: "Кликните на контрольные точки и перетащите их в узел, чтобы подключиться к нему.",
13868 editNode: "Редактировать узел"
13869 }; // Chinese
13870
13871 var cn = {
13872 addDescription: "单击空白处放置新节点。",
13873 addEdge: "添加连接线",
13874 addNode: "添加节点",
13875 back: "返回",
13876 close: "關閉",
13877 createEdgeError: "无法将连接线连接到群集。",
13878 del: "删除选定",
13879 deleteClusterError: "无法删除群集。",
13880 edgeDescription: "单击某个节点并将该连接线拖动到另一个节点以连接它们。",
13881 edit: "编辑",
13882 editClusterError: "无法编辑群集。",
13883 editEdge: "编辑连接线",
13884 editEdgeDescription: "单击控制节点并将它们拖到节点上连接。",
13885 editNode: "编辑节点"
13886 }; // Ukrainian
13887
13888 var uk = {
13889 addDescription: "Kлікніть на вільне місце, щоб додати новий вузол.",
13890 addEdge: "Додати край",
13891 addNode: "Додати вузол",
13892 back: "Назад",
13893 close: "Закрити",
13894 createEdgeError: "Не можливо об'єднати краї в групу.",
13895 del: "Видалити обране",
13896 deleteClusterError: "Групи не можуть бути видалені.",
13897 edgeDescription: "Клікніть на вузол і перетягніть край до іншого вузла, щоб їх з'єднати.",
13898 edit: "Редагувати",
13899 editClusterError: "Групи недоступні для редагування.",
13900 editEdge: "Редагувати край",
13901 editEdgeDescription: "Клікніть на контрольні точки і перетягніть їх у вузол, щоб підключитися до нього.",
13902 editNode: "Редагувати вузол"
13903 }; // French
13904
13905 var fr = {
13906 addDescription: "Cliquez dans un endroit vide pour placer un nœud.",
13907 addEdge: "Ajouter un lien",
13908 addNode: "Ajouter un nœud",
13909 back: "Retour",
13910 close: "Fermer",
13911 createEdgeError: "Impossible de créer un lien vers un cluster.",
13912 del: "Effacer la sélection",
13913 deleteClusterError: "Les clusters ne peuvent pas être effacés.",
13914 edgeDescription: "Cliquez sur un nœud et glissez le lien vers un autre nœud pour les connecter.",
13915 edit: "Éditer",
13916 editClusterError: "Les clusters ne peuvent pas être édités.",
13917 editEdge: "Éditer le lien",
13918 editEdgeDescription: "Cliquez sur les points de contrôle et glissez-les pour connecter un nœud.",
13919 editNode: "Éditer le nœud"
13920 }; // Czech
13921
13922 var cs = {
13923 addDescription: "Kluknutím do prázdného prostoru můžete přidat nový vrchol.",
13924 addEdge: "Přidat hranu",
13925 addNode: "Přidat vrchol",
13926 back: "Zpět",
13927 close: "Zavřít",
13928 createEdgeError: "Nelze připojit hranu ke shluku.",
13929 del: "Smazat výběr",
13930 deleteClusterError: "Nelze mazat shluky.",
13931 edgeDescription: "Přetažením z jednoho vrcholu do druhého můžete spojit tyto vrcholy novou hranou.",
13932 edit: "Upravit",
13933 editClusterError: "Nelze upravovat shluky.",
13934 editEdge: "Upravit hranu",
13935 editEdgeDescription: "Přetažením kontrolního vrcholu hrany ji můžete připojit k jinému vrcholu.",
13936 editNode: "Upravit vrchol"
13937 };
13938
13939 var locales = /*#__PURE__*/Object.freeze({
13940 __proto__: null,
13941 en: en,
13942 de: de,
13943 es: es,
13944 it: it,
13945 nl: nl,
13946 pt: pt,
13947 ru: ru,
13948 cn: cn,
13949 uk: uk,
13950 fr: fr,
13951 cs: cs
13952 });
13953
13954 /**
13955 * Normalizes language code into the format used internally.
13956 *
13957 * @param locales - All the available locales.
13958 * @param rawCode - The original code as supplied by the user.
13959 * @returns Language code in the format language-COUNTRY or language, eventually
13960 * fallbacks to en.
13961 */
13962 function normalizeLanguageCode(locales, rawCode) {
13963 try {
13964 var _rawCode$split = rawCode.split(/[-_ /]/, 2),
13965 _rawCode$split2 = _slicedToArray(_rawCode$split, 2),
13966 rawLanguage = _rawCode$split2[0],
13967 rawCountry = _rawCode$split2[1];
13968
13969 var language = rawLanguage != null ? rawLanguage.toLowerCase() : null;
13970 var country = rawCountry != null ? rawCountry.toUpperCase() : null;
13971
13972 if (language && country) {
13973 var code = language + "-" + country;
13974
13975 if (Object.prototype.hasOwnProperty.call(locales, code)) {
13976 return code;
13977 } else {
13978 var _context;
13979
13980 console.warn(concat(_context = "Unknown variant ".concat(country, " of language ")).call(_context, language, "."));
13981 }
13982 }
13983
13984 if (language) {
13985 var _code = language;
13986
13987 if (Object.prototype.hasOwnProperty.call(locales, _code)) {
13988 return _code;
13989 } else {
13990 console.warn("Unknown language ".concat(language));
13991 }
13992 }
13993
13994 console.warn("Unknown locale ".concat(rawCode, ", falling back to English."));
13995 return "en";
13996 } catch (error) {
13997 console.error(error);
13998 console.warn("Unexpected error while normalizing locale ".concat(rawCode, ", falling back to English."));
13999 return "en";
14000 }
14001 }
14002
14003 /**
14004 * Associates a canvas to a given image, containing a number of renderings
14005 * of the image at various sizes.
14006 *
14007 * This technique is known as 'mipmapping'.
14008 *
14009 * NOTE: Images can also be of type 'data:svg+xml`. This code also works
14010 * for svg, but the mipmapping may not be necessary.
14011 *
14012 * @param {Image} image
14013 */
14014 var CachedImage = /*#__PURE__*/function () {
14015 /**
14016 * @ignore
14017 */
14018 function CachedImage() {
14019 _classCallCheck(this, CachedImage);
14020
14021 this.NUM_ITERATIONS = 4; // Number of items in the coordinates array
14022
14023 this.image = new Image();
14024 this.canvas = document.createElement("canvas");
14025 }
14026 /**
14027 * Called when the image has been successfully loaded.
14028 */
14029
14030
14031 _createClass(CachedImage, [{
14032 key: "init",
14033 value: function init() {
14034 if (this.initialized()) return;
14035 this.src = this.image.src; // For same interface with Image
14036
14037 var w = this.image.width;
14038 var h = this.image.height; // Ease external access
14039
14040 this.width = w;
14041 this.height = h;
14042 var h2 = Math.floor(h / 2);
14043 var h4 = Math.floor(h / 4);
14044 var h8 = Math.floor(h / 8);
14045 var h16 = Math.floor(h / 16);
14046 var w2 = Math.floor(w / 2);
14047 var w4 = Math.floor(w / 4);
14048 var w8 = Math.floor(w / 8);
14049 var w16 = Math.floor(w / 16); // Make canvas as small as possible
14050
14051 this.canvas.width = 3 * w4;
14052 this.canvas.height = h2; // Coordinates and sizes of images contained in the canvas
14053 // Values per row: [top x, left y, width, height]
14054
14055 this.coordinates = [[0, 0, w2, h2], [w2, 0, w4, h4], [w2, h4, w8, h8], [5 * w8, h4, w16, h16]];
14056
14057 this._fillMipMap();
14058 }
14059 /**
14060 * @returns {boolean} true if init() has been called, false otherwise.
14061 */
14062
14063 }, {
14064 key: "initialized",
14065 value: function initialized() {
14066 return this.coordinates !== undefined;
14067 }
14068 /**
14069 * Redraw main image in various sizes to the context.
14070 *
14071 * The rationale behind this is to reduce artefacts due to interpolation
14072 * at differing zoom levels.
14073 *
14074 * Source: http://stackoverflow.com/q/18761404/1223531
14075 *
14076 * This methods takes the resizing out of the drawing loop, in order to
14077 * reduce performance overhead.
14078 *
14079 * TODO: The code assumes that a 2D context can always be gotten. This is
14080 * not necessarily true! OTOH, if not true then usage of this class
14081 * is senseless.
14082 *
14083 * @private
14084 */
14085
14086 }, {
14087 key: "_fillMipMap",
14088 value: function _fillMipMap() {
14089 var ctx = this.canvas.getContext("2d"); // First zoom-level comes from the image
14090
14091 var to = this.coordinates[0];
14092 ctx.drawImage(this.image, to[0], to[1], to[2], to[3]); // The rest are copy actions internal to the canvas/context
14093
14094 for (var iterations = 1; iterations < this.NUM_ITERATIONS; iterations++) {
14095 var from = this.coordinates[iterations - 1];
14096 var _to = this.coordinates[iterations];
14097 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], _to[0], _to[1], _to[2], _to[3]);
14098 }
14099 }
14100 /**
14101 * Draw the image, using the mipmap if necessary.
14102 *
14103 * MipMap is only used if param factor > 2; otherwise, original bitmap
14104 * is resized. This is also used to skip mipmap usage, e.g. by setting factor = 1
14105 *
14106 * Credits to 'Alex de Mulder' for original implementation.
14107 *
14108 * @param {CanvasRenderingContext2D} ctx context on which to draw zoomed image
14109 * @param {Float} factor scale factor at which to draw
14110 * @param {number} left
14111 * @param {number} top
14112 * @param {number} width
14113 * @param {number} height
14114 */
14115
14116 }, {
14117 key: "drawImageAtPosition",
14118 value: function drawImageAtPosition(ctx, factor, left, top, width, height) {
14119 if (!this.initialized()) return; //can't draw image yet not intialized
14120
14121 if (factor > 2) {
14122 // Determine which zoomed image to use
14123 factor *= 0.5;
14124 var iterations = 0;
14125
14126 while (factor > 2 && iterations < this.NUM_ITERATIONS) {
14127 factor *= 0.5;
14128 iterations += 1;
14129 }
14130
14131 if (iterations >= this.NUM_ITERATIONS) {
14132 iterations = this.NUM_ITERATIONS - 1;
14133 } //console.log("iterations: " + iterations);
14134
14135
14136 var from = this.coordinates[iterations];
14137 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], left, top, width, height);
14138 } else {
14139 // Draw image directly
14140 ctx.drawImage(this.image, left, top, width, height);
14141 }
14142 }
14143 }]);
14144
14145 return CachedImage;
14146 }();
14147
14148 /**
14149 * This callback is a callback that accepts an Image.
14150 *
14151 * @callback ImageCallback
14152 * @param {Image} image
14153 */
14154
14155 /**
14156 * This class loads images and keeps them stored.
14157 *
14158 * @param {ImageCallback} callback
14159 */
14160
14161 var Images = /*#__PURE__*/function () {
14162 /**
14163 * @param {ImageCallback} callback
14164 */
14165 function Images(callback) {
14166 _classCallCheck(this, Images);
14167
14168 this.images = {};
14169 this.imageBroken = {};
14170 this.callback = callback;
14171 }
14172 /**
14173 * @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
14174 * @param {string} brokenUrl Url the broken image to try and load
14175 * @param {Image} imageToLoadBrokenUrlOn The image object
14176 */
14177
14178
14179 _createClass(Images, [{
14180 key: "_tryloadBrokenUrl",
14181 value: function _tryloadBrokenUrl(url, brokenUrl, imageToLoadBrokenUrlOn) {
14182 //If these parameters aren't specified then exit the function because nothing constructive can be done
14183 if (url === undefined || imageToLoadBrokenUrlOn === undefined) return;
14184
14185 if (brokenUrl === undefined) {
14186 console.warn("No broken url image defined");
14187 return;
14188 } //Clear the old subscription to the error event and put a new in place that only handle errors in loading the brokenImageUrl
14189
14190
14191 imageToLoadBrokenUrlOn.image.onerror = function () {
14192 console.error("Could not load brokenImage:", brokenUrl); // cache item will contain empty image, this should be OK for default
14193 }; //Set the source of the image to the brokenUrl, this is actually what kicks off the loading of the broken image
14194
14195
14196 imageToLoadBrokenUrlOn.image.src = brokenUrl;
14197 }
14198 /**
14199 *
14200 * @param {vis.Image} imageToRedrawWith
14201 * @private
14202 */
14203
14204 }, {
14205 key: "_redrawWithImage",
14206 value: function _redrawWithImage(imageToRedrawWith) {
14207 if (this.callback) {
14208 this.callback(imageToRedrawWith);
14209 }
14210 }
14211 /**
14212 * @param {string} url Url of the image
14213 * @param {string} brokenUrl Url of an image to use if the url image is not found
14214 * @returns {Image} img The image object
14215 */
14216
14217 }, {
14218 key: "load",
14219 value: function load(url, brokenUrl) {
14220 var _this = this;
14221
14222 //Try and get the image from the cache, if successful then return the cached image
14223 var cachedImage = this.images[url];
14224 if (cachedImage) return cachedImage; //Create a new image
14225
14226 var img = new CachedImage(); // Need to add to cache here, otherwise final return will spawn different copies of the same image,
14227 // Also, there will be multiple loads of the same image.
14228
14229 this.images[url] = img; //Subscribe to the event that is raised if the image loads successfully
14230
14231 img.image.onload = function () {
14232 // Properly init the cached item and then request a redraw
14233 _this._fixImageCoordinates(img.image);
14234
14235 img.init();
14236
14237 _this._redrawWithImage(img);
14238 }; //Subscribe to the event that is raised if the image fails to load
14239
14240
14241 img.image.onerror = function () {
14242 console.error("Could not load image:", url); //Try and load the image specified by the brokenUrl using
14243
14244 _this._tryloadBrokenUrl(url, brokenUrl, img);
14245 }; //Set the source of the image to the url, this is what actually kicks off the loading of the image
14246
14247
14248 img.image.src = url; //Return the new image
14249
14250 return img;
14251 }
14252 /**
14253 * IE11 fix -- thanks dponch!
14254 *
14255 * Local helper function
14256 *
14257 * @param {vis.Image} imageToCache
14258 * @private
14259 */
14260
14261 }, {
14262 key: "_fixImageCoordinates",
14263 value: function _fixImageCoordinates(imageToCache) {
14264 if (imageToCache.width === 0) {
14265 document.body.appendChild(imageToCache);
14266 imageToCache.width = imageToCache.offsetWidth;
14267 imageToCache.height = imageToCache.offsetHeight;
14268 document.body.removeChild(imageToCache);
14269 }
14270 }
14271 }]);
14272
14273 return Images;
14274 }();
14275
14276 var internalMetadata = {exports: {}};
14277
14278 var fails$7 = fails$t;
14279 var arrayBufferNonExtensible = fails$7(function () {
14280 if (typeof ArrayBuffer == 'function') {
14281 var buffer = new ArrayBuffer(8); // eslint-disable-next-line es/no-object-isextensible, es/no-object-defineproperty -- safe
14282
14283 if (Object.isExtensible(buffer)) Object.defineProperty(buffer, 'a', {
14284 value: 8
14285 });
14286 }
14287 });
14288
14289 var fails$6 = fails$t;
14290 var isObject$6 = isObject$j;
14291 var classof$4 = classofRaw$1;
14292 var ARRAY_BUFFER_NON_EXTENSIBLE = arrayBufferNonExtensible; // eslint-disable-next-line es/no-object-isextensible -- safe
14293
14294 var $isExtensible = Object.isExtensible;
14295 var FAILS_ON_PRIMITIVES$1 = fails$6(function () {
14296 $isExtensible(1);
14297 }); // `Object.isExtensible` method
14298 // https://tc39.es/ecma262/#sec-object.isextensible
14299
14300 var objectIsExtensible = FAILS_ON_PRIMITIVES$1 || ARRAY_BUFFER_NON_EXTENSIBLE ? function isExtensible(it) {
14301 if (!isObject$6(it)) return false;
14302 if (ARRAY_BUFFER_NON_EXTENSIBLE && classof$4(it) == 'ArrayBuffer') return false;
14303 return $isExtensible ? $isExtensible(it) : true;
14304 } : $isExtensible;
14305
14306 var fails$5 = fails$t;
14307 var freezing = !fails$5(function () {
14308 // eslint-disable-next-line es/no-object-isextensible, es/no-object-preventextensions -- required for testing
14309 return Object.isExtensible(Object.preventExtensions({}));
14310 });
14311
14312 var $$e = _export;
14313 var uncurryThis$4 = functionUncurryThis;
14314 var hiddenKeys = hiddenKeys$6;
14315 var isObject$5 = isObject$j;
14316 var hasOwn$5 = hasOwnProperty_1;
14317 var defineProperty$2 = objectDefineProperty.f;
14318 var getOwnPropertyNamesModule = objectGetOwnPropertyNames;
14319 var getOwnPropertyNamesExternalModule = objectGetOwnPropertyNamesExternal;
14320 var isExtensible$1 = objectIsExtensible;
14321 var uid = uid$4;
14322 var FREEZING = freezing;
14323 var REQUIRED = false;
14324 var METADATA = uid('meta');
14325 var id$1 = 0;
14326
14327 var setMetadata = function (it) {
14328 defineProperty$2(it, METADATA, {
14329 value: {
14330 objectID: 'O' + id$1++,
14331 // object ID
14332 weakData: {} // weak collections IDs
14333
14334 }
14335 });
14336 };
14337
14338 var fastKey$1 = function (it, create) {
14339 // return a primitive with prefix
14340 if (!isObject$5(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
14341
14342 if (!hasOwn$5(it, METADATA)) {
14343 // can't set metadata to uncaught frozen object
14344 if (!isExtensible$1(it)) return 'F'; // not necessary to add metadata
14345
14346 if (!create) return 'E'; // add missing metadata
14347
14348 setMetadata(it); // return object ID
14349 }
14350
14351 return it[METADATA].objectID;
14352 };
14353
14354 var getWeakData$1 = function (it, create) {
14355 if (!hasOwn$5(it, METADATA)) {
14356 // can't set metadata to uncaught frozen object
14357 if (!isExtensible$1(it)) return true; // not necessary to add metadata
14358
14359 if (!create) return false; // add missing metadata
14360
14361 setMetadata(it); // return the store of weak collections IDs
14362 }
14363
14364 return it[METADATA].weakData;
14365 }; // add metadata on freeze-family methods calling
14366
14367
14368 var onFreeze = function (it) {
14369 if (FREEZING && REQUIRED && isExtensible$1(it) && !hasOwn$5(it, METADATA)) setMetadata(it);
14370 return it;
14371 };
14372
14373 var enable = function () {
14374 meta.enable = function () {
14375 /* empty */
14376 };
14377
14378 REQUIRED = true;
14379 var getOwnPropertyNames = getOwnPropertyNamesModule.f;
14380 var splice = uncurryThis$4([].splice);
14381 var test = {};
14382 test[METADATA] = 1; // prevent exposing of metadata key
14383
14384 if (getOwnPropertyNames(test).length) {
14385 getOwnPropertyNamesModule.f = function (it) {
14386 var result = getOwnPropertyNames(it);
14387
14388 for (var i = 0, length = result.length; i < length; i++) {
14389 if (result[i] === METADATA) {
14390 splice(result, i, 1);
14391 break;
14392 }
14393 }
14394
14395 return result;
14396 };
14397
14398 $$e({
14399 target: 'Object',
14400 stat: true,
14401 forced: true
14402 }, {
14403 getOwnPropertyNames: getOwnPropertyNamesExternalModule.f
14404 });
14405 }
14406 };
14407
14408 var meta = internalMetadata.exports = {
14409 enable: enable,
14410 fastKey: fastKey$1,
14411 getWeakData: getWeakData$1,
14412 onFreeze: onFreeze
14413 };
14414 hiddenKeys[METADATA] = true;
14415
14416 var global$a = global$P;
14417 var bind$3 = functionBindContext;
14418 var call$1 = functionCall;
14419 var anObject$3 = anObject$d;
14420 var tryToString$1 = tryToString$4;
14421 var isArrayIteratorMethod = isArrayIteratorMethod$2;
14422 var lengthOfArrayLike$4 = lengthOfArrayLike$d;
14423 var isPrototypeOf$9 = objectIsPrototypeOf;
14424 var getIterator$5 = getIterator$7;
14425 var getIteratorMethod = getIteratorMethod$8;
14426 var iteratorClose = iteratorClose$2;
14427 var TypeError$5 = global$a.TypeError;
14428
14429 var Result = function (stopped, result) {
14430 this.stopped = stopped;
14431 this.result = result;
14432 };
14433
14434 var ResultPrototype = Result.prototype;
14435
14436 var iterate$3 = function (iterable, unboundFunction, options) {
14437 var that = options && options.that;
14438 var AS_ENTRIES = !!(options && options.AS_ENTRIES);
14439 var IS_ITERATOR = !!(options && options.IS_ITERATOR);
14440 var INTERRUPTED = !!(options && options.INTERRUPTED);
14441 var fn = bind$3(unboundFunction, that);
14442 var iterator, iterFn, index, length, result, next, step;
14443
14444 var stop = function (condition) {
14445 if (iterator) iteratorClose(iterator, 'normal', condition);
14446 return new Result(true, condition);
14447 };
14448
14449 var callFn = function (value) {
14450 if (AS_ENTRIES) {
14451 anObject$3(value);
14452 return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
14453 }
14454
14455 return INTERRUPTED ? fn(value, stop) : fn(value);
14456 };
14457
14458 if (IS_ITERATOR) {
14459 iterator = iterable;
14460 } else {
14461 iterFn = getIteratorMethod(iterable);
14462 if (!iterFn) throw TypeError$5(tryToString$1(iterable) + ' is not iterable'); // optimisation for array iterators
14463
14464 if (isArrayIteratorMethod(iterFn)) {
14465 for (index = 0, length = lengthOfArrayLike$4(iterable); length > index; index++) {
14466 result = callFn(iterable[index]);
14467 if (result && isPrototypeOf$9(ResultPrototype, result)) return result;
14468 }
14469
14470 return new Result(false);
14471 }
14472
14473 iterator = getIterator$5(iterable, iterFn);
14474 }
14475
14476 next = iterator.next;
14477
14478 while (!(step = call$1(next, iterator)).done) {
14479 try {
14480 result = callFn(step.value);
14481 } catch (error) {
14482 iteratorClose(iterator, 'throw', error);
14483 }
14484
14485 if (typeof result == 'object' && result && isPrototypeOf$9(ResultPrototype, result)) return result;
14486 }
14487
14488 return new Result(false);
14489 };
14490
14491 var global$9 = global$P;
14492 var isPrototypeOf$8 = objectIsPrototypeOf;
14493 var TypeError$4 = global$9.TypeError;
14494
14495 var anInstance$3 = function (it, Prototype) {
14496 if (isPrototypeOf$8(Prototype, it)) return it;
14497 throw TypeError$4('Incorrect invocation');
14498 };
14499
14500 var $$d = _export;
14501 var global$8 = global$P;
14502 var InternalMetadataModule$1 = internalMetadata.exports;
14503 var fails$4 = fails$t;
14504 var createNonEnumerableProperty = createNonEnumerableProperty$6;
14505 var iterate$2 = iterate$3;
14506 var anInstance$2 = anInstance$3;
14507 var isCallable = isCallable$h;
14508 var isObject$4 = isObject$j;
14509 var setToStringTag = setToStringTag$5;
14510 var defineProperty$1 = objectDefineProperty.f;
14511 var forEach = arrayIteration.forEach;
14512 var DESCRIPTORS$2 = descriptors;
14513 var InternalStateModule$2 = internalState;
14514 var setInternalState$2 = InternalStateModule$2.set;
14515 var internalStateGetterFor$2 = InternalStateModule$2.getterFor;
14516
14517 var collection$3 = function (CONSTRUCTOR_NAME, wrapper, common) {
14518 var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
14519 var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
14520 var ADDER = IS_MAP ? 'set' : 'add';
14521 var NativeConstructor = global$8[CONSTRUCTOR_NAME];
14522 var NativePrototype = NativeConstructor && NativeConstructor.prototype;
14523 var exported = {};
14524 var Constructor;
14525
14526 if (!DESCRIPTORS$2 || !isCallable(NativeConstructor) || !(IS_WEAK || NativePrototype.forEach && !fails$4(function () {
14527 new NativeConstructor().entries().next();
14528 }))) {
14529 // create collection constructor
14530 Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
14531 InternalMetadataModule$1.enable();
14532 } else {
14533 Constructor = wrapper(function (target, iterable) {
14534 setInternalState$2(anInstance$2(target, Prototype), {
14535 type: CONSTRUCTOR_NAME,
14536 collection: new NativeConstructor()
14537 });
14538 if (iterable != undefined) iterate$2(iterable, target[ADDER], {
14539 that: target,
14540 AS_ENTRIES: IS_MAP
14541 });
14542 });
14543 var Prototype = Constructor.prototype;
14544 var getInternalState = internalStateGetterFor$2(CONSTRUCTOR_NAME);
14545 forEach(['add', 'clear', 'delete', 'forEach', 'get', 'has', 'set', 'keys', 'values', 'entries'], function (KEY) {
14546 var IS_ADDER = KEY == 'add' || KEY == 'set';
14547
14548 if (KEY in NativePrototype && !(IS_WEAK && KEY == 'clear')) {
14549 createNonEnumerableProperty(Prototype, KEY, function (a, b) {
14550 var collection = getInternalState(this).collection;
14551 if (!IS_ADDER && IS_WEAK && !isObject$4(a)) return KEY == 'get' ? undefined : false;
14552 var result = collection[KEY](a === 0 ? 0 : a, b);
14553 return IS_ADDER ? this : result;
14554 });
14555 }
14556 });
14557 IS_WEAK || defineProperty$1(Prototype, 'size', {
14558 configurable: true,
14559 get: function () {
14560 return getInternalState(this).collection.size;
14561 }
14562 });
14563 }
14564
14565 setToStringTag(Constructor, CONSTRUCTOR_NAME, false, true);
14566 exported[CONSTRUCTOR_NAME] = Constructor;
14567 $$d({
14568 global: true,
14569 forced: true
14570 }, exported);
14571 if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
14572 return Constructor;
14573 };
14574
14575 var redefine = redefine$4;
14576
14577 var redefineAll$3 = function (target, src, options) {
14578 for (var key in src) {
14579 if (options && options.unsafe && target[key]) target[key] = src[key];else redefine(target, key, src[key], options);
14580 }
14581
14582 return target;
14583 };
14584
14585 var getBuiltIn$1 = getBuiltIn$9;
14586 var definePropertyModule = objectDefineProperty;
14587 var wellKnownSymbol = wellKnownSymbol$j;
14588 var DESCRIPTORS$1 = descriptors;
14589 var SPECIES = wellKnownSymbol('species');
14590
14591 var setSpecies$1 = function (CONSTRUCTOR_NAME) {
14592 var Constructor = getBuiltIn$1(CONSTRUCTOR_NAME);
14593 var defineProperty = definePropertyModule.f;
14594
14595 if (DESCRIPTORS$1 && Constructor && !Constructor[SPECIES]) {
14596 defineProperty(Constructor, SPECIES, {
14597 configurable: true,
14598 get: function () {
14599 return this;
14600 }
14601 });
14602 }
14603 };
14604
14605 var defineProperty = objectDefineProperty.f;
14606 var create$4 = objectCreate;
14607 var redefineAll$2 = redefineAll$3;
14608 var bind$2 = functionBindContext;
14609 var anInstance$1 = anInstance$3;
14610 var iterate$1 = iterate$3;
14611 var defineIterator = defineIterator$3;
14612 var setSpecies = setSpecies$1;
14613 var DESCRIPTORS = descriptors;
14614 var fastKey = internalMetadata.exports.fastKey;
14615 var InternalStateModule$1 = internalState;
14616 var setInternalState$1 = InternalStateModule$1.set;
14617 var internalStateGetterFor$1 = InternalStateModule$1.getterFor;
14618 var collectionStrong$2 = {
14619 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
14620 var Constructor = wrapper(function (that, iterable) {
14621 anInstance$1(that, Prototype);
14622 setInternalState$1(that, {
14623 type: CONSTRUCTOR_NAME,
14624 index: create$4(null),
14625 first: undefined,
14626 last: undefined,
14627 size: 0
14628 });
14629 if (!DESCRIPTORS) that.size = 0;
14630 if (iterable != undefined) iterate$1(iterable, that[ADDER], {
14631 that: that,
14632 AS_ENTRIES: IS_MAP
14633 });
14634 });
14635 var Prototype = Constructor.prototype;
14636 var getInternalState = internalStateGetterFor$1(CONSTRUCTOR_NAME);
14637
14638 var define = function (that, key, value) {
14639 var state = getInternalState(that);
14640 var entry = getEntry(that, key);
14641 var previous, index; // change existing entry
14642
14643 if (entry) {
14644 entry.value = value; // create new entry
14645 } else {
14646 state.last = entry = {
14647 index: index = fastKey(key, true),
14648 key: key,
14649 value: value,
14650 previous: previous = state.last,
14651 next: undefined,
14652 removed: false
14653 };
14654 if (!state.first) state.first = entry;
14655 if (previous) previous.next = entry;
14656 if (DESCRIPTORS) state.size++;else that.size++; // add to index
14657
14658 if (index !== 'F') state.index[index] = entry;
14659 }
14660
14661 return that;
14662 };
14663
14664 var getEntry = function (that, key) {
14665 var state = getInternalState(that); // fast case
14666
14667 var index = fastKey(key);
14668 var entry;
14669 if (index !== 'F') return state.index[index]; // frozen object case
14670
14671 for (entry = state.first; entry; entry = entry.next) {
14672 if (entry.key == key) return entry;
14673 }
14674 };
14675
14676 redefineAll$2(Prototype, {
14677 // `{ Map, Set }.prototype.clear()` methods
14678 // https://tc39.es/ecma262/#sec-map.prototype.clear
14679 // https://tc39.es/ecma262/#sec-set.prototype.clear
14680 clear: function clear() {
14681 var that = this;
14682 var state = getInternalState(that);
14683 var data = state.index;
14684 var entry = state.first;
14685
14686 while (entry) {
14687 entry.removed = true;
14688 if (entry.previous) entry.previous = entry.previous.next = undefined;
14689 delete data[entry.index];
14690 entry = entry.next;
14691 }
14692
14693 state.first = state.last = undefined;
14694 if (DESCRIPTORS) state.size = 0;else that.size = 0;
14695 },
14696 // `{ Map, Set }.prototype.delete(key)` methods
14697 // https://tc39.es/ecma262/#sec-map.prototype.delete
14698 // https://tc39.es/ecma262/#sec-set.prototype.delete
14699 'delete': function (key) {
14700 var that = this;
14701 var state = getInternalState(that);
14702 var entry = getEntry(that, key);
14703
14704 if (entry) {
14705 var next = entry.next;
14706 var prev = entry.previous;
14707 delete state.index[entry.index];
14708 entry.removed = true;
14709 if (prev) prev.next = next;
14710 if (next) next.previous = prev;
14711 if (state.first == entry) state.first = next;
14712 if (state.last == entry) state.last = prev;
14713 if (DESCRIPTORS) state.size--;else that.size--;
14714 }
14715
14716 return !!entry;
14717 },
14718 // `{ Map, Set }.prototype.forEach(callbackfn, thisArg = undefined)` methods
14719 // https://tc39.es/ecma262/#sec-map.prototype.foreach
14720 // https://tc39.es/ecma262/#sec-set.prototype.foreach
14721 forEach: function forEach(callbackfn
14722 /* , that = undefined */
14723 ) {
14724 var state = getInternalState(this);
14725 var boundFunction = bind$2(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
14726 var entry;
14727
14728 while (entry = entry ? entry.next : state.first) {
14729 boundFunction(entry.value, entry.key, this); // revert to the last existing entry
14730
14731 while (entry && entry.removed) entry = entry.previous;
14732 }
14733 },
14734 // `{ Map, Set}.prototype.has(key)` methods
14735 // https://tc39.es/ecma262/#sec-map.prototype.has
14736 // https://tc39.es/ecma262/#sec-set.prototype.has
14737 has: function has(key) {
14738 return !!getEntry(this, key);
14739 }
14740 });
14741 redefineAll$2(Prototype, IS_MAP ? {
14742 // `Map.prototype.get(key)` method
14743 // https://tc39.es/ecma262/#sec-map.prototype.get
14744 get: function get(key) {
14745 var entry = getEntry(this, key);
14746 return entry && entry.value;
14747 },
14748 // `Map.prototype.set(key, value)` method
14749 // https://tc39.es/ecma262/#sec-map.prototype.set
14750 set: function set(key, value) {
14751 return define(this, key === 0 ? 0 : key, value);
14752 }
14753 } : {
14754 // `Set.prototype.add(value)` method
14755 // https://tc39.es/ecma262/#sec-set.prototype.add
14756 add: function add(value) {
14757 return define(this, value = value === 0 ? 0 : value, value);
14758 }
14759 });
14760 if (DESCRIPTORS) defineProperty(Prototype, 'size', {
14761 get: function () {
14762 return getInternalState(this).size;
14763 }
14764 });
14765 return Constructor;
14766 },
14767 setStrong: function (Constructor, CONSTRUCTOR_NAME, IS_MAP) {
14768 var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
14769 var getInternalCollectionState = internalStateGetterFor$1(CONSTRUCTOR_NAME);
14770 var getInternalIteratorState = internalStateGetterFor$1(ITERATOR_NAME); // `{ Map, Set }.prototype.{ keys, values, entries, @@iterator }()` methods
14771 // https://tc39.es/ecma262/#sec-map.prototype.entries
14772 // https://tc39.es/ecma262/#sec-map.prototype.keys
14773 // https://tc39.es/ecma262/#sec-map.prototype.values
14774 // https://tc39.es/ecma262/#sec-map.prototype-@@iterator
14775 // https://tc39.es/ecma262/#sec-set.prototype.entries
14776 // https://tc39.es/ecma262/#sec-set.prototype.keys
14777 // https://tc39.es/ecma262/#sec-set.prototype.values
14778 // https://tc39.es/ecma262/#sec-set.prototype-@@iterator
14779
14780 defineIterator(Constructor, CONSTRUCTOR_NAME, function (iterated, kind) {
14781 setInternalState$1(this, {
14782 type: ITERATOR_NAME,
14783 target: iterated,
14784 state: getInternalCollectionState(iterated),
14785 kind: kind,
14786 last: undefined
14787 });
14788 }, function () {
14789 var state = getInternalIteratorState(this);
14790 var kind = state.kind;
14791 var entry = state.last; // revert to the last existing entry
14792
14793 while (entry && entry.removed) entry = entry.previous; // get next entry
14794
14795
14796 if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
14797 // or finish the iteration
14798 state.target = undefined;
14799 return {
14800 value: undefined,
14801 done: true
14802 };
14803 } // return step by kind
14804
14805
14806 if (kind == 'keys') return {
14807 value: entry.key,
14808 done: false
14809 };
14810 if (kind == 'values') return {
14811 value: entry.value,
14812 done: false
14813 };
14814 return {
14815 value: [entry.key, entry.value],
14816 done: false
14817 };
14818 }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); // `{ Map, Set }.prototype[@@species]` accessors
14819 // https://tc39.es/ecma262/#sec-get-map-@@species
14820 // https://tc39.es/ecma262/#sec-get-set-@@species
14821
14822 setSpecies(CONSTRUCTOR_NAME);
14823 }
14824 };
14825
14826 var collection$2 = collection$3;
14827 var collectionStrong$1 = collectionStrong$2; // `Map` constructor
14828 // https://tc39.es/ecma262/#sec-map-objects
14829
14830 collection$2('Map', function (init) {
14831 return function Map() {
14832 return init(this, arguments.length ? arguments[0] : undefined);
14833 };
14834 }, collectionStrong$1);
14835
14836 var path$b = path$y;
14837 var map$2 = path$b.Map;
14838
14839 var parent$v = map$2;
14840 var map$1 = parent$v;
14841
14842 var map = map$1;
14843
14844 /**
14845 * This class can store groups and options specific for groups.
14846 */
14847 var Groups = /*#__PURE__*/function () {
14848 /**
14849 * @ignore
14850 */
14851 function Groups() {
14852 _classCallCheck(this, Groups);
14853
14854 this.clear();
14855 this._defaultIndex = 0;
14856 this._groupIndex = 0;
14857 this._defaultGroups = [{
14858 border: "#2B7CE9",
14859 background: "#97C2FC",
14860 highlight: {
14861 border: "#2B7CE9",
14862 background: "#D2E5FF"
14863 },
14864 hover: {
14865 border: "#2B7CE9",
14866 background: "#D2E5FF"
14867 }
14868 }, // 0: blue
14869 {
14870 border: "#FFA500",
14871 background: "#FFFF00",
14872 highlight: {
14873 border: "#FFA500",
14874 background: "#FFFFA3"
14875 },
14876 hover: {
14877 border: "#FFA500",
14878 background: "#FFFFA3"
14879 }
14880 }, // 1: yellow
14881 {
14882 border: "#FA0A10",
14883 background: "#FB7E81",
14884 highlight: {
14885 border: "#FA0A10",
14886 background: "#FFAFB1"
14887 },
14888 hover: {
14889 border: "#FA0A10",
14890 background: "#FFAFB1"
14891 }
14892 }, // 2: red
14893 {
14894 border: "#41A906",
14895 background: "#7BE141",
14896 highlight: {
14897 border: "#41A906",
14898 background: "#A1EC76"
14899 },
14900 hover: {
14901 border: "#41A906",
14902 background: "#A1EC76"
14903 }
14904 }, // 3: green
14905 {
14906 border: "#E129F0",
14907 background: "#EB7DF4",
14908 highlight: {
14909 border: "#E129F0",
14910 background: "#F0B3F5"
14911 },
14912 hover: {
14913 border: "#E129F0",
14914 background: "#F0B3F5"
14915 }
14916 }, // 4: magenta
14917 {
14918 border: "#7C29F0",
14919 background: "#AD85E4",
14920 highlight: {
14921 border: "#7C29F0",
14922 background: "#D3BDF0"
14923 },
14924 hover: {
14925 border: "#7C29F0",
14926 background: "#D3BDF0"
14927 }
14928 }, // 5: purple
14929 {
14930 border: "#C37F00",
14931 background: "#FFA807",
14932 highlight: {
14933 border: "#C37F00",
14934 background: "#FFCA66"
14935 },
14936 hover: {
14937 border: "#C37F00",
14938 background: "#FFCA66"
14939 }
14940 }, // 6: orange
14941 {
14942 border: "#4220FB",
14943 background: "#6E6EFD",
14944 highlight: {
14945 border: "#4220FB",
14946 background: "#9B9BFD"
14947 },
14948 hover: {
14949 border: "#4220FB",
14950 background: "#9B9BFD"
14951 }
14952 }, // 7: darkblue
14953 {
14954 border: "#FD5A77",
14955 background: "#FFC0CB",
14956 highlight: {
14957 border: "#FD5A77",
14958 background: "#FFD1D9"
14959 },
14960 hover: {
14961 border: "#FD5A77",
14962 background: "#FFD1D9"
14963 }
14964 }, // 8: pink
14965 {
14966 border: "#4AD63A",
14967 background: "#C2FABC",
14968 highlight: {
14969 border: "#4AD63A",
14970 background: "#E6FFE3"
14971 },
14972 hover: {
14973 border: "#4AD63A",
14974 background: "#E6FFE3"
14975 }
14976 }, // 9: mint
14977 {
14978 border: "#990000",
14979 background: "#EE0000",
14980 highlight: {
14981 border: "#BB0000",
14982 background: "#FF3333"
14983 },
14984 hover: {
14985 border: "#BB0000",
14986 background: "#FF3333"
14987 }
14988 }, // 10:bright red
14989 {
14990 border: "#FF6000",
14991 background: "#FF6000",
14992 highlight: {
14993 border: "#FF6000",
14994 background: "#FF6000"
14995 },
14996 hover: {
14997 border: "#FF6000",
14998 background: "#FF6000"
14999 }
15000 }, // 12: real orange
15001 {
15002 border: "#97C2FC",
15003 background: "#2B7CE9",
15004 highlight: {
15005 border: "#D2E5FF",
15006 background: "#2B7CE9"
15007 },
15008 hover: {
15009 border: "#D2E5FF",
15010 background: "#2B7CE9"
15011 }
15012 }, // 13: blue
15013 {
15014 border: "#399605",
15015 background: "#255C03",
15016 highlight: {
15017 border: "#399605",
15018 background: "#255C03"
15019 },
15020 hover: {
15021 border: "#399605",
15022 background: "#255C03"
15023 }
15024 }, // 14: green
15025 {
15026 border: "#B70054",
15027 background: "#FF007E",
15028 highlight: {
15029 border: "#B70054",
15030 background: "#FF007E"
15031 },
15032 hover: {
15033 border: "#B70054",
15034 background: "#FF007E"
15035 }
15036 }, // 15: magenta
15037 {
15038 border: "#AD85E4",
15039 background: "#7C29F0",
15040 highlight: {
15041 border: "#D3BDF0",
15042 background: "#7C29F0"
15043 },
15044 hover: {
15045 border: "#D3BDF0",
15046 background: "#7C29F0"
15047 }
15048 }, // 16: purple
15049 {
15050 border: "#4557FA",
15051 background: "#000EA1",
15052 highlight: {
15053 border: "#6E6EFD",
15054 background: "#000EA1"
15055 },
15056 hover: {
15057 border: "#6E6EFD",
15058 background: "#000EA1"
15059 }
15060 }, // 17: darkblue
15061 {
15062 border: "#FFC0CB",
15063 background: "#FD5A77",
15064 highlight: {
15065 border: "#FFD1D9",
15066 background: "#FD5A77"
15067 },
15068 hover: {
15069 border: "#FFD1D9",
15070 background: "#FD5A77"
15071 }
15072 }, // 18: pink
15073 {
15074 border: "#C2FABC",
15075 background: "#74D66A",
15076 highlight: {
15077 border: "#E6FFE3",
15078 background: "#74D66A"
15079 },
15080 hover: {
15081 border: "#E6FFE3",
15082 background: "#74D66A"
15083 }
15084 }, // 19: mint
15085 {
15086 border: "#EE0000",
15087 background: "#990000",
15088 highlight: {
15089 border: "#FF3333",
15090 background: "#BB0000"
15091 },
15092 hover: {
15093 border: "#FF3333",
15094 background: "#BB0000"
15095 }
15096 } // 20:bright red
15097 ];
15098 this.options = {};
15099 this.defaultOptions = {
15100 useDefaultGroups: true
15101 };
15102
15103 assign$2(this.options, this.defaultOptions);
15104 }
15105 /**
15106 *
15107 * @param {object} options
15108 */
15109
15110
15111 _createClass(Groups, [{
15112 key: "setOptions",
15113 value: function setOptions(options) {
15114 var optionFields = ["useDefaultGroups"];
15115
15116 if (options !== undefined) {
15117 for (var groupName in options) {
15118 if (Object.prototype.hasOwnProperty.call(options, groupName)) {
15119 if (indexOf(optionFields).call(optionFields, groupName) === -1) {
15120 var group = options[groupName];
15121 this.add(groupName, group);
15122 }
15123 }
15124 }
15125 }
15126 }
15127 /**
15128 * Clear all groups
15129 */
15130
15131 }, {
15132 key: "clear",
15133 value: function clear() {
15134 this._groups = new map();
15135 this._groupNames = [];
15136 }
15137 /**
15138 * Get group options of a groupname.
15139 * If groupname is not found, a new group may be created.
15140 *
15141 * @param {*} groupname Can be a number, string, Date, etc.
15142 * @param {boolean} [shouldCreate=true] If true, create a new group
15143 * @returns {object} The found or created group
15144 */
15145
15146 }, {
15147 key: "get",
15148 value: function get(groupname) {
15149 var shouldCreate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
15150
15151 var group = this._groups.get(groupname);
15152
15153 if (group === undefined && shouldCreate) {
15154 if (this.options.useDefaultGroups === false && this._groupNames.length > 0) {
15155 // create new group
15156 var index = this._groupIndex % this._groupNames.length;
15157 ++this._groupIndex;
15158 group = {};
15159 group.color = this._groups.get(this._groupNames[index]);
15160
15161 this._groups.set(groupname, group);
15162 } else {
15163 // create new group
15164 var _index = this._defaultIndex % this._defaultGroups.length;
15165
15166 this._defaultIndex++;
15167 group = {};
15168 group.color = this._defaultGroups[_index];
15169
15170 this._groups.set(groupname, group);
15171 }
15172 }
15173
15174 return group;
15175 }
15176 /**
15177 * Add custom group style.
15178 *
15179 * @param {string} groupName - The name of the group, a new group will be
15180 * created if a group with the same name doesn't exist, otherwise the old
15181 * groups style will be overwritten.
15182 * @param {object} style - An object containing borderColor, backgroundColor,
15183 * etc.
15184 * @returns {object} The created group object.
15185 */
15186
15187 }, {
15188 key: "add",
15189 value: function add(groupName, style) {
15190 // Only push group name once to prevent duplicates which would consume more
15191 // RAM and also skew the distribution towards more often updated groups,
15192 // neither of which is desirable.
15193 if (!this._groups.has(groupName)) {
15194 this._groupNames.push(groupName);
15195 }
15196
15197 this._groups.set(groupName, style);
15198
15199 return style;
15200 }
15201 }]);
15202
15203 return Groups;
15204 }();
15205
15206 var $$c = _export; // `Number.isNaN` method
15207 // https://tc39.es/ecma262/#sec-number.isnan
15208
15209 $$c({
15210 target: 'Number',
15211 stat: true
15212 }, {
15213 isNaN: function isNaN(number) {
15214 // eslint-disable-next-line no-self-compare -- NaN check
15215 return number != number;
15216 }
15217 });
15218
15219 var path$a = path$y;
15220 var isNan$2 = path$a.Number.isNaN;
15221
15222 var parent$u = isNan$2;
15223 var isNan$1 = parent$u;
15224
15225 var isNan = isNan$1;
15226
15227 var global$7 = global$P;
15228 var globalIsFinite = global$7.isFinite; // `Number.isFinite` method
15229 // https://tc39.es/ecma262/#sec-number.isfinite
15230 // eslint-disable-next-line es/no-number-isfinite -- safe
15231
15232 var numberIsFinite$1 = Number.isFinite || function isFinite(it) {
15233 return typeof it == 'number' && globalIsFinite(it);
15234 };
15235
15236 var $$b = _export;
15237 var numberIsFinite = numberIsFinite$1; // `Number.isFinite` method
15238 // https://tc39.es/ecma262/#sec-number.isfinite
15239
15240 $$b({
15241 target: 'Number',
15242 stat: true
15243 }, {
15244 isFinite: numberIsFinite
15245 });
15246
15247 var path$9 = path$y;
15248 var _isFinite$2 = path$9.Number.isFinite;
15249
15250 var parent$t = _isFinite$2;
15251 var _isFinite$1 = parent$t;
15252
15253 var _isFinite = _isFinite$1;
15254
15255 var $$a = _export;
15256 var $some = arrayIteration.some;
15257 var arrayMethodIsStrict$3 = arrayMethodIsStrict$6;
15258 var STRICT_METHOD$3 = arrayMethodIsStrict$3('some'); // `Array.prototype.some` method
15259 // https://tc39.es/ecma262/#sec-array.prototype.some
15260
15261 $$a({
15262 target: 'Array',
15263 proto: true,
15264 forced: !STRICT_METHOD$3
15265 }, {
15266 some: function some(callbackfn
15267 /* , thisArg */
15268 ) {
15269 return $some(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
15270 }
15271 });
15272
15273 var entryVirtual$7 = entryVirtual$l;
15274 var some$3 = entryVirtual$7('Array').some;
15275
15276 var isPrototypeOf$7 = objectIsPrototypeOf;
15277 var method$7 = some$3;
15278 var ArrayPrototype$7 = Array.prototype;
15279
15280 var some$2 = function (it) {
15281 var own = it.some;
15282 return it === ArrayPrototype$7 || isPrototypeOf$7(ArrayPrototype$7, it) && own === ArrayPrototype$7.some ? method$7 : own;
15283 };
15284
15285 var parent$s = some$2;
15286 var some$1 = parent$s;
15287
15288 var some = some$1;
15289
15290 var global$6 = global$P;
15291 var isConstructor = isConstructor$4;
15292 var tryToString = tryToString$4;
15293 var TypeError$3 = global$6.TypeError; // `Assert: IsConstructor(argument) is true`
15294
15295 var aConstructor$1 = function (argument) {
15296 if (isConstructor(argument)) return argument;
15297 throw TypeError$3(tryToString(argument) + ' is not a constructor');
15298 };
15299
15300 var $$9 = _export;
15301 var getBuiltIn = getBuiltIn$9;
15302 var apply = functionApply;
15303 var bind$1 = functionBind;
15304 var aConstructor = aConstructor$1;
15305 var anObject$2 = anObject$d;
15306 var isObject$3 = isObject$j;
15307 var create$3 = objectCreate;
15308 var fails$3 = fails$t;
15309 var nativeConstruct = getBuiltIn('Reflect', 'construct');
15310 var ObjectPrototype = Object.prototype;
15311 var push$1 = [].push; // `Reflect.construct` method
15312 // https://tc39.es/ecma262/#sec-reflect.construct
15313 // MS Edge supports only 2 arguments and argumentsList argument is optional
15314 // FF Nightly sets third argument as `new.target`, but does not create `this` from it
15315
15316 var NEW_TARGET_BUG = fails$3(function () {
15317 function F() {
15318 /* empty */
15319 }
15320
15321 return !(nativeConstruct(function () {
15322 /* empty */
15323 }, [], F) instanceof F);
15324 });
15325 var ARGS_BUG = !fails$3(function () {
15326 nativeConstruct(function () {
15327 /* empty */
15328 });
15329 });
15330 var FORCED$2 = NEW_TARGET_BUG || ARGS_BUG;
15331 $$9({
15332 target: 'Reflect',
15333 stat: true,
15334 forced: FORCED$2,
15335 sham: FORCED$2
15336 }, {
15337 construct: function construct(Target, args
15338 /* , newTarget */
15339 ) {
15340 aConstructor(Target);
15341 anObject$2(args);
15342 var newTarget = arguments.length < 3 ? Target : aConstructor(arguments[2]);
15343 if (ARGS_BUG && !NEW_TARGET_BUG) return nativeConstruct(Target, args, newTarget);
15344
15345 if (Target == newTarget) {
15346 // w/o altered newTarget, optimization for 0-4 arguments
15347 switch (args.length) {
15348 case 0:
15349 return new Target();
15350
15351 case 1:
15352 return new Target(args[0]);
15353
15354 case 2:
15355 return new Target(args[0], args[1]);
15356
15357 case 3:
15358 return new Target(args[0], args[1], args[2]);
15359
15360 case 4:
15361 return new Target(args[0], args[1], args[2], args[3]);
15362 } // w/o altered newTarget, lot of arguments case
15363
15364
15365 var $args = [null];
15366 apply(push$1, $args, args);
15367 return new (apply(bind$1, Target, $args))();
15368 } // with altered newTarget, not support built-in constructors
15369
15370
15371 var proto = newTarget.prototype;
15372 var instance = create$3(isObject$3(proto) ? proto : ObjectPrototype);
15373 var result = apply(Target, instance, args);
15374 return isObject$3(result) ? result : instance;
15375 }
15376 });
15377
15378 var path$8 = path$y;
15379 var construct$2 = path$8.Reflect.construct;
15380
15381 var parent$r = construct$2;
15382 var construct$1 = parent$r;
15383
15384 var construct = construct$1;
15385
15386 function _assertThisInitialized(self) {
15387 if (self === void 0) {
15388 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
15389 }
15390
15391 return self;
15392 }
15393
15394 var parent$q = create$6;
15395 var create$2 = parent$q;
15396
15397 var parent$p = create$2;
15398 var create$1 = parent$p;
15399
15400 var create = create$1;
15401
15402 var $$8 = _export;
15403 var setPrototypeOf$5 = objectSetPrototypeOf; // `Object.setPrototypeOf` method
15404 // https://tc39.es/ecma262/#sec-object.setprototypeof
15405
15406 $$8({
15407 target: 'Object',
15408 stat: true
15409 }, {
15410 setPrototypeOf: setPrototypeOf$5
15411 });
15412
15413 var path$7 = path$y;
15414 var setPrototypeOf$4 = path$7.Object.setPrototypeOf;
15415
15416 var parent$o = setPrototypeOf$4;
15417 var setPrototypeOf$3 = parent$o;
15418
15419 var parent$n = setPrototypeOf$3;
15420 var setPrototypeOf$2 = parent$n;
15421
15422 var parent$m = setPrototypeOf$2;
15423 var setPrototypeOf$1 = parent$m;
15424
15425 var setPrototypeOf = setPrototypeOf$1;
15426
15427 function _setPrototypeOf(o, p) {
15428 _setPrototypeOf = setPrototypeOf || function _setPrototypeOf(o, p) {
15429 o.__proto__ = p;
15430 return o;
15431 };
15432
15433 return _setPrototypeOf(o, p);
15434 }
15435
15436 function _inherits(subClass, superClass) {
15437 if (typeof superClass !== "function" && superClass !== null) {
15438 throw new TypeError("Super expression must either be null or a function");
15439 }
15440
15441 subClass.prototype = create(superClass && superClass.prototype, {
15442 constructor: {
15443 value: subClass,
15444 writable: true,
15445 configurable: true
15446 }
15447 });
15448
15449 defineProperty$3(subClass, "prototype", {
15450 writable: false
15451 });
15452
15453 if (superClass) _setPrototypeOf(subClass, superClass);
15454 }
15455
15456 function _possibleConstructorReturn(self, call) {
15457 if (call && (_typeof(call) === "object" || typeof call === "function")) {
15458 return call;
15459 } else if (call !== void 0) {
15460 throw new TypeError("Derived constructors may only return object or undefined");
15461 }
15462
15463 return _assertThisInitialized(self);
15464 }
15465
15466 var parent$l = getPrototypeOf$5;
15467 var getPrototypeOf$3 = parent$l;
15468
15469 var parent$k = getPrototypeOf$3;
15470 var getPrototypeOf$2 = parent$k;
15471
15472 var getPrototypeOf$1 = getPrototypeOf$2;
15473
15474 function _getPrototypeOf(o) {
15475 _getPrototypeOf = setPrototypeOf ? getPrototypeOf$1 : function _getPrototypeOf(o) {
15476 return o.__proto__ || getPrototypeOf$1(o);
15477 };
15478 return _getPrototypeOf(o);
15479 }
15480
15481 var runtime = {exports: {}};
15482
15483 /**
15484 * Copyright (c) 2014-present, Facebook, Inc.
15485 *
15486 * This source code is licensed under the MIT license found in the
15487 * LICENSE file in the root directory of this source tree.
15488 */
15489
15490 (function (module) {
15491 var runtime = function (exports) {
15492
15493 var Op = Object.prototype;
15494 var hasOwn = Op.hasOwnProperty;
15495 var undefined$1; // More compressible than void 0.
15496
15497 var $Symbol = typeof Symbol === "function" ? Symbol : {};
15498 var iteratorSymbol = $Symbol.iterator || "@@iterator";
15499 var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
15500 var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
15501
15502 function define(obj, key, value) {
15503 Object.defineProperty(obj, key, {
15504 value: value,
15505 enumerable: true,
15506 configurable: true,
15507 writable: true
15508 });
15509 return obj[key];
15510 }
15511
15512 try {
15513 // IE 8 has a broken Object.defineProperty that only works on DOM objects.
15514 define({}, "");
15515 } catch (err) {
15516 define = function (obj, key, value) {
15517 return obj[key] = value;
15518 };
15519 }
15520
15521 function wrap(innerFn, outerFn, self, tryLocsList) {
15522 // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
15523 var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
15524 var generator = Object.create(protoGenerator.prototype);
15525 var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
15526 // .throw, and .return methods.
15527
15528 generator._invoke = makeInvokeMethod(innerFn, self, context);
15529 return generator;
15530 }
15531
15532 exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
15533 // record like context.tryEntries[i].completion. This interface could
15534 // have been (and was previously) designed to take a closure to be
15535 // invoked without arguments, but in all the cases we care about we
15536 // already have an existing method we want to call, so there's no need
15537 // to create a new function object. We can even get away with assuming
15538 // the method takes exactly one argument, since that happens to be true
15539 // in every case, so we don't have to touch the arguments object. The
15540 // only additional allocation required is the completion record, which
15541 // has a stable shape and so hopefully should be cheap to allocate.
15542
15543 function tryCatch(fn, obj, arg) {
15544 try {
15545 return {
15546 type: "normal",
15547 arg: fn.call(obj, arg)
15548 };
15549 } catch (err) {
15550 return {
15551 type: "throw",
15552 arg: err
15553 };
15554 }
15555 }
15556
15557 var GenStateSuspendedStart = "suspendedStart";
15558 var GenStateSuspendedYield = "suspendedYield";
15559 var GenStateExecuting = "executing";
15560 var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
15561 // breaking out of the dispatch switch statement.
15562
15563 var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
15564 // .constructor.prototype properties for functions that return Generator
15565 // objects. For full spec compliance, you may wish to configure your
15566 // minifier not to mangle the names of these two functions.
15567
15568 function Generator() {}
15569
15570 function GeneratorFunction() {}
15571
15572 function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
15573 // don't natively support it.
15574
15575
15576 var IteratorPrototype = {};
15577 define(IteratorPrototype, iteratorSymbol, function () {
15578 return this;
15579 });
15580 var getProto = Object.getPrototypeOf;
15581 var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
15582
15583 if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
15584 // This environment has a native %IteratorPrototype%; use it instead
15585 // of the polyfill.
15586 IteratorPrototype = NativeIteratorPrototype;
15587 }
15588
15589 var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
15590 GeneratorFunction.prototype = GeneratorFunctionPrototype;
15591 define(Gp, "constructor", GeneratorFunctionPrototype);
15592 define(GeneratorFunctionPrototype, "constructor", GeneratorFunction);
15593 GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
15594 // Iterator interface in terms of a single ._invoke method.
15595
15596 function defineIteratorMethods(prototype) {
15597 ["next", "throw", "return"].forEach(function (method) {
15598 define(prototype, method, function (arg) {
15599 return this._invoke(method, arg);
15600 });
15601 });
15602 }
15603
15604 exports.isGeneratorFunction = function (genFun) {
15605 var ctor = typeof genFun === "function" && genFun.constructor;
15606 return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
15607 // do is to check its .name property.
15608 (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
15609 };
15610
15611 exports.mark = function (genFun) {
15612 if (Object.setPrototypeOf) {
15613 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
15614 } else {
15615 genFun.__proto__ = GeneratorFunctionPrototype;
15616 define(genFun, toStringTagSymbol, "GeneratorFunction");
15617 }
15618
15619 genFun.prototype = Object.create(Gp);
15620 return genFun;
15621 }; // Within the body of any async function, `await x` is transformed to
15622 // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
15623 // `hasOwn.call(value, "__await")` to determine if the yielded value is
15624 // meant to be awaited.
15625
15626
15627 exports.awrap = function (arg) {
15628 return {
15629 __await: arg
15630 };
15631 };
15632
15633 function AsyncIterator(generator, PromiseImpl) {
15634 function invoke(method, arg, resolve, reject) {
15635 var record = tryCatch(generator[method], generator, arg);
15636
15637 if (record.type === "throw") {
15638 reject(record.arg);
15639 } else {
15640 var result = record.arg;
15641 var value = result.value;
15642
15643 if (value && typeof value === "object" && hasOwn.call(value, "__await")) {
15644 return PromiseImpl.resolve(value.__await).then(function (value) {
15645 invoke("next", value, resolve, reject);
15646 }, function (err) {
15647 invoke("throw", err, resolve, reject);
15648 });
15649 }
15650
15651 return PromiseImpl.resolve(value).then(function (unwrapped) {
15652 // When a yielded Promise is resolved, its final value becomes
15653 // the .value of the Promise<{value,done}> result for the
15654 // current iteration.
15655 result.value = unwrapped;
15656 resolve(result);
15657 }, function (error) {
15658 // If a rejected Promise was yielded, throw the rejection back
15659 // into the async generator function so it can be handled there.
15660 return invoke("throw", error, resolve, reject);
15661 });
15662 }
15663 }
15664
15665 var previousPromise;
15666
15667 function enqueue(method, arg) {
15668 function callInvokeWithMethodAndArg() {
15669 return new PromiseImpl(function (resolve, reject) {
15670 invoke(method, arg, resolve, reject);
15671 });
15672 }
15673
15674 return previousPromise = // If enqueue has been called before, then we want to wait until
15675 // all previous Promises have been resolved before calling invoke,
15676 // so that results are always delivered in the correct order. If
15677 // enqueue has not been called before, then it is important to
15678 // call invoke immediately, without waiting on a callback to fire,
15679 // so that the async generator function has the opportunity to do
15680 // any necessary setup in a predictable way. This predictability
15681 // is why the Promise constructor synchronously invokes its
15682 // executor callback, and why async functions synchronously
15683 // execute code before the first await. Since we implement simple
15684 // async functions in terms of async generators, it is especially
15685 // important to get this right, even though it requires care.
15686 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
15687 // invocations of the iterator.
15688 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
15689 } // Define the unified helper method that is used to implement .next,
15690 // .throw, and .return (see defineIteratorMethods).
15691
15692
15693 this._invoke = enqueue;
15694 }
15695
15696 defineIteratorMethods(AsyncIterator.prototype);
15697 define(AsyncIterator.prototype, asyncIteratorSymbol, function () {
15698 return this;
15699 });
15700 exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
15701 // AsyncIterator objects; they just return a Promise for the value of
15702 // the final result produced by the iterator.
15703
15704 exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
15705 if (PromiseImpl === void 0) PromiseImpl = Promise;
15706 var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
15707 return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
15708 : iter.next().then(function (result) {
15709 return result.done ? result.value : iter.next();
15710 });
15711 };
15712
15713 function makeInvokeMethod(innerFn, self, context) {
15714 var state = GenStateSuspendedStart;
15715 return function invoke(method, arg) {
15716 if (state === GenStateExecuting) {
15717 throw new Error("Generator is already running");
15718 }
15719
15720 if (state === GenStateCompleted) {
15721 if (method === "throw") {
15722 throw arg;
15723 } // Be forgiving, per 25.3.3.3.3 of the spec:
15724 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
15725
15726
15727 return doneResult();
15728 }
15729
15730 context.method = method;
15731 context.arg = arg;
15732
15733 while (true) {
15734 var delegate = context.delegate;
15735
15736 if (delegate) {
15737 var delegateResult = maybeInvokeDelegate(delegate, context);
15738
15739 if (delegateResult) {
15740 if (delegateResult === ContinueSentinel) continue;
15741 return delegateResult;
15742 }
15743 }
15744
15745 if (context.method === "next") {
15746 // Setting context._sent for legacy support of Babel's
15747 // function.sent implementation.
15748 context.sent = context._sent = context.arg;
15749 } else if (context.method === "throw") {
15750 if (state === GenStateSuspendedStart) {
15751 state = GenStateCompleted;
15752 throw context.arg;
15753 }
15754
15755 context.dispatchException(context.arg);
15756 } else if (context.method === "return") {
15757 context.abrupt("return", context.arg);
15758 }
15759
15760 state = GenStateExecuting;
15761 var record = tryCatch(innerFn, self, context);
15762
15763 if (record.type === "normal") {
15764 // If an exception is thrown from innerFn, we leave state ===
15765 // GenStateExecuting and loop back for another invocation.
15766 state = context.done ? GenStateCompleted : GenStateSuspendedYield;
15767
15768 if (record.arg === ContinueSentinel) {
15769 continue;
15770 }
15771
15772 return {
15773 value: record.arg,
15774 done: context.done
15775 };
15776 } else if (record.type === "throw") {
15777 state = GenStateCompleted; // Dispatch the exception by looping back around to the
15778 // context.dispatchException(context.arg) call above.
15779
15780 context.method = "throw";
15781 context.arg = record.arg;
15782 }
15783 }
15784 };
15785 } // Call delegate.iterator[context.method](context.arg) and handle the
15786 // result, either by returning a { value, done } result from the
15787 // delegate iterator, or by modifying context.method and context.arg,
15788 // setting context.delegate to null, and returning the ContinueSentinel.
15789
15790
15791 function maybeInvokeDelegate(delegate, context) {
15792 var method = delegate.iterator[context.method];
15793
15794 if (method === undefined$1) {
15795 // A .throw or .return when the delegate iterator has no .throw
15796 // method always terminates the yield* loop.
15797 context.delegate = null;
15798
15799 if (context.method === "throw") {
15800 // Note: ["return"] must be used for ES3 parsing compatibility.
15801 if (delegate.iterator["return"]) {
15802 // If the delegate iterator has a return method, give it a
15803 // chance to clean up.
15804 context.method = "return";
15805 context.arg = undefined$1;
15806 maybeInvokeDelegate(delegate, context);
15807
15808 if (context.method === "throw") {
15809 // If maybeInvokeDelegate(context) changed context.method from
15810 // "return" to "throw", let that override the TypeError below.
15811 return ContinueSentinel;
15812 }
15813 }
15814
15815 context.method = "throw";
15816 context.arg = new TypeError("The iterator does not provide a 'throw' method");
15817 }
15818
15819 return ContinueSentinel;
15820 }
15821
15822 var record = tryCatch(method, delegate.iterator, context.arg);
15823
15824 if (record.type === "throw") {
15825 context.method = "throw";
15826 context.arg = record.arg;
15827 context.delegate = null;
15828 return ContinueSentinel;
15829 }
15830
15831 var info = record.arg;
15832
15833 if (!info) {
15834 context.method = "throw";
15835 context.arg = new TypeError("iterator result is not an object");
15836 context.delegate = null;
15837 return ContinueSentinel;
15838 }
15839
15840 if (info.done) {
15841 // Assign the result of the finished delegate to the temporary
15842 // variable specified by delegate.resultName (see delegateYield).
15843 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
15844
15845 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
15846 // exception, let the outer generator proceed normally. If
15847 // context.method was "next", forget context.arg since it has been
15848 // "consumed" by the delegate iterator. If context.method was
15849 // "return", allow the original .return call to continue in the
15850 // outer generator.
15851
15852 if (context.method !== "return") {
15853 context.method = "next";
15854 context.arg = undefined$1;
15855 }
15856 } else {
15857 // Re-yield the result returned by the delegate method.
15858 return info;
15859 } // The delegate iterator is finished, so forget it and continue with
15860 // the outer generator.
15861
15862
15863 context.delegate = null;
15864 return ContinueSentinel;
15865 } // Define Generator.prototype.{next,throw,return} in terms of the
15866 // unified ._invoke helper method.
15867
15868
15869 defineIteratorMethods(Gp);
15870 define(Gp, toStringTagSymbol, "Generator"); // A Generator should always return itself as the iterator object when the
15871 // @@iterator function is called on it. Some browsers' implementations of the
15872 // iterator prototype chain incorrectly implement this, causing the Generator
15873 // object to not be returned from this call. This ensures that doesn't happen.
15874 // See https://github.com/facebook/regenerator/issues/274 for more details.
15875
15876 define(Gp, iteratorSymbol, function () {
15877 return this;
15878 });
15879 define(Gp, "toString", function () {
15880 return "[object Generator]";
15881 });
15882
15883 function pushTryEntry(locs) {
15884 var entry = {
15885 tryLoc: locs[0]
15886 };
15887
15888 if (1 in locs) {
15889 entry.catchLoc = locs[1];
15890 }
15891
15892 if (2 in locs) {
15893 entry.finallyLoc = locs[2];
15894 entry.afterLoc = locs[3];
15895 }
15896
15897 this.tryEntries.push(entry);
15898 }
15899
15900 function resetTryEntry(entry) {
15901 var record = entry.completion || {};
15902 record.type = "normal";
15903 delete record.arg;
15904 entry.completion = record;
15905 }
15906
15907 function Context(tryLocsList) {
15908 // The root entry object (effectively a try statement without a catch
15909 // or a finally block) gives us a place to store values thrown from
15910 // locations where there is no enclosing try statement.
15911 this.tryEntries = [{
15912 tryLoc: "root"
15913 }];
15914 tryLocsList.forEach(pushTryEntry, this);
15915 this.reset(true);
15916 }
15917
15918 exports.keys = function (object) {
15919 var keys = [];
15920
15921 for (var key in object) {
15922 keys.push(key);
15923 }
15924
15925 keys.reverse(); // Rather than returning an object with a next method, we keep
15926 // things simple and return the next function itself.
15927
15928 return function next() {
15929 while (keys.length) {
15930 var key = keys.pop();
15931
15932 if (key in object) {
15933 next.value = key;
15934 next.done = false;
15935 return next;
15936 }
15937 } // To avoid creating an additional object, we just hang the .value
15938 // and .done properties off the next function object itself. This
15939 // also ensures that the minifier will not anonymize the function.
15940
15941
15942 next.done = true;
15943 return next;
15944 };
15945 };
15946
15947 function values(iterable) {
15948 if (iterable) {
15949 var iteratorMethod = iterable[iteratorSymbol];
15950
15951 if (iteratorMethod) {
15952 return iteratorMethod.call(iterable);
15953 }
15954
15955 if (typeof iterable.next === "function") {
15956 return iterable;
15957 }
15958
15959 if (!isNaN(iterable.length)) {
15960 var i = -1,
15961 next = function next() {
15962 while (++i < iterable.length) {
15963 if (hasOwn.call(iterable, i)) {
15964 next.value = iterable[i];
15965 next.done = false;
15966 return next;
15967 }
15968 }
15969
15970 next.value = undefined$1;
15971 next.done = true;
15972 return next;
15973 };
15974
15975 return next.next = next;
15976 }
15977 } // Return an iterator with no values.
15978
15979
15980 return {
15981 next: doneResult
15982 };
15983 }
15984
15985 exports.values = values;
15986
15987 function doneResult() {
15988 return {
15989 value: undefined$1,
15990 done: true
15991 };
15992 }
15993
15994 Context.prototype = {
15995 constructor: Context,
15996 reset: function (skipTempReset) {
15997 this.prev = 0;
15998 this.next = 0; // Resetting context._sent for legacy support of Babel's
15999 // function.sent implementation.
16000
16001 this.sent = this._sent = undefined$1;
16002 this.done = false;
16003 this.delegate = null;
16004 this.method = "next";
16005 this.arg = undefined$1;
16006 this.tryEntries.forEach(resetTryEntry);
16007
16008 if (!skipTempReset) {
16009 for (var name in this) {
16010 // Not sure about the optimal order of these conditions:
16011 if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
16012 this[name] = undefined$1;
16013 }
16014 }
16015 }
16016 },
16017 stop: function () {
16018 this.done = true;
16019 var rootEntry = this.tryEntries[0];
16020 var rootRecord = rootEntry.completion;
16021
16022 if (rootRecord.type === "throw") {
16023 throw rootRecord.arg;
16024 }
16025
16026 return this.rval;
16027 },
16028 dispatchException: function (exception) {
16029 if (this.done) {
16030 throw exception;
16031 }
16032
16033 var context = this;
16034
16035 function handle(loc, caught) {
16036 record.type = "throw";
16037 record.arg = exception;
16038 context.next = loc;
16039
16040 if (caught) {
16041 // If the dispatched exception was caught by a catch block,
16042 // then let that catch block handle the exception normally.
16043 context.method = "next";
16044 context.arg = undefined$1;
16045 }
16046
16047 return !!caught;
16048 }
16049
16050 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
16051 var entry = this.tryEntries[i];
16052 var record = entry.completion;
16053
16054 if (entry.tryLoc === "root") {
16055 // Exception thrown outside of any try block that could handle
16056 // it, so set the completion value of the entire function to
16057 // throw the exception.
16058 return handle("end");
16059 }
16060
16061 if (entry.tryLoc <= this.prev) {
16062 var hasCatch = hasOwn.call(entry, "catchLoc");
16063 var hasFinally = hasOwn.call(entry, "finallyLoc");
16064
16065 if (hasCatch && hasFinally) {
16066 if (this.prev < entry.catchLoc) {
16067 return handle(entry.catchLoc, true);
16068 } else if (this.prev < entry.finallyLoc) {
16069 return handle(entry.finallyLoc);
16070 }
16071 } else if (hasCatch) {
16072 if (this.prev < entry.catchLoc) {
16073 return handle(entry.catchLoc, true);
16074 }
16075 } else if (hasFinally) {
16076 if (this.prev < entry.finallyLoc) {
16077 return handle(entry.finallyLoc);
16078 }
16079 } else {
16080 throw new Error("try statement without catch or finally");
16081 }
16082 }
16083 }
16084 },
16085 abrupt: function (type, arg) {
16086 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
16087 var entry = this.tryEntries[i];
16088
16089 if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
16090 var finallyEntry = entry;
16091 break;
16092 }
16093 }
16094
16095 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
16096 // Ignore the finally entry if control is not jumping to a
16097 // location outside the try/catch block.
16098 finallyEntry = null;
16099 }
16100
16101 var record = finallyEntry ? finallyEntry.completion : {};
16102 record.type = type;
16103 record.arg = arg;
16104
16105 if (finallyEntry) {
16106 this.method = "next";
16107 this.next = finallyEntry.finallyLoc;
16108 return ContinueSentinel;
16109 }
16110
16111 return this.complete(record);
16112 },
16113 complete: function (record, afterLoc) {
16114 if (record.type === "throw") {
16115 throw record.arg;
16116 }
16117
16118 if (record.type === "break" || record.type === "continue") {
16119 this.next = record.arg;
16120 } else if (record.type === "return") {
16121 this.rval = this.arg = record.arg;
16122 this.method = "return";
16123 this.next = "end";
16124 } else if (record.type === "normal" && afterLoc) {
16125 this.next = afterLoc;
16126 }
16127
16128 return ContinueSentinel;
16129 },
16130 finish: function (finallyLoc) {
16131 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
16132 var entry = this.tryEntries[i];
16133
16134 if (entry.finallyLoc === finallyLoc) {
16135 this.complete(entry.completion, entry.afterLoc);
16136 resetTryEntry(entry);
16137 return ContinueSentinel;
16138 }
16139 }
16140 },
16141 "catch": function (tryLoc) {
16142 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
16143 var entry = this.tryEntries[i];
16144
16145 if (entry.tryLoc === tryLoc) {
16146 var record = entry.completion;
16147
16148 if (record.type === "throw") {
16149 var thrown = record.arg;
16150 resetTryEntry(entry);
16151 }
16152
16153 return thrown;
16154 }
16155 } // The context.catch method must only be called with a location
16156 // argument that corresponds to a known catch block.
16157
16158
16159 throw new Error("illegal catch attempt");
16160 },
16161 delegateYield: function (iterable, resultName, nextLoc) {
16162 this.delegate = {
16163 iterator: values(iterable),
16164 resultName: resultName,
16165 nextLoc: nextLoc
16166 };
16167
16168 if (this.method === "next") {
16169 // Deliberately forget the last sent value so that we don't
16170 // accidentally pass it on to the delegate.
16171 this.arg = undefined$1;
16172 }
16173
16174 return ContinueSentinel;
16175 }
16176 }; // Regardless of whether this script is executing as a CommonJS module
16177 // or not, return the runtime object so that we can declare the variable
16178 // regeneratorRuntime in the outer scope, which allows this module to be
16179 // injected easily by `bin/regenerator --include-runtime script.js`.
16180
16181 return exports;
16182 }( // If this script is executing as a CommonJS module, use module.exports
16183 // as the regeneratorRuntime namespace. Otherwise create a new empty
16184 // object. Either way, the resulting object will be used to initialize
16185 // the regeneratorRuntime variable at the top of this file.
16186 module.exports );
16187
16188 try {
16189 regeneratorRuntime = runtime;
16190 } catch (accidentalStrictMode) {
16191 // This module should not be running in strict mode, so the above
16192 // assignment should always work unless something is misconfigured. Just
16193 // in case runtime.js accidentally runs in strict mode, in modern engines
16194 // we can explicitly access globalThis. In older engines we can escape
16195 // strict mode using a global Function call. This could conceivably fail
16196 // if a Content Security Policy forbids using Function, but in that case
16197 // the proper solution is to fix the accidental strict mode problem. If
16198 // you've misconfigured your bundler to force strict mode and applied a
16199 // CSP to forbid Function, and you're not willing to fix either of those
16200 // problems, please detail your unique predicament in a GitHub issue.
16201 if (typeof globalThis === "object") {
16202 globalThis.regeneratorRuntime = runtime;
16203 } else {
16204 Function("r", "regeneratorRuntime = r")(runtime);
16205 }
16206 }
16207 })(runtime);
16208
16209 var regenerator = runtime.exports;
16210
16211 var global$5 = global$P;
16212 var aCallable$2 = aCallable$7;
16213 var toObject$2 = toObject$e;
16214 var IndexedObject = indexedObject;
16215 var lengthOfArrayLike$3 = lengthOfArrayLike$d;
16216 var TypeError$2 = global$5.TypeError; // `Array.prototype.{ reduce, reduceRight }` methods implementation
16217
16218 var createMethod = function (IS_RIGHT) {
16219 return function (that, callbackfn, argumentsLength, memo) {
16220 aCallable$2(callbackfn);
16221 var O = toObject$2(that);
16222 var self = IndexedObject(O);
16223 var length = lengthOfArrayLike$3(O);
16224 var index = IS_RIGHT ? length - 1 : 0;
16225 var i = IS_RIGHT ? -1 : 1;
16226 if (argumentsLength < 2) while (true) {
16227 if (index in self) {
16228 memo = self[index];
16229 index += i;
16230 break;
16231 }
16232
16233 index += i;
16234
16235 if (IS_RIGHT ? index < 0 : length <= index) {
16236 throw TypeError$2('Reduce of empty array with no initial value');
16237 }
16238 }
16239
16240 for (; IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
16241 memo = callbackfn(memo, self[index], index, O);
16242 }
16243
16244 return memo;
16245 };
16246 };
16247
16248 var arrayReduce = {
16249 // `Array.prototype.reduce` method
16250 // https://tc39.es/ecma262/#sec-array.prototype.reduce
16251 left: createMethod(false),
16252 // `Array.prototype.reduceRight` method
16253 // https://tc39.es/ecma262/#sec-array.prototype.reduceright
16254 right: createMethod(true)
16255 };
16256
16257 var classof$3 = classofRaw$1;
16258 var global$4 = global$P;
16259 var engineIsNode = classof$3(global$4.process) == 'process';
16260
16261 var $$7 = _export;
16262 var $reduce = arrayReduce.left;
16263 var arrayMethodIsStrict$2 = arrayMethodIsStrict$6;
16264 var CHROME_VERSION = engineV8Version;
16265 var IS_NODE = engineIsNode;
16266 var STRICT_METHOD$2 = arrayMethodIsStrict$2('reduce'); // Chrome 80-82 has a critical bug
16267 // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
16268
16269 var CHROME_BUG = !IS_NODE && CHROME_VERSION > 79 && CHROME_VERSION < 83; // `Array.prototype.reduce` method
16270 // https://tc39.es/ecma262/#sec-array.prototype.reduce
16271
16272 $$7({
16273 target: 'Array',
16274 proto: true,
16275 forced: !STRICT_METHOD$2 || CHROME_BUG
16276 }, {
16277 reduce: function reduce(callbackfn
16278 /* , initialValue */
16279 ) {
16280 var length = arguments.length;
16281 return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : undefined);
16282 }
16283 });
16284
16285 var entryVirtual$6 = entryVirtual$l;
16286 var reduce$3 = entryVirtual$6('Array').reduce;
16287
16288 var isPrototypeOf$6 = objectIsPrototypeOf;
16289 var method$6 = reduce$3;
16290 var ArrayPrototype$6 = Array.prototype;
16291
16292 var reduce$2 = function (it) {
16293 var own = it.reduce;
16294 return it === ArrayPrototype$6 || isPrototypeOf$6(ArrayPrototype$6, it) && own === ArrayPrototype$6.reduce ? method$6 : own;
16295 };
16296
16297 var parent$j = reduce$2;
16298 var reduce$1 = parent$j;
16299
16300 var reduce = reduce$1;
16301
16302 var global$3 = global$P;
16303 var isArray = isArray$d;
16304 var lengthOfArrayLike$2 = lengthOfArrayLike$d;
16305 var bind = functionBindContext;
16306 var TypeError$1 = global$3.TypeError; // `FlattenIntoArray` abstract operation
16307 // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
16308
16309 var flattenIntoArray$1 = function (target, original, source, sourceLen, start, depth, mapper, thisArg) {
16310 var targetIndex = start;
16311 var sourceIndex = 0;
16312 var mapFn = mapper ? bind(mapper, thisArg) : false;
16313 var element, elementLen;
16314
16315 while (sourceIndex < sourceLen) {
16316 if (sourceIndex in source) {
16317 element = mapFn ? mapFn(source[sourceIndex], sourceIndex, original) : source[sourceIndex];
16318
16319 if (depth > 0 && isArray(element)) {
16320 elementLen = lengthOfArrayLike$2(element);
16321 targetIndex = flattenIntoArray$1(target, original, element, elementLen, targetIndex, depth - 1) - 1;
16322 } else {
16323 if (targetIndex >= 0x1FFFFFFFFFFFFF) throw TypeError$1('Exceed the acceptable array length');
16324 target[targetIndex] = element;
16325 }
16326
16327 targetIndex++;
16328 }
16329
16330 sourceIndex++;
16331 }
16332
16333 return targetIndex;
16334 };
16335
16336 var flattenIntoArray_1 = flattenIntoArray$1;
16337
16338 var $$6 = _export;
16339 var flattenIntoArray = flattenIntoArray_1;
16340 var aCallable$1 = aCallable$7;
16341 var toObject$1 = toObject$e;
16342 var lengthOfArrayLike$1 = lengthOfArrayLike$d;
16343 var arraySpeciesCreate = arraySpeciesCreate$4; // `Array.prototype.flatMap` method
16344 // https://tc39.es/ecma262/#sec-array.prototype.flatmap
16345
16346 $$6({
16347 target: 'Array',
16348 proto: true
16349 }, {
16350 flatMap: function flatMap(callbackfn
16351 /* , thisArg */
16352 ) {
16353 var O = toObject$1(this);
16354 var sourceLen = lengthOfArrayLike$1(O);
16355 var A;
16356 aCallable$1(callbackfn);
16357 A = arraySpeciesCreate(O, 0);
16358 A.length = flattenIntoArray(A, O, O, sourceLen, 0, 1, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
16359 return A;
16360 }
16361 });
16362
16363 var entryVirtual$5 = entryVirtual$l;
16364 var flatMap$3 = entryVirtual$5('Array').flatMap;
16365
16366 var isPrototypeOf$5 = objectIsPrototypeOf;
16367 var method$5 = flatMap$3;
16368 var ArrayPrototype$5 = Array.prototype;
16369
16370 var flatMap$2 = function (it) {
16371 var own = it.flatMap;
16372 return it === ArrayPrototype$5 || isPrototypeOf$5(ArrayPrototype$5, it) && own === ArrayPrototype$5.flatMap ? method$5 : own;
16373 };
16374
16375 var parent$i = flatMap$2;
16376 var flatMap$1 = parent$i;
16377
16378 var flatMap = flatMap$1;
16379
16380 var collection$1 = collection$3;
16381 var collectionStrong = collectionStrong$2; // `Set` constructor
16382 // https://tc39.es/ecma262/#sec-set-objects
16383
16384 collection$1('Set', function (init) {
16385 return function Set() {
16386 return init(this, arguments.length ? arguments[0] : undefined);
16387 };
16388 }, collectionStrong);
16389
16390 var path$6 = path$y;
16391 var set$2 = path$6.Set;
16392
16393 var parent$h = set$2;
16394 var set$1 = parent$h;
16395
16396 var set = set$1;
16397
16398 var iterator = iterator$4;
16399
16400 var getIterator$4 = getIterator$7;
16401 var getIterator_1 = getIterator$4;
16402
16403 var parent$g = getIterator_1;
16404 var getIterator$3 = parent$g;
16405
16406 var parent$f = getIterator$3;
16407 var getIterator$2 = parent$f;
16408
16409 var parent$e = getIterator$2;
16410 var getIterator$1 = parent$e;
16411
16412 var getIterator = getIterator$1;
16413
16414 var arraySlice = arraySliceSimple;
16415 var floor = Math.floor;
16416
16417 var mergeSort = function (array, comparefn) {
16418 var length = array.length;
16419 var middle = floor(length / 2);
16420 return length < 8 ? insertionSort(array, comparefn) : merge(array, mergeSort(arraySlice(array, 0, middle), comparefn), mergeSort(arraySlice(array, middle), comparefn), comparefn);
16421 };
16422
16423 var insertionSort = function (array, comparefn) {
16424 var length = array.length;
16425 var i = 1;
16426 var element, j;
16427
16428 while (i < length) {
16429 j = i;
16430 element = array[i];
16431
16432 while (j && comparefn(array[j - 1], element) > 0) {
16433 array[j] = array[--j];
16434 }
16435
16436 if (j !== i++) array[j] = element;
16437 }
16438
16439 return array;
16440 };
16441
16442 var merge = function (array, left, right, comparefn) {
16443 var llength = left.length;
16444 var rlength = right.length;
16445 var lindex = 0;
16446 var rindex = 0;
16447
16448 while (lindex < llength || rindex < rlength) {
16449 array[lindex + rindex] = lindex < llength && rindex < rlength ? comparefn(left[lindex], right[rindex]) <= 0 ? left[lindex++] : right[rindex++] : lindex < llength ? left[lindex++] : right[rindex++];
16450 }
16451
16452 return array;
16453 };
16454
16455 var arraySort = mergeSort;
16456
16457 var userAgent$1 = engineUserAgent;
16458 var firefox = userAgent$1.match(/firefox\/(\d+)/i);
16459 var engineFfVersion = !!firefox && +firefox[1];
16460
16461 var UA = engineUserAgent;
16462 var engineIsIeOrEdge = /MSIE|Trident/.test(UA);
16463
16464 var userAgent = engineUserAgent;
16465 var webkit = userAgent.match(/AppleWebKit\/(\d+)\./);
16466 var engineWebkitVersion = !!webkit && +webkit[1];
16467
16468 var $$5 = _export;
16469 var uncurryThis$3 = functionUncurryThis;
16470 var aCallable = aCallable$7;
16471 var toObject = toObject$e;
16472 var lengthOfArrayLike = lengthOfArrayLike$d;
16473 var toString$1 = toString$8;
16474 var fails$2 = fails$t;
16475 var internalSort = arraySort;
16476 var arrayMethodIsStrict$1 = arrayMethodIsStrict$6;
16477 var FF = engineFfVersion;
16478 var IE_OR_EDGE = engineIsIeOrEdge;
16479 var V8 = engineV8Version;
16480 var WEBKIT = engineWebkitVersion;
16481 var test = [];
16482 var un$Sort = uncurryThis$3(test.sort);
16483 var push = uncurryThis$3(test.push); // IE8-
16484
16485 var FAILS_ON_UNDEFINED = fails$2(function () {
16486 test.sort(undefined);
16487 }); // V8 bug
16488
16489 var FAILS_ON_NULL = fails$2(function () {
16490 test.sort(null);
16491 }); // Old WebKit
16492
16493 var STRICT_METHOD$1 = arrayMethodIsStrict$1('sort');
16494 var STABLE_SORT = !fails$2(function () {
16495 // feature detection can be too slow, so check engines versions
16496 if (V8) return V8 < 70;
16497 if (FF && FF > 3) return;
16498 if (IE_OR_EDGE) return true;
16499 if (WEBKIT) return WEBKIT < 603;
16500 var result = '';
16501 var code, chr, value, index; // generate an array with more 512 elements (Chakra and old V8 fails only in this case)
16502
16503 for (code = 65; code < 76; code++) {
16504 chr = String.fromCharCode(code);
16505
16506 switch (code) {
16507 case 66:
16508 case 69:
16509 case 70:
16510 case 72:
16511 value = 3;
16512 break;
16513
16514 case 68:
16515 case 71:
16516 value = 4;
16517 break;
16518
16519 default:
16520 value = 2;
16521 }
16522
16523 for (index = 0; index < 47; index++) {
16524 test.push({
16525 k: chr + index,
16526 v: value
16527 });
16528 }
16529 }
16530
16531 test.sort(function (a, b) {
16532 return b.v - a.v;
16533 });
16534
16535 for (index = 0; index < test.length; index++) {
16536 chr = test[index].k.charAt(0);
16537 if (result.charAt(result.length - 1) !== chr) result += chr;
16538 }
16539
16540 return result !== 'DGBEFHACIJK';
16541 });
16542 var FORCED$1 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$1 || !STABLE_SORT;
16543
16544 var getSortCompare = function (comparefn) {
16545 return function (x, y) {
16546 if (y === undefined) return -1;
16547 if (x === undefined) return 1;
16548 if (comparefn !== undefined) return +comparefn(x, y) || 0;
16549 return toString$1(x) > toString$1(y) ? 1 : -1;
16550 };
16551 }; // `Array.prototype.sort` method
16552 // https://tc39.es/ecma262/#sec-array.prototype.sort
16553
16554
16555 $$5({
16556 target: 'Array',
16557 proto: true,
16558 forced: FORCED$1
16559 }, {
16560 sort: function sort(comparefn) {
16561 if (comparefn !== undefined) aCallable(comparefn);
16562 var array = toObject(this);
16563 if (STABLE_SORT) return comparefn === undefined ? un$Sort(array) : un$Sort(array, comparefn);
16564 var items = [];
16565 var arrayLength = lengthOfArrayLike(array);
16566 var itemsLength, index;
16567
16568 for (index = 0; index < arrayLength; index++) {
16569 if (index in array) push(items, array[index]);
16570 }
16571
16572 internalSort(items, getSortCompare(comparefn));
16573 itemsLength = items.length;
16574 index = 0;
16575
16576 while (index < itemsLength) array[index] = items[index++];
16577
16578 while (index < arrayLength) delete array[index++];
16579
16580 return array;
16581 }
16582 });
16583
16584 var entryVirtual$4 = entryVirtual$l;
16585 var sort$3 = entryVirtual$4('Array').sort;
16586
16587 var isPrototypeOf$4 = objectIsPrototypeOf;
16588 var method$4 = sort$3;
16589 var ArrayPrototype$4 = Array.prototype;
16590
16591 var sort$2 = function (it) {
16592 var own = it.sort;
16593 return it === ArrayPrototype$4 || isPrototypeOf$4(ArrayPrototype$4, it) && own === ArrayPrototype$4.sort ? method$4 : own;
16594 };
16595
16596 var parent$d = sort$2;
16597 var sort$1 = parent$d;
16598
16599 var sort = sort$1;
16600
16601 var entryVirtual$3 = entryVirtual$l;
16602 var keys$3 = entryVirtual$3('Array').keys;
16603
16604 var parent$c = keys$3;
16605 var keys$2 = parent$c;
16606
16607 var classof$2 = classof$e;
16608 var hasOwn$4 = hasOwnProperty_1;
16609 var isPrototypeOf$3 = objectIsPrototypeOf;
16610 var method$3 = keys$2;
16611 var ArrayPrototype$3 = Array.prototype;
16612 var DOMIterables$2 = {
16613 DOMTokenList: true,
16614 NodeList: true
16615 };
16616
16617 var keys$1 = function (it) {
16618 var own = it.keys;
16619 return it === ArrayPrototype$3 || isPrototypeOf$3(ArrayPrototype$3, it) && own === ArrayPrototype$3.keys || hasOwn$4(DOMIterables$2, classof$2(it)) ? method$3 : own;
16620 };
16621
16622 var keys = keys$1;
16623
16624 var entryVirtual$2 = entryVirtual$l;
16625 var values$3 = entryVirtual$2('Array').values;
16626
16627 var parent$b = values$3;
16628 var values$2 = parent$b;
16629
16630 var classof$1 = classof$e;
16631 var hasOwn$3 = hasOwnProperty_1;
16632 var isPrototypeOf$2 = objectIsPrototypeOf;
16633 var method$2 = values$2;
16634 var ArrayPrototype$2 = Array.prototype;
16635 var DOMIterables$1 = {
16636 DOMTokenList: true,
16637 NodeList: true
16638 };
16639
16640 var values$1 = function (it) {
16641 var own = it.values;
16642 return it === ArrayPrototype$2 || isPrototypeOf$2(ArrayPrototype$2, it) && own === ArrayPrototype$2.values || hasOwn$3(DOMIterables$1, classof$1(it)) ? method$2 : own;
16643 };
16644
16645 var values = values$1;
16646
16647 var entryVirtual$1 = entryVirtual$l;
16648 var entries$3 = entryVirtual$1('Array').entries;
16649
16650 var parent$a = entries$3;
16651 var entries$2 = parent$a;
16652
16653 var classof = classof$e;
16654 var hasOwn$2 = hasOwnProperty_1;
16655 var isPrototypeOf$1 = objectIsPrototypeOf;
16656 var method$1 = entries$2;
16657 var ArrayPrototype$1 = Array.prototype;
16658 var DOMIterables = {
16659 DOMTokenList: true,
16660 NodeList: true
16661 };
16662
16663 var entries$1 = function (it) {
16664 var own = it.entries;
16665 return it === ArrayPrototype$1 || isPrototypeOf$1(ArrayPrototype$1, it) && own === ArrayPrototype$1.entries || hasOwn$2(DOMIterables, classof(it)) ? method$1 : own;
16666 };
16667
16668 var entries = entries$1;
16669
16670 // Unique ID creation requires a high quality random # generator. In the browser we therefore
16671 // require the crypto API and do not support built-in fallback to lower quality random number
16672 // generators (like Math.random()).
16673 var getRandomValues;
16674 var rnds8 = new Uint8Array(16);
16675 function rng() {
16676 // lazy load so that environments that need to polyfill have a chance to do so
16677 if (!getRandomValues) {
16678 // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also,
16679 // find the complete implementation of crypto (msCrypto) on IE11.
16680 getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);
16681
16682 if (!getRandomValues) {
16683 throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
16684 }
16685 }
16686
16687 return getRandomValues(rnds8);
16688 }
16689
16690 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;
16691
16692 function validate(uuid) {
16693 return typeof uuid === 'string' && REGEX.test(uuid);
16694 }
16695
16696 /**
16697 * Convert array of 16 byte values to UUID string format of the form:
16698 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
16699 */
16700
16701 var byteToHex = [];
16702
16703 for (var i = 0; i < 256; ++i) {
16704 byteToHex.push((i + 0x100).toString(16).substr(1));
16705 }
16706
16707 function stringify(arr) {
16708 var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; // Note: Be careful editing this code! It's been tuned for performance
16709 // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
16710
16711 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
16712 // of the following:
16713 // - One or more input array values don't map to a hex octet (leading to
16714 // "undefined" in the uuid)
16715 // - Invalid input values for the RFC `version` or `variant` fields
16716
16717 if (!validate(uuid)) {
16718 throw TypeError('Stringified UUID is invalid');
16719 }
16720
16721 return uuid;
16722 }
16723
16724 function v4(options, buf, offset) {
16725 options = options || {};
16726 var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
16727
16728 rnds[6] = rnds[6] & 0x0f | 0x40;
16729 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
16730
16731 if (buf) {
16732 offset = offset || 0;
16733
16734 for (var i = 0; i < 16; ++i) {
16735 buf[offset + i] = rnds[i];
16736 }
16737
16738 return buf;
16739 }
16740
16741 return stringify(rnds);
16742 }
16743
16744 var _Symbol$iterator;
16745
16746 function ownKeys$4(object, enumerableOnly) { var keys = keys$4(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); enumerableOnly && (symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$3(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
16747
16748 function _objectSpread$4(target) { for (var i = 1; i < arguments.length; i++) { var _context32, _context33; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? forEach$2(_context32 = ownKeys$4(Object(source), !0)).call(_context32, function (key) { _defineProperty(target, key, source[key]); }) : getOwnPropertyDescriptors ? defineProperties(target, getOwnPropertyDescriptors(source)) : forEach$2(_context33 = ownKeys$4(Object(source))).call(_context33, function (key) { defineProperty$6(target, key, getOwnPropertyDescriptor$3(source, key)); }); } return target; }
16749
16750 function _createSuper$t(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$t(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
16751
16752 function _isNativeReflectConstruct$t() { if (typeof Reflect === "undefined" || !construct) return false; if (construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
16753
16754 function _createForOfIteratorHelper$7(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$2(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; } } }; }
16755
16756 function _unsupportedIterableToArray$7(o, minLen) { var _context31; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$7(o, minLen); var n = slice(_context31 = Object.prototype.toString.call(o)).call(_context31, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return from$3(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$7(o, minLen); }
16757
16758 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; }
16759 /**
16760 * Create new data pipe.
16761 *
16762 * @param from - The source data set or data view.
16763 * @remarks
16764 * Example usage:
16765 * ```typescript
16766 * interface AppItem {
16767 * whoami: string;
16768 * appData: unknown;
16769 * visData: VisItem;
16770 * }
16771 * interface VisItem {
16772 * id: number;
16773 * label: string;
16774 * color: string;
16775 * x: number;
16776 * y: number;
16777 * }
16778 *
16779 * const ds1 = new DataSet<AppItem, "whoami">([], { fieldId: "whoami" });
16780 * const ds2 = new DataSet<VisItem, "id">();
16781 *
16782 * const pipe = createNewDataPipeFrom(ds1)
16783 * .filter((item): boolean => item.enabled === true)
16784 * .map<VisItem, "id">((item): VisItem => item.visData)
16785 * .to(ds2);
16786 *
16787 * pipe.start();
16788 * ```
16789 * @returns A factory whose methods can be used to configure the pipe.
16790 */
16791
16792 function createNewDataPipeFrom(from) {
16793 return new DataPipeUnderConstruction(from);
16794 }
16795 /**
16796 * Internal implementation of the pipe. This should be accessible only through
16797 * `createNewDataPipeFrom` from the outside.
16798 *
16799 * @typeParam SI - Source item type.
16800 * @typeParam SP - Source item type's id property name.
16801 * @typeParam TI - Target item type.
16802 * @typeParam TP - Target item type's id property name.
16803 */
16804
16805
16806 var SimpleDataPipe = /*#__PURE__*/function () {
16807 /**
16808 * Bound listeners for use with `DataInterface['on' | 'off']`.
16809 */
16810
16811 /**
16812 * Create a new data pipe.
16813 *
16814 * @param _source - The data set or data view that will be observed.
16815 * @param _transformers - An array of transforming functions to be used to
16816 * filter or transform the items in the pipe.
16817 * @param _target - The data set or data view that will receive the items.
16818 */
16819 function SimpleDataPipe(_source, _transformers, _target) {
16820 var _context, _context2, _context3;
16821
16822 _classCallCheck(this, SimpleDataPipe);
16823
16824 _defineProperty(this, "_source", void 0);
16825
16826 _defineProperty(this, "_transformers", void 0);
16827
16828 _defineProperty(this, "_target", void 0);
16829
16830 _defineProperty(this, "_listeners", {
16831 add: bind$6(_context = this._add).call(_context, this),
16832 remove: bind$6(_context2 = this._remove).call(_context2, this),
16833 update: bind$6(_context3 = this._update).call(_context3, this)
16834 });
16835
16836 this._source = _source;
16837 this._transformers = _transformers;
16838 this._target = _target;
16839 }
16840 /** @inheritDoc */
16841
16842
16843 _createClass(SimpleDataPipe, [{
16844 key: "all",
16845 value: function all() {
16846 this._target.update(this._transformItems(this._source.get()));
16847
16848 return this;
16849 }
16850 /** @inheritDoc */
16851
16852 }, {
16853 key: "start",
16854 value: function start() {
16855 this._source.on("add", this._listeners.add);
16856
16857 this._source.on("remove", this._listeners.remove);
16858
16859 this._source.on("update", this._listeners.update);
16860
16861 return this;
16862 }
16863 /** @inheritDoc */
16864
16865 }, {
16866 key: "stop",
16867 value: function stop() {
16868 this._source.off("add", this._listeners.add);
16869
16870 this._source.off("remove", this._listeners.remove);
16871
16872 this._source.off("update", this._listeners.update);
16873
16874 return this;
16875 }
16876 /**
16877 * Apply the transformers to the items.
16878 *
16879 * @param items - The items to be transformed.
16880 * @returns The transformed items.
16881 */
16882
16883 }, {
16884 key: "_transformItems",
16885 value: function _transformItems(items) {
16886 var _context4;
16887
16888 return reduce(_context4 = this._transformers).call(_context4, function (items, transform) {
16889 return transform(items);
16890 }, items);
16891 }
16892 /**
16893 * Handle an add event.
16894 *
16895 * @param _name - Ignored.
16896 * @param payload - The payload containing the ids of the added items.
16897 */
16898
16899 }, {
16900 key: "_add",
16901 value: function _add(_name, payload) {
16902 if (payload == null) {
16903 return;
16904 }
16905
16906 this._target.add(this._transformItems(this._source.get(payload.items)));
16907 }
16908 /**
16909 * Handle an update event.
16910 *
16911 * @param _name - Ignored.
16912 * @param payload - The payload containing the ids of the updated items.
16913 */
16914
16915 }, {
16916 key: "_update",
16917 value: function _update(_name, payload) {
16918 if (payload == null) {
16919 return;
16920 }
16921
16922 this._target.update(this._transformItems(this._source.get(payload.items)));
16923 }
16924 /**
16925 * Handle a remove event.
16926 *
16927 * @param _name - Ignored.
16928 * @param payload - The payload containing the data of the removed items.
16929 */
16930
16931 }, {
16932 key: "_remove",
16933 value: function _remove(_name, payload) {
16934 if (payload == null) {
16935 return;
16936 }
16937
16938 this._target.remove(this._transformItems(payload.oldData));
16939 }
16940 }]);
16941
16942 return SimpleDataPipe;
16943 }();
16944 /**
16945 * Internal implementation of the pipe factory. This should be accessible
16946 * only through `createNewDataPipeFrom` from the outside.
16947 *
16948 * @typeParam TI - Target item type.
16949 * @typeParam TP - Target item type's id property name.
16950 */
16951
16952
16953 var DataPipeUnderConstruction = /*#__PURE__*/function () {
16954 /**
16955 * Array transformers used to transform items within the pipe. This is typed
16956 * as any for the sake of simplicity.
16957 */
16958
16959 /**
16960 * Create a new data pipe factory. This is an internal constructor that
16961 * should never be called from outside of this file.
16962 *
16963 * @param _source - The source data set or data view for this pipe.
16964 */
16965 function DataPipeUnderConstruction(_source) {
16966 _classCallCheck(this, DataPipeUnderConstruction);
16967
16968 _defineProperty(this, "_source", void 0);
16969
16970 _defineProperty(this, "_transformers", []);
16971
16972 this._source = _source;
16973 }
16974 /**
16975 * Filter the items.
16976 *
16977 * @param callback - A filtering function that returns true if given item
16978 * should be piped and false if not.
16979 * @returns This factory for further configuration.
16980 */
16981
16982
16983 _createClass(DataPipeUnderConstruction, [{
16984 key: "filter",
16985 value: function filter$1(callback) {
16986 this._transformers.push(function (input) {
16987 return filter(input).call(input, callback);
16988 });
16989
16990 return this;
16991 }
16992 /**
16993 * Map each source item to a new type.
16994 *
16995 * @param callback - A mapping function that takes a source item and returns
16996 * corresponding mapped item.
16997 * @typeParam TI - Target item type.
16998 * @typeParam TP - Target item type's id property name.
16999 * @returns This factory for further configuration.
17000 */
17001
17002 }, {
17003 key: "map",
17004 value: function map(callback) {
17005 this._transformers.push(function (input) {
17006 return map$3(input).call(input, callback);
17007 });
17008
17009 return this;
17010 }
17011 /**
17012 * Map each source item to zero or more items of a new type.
17013 *
17014 * @param callback - A mapping function that takes a source item and returns
17015 * an array of corresponding mapped items.
17016 * @typeParam TI - Target item type.
17017 * @typeParam TP - Target item type's id property name.
17018 * @returns This factory for further configuration.
17019 */
17020
17021 }, {
17022 key: "flatMap",
17023 value: function flatMap$1(callback) {
17024 this._transformers.push(function (input) {
17025 return flatMap(input).call(input, callback);
17026 });
17027
17028 return this;
17029 }
17030 /**
17031 * Connect this pipe to given data set.
17032 *
17033 * @param target - The data set that will receive the items from this pipe.
17034 * @returns The pipe connected between given data sets and performing
17035 * configured transformation on the processed items.
17036 */
17037
17038 }, {
17039 key: "to",
17040 value: function to(target) {
17041 return new SimpleDataPipe(this._source, this._transformers, target);
17042 }
17043 }]);
17044
17045 return DataPipeUnderConstruction;
17046 }();
17047 /**
17048 * Determine whether a value can be used as an id.
17049 *
17050 * @param value - Input value of unknown type.
17051 * @returns True if the value is valid id, false otherwise.
17052 */
17053
17054
17055 function isId(value) {
17056 return typeof value === "string" || typeof value === "number";
17057 }
17058 /**
17059 * A queue.
17060 *
17061 * @typeParam T - The type of method names to be replaced by queued versions.
17062 */
17063
17064
17065 var Queue = /*#__PURE__*/function () {
17066 /** Delay in milliseconds. If defined the queue will be periodically flushed. */
17067
17068 /** Maximum number of entries in the queue before it will be flushed. */
17069
17070 /**
17071 * Construct a new Queue.
17072 *
17073 * @param options - Queue configuration.
17074 */
17075 function Queue(options) {
17076 _classCallCheck(this, Queue);
17077
17078 _defineProperty(this, "delay", void 0);
17079
17080 _defineProperty(this, "max", void 0);
17081
17082 _defineProperty(this, "_queue", []);
17083
17084 _defineProperty(this, "_timeout", null);
17085
17086 _defineProperty(this, "_extended", null);
17087
17088 // options
17089 this.delay = null;
17090 this.max = Infinity;
17091 this.setOptions(options);
17092 }
17093 /**
17094 * Update the configuration of the queue.
17095 *
17096 * @param options - Queue configuration.
17097 */
17098
17099
17100 _createClass(Queue, [{
17101 key: "setOptions",
17102 value: function setOptions(options) {
17103 if (options && typeof options.delay !== "undefined") {
17104 this.delay = options.delay;
17105 }
17106
17107 if (options && typeof options.max !== "undefined") {
17108 this.max = options.max;
17109 }
17110
17111 this._flushIfNeeded();
17112 }
17113 /**
17114 * Extend an object with queuing functionality.
17115 * The object will be extended with a function flush, and the methods provided in options.replace will be replaced with queued ones.
17116 *
17117 * @param object - The object to be extended.
17118 * @param options - Additional options.
17119 * @returns The created queue.
17120 */
17121
17122 }, {
17123 key: "destroy",
17124 value:
17125 /**
17126 * Destroy the queue. The queue will first flush all queued actions, and in case it has extended an object, will restore the original object.
17127 */
17128 function destroy() {
17129 this.flush();
17130
17131 if (this._extended) {
17132 var object = this._extended.object;
17133 var methods = this._extended.methods;
17134
17135 for (var i = 0; i < methods.length; i++) {
17136 var method = methods[i];
17137
17138 if (method.original) {
17139 // @TODO: better solution?
17140 object[method.name] = method.original;
17141 } else {
17142 // @TODO: better solution?
17143 delete object[method.name];
17144 }
17145 }
17146
17147 this._extended = null;
17148 }
17149 }
17150 /**
17151 * Replace a method on an object with a queued version.
17152 *
17153 * @param object - Object having the method.
17154 * @param method - The method name.
17155 */
17156
17157 }, {
17158 key: "replace",
17159 value: function replace(object, method) {
17160 /* eslint-disable-next-line @typescript-eslint/no-this-alias -- Function this is necessary in the function bellow, so class this has to be saved into a variable here. */
17161 var me = this;
17162 var original = object[method];
17163
17164 if (!original) {
17165 throw new Error("Method " + method + " undefined");
17166 }
17167
17168 object[method] = function () {
17169 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
17170 args[_key] = arguments[_key];
17171 }
17172
17173 // add this call to the queue
17174 me.queue({
17175 args: args,
17176 fn: original,
17177 context: this
17178 });
17179 };
17180 }
17181 /**
17182 * Queue a call.
17183 *
17184 * @param entry - The function or entry to be queued.
17185 */
17186
17187 }, {
17188 key: "queue",
17189 value: function queue(entry) {
17190 if (typeof entry === "function") {
17191 this._queue.push({
17192 fn: entry
17193 });
17194 } else {
17195 this._queue.push(entry);
17196 }
17197
17198 this._flushIfNeeded();
17199 }
17200 /**
17201 * Check whether the queue needs to be flushed.
17202 */
17203
17204 }, {
17205 key: "_flushIfNeeded",
17206 value: function _flushIfNeeded() {
17207 var _this = this;
17208
17209 // flush when the maximum is exceeded.
17210 if (this._queue.length > this.max) {
17211 this.flush();
17212 } // flush after a period of inactivity when a delay is configured
17213
17214
17215 if (this._timeout != null) {
17216 clearTimeout(this._timeout);
17217 this._timeout = null;
17218 }
17219
17220 if (this.queue.length > 0 && typeof this.delay === "number") {
17221 this._timeout = setTimeout$1(function () {
17222 _this.flush();
17223 }, this.delay);
17224 }
17225 }
17226 /**
17227 * Flush all queued calls
17228 */
17229
17230 }, {
17231 key: "flush",
17232 value: function flush() {
17233 var _context5, _context6;
17234
17235 forEach$2(_context5 = splice$1(_context6 = this._queue).call(_context6, 0)).call(_context5, function (entry) {
17236 entry.fn.apply(entry.context || entry.fn, entry.args || []);
17237 });
17238 }
17239 }], [{
17240 key: "extend",
17241 value: function extend(object, options) {
17242 var queue = new Queue(options);
17243
17244 if (object.flush !== undefined) {
17245 throw new Error("Target object already has a property flush");
17246 }
17247
17248 object.flush = function () {
17249 queue.flush();
17250 };
17251
17252 var methods = [{
17253 name: "flush",
17254 original: undefined
17255 }];
17256
17257 if (options && options.replace) {
17258 for (var i = 0; i < options.replace.length; i++) {
17259 var name = options.replace[i];
17260 methods.push({
17261 name: name,
17262 // @TODO: better solution?
17263 original: object[name]
17264 }); // @TODO: better solution?
17265
17266 queue.replace(object, name);
17267 }
17268 }
17269
17270 queue._extended = {
17271 object: object,
17272 methods: methods
17273 };
17274 return queue;
17275 }
17276 }]);
17277
17278 return Queue;
17279 }();
17280 /**
17281 * [[DataSet]] code that can be reused in [[DataView]] or other similar implementations of [[DataInterface]].
17282 *
17283 * @typeParam Item - Item type that may or may not have an id.
17284 * @typeParam IdProp - Name of the property that contains the id.
17285 */
17286
17287
17288 var DataSetPart = /*#__PURE__*/function () {
17289 function DataSetPart() {
17290 _classCallCheck(this, DataSetPart);
17291
17292 _defineProperty(this, "_subscribers", {
17293 "*": [],
17294 add: [],
17295 remove: [],
17296 update: []
17297 });
17298
17299 _defineProperty(this, "subscribe", DataSetPart.prototype.on);
17300
17301 _defineProperty(this, "unsubscribe", DataSetPart.prototype.off);
17302 }
17303
17304 _createClass(DataSetPart, [{
17305 key: "_trigger",
17306 value:
17307 /**
17308 * Trigger an event
17309 *
17310 * @param event - Event name.
17311 * @param payload - Event payload.
17312 * @param senderId - Id of the sender.
17313 */
17314 function _trigger(event, payload, senderId) {
17315 var _context7, _context8;
17316
17317 if (event === "*") {
17318 throw new Error("Cannot trigger event *");
17319 }
17320
17321 forEach$2(_context7 = concat(_context8 = []).call(_context8, _toConsumableArray(this._subscribers[event]), _toConsumableArray(this._subscribers["*"]))).call(_context7, function (subscriber) {
17322 subscriber(event, payload, senderId != null ? senderId : null);
17323 });
17324 }
17325 /**
17326 * Subscribe to an event, add an event listener.
17327 *
17328 * @remarks Non-function callbacks are ignored.
17329 * @param event - Event name.
17330 * @param callback - Callback method.
17331 */
17332
17333 }, {
17334 key: "on",
17335 value: function on(event, callback) {
17336 if (typeof callback === "function") {
17337 this._subscribers[event].push(callback);
17338 } // @TODO: Maybe throw for invalid callbacks?
17339
17340 }
17341 /**
17342 * Unsubscribe from an event, remove an event listener.
17343 *
17344 * @remarks If the same callback was subscribed more than once **all** occurences will be removed.
17345 * @param event - Event name.
17346 * @param callback - Callback method.
17347 */
17348
17349 }, {
17350 key: "off",
17351 value: function off(event, callback) {
17352 var _context9;
17353
17354 this._subscribers[event] = filter(_context9 = this._subscribers[event]).call(_context9, function (subscriber) {
17355 return subscriber !== callback;
17356 });
17357 }
17358 /**
17359 * @deprecated Use on instead (PS: DataView.subscribe === DataView.on).
17360 */
17361
17362 }]);
17363
17364 return DataSetPart;
17365 }();
17366 /**
17367 * Data stream
17368 *
17369 * @remarks
17370 * [[DataStream]] offers an always up to date stream of items from a [[DataSet]] or [[DataView]].
17371 * That means that the stream is evaluated at the time of iteration, conversion to another data type or when [[cache]] is called, not when the [[DataStream]] was created.
17372 * Multiple invocations of for example [[toItemArray]] may yield different results (if the data source like for example [[DataSet]] gets modified).
17373 * @typeParam Item - The item type this stream is going to work with.
17374 */
17375
17376
17377 _Symbol$iterator = iterator;
17378
17379 var DataStream = /*#__PURE__*/function () {
17380 /**
17381 * Create a new data stream.
17382 *
17383 * @param pairs - The id, item pairs.
17384 */
17385 function DataStream(pairs) {
17386 _classCallCheck(this, DataStream);
17387
17388 _defineProperty(this, "_pairs", void 0);
17389
17390 this._pairs = pairs;
17391 }
17392 /**
17393 * Return an iterable of key, value pairs for every entry in the stream.
17394 */
17395
17396
17397 _createClass(DataStream, [{
17398 key: _Symbol$iterator,
17399 value:
17400 /*#__PURE__*/
17401 regenerator.mark(function value() {
17402 var _iterator, _step, _step$value, id, item;
17403
17404 return regenerator.wrap(function value$(_context10) {
17405 while (1) {
17406 switch (_context10.prev = _context10.next) {
17407 case 0:
17408 _iterator = _createForOfIteratorHelper$7(this._pairs);
17409 _context10.prev = 1;
17410
17411 _iterator.s();
17412
17413 case 3:
17414 if ((_step = _iterator.n()).done) {
17415 _context10.next = 9;
17416 break;
17417 }
17418
17419 _step$value = _slicedToArray(_step.value, 2), id = _step$value[0], item = _step$value[1];
17420 _context10.next = 7;
17421 return [id, item];
17422
17423 case 7:
17424 _context10.next = 3;
17425 break;
17426
17427 case 9:
17428 _context10.next = 14;
17429 break;
17430
17431 case 11:
17432 _context10.prev = 11;
17433 _context10.t0 = _context10["catch"](1);
17434
17435 _iterator.e(_context10.t0);
17436
17437 case 14:
17438 _context10.prev = 14;
17439
17440 _iterator.f();
17441
17442 return _context10.finish(14);
17443
17444 case 17:
17445 case "end":
17446 return _context10.stop();
17447 }
17448 }
17449 }, value, this, [[1, 11, 14, 17]]);
17450 })
17451 /**
17452 * Return an iterable of key, value pairs for every entry in the stream.
17453 */
17454
17455 }, {
17456 key: "entries",
17457 value:
17458 /*#__PURE__*/
17459 regenerator.mark(function entries() {
17460 var _iterator2, _step2, _step2$value, id, item;
17461
17462 return regenerator.wrap(function entries$(_context11) {
17463 while (1) {
17464 switch (_context11.prev = _context11.next) {
17465 case 0:
17466 _iterator2 = _createForOfIteratorHelper$7(this._pairs);
17467 _context11.prev = 1;
17468
17469 _iterator2.s();
17470
17471 case 3:
17472 if ((_step2 = _iterator2.n()).done) {
17473 _context11.next = 9;
17474 break;
17475 }
17476
17477 _step2$value = _slicedToArray(_step2.value, 2), id = _step2$value[0], item = _step2$value[1];
17478 _context11.next = 7;
17479 return [id, item];
17480
17481 case 7:
17482 _context11.next = 3;
17483 break;
17484
17485 case 9:
17486 _context11.next = 14;
17487 break;
17488
17489 case 11:
17490 _context11.prev = 11;
17491 _context11.t0 = _context11["catch"](1);
17492
17493 _iterator2.e(_context11.t0);
17494
17495 case 14:
17496 _context11.prev = 14;
17497
17498 _iterator2.f();
17499
17500 return _context11.finish(14);
17501
17502 case 17:
17503 case "end":
17504 return _context11.stop();
17505 }
17506 }
17507 }, entries, this, [[1, 11, 14, 17]]);
17508 })
17509 /**
17510 * Return an iterable of keys in the stream.
17511 */
17512
17513 }, {
17514 key: "keys",
17515 value:
17516 /*#__PURE__*/
17517 regenerator.mark(function keys() {
17518 var _iterator3, _step3, _step3$value, id;
17519
17520 return regenerator.wrap(function keys$(_context12) {
17521 while (1) {
17522 switch (_context12.prev = _context12.next) {
17523 case 0:
17524 _iterator3 = _createForOfIteratorHelper$7(this._pairs);
17525 _context12.prev = 1;
17526
17527 _iterator3.s();
17528
17529 case 3:
17530 if ((_step3 = _iterator3.n()).done) {
17531 _context12.next = 9;
17532 break;
17533 }
17534
17535 _step3$value = _slicedToArray(_step3.value, 1), id = _step3$value[0];
17536 _context12.next = 7;
17537 return id;
17538
17539 case 7:
17540 _context12.next = 3;
17541 break;
17542
17543 case 9:
17544 _context12.next = 14;
17545 break;
17546
17547 case 11:
17548 _context12.prev = 11;
17549 _context12.t0 = _context12["catch"](1);
17550
17551 _iterator3.e(_context12.t0);
17552
17553 case 14:
17554 _context12.prev = 14;
17555
17556 _iterator3.f();
17557
17558 return _context12.finish(14);
17559
17560 case 17:
17561 case "end":
17562 return _context12.stop();
17563 }
17564 }
17565 }, keys, this, [[1, 11, 14, 17]]);
17566 })
17567 /**
17568 * Return an iterable of values in the stream.
17569 */
17570
17571 }, {
17572 key: "values",
17573 value:
17574 /*#__PURE__*/
17575 regenerator.mark(function values() {
17576 var _iterator4, _step4, _step4$value, item;
17577
17578 return regenerator.wrap(function values$(_context13) {
17579 while (1) {
17580 switch (_context13.prev = _context13.next) {
17581 case 0:
17582 _iterator4 = _createForOfIteratorHelper$7(this._pairs);
17583 _context13.prev = 1;
17584
17585 _iterator4.s();
17586
17587 case 3:
17588 if ((_step4 = _iterator4.n()).done) {
17589 _context13.next = 9;
17590 break;
17591 }
17592
17593 _step4$value = _slicedToArray(_step4.value, 2), item = _step4$value[1];
17594 _context13.next = 7;
17595 return item;
17596
17597 case 7:
17598 _context13.next = 3;
17599 break;
17600
17601 case 9:
17602 _context13.next = 14;
17603 break;
17604
17605 case 11:
17606 _context13.prev = 11;
17607 _context13.t0 = _context13["catch"](1);
17608
17609 _iterator4.e(_context13.t0);
17610
17611 case 14:
17612 _context13.prev = 14;
17613
17614 _iterator4.f();
17615
17616 return _context13.finish(14);
17617
17618 case 17:
17619 case "end":
17620 return _context13.stop();
17621 }
17622 }
17623 }, values, this, [[1, 11, 14, 17]]);
17624 })
17625 /**
17626 * Return an array containing all the ids in this stream.
17627 *
17628 * @remarks
17629 * The array may contain duplicities.
17630 * @returns The array with all ids from this stream.
17631 */
17632
17633 }, {
17634 key: "toIdArray",
17635 value: function toIdArray() {
17636 var _context14;
17637
17638 return map$3(_context14 = _toConsumableArray(this._pairs)).call(_context14, function (pair) {
17639 return pair[0];
17640 });
17641 }
17642 /**
17643 * Return an array containing all the items in this stream.
17644 *
17645 * @remarks
17646 * The array may contain duplicities.
17647 * @returns The array with all items from this stream.
17648 */
17649
17650 }, {
17651 key: "toItemArray",
17652 value: function toItemArray() {
17653 var _context15;
17654
17655 return map$3(_context15 = _toConsumableArray(this._pairs)).call(_context15, function (pair) {
17656 return pair[1];
17657 });
17658 }
17659 /**
17660 * Return an array containing all the entries in this stream.
17661 *
17662 * @remarks
17663 * The array may contain duplicities.
17664 * @returns The array with all entries from this stream.
17665 */
17666
17667 }, {
17668 key: "toEntryArray",
17669 value: function toEntryArray() {
17670 return _toConsumableArray(this._pairs);
17671 }
17672 /**
17673 * Return an object map containing all the items in this stream accessible by ids.
17674 *
17675 * @remarks
17676 * In case of duplicate ids (coerced to string so `7 == '7'`) the last encoutered appears in the returned object.
17677 * @returns The object map of all id → item pairs from this stream.
17678 */
17679
17680 }, {
17681 key: "toObjectMap",
17682 value: function toObjectMap() {
17683 var map = create$5(null);
17684
17685 var _iterator5 = _createForOfIteratorHelper$7(this._pairs),
17686 _step5;
17687
17688 try {
17689 for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
17690 var _step5$value = _slicedToArray(_step5.value, 2),
17691 id = _step5$value[0],
17692 item = _step5$value[1];
17693
17694 map[id] = item;
17695 }
17696 } catch (err) {
17697 _iterator5.e(err);
17698 } finally {
17699 _iterator5.f();
17700 }
17701
17702 return map;
17703 }
17704 /**
17705 * Return a map containing all the items in this stream accessible by ids.
17706 *
17707 * @returns The map of all id → item pairs from this stream.
17708 */
17709
17710 }, {
17711 key: "toMap",
17712 value: function toMap() {
17713 return new map(this._pairs);
17714 }
17715 /**
17716 * Return a set containing all the (unique) ids in this stream.
17717 *
17718 * @returns The set of all ids from this stream.
17719 */
17720
17721 }, {
17722 key: "toIdSet",
17723 value: function toIdSet() {
17724 return new set(this.toIdArray());
17725 }
17726 /**
17727 * Return a set containing all the (unique) items in this stream.
17728 *
17729 * @returns The set of all items from this stream.
17730 */
17731
17732 }, {
17733 key: "toItemSet",
17734 value: function toItemSet() {
17735 return new set(this.toItemArray());
17736 }
17737 /**
17738 * Cache the items from this stream.
17739 *
17740 * @remarks
17741 * This method allows for items to be fetched immediatelly and used (possibly multiple times) later.
17742 * It can also be used to optimize performance as [[DataStream]] would otherwise reevaluate everything upon each iteration.
17743 *
17744 * ## Example
17745 * ```javascript
17746 * const ds = new DataSet([…])
17747 *
17748 * const cachedStream = ds.stream()
17749 * .filter(…)
17750 * .sort(…)
17751 * .map(…)
17752 * .cached(…) // Data are fetched, processed and cached here.
17753 *
17754 * ds.clear()
17755 * chachedStream // Still has all the items.
17756 * ```
17757 * @returns A new [[DataStream]] with cached items (detached from the original [[DataSet]]).
17758 */
17759
17760 }, {
17761 key: "cache",
17762 value: function cache() {
17763 return new DataStream(_toConsumableArray(this._pairs));
17764 }
17765 /**
17766 * Get the distinct values of given property.
17767 *
17768 * @param callback - The function that picks and possibly converts the property.
17769 * @typeParam T - The type of the distinct value.
17770 * @returns A set of all distinct properties.
17771 */
17772
17773 }, {
17774 key: "distinct",
17775 value: function distinct(callback) {
17776 var set$1 = new set();
17777
17778 var _iterator6 = _createForOfIteratorHelper$7(this._pairs),
17779 _step6;
17780
17781 try {
17782 for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
17783 var _step6$value = _slicedToArray(_step6.value, 2),
17784 id = _step6$value[0],
17785 item = _step6$value[1];
17786
17787 set$1.add(callback(item, id));
17788 }
17789 } catch (err) {
17790 _iterator6.e(err);
17791 } finally {
17792 _iterator6.f();
17793 }
17794
17795 return set$1;
17796 }
17797 /**
17798 * Filter the items of the stream.
17799 *
17800 * @param callback - The function that decides whether an item will be included.
17801 * @returns A new data stream with the filtered items.
17802 */
17803
17804 }, {
17805 key: "filter",
17806 value: function filter(callback) {
17807 var pairs = this._pairs;
17808 return new DataStream(_defineProperty({}, iterator, /*#__PURE__*/regenerator.mark(function _callee() {
17809 var _iterator7, _step7, _step7$value, id, item;
17810
17811 return regenerator.wrap(function _callee$(_context16) {
17812 while (1) {
17813 switch (_context16.prev = _context16.next) {
17814 case 0:
17815 _iterator7 = _createForOfIteratorHelper$7(pairs);
17816 _context16.prev = 1;
17817
17818 _iterator7.s();
17819
17820 case 3:
17821 if ((_step7 = _iterator7.n()).done) {
17822 _context16.next = 10;
17823 break;
17824 }
17825
17826 _step7$value = _slicedToArray(_step7.value, 2), id = _step7$value[0], item = _step7$value[1];
17827
17828 if (!callback(item, id)) {
17829 _context16.next = 8;
17830 break;
17831 }
17832
17833 _context16.next = 8;
17834 return [id, item];
17835
17836 case 8:
17837 _context16.next = 3;
17838 break;
17839
17840 case 10:
17841 _context16.next = 15;
17842 break;
17843
17844 case 12:
17845 _context16.prev = 12;
17846 _context16.t0 = _context16["catch"](1);
17847
17848 _iterator7.e(_context16.t0);
17849
17850 case 15:
17851 _context16.prev = 15;
17852
17853 _iterator7.f();
17854
17855 return _context16.finish(15);
17856
17857 case 18:
17858 case "end":
17859 return _context16.stop();
17860 }
17861 }
17862 }, _callee, null, [[1, 12, 15, 18]]);
17863 })));
17864 }
17865 /**
17866 * Execute a callback for each item of the stream.
17867 *
17868 * @param callback - The function that will be invoked for each item.
17869 */
17870
17871 }, {
17872 key: "forEach",
17873 value: function forEach(callback) {
17874 var _iterator8 = _createForOfIteratorHelper$7(this._pairs),
17875 _step8;
17876
17877 try {
17878 for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
17879 var _step8$value = _slicedToArray(_step8.value, 2),
17880 id = _step8$value[0],
17881 item = _step8$value[1];
17882
17883 callback(item, id);
17884 }
17885 } catch (err) {
17886 _iterator8.e(err);
17887 } finally {
17888 _iterator8.f();
17889 }
17890 }
17891 /**
17892 * Map the items into a different type.
17893 *
17894 * @param callback - The function that does the conversion.
17895 * @typeParam Mapped - The type of the item after mapping.
17896 * @returns A new data stream with the mapped items.
17897 */
17898
17899 }, {
17900 key: "map",
17901 value: function map(callback) {
17902 var pairs = this._pairs;
17903 return new DataStream(_defineProperty({}, iterator, /*#__PURE__*/regenerator.mark(function _callee2() {
17904 var _iterator9, _step9, _step9$value, id, item;
17905
17906 return regenerator.wrap(function _callee2$(_context17) {
17907 while (1) {
17908 switch (_context17.prev = _context17.next) {
17909 case 0:
17910 _iterator9 = _createForOfIteratorHelper$7(pairs);
17911 _context17.prev = 1;
17912
17913 _iterator9.s();
17914
17915 case 3:
17916 if ((_step9 = _iterator9.n()).done) {
17917 _context17.next = 9;
17918 break;
17919 }
17920
17921 _step9$value = _slicedToArray(_step9.value, 2), id = _step9$value[0], item = _step9$value[1];
17922 _context17.next = 7;
17923 return [id, callback(item, id)];
17924
17925 case 7:
17926 _context17.next = 3;
17927 break;
17928
17929 case 9:
17930 _context17.next = 14;
17931 break;
17932
17933 case 11:
17934 _context17.prev = 11;
17935 _context17.t0 = _context17["catch"](1);
17936
17937 _iterator9.e(_context17.t0);
17938
17939 case 14:
17940 _context17.prev = 14;
17941
17942 _iterator9.f();
17943
17944 return _context17.finish(14);
17945
17946 case 17:
17947 case "end":
17948 return _context17.stop();
17949 }
17950 }
17951 }, _callee2, null, [[1, 11, 14, 17]]);
17952 })));
17953 }
17954 /**
17955 * Get the item with the maximum value of given property.
17956 *
17957 * @param callback - The function that picks and possibly converts the property.
17958 * @returns The item with the maximum if found otherwise null.
17959 */
17960
17961 }, {
17962 key: "max",
17963 value: function max(callback) {
17964 var iter = getIterator(this._pairs);
17965
17966 var curr = iter.next();
17967
17968 if (curr.done) {
17969 return null;
17970 }
17971
17972 var maxItem = curr.value[1];
17973 var maxValue = callback(curr.value[1], curr.value[0]);
17974
17975 while (!(curr = iter.next()).done) {
17976 var _curr$value = _slicedToArray(curr.value, 2),
17977 id = _curr$value[0],
17978 item = _curr$value[1];
17979
17980 var _value = callback(item, id);
17981
17982 if (_value > maxValue) {
17983 maxValue = _value;
17984 maxItem = item;
17985 }
17986 }
17987
17988 return maxItem;
17989 }
17990 /**
17991 * Get the item with the minimum value of given property.
17992 *
17993 * @param callback - The function that picks and possibly converts the property.
17994 * @returns The item with the minimum if found otherwise null.
17995 */
17996
17997 }, {
17998 key: "min",
17999 value: function min(callback) {
18000 var iter = getIterator(this._pairs);
18001
18002 var curr = iter.next();
18003
18004 if (curr.done) {
18005 return null;
18006 }
18007
18008 var minItem = curr.value[1];
18009 var minValue = callback(curr.value[1], curr.value[0]);
18010
18011 while (!(curr = iter.next()).done) {
18012 var _curr$value2 = _slicedToArray(curr.value, 2),
18013 id = _curr$value2[0],
18014 item = _curr$value2[1];
18015
18016 var _value2 = callback(item, id);
18017
18018 if (_value2 < minValue) {
18019 minValue = _value2;
18020 minItem = item;
18021 }
18022 }
18023
18024 return minItem;
18025 }
18026 /**
18027 * Reduce the items into a single value.
18028 *
18029 * @param callback - The function that does the reduction.
18030 * @param accumulator - The initial value of the accumulator.
18031 * @typeParam T - The type of the accumulated value.
18032 * @returns The reduced value.
18033 */
18034
18035 }, {
18036 key: "reduce",
18037 value: function reduce(callback, accumulator) {
18038 var _iterator10 = _createForOfIteratorHelper$7(this._pairs),
18039 _step10;
18040
18041 try {
18042 for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
18043 var _step10$value = _slicedToArray(_step10.value, 2),
18044 id = _step10$value[0],
18045 item = _step10$value[1];
18046
18047 accumulator = callback(accumulator, item, id);
18048 }
18049 } catch (err) {
18050 _iterator10.e(err);
18051 } finally {
18052 _iterator10.f();
18053 }
18054
18055 return accumulator;
18056 }
18057 /**
18058 * Sort the items.
18059 *
18060 * @param callback - Item comparator.
18061 * @returns A new stream with sorted items.
18062 */
18063
18064 }, {
18065 key: "sort",
18066 value: function sort$1(callback) {
18067 var _this2 = this;
18068
18069 return new DataStream(_defineProperty({}, iterator, function () {
18070 var _context18;
18071
18072 return getIterator(sort(_context18 = _toConsumableArray(_this2._pairs)).call(_context18, function (_ref, _ref2) {
18073 var _ref3 = _slicedToArray(_ref, 2),
18074 idA = _ref3[0],
18075 itemA = _ref3[1];
18076
18077 var _ref4 = _slicedToArray(_ref2, 2),
18078 idB = _ref4[0],
18079 itemB = _ref4[1];
18080
18081 return callback(itemA, itemB, idA, idB);
18082 }));
18083 }));
18084 }
18085 }]);
18086
18087 return DataStream;
18088 }();
18089 /**
18090 * Add an id to given item if it doesn't have one already.
18091 *
18092 * @remarks
18093 * The item will be modified.
18094 * @param item - The item that will have an id after a call to this function.
18095 * @param idProp - The key of the id property.
18096 * @typeParam Item - Item type that may or may not have an id.
18097 * @typeParam IdProp - Name of the property that contains the id.
18098 * @returns true
18099 */
18100
18101
18102 function ensureFullItem(item, idProp) {
18103 if (item[idProp] == null) {
18104 // generate an id
18105 item[idProp] = v4();
18106 }
18107
18108 return item;
18109 }
18110 /**
18111 * # DataSet
18112 *
18113 * Vis.js comes with a flexible DataSet, which can be used to hold and
18114 * manipulate unstructured data and listen for changes in the data. The DataSet
18115 * is key/value based. Data items can be added, updated and removed from the
18116 * DataSet, and one can subscribe to changes in the DataSet. The data in the
18117 * DataSet can be filtered and ordered. Data can be normalized when appending it
18118 * to the DataSet as well.
18119 *
18120 * ## Example
18121 *
18122 * The following example shows how to use a DataSet.
18123 *
18124 * ```javascript
18125 * // create a DataSet
18126 * var options = {};
18127 * var data = new vis.DataSet(options);
18128 *
18129 * // add items
18130 * // note that the data items can contain different properties and data formats
18131 * data.add([
18132 * {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
18133 * {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
18134 * {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
18135 * {id: 4, text: 'item 4'}
18136 * ]);
18137 *
18138 * // subscribe to any change in the DataSet
18139 * data.on('*', function (event, properties, senderId) {
18140 * console.log('event', event, properties);
18141 * });
18142 *
18143 * // update an existing item
18144 * data.update({id: 2, group: 1});
18145 *
18146 * // remove an item
18147 * data.remove(4);
18148 *
18149 * // get all ids
18150 * var ids = data.getIds();
18151 * console.log('ids', ids);
18152 *
18153 * // get a specific item
18154 * var item1 = data.get(1);
18155 * console.log('item1', item1);
18156 *
18157 * // retrieve a filtered subset of the data
18158 * var items = data.get({
18159 * filter: function (item) {
18160 * return item.group == 1;
18161 * }
18162 * });
18163 * console.log('filtered items', items);
18164 * ```
18165 *
18166 * @typeParam Item - Item type that may or may not have an id.
18167 * @typeParam IdProp - Name of the property that contains the id.
18168 */
18169
18170
18171 var DataSet = /*#__PURE__*/function (_DataSetPart) {
18172 _inherits(DataSet, _DataSetPart);
18173
18174 var _super = _createSuper$t(DataSet);
18175
18176 /**
18177 * Construct a new DataSet.
18178 *
18179 * @param data - Initial data or options.
18180 * @param options - Options (type error if data is also options).
18181 */
18182 function DataSet(data, options) {
18183 var _this3;
18184
18185 _classCallCheck(this, DataSet);
18186
18187 _this3 = _super.call(this); // correctly read optional arguments
18188
18189 _defineProperty(_assertThisInitialized(_this3), "flush", void 0);
18190
18191 _defineProperty(_assertThisInitialized(_this3), "length", void 0);
18192
18193 _defineProperty(_assertThisInitialized(_this3), "_options", void 0);
18194
18195 _defineProperty(_assertThisInitialized(_this3), "_data", void 0);
18196
18197 _defineProperty(_assertThisInitialized(_this3), "_idProp", void 0);
18198
18199 _defineProperty(_assertThisInitialized(_this3), "_queue", null);
18200
18201 if (data && !isArray$2(data)) {
18202 options = data;
18203 data = [];
18204 }
18205
18206 _this3._options = options || {};
18207 _this3._data = new map(); // map with data indexed by id
18208
18209 _this3.length = 0; // number of items in the DataSet
18210
18211 _this3._idProp = _this3._options.fieldId || "id"; // name of the field containing id
18212 // add initial data when provided
18213
18214 if (data && data.length) {
18215 _this3.add(data);
18216 }
18217
18218 _this3.setOptions(options);
18219
18220 return _this3;
18221 }
18222 /**
18223 * Set new options.
18224 *
18225 * @param options - The new options.
18226 */
18227
18228
18229 _createClass(DataSet, [{
18230 key: "idProp",
18231 get:
18232 /** Flush all queued calls. */
18233
18234 /** @inheritDoc */
18235
18236 /** @inheritDoc */
18237 function get() {
18238 return this._idProp;
18239 }
18240 }, {
18241 key: "setOptions",
18242 value: function setOptions(options) {
18243 if (options && options.queue !== undefined) {
18244 if (options.queue === false) {
18245 // delete queue if loaded
18246 if (this._queue) {
18247 this._queue.destroy();
18248
18249 this._queue = null;
18250 }
18251 } else {
18252 // create queue and update its options
18253 if (!this._queue) {
18254 this._queue = Queue.extend(this, {
18255 replace: ["add", "update", "remove"]
18256 });
18257 }
18258
18259 if (options.queue && _typeof(options.queue) === "object") {
18260 this._queue.setOptions(options.queue);
18261 }
18262 }
18263 }
18264 }
18265 /**
18266 * Add a data item or an array with items.
18267 *
18268 * After the items are added to the DataSet, the DataSet will trigger an event `add`. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
18269 *
18270 * ## Example
18271 *
18272 * ```javascript
18273 * // create a DataSet
18274 * const data = new vis.DataSet()
18275 *
18276 * // add items
18277 * const ids = data.add([
18278 * { id: 1, text: 'item 1' },
18279 * { id: 2, text: 'item 2' },
18280 * { text: 'item without an id' }
18281 * ])
18282 *
18283 * console.log(ids) // [1, 2, '<UUIDv4>']
18284 * ```
18285 *
18286 * @param data - Items to be added (ids will be generated if missing).
18287 * @param senderId - Sender id.
18288 * @returns addedIds - Array with the ids (generated if not present) of the added items.
18289 * @throws When an item with the same id as any of the added items already exists.
18290 */
18291
18292 }, {
18293 key: "add",
18294 value: function add(data, senderId) {
18295 var _this4 = this;
18296
18297 var addedIds = [];
18298 var id;
18299
18300 if (isArray$2(data)) {
18301 // Array
18302 var idsToAdd = map$3(data).call(data, function (d) {
18303 return d[_this4._idProp];
18304 });
18305
18306 if (some(idsToAdd).call(idsToAdd, function (id) {
18307 return _this4._data.has(id);
18308 })) {
18309 throw new Error("A duplicate id was found in the parameter array.");
18310 }
18311
18312 for (var i = 0, len = data.length; i < len; i++) {
18313 id = this._addItem(data[i]);
18314 addedIds.push(id);
18315 }
18316 } else if (data && _typeof(data) === "object") {
18317 // Single item
18318 id = this._addItem(data);
18319 addedIds.push(id);
18320 } else {
18321 throw new Error("Unknown dataType");
18322 }
18323
18324 if (addedIds.length) {
18325 this._trigger("add", {
18326 items: addedIds
18327 }, senderId);
18328 }
18329
18330 return addedIds;
18331 }
18332 /**
18333 * Update existing items. When an item does not exist, it will be created.
18334 *
18335 * @remarks
18336 * The provided properties will be merged in the existing item. When an item does not exist, it will be created.
18337 *
18338 * After the items are updated, the DataSet will trigger an event `add` for the added items, and an event `update`. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
18339 *
18340 * ## Example
18341 *
18342 * ```javascript
18343 * // create a DataSet
18344 * const data = new vis.DataSet([
18345 * { id: 1, text: 'item 1' },
18346 * { id: 2, text: 'item 2' },
18347 * { id: 3, text: 'item 3' }
18348 * ])
18349 *
18350 * // update items
18351 * const ids = data.update([
18352 * { id: 2, text: 'item 2 (updated)' },
18353 * { id: 4, text: 'item 4 (new)' }
18354 * ])
18355 *
18356 * console.log(ids) // [2, 4]
18357 * ```
18358 *
18359 * ## Warning for TypeScript users
18360 * This method may introduce partial items into the data set. Use add or updateOnly instead for better type safety.
18361 * @param data - Items to be updated (if the id is already present) or added (if the id is missing).
18362 * @param senderId - Sender id.
18363 * @returns updatedIds - The ids of the added (these may be newly generated if there was no id in the item from the data) or updated items.
18364 * @throws When the supplied data is neither an item nor an array of items.
18365 */
18366
18367 }, {
18368 key: "update",
18369 value: function update(data, senderId) {
18370 var _this5 = this;
18371
18372 var addedIds = [];
18373 var updatedIds = [];
18374 var oldData = [];
18375 var updatedData = [];
18376 var idProp = this._idProp;
18377
18378 var addOrUpdate = function addOrUpdate(item) {
18379 var origId = item[idProp];
18380
18381 if (origId != null && _this5._data.has(origId)) {
18382 var fullItem = item; // it has an id, therefore it is a fullitem
18383
18384 var oldItem = assign$2({}, _this5._data.get(origId)); // update item
18385
18386
18387 var id = _this5._updateItem(fullItem);
18388
18389 updatedIds.push(id);
18390 updatedData.push(fullItem);
18391 oldData.push(oldItem);
18392 } else {
18393 // add new item
18394 var _id = _this5._addItem(item);
18395
18396 addedIds.push(_id);
18397 }
18398 };
18399
18400 if (isArray$2(data)) {
18401 // Array
18402 for (var i = 0, len = data.length; i < len; i++) {
18403 if (data[i] && _typeof(data[i]) === "object") {
18404 addOrUpdate(data[i]);
18405 } else {
18406 console.warn("Ignoring input item, which is not an object at index " + i);
18407 }
18408 }
18409 } else if (data && _typeof(data) === "object") {
18410 // Single item
18411 addOrUpdate(data);
18412 } else {
18413 throw new Error("Unknown dataType");
18414 }
18415
18416 if (addedIds.length) {
18417 this._trigger("add", {
18418 items: addedIds
18419 }, senderId);
18420 }
18421
18422 if (updatedIds.length) {
18423 var props = {
18424 items: updatedIds,
18425 oldData: oldData,
18426 data: updatedData
18427 }; // TODO: remove deprecated property 'data' some day
18428 //Object.defineProperty(props, 'data', {
18429 // 'get': (function() {
18430 // console.warn('Property data is deprecated. Use DataSet.get(ids) to retrieve the new data, use the oldData property on this object to get the old data');
18431 // return updatedData;
18432 // }).bind(this)
18433 //});
18434
18435 this._trigger("update", props, senderId);
18436 }
18437
18438 return concat(addedIds).call(addedIds, updatedIds);
18439 }
18440 /**
18441 * Update existing items. When an item does not exist, an error will be thrown.
18442 *
18443 * @remarks
18444 * The provided properties will be deeply merged into the existing item.
18445 * When an item does not exist (id not present in the data set or absent), an error will be thrown and nothing will be changed.
18446 *
18447 * After the items are updated, the DataSet will trigger an event `update`.
18448 * When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
18449 *
18450 * ## Example
18451 *
18452 * ```javascript
18453 * // create a DataSet
18454 * const data = new vis.DataSet([
18455 * { id: 1, text: 'item 1' },
18456 * { id: 2, text: 'item 2' },
18457 * { id: 3, text: 'item 3' },
18458 * ])
18459 *
18460 * // update items
18461 * const ids = data.update([
18462 * { id: 2, text: 'item 2 (updated)' }, // works
18463 * // { id: 4, text: 'item 4 (new)' }, // would throw
18464 * // { text: 'item 4 (new)' }, // would also throw
18465 * ])
18466 *
18467 * console.log(ids) // [2]
18468 * ```
18469 * @param data - Updates (the id and optionally other props) to the items in this data set.
18470 * @param senderId - Sender id.
18471 * @returns updatedIds - The ids of the updated items.
18472 * @throws When the supplied data is neither an item nor an array of items, when the ids are missing.
18473 */
18474
18475 }, {
18476 key: "updateOnly",
18477 value: function updateOnly(data, senderId) {
18478 var _context19,
18479 _this6 = this;
18480
18481 if (!isArray$2(data)) {
18482 data = [data];
18483 }
18484
18485 var updateEventData = map$3(_context19 = map$3(data).call(data, function (update) {
18486 var oldData = _this6._data.get(update[_this6._idProp]);
18487
18488 if (oldData == null) {
18489 throw new Error("Updating non-existent items is not allowed.");
18490 }
18491
18492 return {
18493 oldData: oldData,
18494 update: update
18495 };
18496 })).call(_context19, function (_ref5) {
18497 var oldData = _ref5.oldData,
18498 update = _ref5.update;
18499 var id = oldData[_this6._idProp];
18500 var updatedData = pureDeepObjectAssign(oldData, update);
18501
18502 _this6._data.set(id, updatedData);
18503
18504 return {
18505 id: id,
18506 oldData: oldData,
18507 updatedData: updatedData
18508 };
18509 });
18510
18511 if (updateEventData.length) {
18512 var props = {
18513 items: map$3(updateEventData).call(updateEventData, function (value) {
18514 return value.id;
18515 }),
18516 oldData: map$3(updateEventData).call(updateEventData, function (value) {
18517 return value.oldData;
18518 }),
18519 data: map$3(updateEventData).call(updateEventData, function (value) {
18520 return value.updatedData;
18521 })
18522 }; // TODO: remove deprecated property 'data' some day
18523 //Object.defineProperty(props, 'data', {
18524 // 'get': (function() {
18525 // console.warn('Property data is deprecated. Use DataSet.get(ids) to retrieve the new data, use the oldData property on this object to get the old data');
18526 // return updatedData;
18527 // }).bind(this)
18528 //});
18529
18530 this._trigger("update", props, senderId);
18531
18532 return props.items;
18533 } else {
18534 return [];
18535 }
18536 }
18537 /** @inheritDoc */
18538
18539 }, {
18540 key: "get",
18541 value: function get(first, second) {
18542 // @TODO: Woudn't it be better to split this into multiple methods?
18543 // parse the arguments
18544 var id = undefined;
18545 var ids = undefined;
18546 var options = undefined;
18547
18548 if (isId(first)) {
18549 // get(id [, options])
18550 id = first;
18551 options = second;
18552 } else if (isArray$2(first)) {
18553 // get(ids [, options])
18554 ids = first;
18555 options = second;
18556 } else {
18557 // get([, options])
18558 options = first;
18559 } // determine the return type
18560
18561
18562 var returnType = options && options.returnType === "Object" ? "Object" : "Array"; // @TODO: WTF is this? Or am I missing something?
18563 // var returnType
18564 // if (options && options.returnType) {
18565 // var allowedValues = ['Array', 'Object']
18566 // returnType =
18567 // allowedValues.indexOf(options.returnType) == -1
18568 // ? 'Array'
18569 // : options.returnType
18570 // } else {
18571 // returnType = 'Array'
18572 // }
18573 // build options
18574
18575 var filter$1 = options && filter(options);
18576
18577 var items = [];
18578 var item = undefined;
18579 var itemIds = undefined;
18580 var itemId = undefined; // convert items
18581
18582 if (id != null) {
18583 // return a single item
18584 item = this._data.get(id);
18585
18586 if (item && filter$1 && !filter$1(item)) {
18587 item = undefined;
18588 }
18589 } else if (ids != null) {
18590 // return a subset of items
18591 for (var i = 0, len = ids.length; i < len; i++) {
18592 item = this._data.get(ids[i]);
18593
18594 if (item != null && (!filter$1 || filter$1(item))) {
18595 items.push(item);
18596 }
18597 }
18598 } else {
18599 var _context20;
18600
18601 // return all items
18602 itemIds = _toConsumableArray(keys(_context20 = this._data).call(_context20));
18603
18604 for (var _i = 0, _len2 = itemIds.length; _i < _len2; _i++) {
18605 itemId = itemIds[_i];
18606 item = this._data.get(itemId);
18607
18608 if (item != null && (!filter$1 || filter$1(item))) {
18609 items.push(item);
18610 }
18611 }
18612 } // order the results
18613
18614
18615 if (options && options.order && id == undefined) {
18616 this._sort(items, options.order);
18617 } // filter fields of the items
18618
18619
18620 if (options && options.fields) {
18621 var fields = options.fields;
18622
18623 if (id != undefined && item != null) {
18624 item = this._filterFields(item, fields);
18625 } else {
18626 for (var _i2 = 0, _len3 = items.length; _i2 < _len3; _i2++) {
18627 items[_i2] = this._filterFields(items[_i2], fields);
18628 }
18629 }
18630 } // return the results
18631
18632
18633 if (returnType == "Object") {
18634 var result = {};
18635
18636 for (var _i3 = 0, _len4 = items.length; _i3 < _len4; _i3++) {
18637 var resultant = items[_i3]; // @TODO: Shoudn't this be this._fieldId?
18638 // result[resultant.id] = resultant
18639
18640 var _id2 = resultant[this._idProp];
18641 result[_id2] = resultant;
18642 }
18643
18644 return result;
18645 } else {
18646 if (id != null) {
18647 var _item;
18648
18649 // a single item
18650 return (_item = item) !== null && _item !== void 0 ? _item : null;
18651 } else {
18652 // just return our array
18653 return items;
18654 }
18655 }
18656 }
18657 /** @inheritDoc */
18658
18659 }, {
18660 key: "getIds",
18661 value: function getIds(options) {
18662 var data = this._data;
18663
18664 var filter$1 = options && filter(options);
18665
18666 var order = options && options.order;
18667
18668 var itemIds = _toConsumableArray(keys(data).call(data));
18669
18670 var ids = [];
18671
18672 if (filter$1) {
18673 // get filtered items
18674 if (order) {
18675 // create ordered list
18676 var items = [];
18677
18678 for (var i = 0, len = itemIds.length; i < len; i++) {
18679 var id = itemIds[i];
18680
18681 var item = this._data.get(id);
18682
18683 if (item != null && filter$1(item)) {
18684 items.push(item);
18685 }
18686 }
18687
18688 this._sort(items, order);
18689
18690 for (var _i4 = 0, _len5 = items.length; _i4 < _len5; _i4++) {
18691 ids.push(items[_i4][this._idProp]);
18692 }
18693 } else {
18694 // create unordered list
18695 for (var _i5 = 0, _len6 = itemIds.length; _i5 < _len6; _i5++) {
18696 var _id3 = itemIds[_i5];
18697
18698 var _item2 = this._data.get(_id3);
18699
18700 if (_item2 != null && filter$1(_item2)) {
18701 ids.push(_item2[this._idProp]);
18702 }
18703 }
18704 }
18705 } else {
18706 // get all items
18707 if (order) {
18708 // create an ordered list
18709 var _items = [];
18710
18711 for (var _i6 = 0, _len7 = itemIds.length; _i6 < _len7; _i6++) {
18712 var _id4 = itemIds[_i6];
18713
18714 _items.push(data.get(_id4));
18715 }
18716
18717 this._sort(_items, order);
18718
18719 for (var _i7 = 0, _len8 = _items.length; _i7 < _len8; _i7++) {
18720 ids.push(_items[_i7][this._idProp]);
18721 }
18722 } else {
18723 // create unordered list
18724 for (var _i8 = 0, _len9 = itemIds.length; _i8 < _len9; _i8++) {
18725 var _id5 = itemIds[_i8];
18726
18727 var _item3 = data.get(_id5);
18728
18729 if (_item3 != null) {
18730 ids.push(_item3[this._idProp]);
18731 }
18732 }
18733 }
18734 }
18735
18736 return ids;
18737 }
18738 /** @inheritDoc */
18739
18740 }, {
18741 key: "getDataSet",
18742 value: function getDataSet() {
18743 return this;
18744 }
18745 /** @inheritDoc */
18746
18747 }, {
18748 key: "forEach",
18749 value: function forEach(callback, options) {
18750 var filter$1 = options && filter(options);
18751
18752 var data = this._data;
18753
18754 var itemIds = _toConsumableArray(keys(data).call(data));
18755
18756 if (options && options.order) {
18757 // execute forEach on ordered list
18758 var items = this.get(options);
18759
18760 for (var i = 0, len = items.length; i < len; i++) {
18761 var item = items[i];
18762 var id = item[this._idProp];
18763 callback(item, id);
18764 }
18765 } else {
18766 // unordered
18767 for (var _i9 = 0, _len10 = itemIds.length; _i9 < _len10; _i9++) {
18768 var _id6 = itemIds[_i9];
18769
18770 var _item4 = this._data.get(_id6);
18771
18772 if (_item4 != null && (!filter$1 || filter$1(_item4))) {
18773 callback(_item4, _id6);
18774 }
18775 }
18776 }
18777 }
18778 /** @inheritDoc */
18779
18780 }, {
18781 key: "map",
18782 value: function map(callback, options) {
18783 var filter$1 = options && filter(options);
18784
18785 var mappedItems = [];
18786 var data = this._data;
18787
18788 var itemIds = _toConsumableArray(keys(data).call(data)); // convert and filter items
18789
18790
18791 for (var i = 0, len = itemIds.length; i < len; i++) {
18792 var id = itemIds[i];
18793
18794 var item = this._data.get(id);
18795
18796 if (item != null && (!filter$1 || filter$1(item))) {
18797 mappedItems.push(callback(item, id));
18798 }
18799 } // order items
18800
18801
18802 if (options && options.order) {
18803 this._sort(mappedItems, options.order);
18804 }
18805
18806 return mappedItems;
18807 }
18808 /**
18809 * Filter the fields of an item.
18810 *
18811 * @param item - The item whose fields should be filtered.
18812 * @param fields - The names of the fields that will be kept.
18813 * @typeParam K - Field name type.
18814 * @returns The item without any additional fields.
18815 */
18816
18817 }, {
18818 key: "_filterFields",
18819 value: function _filterFields(item, fields) {
18820 var _context21;
18821
18822 if (!item) {
18823 // item is null
18824 return item;
18825 }
18826
18827 return reduce(_context21 = isArray$2(fields) ? // Use the supplied array
18828 fields : // Use the keys of the supplied object
18829 keys$4(fields)).call(_context21, function (filteredItem, field) {
18830 filteredItem[field] = item[field];
18831 return filteredItem;
18832 }, {});
18833 }
18834 /**
18835 * Sort the provided array with items.
18836 *
18837 * @param items - Items to be sorted in place.
18838 * @param order - A field name or custom sort function.
18839 * @typeParam T - The type of the items in the items array.
18840 */
18841
18842 }, {
18843 key: "_sort",
18844 value: function _sort(items, order) {
18845 if (typeof order === "string") {
18846 // order by provided field name
18847 var name = order; // field name
18848
18849 sort(items).call(items, function (a, b) {
18850 // @TODO: How to treat missing properties?
18851 var av = a[name];
18852 var bv = b[name];
18853 return av > bv ? 1 : av < bv ? -1 : 0;
18854 });
18855 } else if (typeof order === "function") {
18856 // order by sort function
18857 sort(items).call(items, order);
18858 } else {
18859 // TODO: extend order by an Object {field:string, direction:string}
18860 // where direction can be 'asc' or 'desc'
18861 throw new TypeError("Order must be a function or a string");
18862 }
18863 }
18864 /**
18865 * Remove an item or multiple items by “reference” (only the id is used) or by id.
18866 *
18867 * The method ignores removal of non-existing items, and returns an array containing the ids of the items which are actually removed from the DataSet.
18868 *
18869 * After the items are removed, the DataSet will trigger an event `remove` for the removed items. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
18870 *
18871 * ## Example
18872 * ```javascript
18873 * // create a DataSet
18874 * const data = new vis.DataSet([
18875 * { id: 1, text: 'item 1' },
18876 * { id: 2, text: 'item 2' },
18877 * { id: 3, text: 'item 3' }
18878 * ])
18879 *
18880 * // remove items
18881 * const ids = data.remove([2, { id: 3 }, 4])
18882 *
18883 * console.log(ids) // [2, 3]
18884 * ```
18885 *
18886 * @param id - One or more items or ids of items to be removed.
18887 * @param senderId - Sender id.
18888 * @returns The ids of the removed items.
18889 */
18890
18891 }, {
18892 key: "remove",
18893 value: function remove(id, senderId) {
18894 var removedIds = [];
18895 var removedItems = []; // force everything to be an array for simplicity
18896
18897 var ids = isArray$2(id) ? id : [id];
18898
18899 for (var i = 0, len = ids.length; i < len; i++) {
18900 var item = this._remove(ids[i]);
18901
18902 if (item) {
18903 var itemId = item[this._idProp];
18904
18905 if (itemId != null) {
18906 removedIds.push(itemId);
18907 removedItems.push(item);
18908 }
18909 }
18910 }
18911
18912 if (removedIds.length) {
18913 this._trigger("remove", {
18914 items: removedIds,
18915 oldData: removedItems
18916 }, senderId);
18917 }
18918
18919 return removedIds;
18920 }
18921 /**
18922 * Remove an item by its id or reference.
18923 *
18924 * @param id - Id of an item or the item itself.
18925 * @returns The removed item if removed, null otherwise.
18926 */
18927
18928 }, {
18929 key: "_remove",
18930 value: function _remove(id) {
18931 // @TODO: It origianlly returned the item although the docs say id.
18932 // The code expects the item, so probably an error in the docs.
18933 var ident; // confirm the id to use based on the args type
18934
18935 if (isId(id)) {
18936 ident = id;
18937 } else if (id && _typeof(id) === "object") {
18938 ident = id[this._idProp]; // look for the identifier field using ._idProp
18939 } // do the removing if the item is found
18940
18941
18942 if (ident != null && this._data.has(ident)) {
18943 var item = this._data.get(ident) || null;
18944
18945 this._data.delete(ident);
18946
18947 --this.length;
18948 return item;
18949 }
18950
18951 return null;
18952 }
18953 /**
18954 * Clear the entire data set.
18955 *
18956 * After the items are removed, the [[DataSet]] will trigger an event `remove` for all removed items. When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
18957 *
18958 * @param senderId - Sender id.
18959 * @returns removedIds - The ids of all removed items.
18960 */
18961
18962 }, {
18963 key: "clear",
18964 value: function clear(senderId) {
18965 var _context22;
18966
18967 var ids = _toConsumableArray(keys(_context22 = this._data).call(_context22));
18968
18969 var items = [];
18970
18971 for (var i = 0, len = ids.length; i < len; i++) {
18972 items.push(this._data.get(ids[i]));
18973 }
18974
18975 this._data.clear();
18976
18977 this.length = 0;
18978
18979 this._trigger("remove", {
18980 items: ids,
18981 oldData: items
18982 }, senderId);
18983
18984 return ids;
18985 }
18986 /**
18987 * Find the item with maximum value of a specified field.
18988 *
18989 * @param field - Name of the property that should be searched for max value.
18990 * @returns Item containing max value, or null if no items.
18991 */
18992
18993 }, {
18994 key: "max",
18995 value: function max(field) {
18996 var _context23;
18997
18998 var max = null;
18999 var maxField = null;
19000
19001 var _iterator11 = _createForOfIteratorHelper$7(values(_context23 = this._data).call(_context23)),
19002 _step11;
19003
19004 try {
19005 for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
19006 var item = _step11.value;
19007 var itemField = item[field];
19008
19009 if (typeof itemField === "number" && (maxField == null || itemField > maxField)) {
19010 max = item;
19011 maxField = itemField;
19012 }
19013 }
19014 } catch (err) {
19015 _iterator11.e(err);
19016 } finally {
19017 _iterator11.f();
19018 }
19019
19020 return max || null;
19021 }
19022 /**
19023 * Find the item with minimum value of a specified field.
19024 *
19025 * @param field - Name of the property that should be searched for min value.
19026 * @returns Item containing min value, or null if no items.
19027 */
19028
19029 }, {
19030 key: "min",
19031 value: function min(field) {
19032 var _context24;
19033
19034 var min = null;
19035 var minField = null;
19036
19037 var _iterator12 = _createForOfIteratorHelper$7(values(_context24 = this._data).call(_context24)),
19038 _step12;
19039
19040 try {
19041 for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
19042 var item = _step12.value;
19043 var itemField = item[field];
19044
19045 if (typeof itemField === "number" && (minField == null || itemField < minField)) {
19046 min = item;
19047 minField = itemField;
19048 }
19049 }
19050 } catch (err) {
19051 _iterator12.e(err);
19052 } finally {
19053 _iterator12.f();
19054 }
19055
19056 return min || null;
19057 }
19058 /**
19059 * Find all distinct values of a specified field
19060 *
19061 * @param prop - The property name whose distinct values should be returned.
19062 * @returns Unordered array containing all distinct values. Items without specified property are ignored.
19063 */
19064
19065 }, {
19066 key: "distinct",
19067 value: function distinct(prop) {
19068 var data = this._data;
19069
19070 var itemIds = _toConsumableArray(keys(data).call(data));
19071
19072 var values = [];
19073 var count = 0;
19074
19075 for (var i = 0, len = itemIds.length; i < len; i++) {
19076 var id = itemIds[i];
19077 var item = data.get(id);
19078 var _value3 = item[prop];
19079 var exists = false;
19080
19081 for (var j = 0; j < count; j++) {
19082 if (values[j] == _value3) {
19083 exists = true;
19084 break;
19085 }
19086 }
19087
19088 if (!exists && _value3 !== undefined) {
19089 values[count] = _value3;
19090 count++;
19091 }
19092 }
19093
19094 return values;
19095 }
19096 /**
19097 * Add a single item. Will fail when an item with the same id already exists.
19098 *
19099 * @param item - A new item to be added.
19100 * @returns Added item's id. An id is generated when it is not present in the item.
19101 */
19102
19103 }, {
19104 key: "_addItem",
19105 value: function _addItem(item) {
19106 var fullItem = ensureFullItem(item, this._idProp);
19107 var id = fullItem[this._idProp]; // check whether this id is already taken
19108
19109 if (this._data.has(id)) {
19110 // item already exists
19111 throw new Error("Cannot add item: item with id " + id + " already exists");
19112 }
19113
19114 this._data.set(id, fullItem);
19115
19116 ++this.length;
19117 return id;
19118 }
19119 /**
19120 * Update a single item: merge with existing item.
19121 * Will fail when the item has no id, or when there does not exist an item with the same id.
19122 *
19123 * @param update - The new item
19124 * @returns The id of the updated item.
19125 */
19126
19127 }, {
19128 key: "_updateItem",
19129 value: function _updateItem(update) {
19130 var id = update[this._idProp];
19131
19132 if (id == null) {
19133 throw new Error("Cannot update item: item has no id (item: " + stringify$1(update) + ")");
19134 }
19135
19136 var item = this._data.get(id);
19137
19138 if (!item) {
19139 // item doesn't exist
19140 throw new Error("Cannot update item: no item with id " + id + " found");
19141 }
19142
19143 this._data.set(id, _objectSpread$4(_objectSpread$4({}, item), update));
19144
19145 return id;
19146 }
19147 /** @inheritDoc */
19148
19149 }, {
19150 key: "stream",
19151 value: function stream(ids) {
19152 if (ids) {
19153 var data = this._data;
19154 return new DataStream(_defineProperty({}, iterator, /*#__PURE__*/regenerator.mark(function _callee3() {
19155 var _iterator13, _step13, id, item;
19156
19157 return regenerator.wrap(function _callee3$(_context25) {
19158 while (1) {
19159 switch (_context25.prev = _context25.next) {
19160 case 0:
19161 _iterator13 = _createForOfIteratorHelper$7(ids);
19162 _context25.prev = 1;
19163
19164 _iterator13.s();
19165
19166 case 3:
19167 if ((_step13 = _iterator13.n()).done) {
19168 _context25.next = 11;
19169 break;
19170 }
19171
19172 id = _step13.value;
19173 item = data.get(id);
19174
19175 if (!(item != null)) {
19176 _context25.next = 9;
19177 break;
19178 }
19179
19180 _context25.next = 9;
19181 return [id, item];
19182
19183 case 9:
19184 _context25.next = 3;
19185 break;
19186
19187 case 11:
19188 _context25.next = 16;
19189 break;
19190
19191 case 13:
19192 _context25.prev = 13;
19193 _context25.t0 = _context25["catch"](1);
19194
19195 _iterator13.e(_context25.t0);
19196
19197 case 16:
19198 _context25.prev = 16;
19199
19200 _iterator13.f();
19201
19202 return _context25.finish(16);
19203
19204 case 19:
19205 case "end":
19206 return _context25.stop();
19207 }
19208 }
19209 }, _callee3, null, [[1, 13, 16, 19]]);
19210 })));
19211 } else {
19212 var _context26;
19213
19214 return new DataStream(_defineProperty({}, iterator, bind$6(_context26 = entries(this._data)).call(_context26, this._data)));
19215 }
19216 }
19217 }]);
19218
19219 return DataSet;
19220 }(DataSetPart);
19221 /**
19222 * DataView
19223 *
19224 * A DataView offers a filtered and/or formatted view on a DataSet. One can subscribe to changes in a DataView, and easily get filtered or formatted data without having to specify filters and field types all the time.
19225 *
19226 * ## Example
19227 * ```javascript
19228 * // create a DataSet
19229 * var data = new vis.DataSet();
19230 * data.add([
19231 * {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
19232 * {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
19233 * {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
19234 * {id: 4, text: 'item 4'}
19235 * ]);
19236 *
19237 * // create a DataView
19238 * // the view will only contain items having a property group with value 1,
19239 * // and will only output fields id, text, and date.
19240 * var view = new vis.DataView(data, {
19241 * filter: function (item) {
19242 * return (item.group == 1);
19243 * },
19244 * fields: ['id', 'text', 'date']
19245 * });
19246 *
19247 * // subscribe to any change in the DataView
19248 * view.on('*', function (event, properties, senderId) {
19249 * console.log('event', event, properties);
19250 * });
19251 *
19252 * // update an item in the data set
19253 * data.update({id: 2, group: 1});
19254 *
19255 * // get all ids in the view
19256 * var ids = view.getIds();
19257 * console.log('ids', ids); // will output [1, 2]
19258 *
19259 * // get all items in the view
19260 * var items = view.get();
19261 * ```
19262 *
19263 * @typeParam Item - Item type that may or may not have an id.
19264 * @typeParam IdProp - Name of the property that contains the id.
19265 */
19266
19267
19268 var DataView = /*#__PURE__*/function (_DataSetPart2) {
19269 _inherits(DataView, _DataSetPart2);
19270
19271 var _super2 = _createSuper$t(DataView);
19272
19273 /**
19274 * Create a DataView.
19275 *
19276 * @param data - The instance containing data (directly or indirectly).
19277 * @param options - Options to configure this data view.
19278 */
19279 function DataView(data, options) {
19280 var _context27;
19281
19282 var _this7;
19283
19284 _classCallCheck(this, DataView);
19285
19286 _this7 = _super2.call(this);
19287
19288 _defineProperty(_assertThisInitialized(_this7), "length", 0);
19289
19290 _defineProperty(_assertThisInitialized(_this7), "_listener", void 0);
19291
19292 _defineProperty(_assertThisInitialized(_this7), "_data", void 0);
19293
19294 _defineProperty(_assertThisInitialized(_this7), "_ids", new set());
19295
19296 _defineProperty(_assertThisInitialized(_this7), "_options", void 0);
19297
19298 _this7._options = options || {};
19299 _this7._listener = bind$6(_context27 = _this7._onEvent).call(_context27, _assertThisInitialized(_this7));
19300
19301 _this7.setData(data);
19302
19303 return _this7;
19304 } // TODO: implement a function .config() to dynamically update things like configured filter
19305 // and trigger changes accordingly
19306
19307 /**
19308 * Set a data source for the view.
19309 *
19310 * @param data - The instance containing data (directly or indirectly).
19311 * @remarks
19312 * Note that when the data view is bound to a data set it won't be garbage
19313 * collected unless the data set is too. Use `dataView.setData(null)` or
19314 * `dataView.dispose()` to enable garbage collection before you lose the last
19315 * reference.
19316 */
19317
19318
19319 _createClass(DataView, [{
19320 key: "idProp",
19321 get:
19322 /** @inheritDoc */
19323
19324 /** @inheritDoc */
19325 function get() {
19326 return this.getDataSet().idProp;
19327 }
19328 }, {
19329 key: "setData",
19330 value: function setData(data) {
19331 if (this._data) {
19332 // unsubscribe from current dataset
19333 if (this._data.off) {
19334 this._data.off("*", this._listener);
19335 } // trigger a remove of all items in memory
19336
19337
19338 var ids = this._data.getIds({
19339 filter: filter(this._options)
19340 });
19341
19342 var items = this._data.get(ids);
19343
19344 this._ids.clear();
19345
19346 this.length = 0;
19347
19348 this._trigger("remove", {
19349 items: ids,
19350 oldData: items
19351 });
19352 }
19353
19354 if (data != null) {
19355 this._data = data; // trigger an add of all added items
19356
19357 var _ids = this._data.getIds({
19358 filter: filter(this._options)
19359 });
19360
19361 for (var i = 0, len = _ids.length; i < len; i++) {
19362 var id = _ids[i];
19363
19364 this._ids.add(id);
19365 }
19366
19367 this.length = _ids.length;
19368
19369 this._trigger("add", {
19370 items: _ids
19371 });
19372 } else {
19373 this._data = new DataSet();
19374 } // subscribe to new dataset
19375
19376
19377 if (this._data.on) {
19378 this._data.on("*", this._listener);
19379 }
19380 }
19381 /**
19382 * Refresh the DataView.
19383 * Useful when the DataView has a filter function containing a variable parameter.
19384 */
19385
19386 }, {
19387 key: "refresh",
19388 value: function refresh() {
19389 var ids = this._data.getIds({
19390 filter: filter(this._options)
19391 });
19392
19393 var oldIds = _toConsumableArray(this._ids);
19394
19395 var newIds = {};
19396 var addedIds = [];
19397 var removedIds = [];
19398 var removedItems = []; // check for additions
19399
19400 for (var i = 0, len = ids.length; i < len; i++) {
19401 var id = ids[i];
19402 newIds[id] = true;
19403
19404 if (!this._ids.has(id)) {
19405 addedIds.push(id);
19406
19407 this._ids.add(id);
19408 }
19409 } // check for removals
19410
19411
19412 for (var _i10 = 0, _len11 = oldIds.length; _i10 < _len11; _i10++) {
19413 var _id7 = oldIds[_i10];
19414
19415 var item = this._data.get(_id7);
19416
19417 if (item == null) {
19418 // @TODO: Investigate.
19419 // Doesn't happen during tests or examples.
19420 // Is it really impossible or could it eventually happen?
19421 // How to handle it if it does? The types guarantee non-nullable items.
19422 console.error("If you see this, report it please.");
19423 } else if (!newIds[_id7]) {
19424 removedIds.push(_id7);
19425 removedItems.push(item);
19426
19427 this._ids.delete(_id7);
19428 }
19429 }
19430
19431 this.length += addedIds.length - removedIds.length; // trigger events
19432
19433 if (addedIds.length) {
19434 this._trigger("add", {
19435 items: addedIds
19436 });
19437 }
19438
19439 if (removedIds.length) {
19440 this._trigger("remove", {
19441 items: removedIds,
19442 oldData: removedItems
19443 });
19444 }
19445 }
19446 /** @inheritDoc */
19447
19448 }, {
19449 key: "get",
19450 value: function get(first, second) {
19451 if (this._data == null) {
19452 return null;
19453 } // parse the arguments
19454
19455
19456 var ids = null;
19457 var options;
19458
19459 if (isId(first) || isArray$2(first)) {
19460 ids = first;
19461 options = second;
19462 } else {
19463 options = first;
19464 } // extend the options with the default options and provided options
19465
19466
19467 var viewOptions = assign$2({}, this._options, options); // create a combined filter method when needed
19468
19469
19470 var thisFilter = filter(this._options);
19471
19472 var optionsFilter = options && filter(options);
19473
19474 if (thisFilter && optionsFilter) {
19475 viewOptions.filter = function (item) {
19476 return thisFilter(item) && optionsFilter(item);
19477 };
19478 }
19479
19480 if (ids == null) {
19481 return this._data.get(viewOptions);
19482 } else {
19483 return this._data.get(ids, viewOptions);
19484 }
19485 }
19486 /** @inheritDoc */
19487
19488 }, {
19489 key: "getIds",
19490 value: function getIds(options) {
19491 if (this._data.length) {
19492 var defaultFilter = filter(this._options);
19493
19494 var optionsFilter = options != null ? filter(options) : null;
19495 var filter$1;
19496
19497 if (optionsFilter) {
19498 if (defaultFilter) {
19499 filter$1 = function filter(item) {
19500 return defaultFilter(item) && optionsFilter(item);
19501 };
19502 } else {
19503 filter$1 = optionsFilter;
19504 }
19505 } else {
19506 filter$1 = defaultFilter;
19507 }
19508
19509 return this._data.getIds({
19510 filter: filter$1,
19511 order: options && options.order
19512 });
19513 } else {
19514 return [];
19515 }
19516 }
19517 /** @inheritDoc */
19518
19519 }, {
19520 key: "forEach",
19521 value: function forEach(callback, options) {
19522 if (this._data) {
19523 var _context28;
19524
19525 var defaultFilter = filter(this._options);
19526
19527 var optionsFilter = options && filter(options);
19528
19529 var filter$1;
19530
19531 if (optionsFilter) {
19532 if (defaultFilter) {
19533 filter$1 = function filter(item) {
19534 return defaultFilter(item) && optionsFilter(item);
19535 };
19536 } else {
19537 filter$1 = optionsFilter;
19538 }
19539 } else {
19540 filter$1 = defaultFilter;
19541 }
19542
19543 forEach$2(_context28 = this._data).call(_context28, callback, {
19544 filter: filter$1,
19545 order: options && options.order
19546 });
19547 }
19548 }
19549 /** @inheritDoc */
19550
19551 }, {
19552 key: "map",
19553 value: function map(callback, options) {
19554 if (this._data) {
19555 var _context29;
19556
19557 var defaultFilter = filter(this._options);
19558
19559 var optionsFilter = options && filter(options);
19560
19561 var filter$1;
19562
19563 if (optionsFilter) {
19564 if (defaultFilter) {
19565 filter$1 = function filter(item) {
19566 return defaultFilter(item) && optionsFilter(item);
19567 };
19568 } else {
19569 filter$1 = optionsFilter;
19570 }
19571 } else {
19572 filter$1 = defaultFilter;
19573 }
19574
19575 return map$3(_context29 = this._data).call(_context29, callback, {
19576 filter: filter$1,
19577 order: options && options.order
19578 });
19579 } else {
19580 return [];
19581 }
19582 }
19583 /** @inheritDoc */
19584
19585 }, {
19586 key: "getDataSet",
19587 value: function getDataSet() {
19588 return this._data.getDataSet();
19589 }
19590 /** @inheritDoc */
19591
19592 }, {
19593 key: "stream",
19594 value: function stream(ids) {
19595 var _context30;
19596
19597 return this._data.stream(ids || _defineProperty({}, iterator, bind$6(_context30 = keys(this._ids)).call(_context30, this._ids)));
19598 }
19599 /**
19600 * Render the instance unusable prior to garbage collection.
19601 *
19602 * @remarks
19603 * The intention of this method is to help discover scenarios where the data
19604 * view is being used when the programmer thinks it has been garbage collected
19605 * already. It's stricter version of `dataView.setData(null)`.
19606 */
19607
19608 }, {
19609 key: "dispose",
19610 value: function dispose() {
19611 var _this$_data;
19612
19613 if ((_this$_data = this._data) !== null && _this$_data !== void 0 && _this$_data.off) {
19614 this._data.off("*", this._listener);
19615 }
19616
19617 var message = "This data view has already been disposed of.";
19618 var replacement = {
19619 get: function get() {
19620 throw new Error(message);
19621 },
19622 set: function set() {
19623 throw new Error(message);
19624 },
19625 configurable: false
19626 };
19627
19628 var _iterator14 = _createForOfIteratorHelper$7(ownKeys$6(DataView.prototype)),
19629 _step14;
19630
19631 try {
19632 for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
19633 var key = _step14.value;
19634
19635 defineProperty$6(this, key, replacement);
19636 }
19637 } catch (err) {
19638 _iterator14.e(err);
19639 } finally {
19640 _iterator14.f();
19641 }
19642 }
19643 /**
19644 * Event listener. Will propagate all events from the connected data set to the subscribers of the DataView, but will filter the items and only trigger when there are changes in the filtered data set.
19645 *
19646 * @param event - The name of the event.
19647 * @param params - Parameters of the event.
19648 * @param senderId - Id supplied by the sender.
19649 */
19650
19651 }, {
19652 key: "_onEvent",
19653 value: function _onEvent(event, params, senderId) {
19654 if (!params || !params.items || !this._data) {
19655 return;
19656 }
19657
19658 var ids = params.items;
19659 var addedIds = [];
19660 var updatedIds = [];
19661 var removedIds = [];
19662 var oldItems = [];
19663 var updatedItems = [];
19664 var removedItems = [];
19665
19666 switch (event) {
19667 case "add":
19668 // filter the ids of the added items
19669 for (var i = 0, len = ids.length; i < len; i++) {
19670 var id = ids[i];
19671 var item = this.get(id);
19672
19673 if (item) {
19674 this._ids.add(id);
19675
19676 addedIds.push(id);
19677 }
19678 }
19679
19680 break;
19681
19682 case "update":
19683 // determine the event from the views viewpoint: an updated
19684 // item can be added, updated, or removed from this view.
19685 for (var _i11 = 0, _len12 = ids.length; _i11 < _len12; _i11++) {
19686 var _id8 = ids[_i11];
19687
19688 var _item5 = this.get(_id8);
19689
19690 if (_item5) {
19691 if (this._ids.has(_id8)) {
19692 updatedIds.push(_id8);
19693 updatedItems.push(params.data[_i11]);
19694 oldItems.push(params.oldData[_i11]);
19695 } else {
19696 this._ids.add(_id8);
19697
19698 addedIds.push(_id8);
19699 }
19700 } else {
19701 if (this._ids.has(_id8)) {
19702 this._ids.delete(_id8);
19703
19704 removedIds.push(_id8);
19705 removedItems.push(params.oldData[_i11]);
19706 }
19707 }
19708 }
19709
19710 break;
19711
19712 case "remove":
19713 // filter the ids of the removed items
19714 for (var _i12 = 0, _len13 = ids.length; _i12 < _len13; _i12++) {
19715 var _id9 = ids[_i12];
19716
19717 if (this._ids.has(_id9)) {
19718 this._ids.delete(_id9);
19719
19720 removedIds.push(_id9);
19721 removedItems.push(params.oldData[_i12]);
19722 }
19723 }
19724
19725 break;
19726 }
19727
19728 this.length += addedIds.length - removedIds.length;
19729
19730 if (addedIds.length) {
19731 this._trigger("add", {
19732 items: addedIds
19733 }, senderId);
19734 }
19735
19736 if (updatedIds.length) {
19737 this._trigger("update", {
19738 items: updatedIds,
19739 oldData: oldItems,
19740 data: updatedItems
19741 }, senderId);
19742 }
19743
19744 if (removedIds.length) {
19745 this._trigger("remove", {
19746 items: removedIds,
19747 oldData: removedItems
19748 }, senderId);
19749 }
19750 }
19751 }]);
19752
19753 return DataView;
19754 }(DataSetPart);
19755 /**
19756 * Check that given value is compatible with Vis Data Set interface.
19757 *
19758 * @param idProp - The expected property to contain item id.
19759 * @param v - The value to be tested.
19760 * @returns True if all expected values and methods match, false otherwise.
19761 */
19762
19763
19764 function isDataSetLike(idProp, v) {
19765 return _typeof(v) === "object" && v !== null && idProp === v.idProp && typeof v.add === "function" && typeof v.clear === "function" && typeof v.distinct === "function" && typeof forEach$2(v) === "function" && typeof v.get === "function" && typeof v.getDataSet === "function" && typeof v.getIds === "function" && typeof v.length === "number" && typeof map$3(v) === "function" && typeof v.max === "function" && typeof v.min === "function" && typeof v.off === "function" && typeof v.on === "function" && typeof v.remove === "function" && typeof v.setOptions === "function" && typeof v.stream === "function" && typeof v.update === "function" && typeof v.updateOnly === "function";
19766 }
19767 /**
19768 * Check that given value is compatible with Vis Data View interface.
19769 *
19770 * @param idProp - The expected property to contain item id.
19771 * @param v - The value to be tested.
19772 * @returns True if all expected values and methods match, false otherwise.
19773 */
19774
19775
19776 function isDataViewLike(idProp, v) {
19777 return _typeof(v) === "object" && v !== null && idProp === v.idProp && typeof forEach$2(v) === "function" && typeof v.get === "function" && typeof v.getDataSet === "function" && typeof v.getIds === "function" && typeof v.length === "number" && typeof map$3(v) === "function" && typeof v.off === "function" && typeof v.on === "function" && typeof v.stream === "function" && isDataSetLike(idProp, v.getDataSet());
19778 }
19779
19780 var index = /*#__PURE__*/Object.freeze({
19781 __proto__: null,
19782 DELETE: DELETE,
19783 DataSet: DataSet,
19784 DataStream: DataStream,
19785 DataView: DataView,
19786 Queue: Queue,
19787 createNewDataPipeFrom: createNewDataPipeFrom,
19788 isDataSetLike: isDataSetLike,
19789 isDataViewLike: isDataViewLike
19790 });
19791
19792 var global$2 = global$P;
19793 var fails$1 = fails$t;
19794 var uncurryThis$2 = functionUncurryThis;
19795 var toString = toString$8;
19796 var trim = stringTrim.trim;
19797 var whitespaces = whitespaces$4;
19798 var charAt = uncurryThis$2(''.charAt);
19799 var n$ParseFloat = global$2.parseFloat;
19800 var Symbol$1 = global$2.Symbol;
19801 var ITERATOR = Symbol$1 && Symbol$1.iterator;
19802 var FORCED = 1 / n$ParseFloat(whitespaces + '-0') !== -Infinity // MS Edge 18- broken with boxed symbols
19803 || ITERATOR && !fails$1(function () {
19804 n$ParseFloat(Object(ITERATOR));
19805 }); // `parseFloat` method
19806 // https://tc39.es/ecma262/#sec-parsefloat-string
19807
19808 var numberParseFloat = FORCED ? function parseFloat(string) {
19809 var trimmedString = trim(toString(string));
19810 var result = n$ParseFloat(trimmedString);
19811 return result === 0 && charAt(trimmedString, 0) == '-' ? -0 : result;
19812 } : n$ParseFloat;
19813
19814 var $$4 = _export;
19815 var $parseFloat = numberParseFloat; // `parseFloat` method
19816 // https://tc39.es/ecma262/#sec-parsefloat-string
19817
19818 $$4({
19819 global: true,
19820 forced: parseFloat != $parseFloat
19821 }, {
19822 parseFloat: $parseFloat
19823 });
19824
19825 var path$5 = path$y;
19826 var _parseFloat$2 = path$5.parseFloat;
19827
19828 var parent$9 = _parseFloat$2;
19829 var _parseFloat$1 = parent$9;
19830
19831 var _parseFloat = _parseFloat$1;
19832
19833 var $$3 = _export;
19834 var fails = fails$t;
19835 var getOwnPropertyNames$3 = objectGetOwnPropertyNamesExternal.f; // eslint-disable-next-line es/no-object-getownpropertynames -- required for testing
19836
19837 var FAILS_ON_PRIMITIVES = fails(function () {
19838 return !Object.getOwnPropertyNames(1);
19839 }); // `Object.getOwnPropertyNames` method
19840 // https://tc39.es/ecma262/#sec-object.getownpropertynames
19841
19842 $$3({
19843 target: 'Object',
19844 stat: true,
19845 forced: FAILS_ON_PRIMITIVES
19846 }, {
19847 getOwnPropertyNames: getOwnPropertyNames$3
19848 });
19849
19850 var path$4 = path$y;
19851 var Object$1 = path$4.Object;
19852
19853 var getOwnPropertyNames$2 = function getOwnPropertyNames(it) {
19854 return Object$1.getOwnPropertyNames(it);
19855 };
19856
19857 var parent$8 = getOwnPropertyNames$2;
19858 var getOwnPropertyNames$1 = parent$8;
19859
19860 var getOwnPropertyNames = getOwnPropertyNames$1;
19861
19862 /**
19863 * Helper functions for components
19864 */
19865
19866 /**
19867 * Determine values to use for (sub)options of 'chosen'.
19868 *
19869 * This option is either a boolean or an object whose values should be examined further.
19870 * The relevant structures are:
19871 *
19872 * - chosen: <boolean value>
19873 * - chosen: { subOption: <boolean or function> }
19874 *
19875 * Where subOption is 'node', 'edge' or 'label'.
19876 *
19877 * The intention of this method appears to be to set a specific priority to the options;
19878 * Since most properties are either bridged or merged into the local options objects, there
19879 * is not much point in handling them separately.
19880 * TODO: examine if 'most' in previous sentence can be replaced with 'all'. In that case, we
19881 * should be able to get rid of this method.
19882 *
19883 * @param {string} subOption option within object 'chosen' to consider; either 'node', 'edge' or 'label'
19884 * @param {object} pile array of options objects to consider
19885 * @returns {boolean | Function} value for passed subOption of 'chosen' to use
19886 */
19887
19888 function choosify(subOption, pile) {
19889 // allowed values for subOption
19890 var allowed = ["node", "edge", "label"];
19891 var value = true;
19892 var chosen = topMost(pile, "chosen");
19893
19894 if (typeof chosen === "boolean") {
19895 value = chosen;
19896 } else if (_typeof(chosen) === "object") {
19897 if (indexOf(allowed).call(allowed, subOption) === -1) {
19898 throw new Error("choosify: subOption '" + subOption + "' should be one of " + "'" + allowed.join("', '") + "'");
19899 }
19900
19901 var chosenEdge = topMost(pile, ["chosen", subOption]);
19902
19903 if (typeof chosenEdge === "boolean" || typeof chosenEdge === "function") {
19904 value = chosenEdge;
19905 }
19906 }
19907
19908 return value;
19909 }
19910 /**
19911 * Check if the point falls within the given rectangle.
19912 *
19913 * @param {rect} rect
19914 * @param {point} point
19915 * @param {rotationPoint} [rotationPoint] if specified, the rotation that applies to the rectangle.
19916 * @returns {boolean} true if point within rectangle, false otherwise
19917 */
19918
19919 function pointInRect(rect, point, rotationPoint) {
19920 if (rect.width <= 0 || rect.height <= 0) {
19921 return false; // early out
19922 }
19923
19924 if (rotationPoint !== undefined) {
19925 // Rotate the point the same amount as the rectangle
19926 var tmp = {
19927 x: point.x - rotationPoint.x,
19928 y: point.y - rotationPoint.y
19929 };
19930
19931 if (rotationPoint.angle !== 0) {
19932 // In order to get the coordinates the same, you need to
19933 // rotate in the reverse direction
19934 var angle = -rotationPoint.angle;
19935 var tmp2 = {
19936 x: Math.cos(angle) * tmp.x - Math.sin(angle) * tmp.y,
19937 y: Math.sin(angle) * tmp.x + Math.cos(angle) * tmp.y
19938 };
19939 point = tmp2;
19940 } else {
19941 point = tmp;
19942 } // Note that if a rotation is specified, the rectangle coordinates
19943 // are **not* the full canvas coordinates. They are relative to the
19944 // rotationPoint. Hence, the point coordinates need not be translated
19945 // back in this case.
19946
19947 }
19948
19949 var right = rect.x + rect.width;
19950 var bottom = rect.y + rect.width;
19951 return rect.left < point.x && right > point.x && rect.top < point.y && bottom > point.y;
19952 }
19953 /**
19954 * Check if given value is acceptable as a label text.
19955 *
19956 * @param {*} text value to check; can be anything at this point
19957 * @returns {boolean} true if valid label value, false otherwise
19958 */
19959
19960 function isValidLabel(text) {
19961 // Note that this is quite strict: types that *might* be converted to string are disallowed
19962 return typeof text === "string" && text !== "";
19963 }
19964 /**
19965 * Returns x, y of self reference circle based on provided angle
19966 *
19967 * @param {object} ctx
19968 * @param {number} angle
19969 * @param {number} radius
19970 * @param {VisNode} node
19971 * @returns {object} x and y coordinates
19972 */
19973
19974 function getSelfRefCoordinates(ctx, angle, radius, node) {
19975 var x = node.x;
19976 var y = node.y;
19977
19978 if (typeof node.distanceToBorder === "function") {
19979 //calculating opposite and adjacent
19980 //distaneToBorder becomes Hypotenuse.
19981 //Formulas sin(a) = Opposite / Hypotenuse and cos(a) = Adjacent / Hypotenuse
19982 var toBorderDist = node.distanceToBorder(ctx, angle);
19983 var yFromNodeCenter = Math.sin(angle) * toBorderDist;
19984 var xFromNodeCenter = Math.cos(angle) * toBorderDist; //xFromNodeCenter is basically x and if xFromNodeCenter equals to the distance to border then it means
19985 //that y does not need calculation because it is equal node.height / 2 or node.y
19986 //same thing with yFromNodeCenter and if yFromNodeCenter equals to the distance to border then it means
19987 //that x is equal node.width / 2 or node.x
19988
19989 if (xFromNodeCenter === toBorderDist) {
19990 x += toBorderDist;
19991 y = node.y;
19992 } else if (yFromNodeCenter === toBorderDist) {
19993 x = node.x;
19994 y -= toBorderDist;
19995 } else {
19996 x += xFromNodeCenter;
19997 y -= yFromNodeCenter;
19998 }
19999 } else if (node.shape.width > node.shape.height) {
20000 x = node.x + node.shape.width * 0.5;
20001 y = node.y - radius;
20002 } else {
20003 x = node.x + radius;
20004 y = node.y - node.shape.height * 0.5;
20005 }
20006
20007 return {
20008 x: x,
20009 y: y
20010 };
20011 }
20012
20013 /**
20014 * Callback to determine text dimensions, using the parent label settings.
20015 *
20016 * @callback MeasureText
20017 * @param {text} text
20018 * @param {text} mod
20019 * @returns {object} { width, values} width in pixels and font attributes
20020 */
20021
20022 /**
20023 * Helper class for Label which collects results of splitting labels into lines and blocks.
20024 *
20025 * @private
20026 */
20027 var LabelAccumulator = /*#__PURE__*/function () {
20028 /**
20029 * @param {MeasureText} measureText
20030 */
20031 function LabelAccumulator(measureText) {
20032 _classCallCheck(this, LabelAccumulator);
20033
20034 this.measureText = measureText;
20035 this.current = 0;
20036 this.width = 0;
20037 this.height = 0;
20038 this.lines = [];
20039 }
20040 /**
20041 * Append given text to the given line.
20042 *
20043 * @param {number} l index of line to add to
20044 * @param {string} text string to append to line
20045 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
20046 * @private
20047 */
20048
20049
20050 _createClass(LabelAccumulator, [{
20051 key: "_add",
20052 value: function _add(l, text) {
20053 var mod = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "normal";
20054
20055 if (this.lines[l] === undefined) {
20056 this.lines[l] = {
20057 width: 0,
20058 height: 0,
20059 blocks: []
20060 };
20061 } // We still need to set a block for undefined and empty texts, hence return at this point
20062 // This is necessary because we don't know at this point if we're at the
20063 // start of an empty line or not.
20064 // To compensate, empty blocks are removed in `finalize()`.
20065 //
20066 // Empty strings should still have a height
20067
20068
20069 var tmpText = text;
20070 if (text === undefined || text === "") tmpText = " "; // Determine width and get the font properties
20071
20072 var result = this.measureText(tmpText, mod);
20073
20074 var block = assign$2({}, values(result));
20075
20076 block.text = text;
20077 block.width = result.width;
20078 block.mod = mod;
20079
20080 if (text === undefined || text === "") {
20081 block.width = 0;
20082 }
20083
20084 this.lines[l].blocks.push(block); // Update the line width. We need this for determining if a string goes over max width
20085
20086 this.lines[l].width += block.width;
20087 }
20088 /**
20089 * Returns the width in pixels of the current line.
20090 *
20091 * @returns {number}
20092 */
20093
20094 }, {
20095 key: "curWidth",
20096 value: function curWidth() {
20097 var line = this.lines[this.current];
20098 if (line === undefined) return 0;
20099 return line.width;
20100 }
20101 /**
20102 * Add text in block to current line
20103 *
20104 * @param {string} text
20105 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
20106 */
20107
20108 }, {
20109 key: "append",
20110 value: function append(text) {
20111 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "normal";
20112
20113 this._add(this.current, text, mod);
20114 }
20115 /**
20116 * Add text in block to current line and start a new line
20117 *
20118 * @param {string} text
20119 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
20120 */
20121
20122 }, {
20123 key: "newLine",
20124 value: function newLine(text) {
20125 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "normal";
20126
20127 this._add(this.current, text, mod);
20128
20129 this.current++;
20130 }
20131 /**
20132 * Determine and set the heights of all the lines currently contained in this instance
20133 *
20134 * Note that width has already been set.
20135 *
20136 * @private
20137 */
20138
20139 }, {
20140 key: "determineLineHeights",
20141 value: function determineLineHeights() {
20142 for (var k = 0; k < this.lines.length; k++) {
20143 var line = this.lines[k]; // Looking for max height of blocks in line
20144
20145 var height = 0;
20146
20147 if (line.blocks !== undefined) {
20148 // Can happen if text contains e.g. '\n '
20149 for (var l = 0; l < line.blocks.length; l++) {
20150 var block = line.blocks[l];
20151
20152 if (height < block.height) {
20153 height = block.height;
20154 }
20155 }
20156 }
20157
20158 line.height = height;
20159 }
20160 }
20161 /**
20162 * Determine the full size of the label text, as determined by current lines and blocks
20163 *
20164 * @private
20165 */
20166
20167 }, {
20168 key: "determineLabelSize",
20169 value: function determineLabelSize() {
20170 var width = 0;
20171 var height = 0;
20172
20173 for (var k = 0; k < this.lines.length; k++) {
20174 var line = this.lines[k];
20175
20176 if (line.width > width) {
20177 width = line.width;
20178 }
20179
20180 height += line.height;
20181 }
20182
20183 this.width = width;
20184 this.height = height;
20185 }
20186 /**
20187 * Remove all empty blocks and empty lines we don't need
20188 *
20189 * This must be done after the width/height determination,
20190 * so that these are set properly for processing here.
20191 *
20192 * @returns {Array<Line>} Lines with empty blocks (and some empty lines) removed
20193 * @private
20194 */
20195
20196 }, {
20197 key: "removeEmptyBlocks",
20198 value: function removeEmptyBlocks() {
20199 var tmpLines = [];
20200
20201 for (var k = 0; k < this.lines.length; k++) {
20202 var line = this.lines[k]; // Note: an empty line in between text has width zero but is still relevant to layout.
20203 // So we can't use width for testing empty line here
20204
20205 if (line.blocks.length === 0) continue; // Discard final empty line always
20206
20207 if (k === this.lines.length - 1) {
20208 if (line.width === 0) continue;
20209 }
20210
20211 var tmpLine = {};
20212
20213 assign$2(tmpLine, line);
20214
20215 tmpLine.blocks = [];
20216 var firstEmptyBlock = void 0;
20217 var tmpBlocks = [];
20218
20219 for (var l = 0; l < line.blocks.length; l++) {
20220 var block = line.blocks[l];
20221
20222 if (block.width !== 0) {
20223 tmpBlocks.push(block);
20224 } else {
20225 if (firstEmptyBlock === undefined) {
20226 firstEmptyBlock = block;
20227 }
20228 }
20229 } // Ensure that there is *some* text present
20230
20231
20232 if (tmpBlocks.length === 0 && firstEmptyBlock !== undefined) {
20233 tmpBlocks.push(firstEmptyBlock);
20234 }
20235
20236 tmpLine.blocks = tmpBlocks;
20237 tmpLines.push(tmpLine);
20238 }
20239
20240 return tmpLines;
20241 }
20242 /**
20243 * Set the sizes for all lines and the whole thing.
20244 *
20245 * @returns {{width: (number|*), height: (number|*), lines: Array}}
20246 */
20247
20248 }, {
20249 key: "finalize",
20250 value: function finalize() {
20251 //console.log(JSON.stringify(this.lines, null, 2));
20252 this.determineLineHeights();
20253 this.determineLabelSize();
20254 var tmpLines = this.removeEmptyBlocks(); // Return a simple hash object for further processing.
20255
20256 return {
20257 width: this.width,
20258 height: this.height,
20259 lines: tmpLines
20260 };
20261 }
20262 }]);
20263
20264 return LabelAccumulator;
20265 }();
20266
20267 var tagPattern = {
20268 // HTML
20269 "<b>": /<b>/,
20270 "<i>": /<i>/,
20271 "<code>": /<code>/,
20272 "</b>": /<\/b>/,
20273 "</i>": /<\/i>/,
20274 "</code>": /<\/code>/,
20275 // Markdown
20276 "*": /\*/,
20277 // bold
20278 _: /_/,
20279 // ital
20280 "`": /`/,
20281 // mono
20282 afterBold: /[^*]/,
20283 afterItal: /[^_]/,
20284 afterMono: /[^`]/
20285 };
20286 /**
20287 * Internal helper class for parsing the markup tags for HTML and Markdown.
20288 *
20289 * NOTE: Sequences of tabs and spaces are reduced to single space.
20290 * Scan usage of `this.spacing` within method
20291 */
20292
20293 var MarkupAccumulator = /*#__PURE__*/function () {
20294 /**
20295 * Create an instance
20296 *
20297 * @param {string} text text to parse for markup
20298 */
20299 function MarkupAccumulator(text) {
20300 _classCallCheck(this, MarkupAccumulator);
20301
20302 this.text = text;
20303 this.bold = false;
20304 this.ital = false;
20305 this.mono = false;
20306 this.spacing = false;
20307 this.position = 0;
20308 this.buffer = "";
20309 this.modStack = [];
20310 this.blocks = [];
20311 }
20312 /**
20313 * Return the mod label currently on the top of the stack
20314 *
20315 * @returns {string} label of topmost mod
20316 * @private
20317 */
20318
20319
20320 _createClass(MarkupAccumulator, [{
20321 key: "mod",
20322 value: function mod() {
20323 return this.modStack.length === 0 ? "normal" : this.modStack[0];
20324 }
20325 /**
20326 * Return the mod label currently active
20327 *
20328 * @returns {string} label of active mod
20329 * @private
20330 */
20331
20332 }, {
20333 key: "modName",
20334 value: function modName() {
20335 if (this.modStack.length === 0) return "normal";else if (this.modStack[0] === "mono") return "mono";else {
20336 if (this.bold && this.ital) {
20337 return "boldital";
20338 } else if (this.bold) {
20339 return "bold";
20340 } else if (this.ital) {
20341 return "ital";
20342 }
20343 }
20344 }
20345 /**
20346 * @private
20347 */
20348
20349 }, {
20350 key: "emitBlock",
20351 value: function emitBlock() {
20352 if (this.spacing) {
20353 this.add(" ");
20354 this.spacing = false;
20355 }
20356
20357 if (this.buffer.length > 0) {
20358 this.blocks.push({
20359 text: this.buffer,
20360 mod: this.modName()
20361 });
20362 this.buffer = "";
20363 }
20364 }
20365 /**
20366 * Output text to buffer
20367 *
20368 * @param {string} text text to add
20369 * @private
20370 */
20371
20372 }, {
20373 key: "add",
20374 value: function add(text) {
20375 if (text === " ") {
20376 this.spacing = true;
20377 }
20378
20379 if (this.spacing) {
20380 this.buffer += " ";
20381 this.spacing = false;
20382 }
20383
20384 if (text != " ") {
20385 this.buffer += text;
20386 }
20387 }
20388 /**
20389 * Handle parsing of whitespace
20390 *
20391 * @param {string} ch the character to check
20392 * @returns {boolean} true if the character was processed as whitespace, false otherwise
20393 */
20394
20395 }, {
20396 key: "parseWS",
20397 value: function parseWS(ch) {
20398 if (/[ \t]/.test(ch)) {
20399 if (!this.mono) {
20400 this.spacing = true;
20401 } else {
20402 this.add(ch);
20403 }
20404
20405 return true;
20406 }
20407
20408 return false;
20409 }
20410 /**
20411 * @param {string} tagName label for block type to set
20412 * @private
20413 */
20414
20415 }, {
20416 key: "setTag",
20417 value: function setTag(tagName) {
20418 this.emitBlock();
20419 this[tagName] = true;
20420 this.modStack.unshift(tagName);
20421 }
20422 /**
20423 * @param {string} tagName label for block type to unset
20424 * @private
20425 */
20426
20427 }, {
20428 key: "unsetTag",
20429 value: function unsetTag(tagName) {
20430 this.emitBlock();
20431 this[tagName] = false;
20432 this.modStack.shift();
20433 }
20434 /**
20435 * @param {string} tagName label for block type we are currently processing
20436 * @param {string|RegExp} tag string to match in text
20437 * @returns {boolean} true if the tag was processed, false otherwise
20438 */
20439
20440 }, {
20441 key: "parseStartTag",
20442 value: function parseStartTag(tagName, tag) {
20443 // Note: if 'mono' passed as tagName, there is a double check here. This is OK
20444 if (!this.mono && !this[tagName] && this.match(tag)) {
20445 this.setTag(tagName);
20446 return true;
20447 }
20448
20449 return false;
20450 }
20451 /**
20452 * @param {string|RegExp} tag
20453 * @param {number} [advance=true] if set, advance current position in text
20454 * @returns {boolean} true if match at given position, false otherwise
20455 * @private
20456 */
20457
20458 }, {
20459 key: "match",
20460 value: function match(tag) {
20461 var advance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
20462
20463 var _this$prepareRegExp = this.prepareRegExp(tag),
20464 _this$prepareRegExp2 = _slicedToArray(_this$prepareRegExp, 2),
20465 regExp = _this$prepareRegExp2[0],
20466 length = _this$prepareRegExp2[1];
20467
20468 var matched = regExp.test(this.text.substr(this.position, length));
20469
20470 if (matched && advance) {
20471 this.position += length - 1;
20472 }
20473
20474 return matched;
20475 }
20476 /**
20477 * @param {string} tagName label for block type we are currently processing
20478 * @param {string|RegExp} tag string to match in text
20479 * @param {RegExp} [nextTag] regular expression to match for characters *following* the current tag
20480 * @returns {boolean} true if the tag was processed, false otherwise
20481 */
20482
20483 }, {
20484 key: "parseEndTag",
20485 value: function parseEndTag(tagName, tag, nextTag) {
20486 var checkTag = this.mod() === tagName;
20487
20488 if (tagName === "mono") {
20489 // special handling for 'mono'
20490 checkTag = checkTag && this.mono;
20491 } else {
20492 checkTag = checkTag && !this.mono;
20493 }
20494
20495 if (checkTag && this.match(tag)) {
20496 if (nextTag !== undefined) {
20497 // Purpose of the following match is to prevent a direct unset/set of a given tag
20498 // E.g. '*bold **still bold*' => '*bold still bold*'
20499 if (this.position === this.text.length - 1 || this.match(nextTag, false)) {
20500 this.unsetTag(tagName);
20501 }
20502 } else {
20503 this.unsetTag(tagName);
20504 }
20505
20506 return true;
20507 }
20508
20509 return false;
20510 }
20511 /**
20512 * @param {string|RegExp} tag string to match in text
20513 * @param {value} value string to replace tag with, if found at current position
20514 * @returns {boolean} true if the tag was processed, false otherwise
20515 */
20516
20517 }, {
20518 key: "replace",
20519 value: function replace(tag, value) {
20520 if (this.match(tag)) {
20521 this.add(value);
20522 this.position += length - 1;
20523 return true;
20524 }
20525
20526 return false;
20527 }
20528 /**
20529 * Create a regular expression for the tag if it isn't already one.
20530 *
20531 * The return value is an array `[RegExp, number]`, with exactly two value, where:
20532 * - RegExp is the regular expression to use
20533 * - number is the lenth of the input string to match
20534 *
20535 * @param {string|RegExp} tag string to match in text
20536 * @returns {Array} regular expression to use and length of input string to match
20537 * @private
20538 */
20539
20540 }, {
20541 key: "prepareRegExp",
20542 value: function prepareRegExp(tag) {
20543 var length;
20544 var regExp;
20545
20546 if (tag instanceof RegExp) {
20547 regExp = tag;
20548 length = 1; // ASSUMPTION: regexp only tests one character
20549 } else {
20550 // use prepared regexp if present
20551 var prepared = tagPattern[tag];
20552
20553 if (prepared !== undefined) {
20554 regExp = prepared;
20555 } else {
20556 regExp = new RegExp(tag);
20557 }
20558
20559 length = tag.length;
20560 }
20561
20562 return [regExp, length];
20563 }
20564 }]);
20565
20566 return MarkupAccumulator;
20567 }();
20568 /**
20569 * Helper class for Label which explodes the label text into lines and blocks within lines
20570 *
20571 * @private
20572 */
20573
20574
20575 var LabelSplitter = /*#__PURE__*/function () {
20576 /**
20577 * @param {CanvasRenderingContext2D} ctx Canvas rendering context
20578 * @param {Label} parent reference to the Label instance using current instance
20579 * @param {boolean} selected
20580 * @param {boolean} hover
20581 */
20582 function LabelSplitter(ctx, parent, selected, hover) {
20583 var _this = this;
20584
20585 _classCallCheck(this, LabelSplitter);
20586
20587 this.ctx = ctx;
20588 this.parent = parent;
20589 this.selected = selected;
20590 this.hover = hover;
20591 /**
20592 * Callback to determine text width; passed to LabelAccumulator instance
20593 *
20594 * @param {string} text string to determine width of
20595 * @param {string} mod font type to use for this text
20596 * @returns {object} { width, values} width in pixels and font attributes
20597 */
20598
20599 var textWidth = function textWidth(text, mod) {
20600 if (text === undefined) return 0; // TODO: This can be done more efficiently with caching
20601 // This will set the ctx.font correctly, depending on selected/hover and mod - so that ctx.measureText() will be accurate.
20602
20603 var values = _this.parent.getFormattingValues(ctx, selected, hover, mod);
20604
20605 var width = 0;
20606
20607 if (text !== "") {
20608 var measure = _this.ctx.measureText(text);
20609
20610 width = measure.width;
20611 }
20612
20613 return {
20614 width: width,
20615 values: values
20616 };
20617 };
20618
20619 this.lines = new LabelAccumulator(textWidth);
20620 }
20621 /**
20622 * Split passed text of a label into lines and blocks.
20623 *
20624 * # NOTE
20625 *
20626 * The handling of spacing is option dependent:
20627 *
20628 * - if `font.multi : false`, all spaces are retained
20629 * - if `font.multi : true`, every sequence of spaces is compressed to a single space
20630 *
20631 * This might not be the best way to do it, but this is as it has been working till now.
20632 * In order not to break existing functionality, for the time being this behaviour will
20633 * be retained in any code changes.
20634 *
20635 * @param {string} text text to split
20636 * @returns {Array<line>}
20637 */
20638
20639
20640 _createClass(LabelSplitter, [{
20641 key: "process",
20642 value: function process(text) {
20643 if (!isValidLabel(text)) {
20644 return this.lines.finalize();
20645 }
20646
20647 var font = this.parent.fontOptions; // Normalize the end-of-line's to a single representation - order important
20648
20649 text = text.replace(/\r\n/g, "\n"); // Dos EOL's
20650
20651 text = text.replace(/\r/g, "\n"); // Mac EOL's
20652 // Note that at this point, there can be no \r's in the text.
20653 // This is used later on splitStringIntoLines() to split multifont texts.
20654
20655 var nlLines = String(text).split("\n");
20656 var lineCount = nlLines.length;
20657
20658 if (font.multi) {
20659 // Multi-font case: styling tags active
20660 for (var i = 0; i < lineCount; i++) {
20661 var blocks = this.splitBlocks(nlLines[i], font.multi); // Post: Sequences of tabs and spaces are reduced to single space
20662
20663 if (blocks === undefined) continue;
20664
20665 if (blocks.length === 0) {
20666 this.lines.newLine("");
20667 continue;
20668 }
20669
20670 if (font.maxWdt > 0) {
20671 // widthConstraint.maximum defined
20672 //console.log('Running widthConstraint multi, max: ' + this.fontOptions.maxWdt);
20673 for (var j = 0; j < blocks.length; j++) {
20674 var mod = blocks[j].mod;
20675 var _text = blocks[j].text;
20676 this.splitStringIntoLines(_text, mod, true);
20677 }
20678 } else {
20679 // widthConstraint.maximum NOT defined
20680 for (var _j = 0; _j < blocks.length; _j++) {
20681 var _mod = blocks[_j].mod;
20682 var _text2 = blocks[_j].text;
20683 this.lines.append(_text2, _mod);
20684 }
20685 }
20686
20687 this.lines.newLine();
20688 }
20689 } else {
20690 // Single-font case
20691 if (font.maxWdt > 0) {
20692 // widthConstraint.maximum defined
20693 // console.log('Running widthConstraint normal, max: ' + this.fontOptions.maxWdt);
20694 for (var _i = 0; _i < lineCount; _i++) {
20695 this.splitStringIntoLines(nlLines[_i]);
20696 }
20697 } else {
20698 // widthConstraint.maximum NOT defined
20699 for (var _i2 = 0; _i2 < lineCount; _i2++) {
20700 this.lines.newLine(nlLines[_i2]);
20701 }
20702 }
20703 }
20704
20705 return this.lines.finalize();
20706 }
20707 /**
20708 * normalize the markup system
20709 *
20710 * @param {boolean|'md'|'markdown'|'html'} markupSystem
20711 * @returns {string}
20712 */
20713
20714 }, {
20715 key: "decodeMarkupSystem",
20716 value: function decodeMarkupSystem(markupSystem) {
20717 var system = "none";
20718
20719 if (markupSystem === "markdown" || markupSystem === "md") {
20720 system = "markdown";
20721 } else if (markupSystem === true || markupSystem === "html") {
20722 system = "html";
20723 }
20724
20725 return system;
20726 }
20727 /**
20728 *
20729 * @param {string} text
20730 * @returns {Array}
20731 */
20732
20733 }, {
20734 key: "splitHtmlBlocks",
20735 value: function splitHtmlBlocks(text) {
20736 var s = new MarkupAccumulator(text);
20737
20738 var parseEntities = function parseEntities(ch) {
20739 if (/&/.test(ch)) {
20740 var parsed = s.replace(s.text, "&lt;", "<") || s.replace(s.text, "&amp;", "&");
20741
20742 if (!parsed) {
20743 s.add("&");
20744 }
20745
20746 return true;
20747 }
20748
20749 return false;
20750 };
20751
20752 while (s.position < s.text.length) {
20753 var ch = s.text.charAt(s.position);
20754 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);
20755
20756 if (!parsed) {
20757 s.add(ch);
20758 }
20759
20760 s.position++;
20761 }
20762
20763 s.emitBlock();
20764 return s.blocks;
20765 }
20766 /**
20767 *
20768 * @param {string} text
20769 * @returns {Array}
20770 */
20771
20772 }, {
20773 key: "splitMarkdownBlocks",
20774 value: function splitMarkdownBlocks(text) {
20775 var _this2 = this;
20776
20777 var s = new MarkupAccumulator(text);
20778 var beginable = true;
20779
20780 var parseOverride = function parseOverride(ch) {
20781 if (/\\/.test(ch)) {
20782 if (s.position < _this2.text.length + 1) {
20783 s.position++;
20784 ch = _this2.text.charAt(s.position);
20785
20786 if (/ \t/.test(ch)) {
20787 s.spacing = true;
20788 } else {
20789 s.add(ch);
20790 beginable = false;
20791 }
20792 }
20793
20794 return true;
20795 }
20796
20797 return false;
20798 };
20799
20800 while (s.position < s.text.length) {
20801 var ch = s.text.charAt(s.position);
20802 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");
20803
20804 if (!parsed) {
20805 s.add(ch);
20806 beginable = false;
20807 }
20808
20809 s.position++;
20810 }
20811
20812 s.emitBlock();
20813 return s.blocks;
20814 }
20815 /**
20816 * Explodes a piece of text into single-font blocks using a given markup
20817 *
20818 * @param {string} text
20819 * @param {boolean|'md'|'markdown'|'html'} markupSystem
20820 * @returns {Array.<{text: string, mod: string}>}
20821 * @private
20822 */
20823
20824 }, {
20825 key: "splitBlocks",
20826 value: function splitBlocks(text, markupSystem) {
20827 var system = this.decodeMarkupSystem(markupSystem);
20828
20829 if (system === "none") {
20830 return [{
20831 text: text,
20832 mod: "normal"
20833 }];
20834 } else if (system === "markdown") {
20835 return this.splitMarkdownBlocks(text);
20836 } else if (system === "html") {
20837 return this.splitHtmlBlocks(text);
20838 }
20839 }
20840 /**
20841 * @param {string} text
20842 * @returns {boolean} true if text length over the current max with
20843 * @private
20844 */
20845
20846 }, {
20847 key: "overMaxWidth",
20848 value: function overMaxWidth(text) {
20849 var width = this.ctx.measureText(text).width;
20850 return this.lines.curWidth() + width > this.parent.fontOptions.maxWdt;
20851 }
20852 /**
20853 * Determine the longest part of the sentence which still fits in the
20854 * current max width.
20855 *
20856 * @param {Array} words Array of strings signifying a text lines
20857 * @returns {number} index of first item in string making string go over max
20858 * @private
20859 */
20860
20861 }, {
20862 key: "getLongestFit",
20863 value: function getLongestFit(words) {
20864 var text = "";
20865 var w = 0;
20866
20867 while (w < words.length) {
20868 var pre = text === "" ? "" : " ";
20869 var newText = text + pre + words[w];
20870 if (this.overMaxWidth(newText)) break;
20871 text = newText;
20872 w++;
20873 }
20874
20875 return w;
20876 }
20877 /**
20878 * Determine the longest part of the string which still fits in the
20879 * current max width.
20880 *
20881 * @param {Array} words Array of strings signifying a text lines
20882 * @returns {number} index of first item in string making string go over max
20883 */
20884
20885 }, {
20886 key: "getLongestFitWord",
20887 value: function getLongestFitWord(words) {
20888 var w = 0;
20889
20890 while (w < words.length) {
20891 if (this.overMaxWidth(slice(words).call(words, 0, w))) break;
20892 w++;
20893 }
20894
20895 return w;
20896 }
20897 /**
20898 * Split the passed text into lines, according to width constraint (if any).
20899 *
20900 * The method assumes that the input string is a single line, i.e. without lines break.
20901 *
20902 * This method retains spaces, if still present (case `font.multi: false`).
20903 * A space which falls on an internal line break, will be replaced by a newline.
20904 * There is no special handling of tabs; these go along with the flow.
20905 *
20906 * @param {string} str
20907 * @param {string} [mod='normal']
20908 * @param {boolean} [appendLast=false]
20909 * @private
20910 */
20911
20912 }, {
20913 key: "splitStringIntoLines",
20914 value: function splitStringIntoLines(str) {
20915 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "normal";
20916 var appendLast = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
20917 // Set the canvas context font, based upon the current selected/hover state
20918 // and the provided mod, so the text measurement performed by getLongestFit
20919 // will be accurate - and not just use the font of whoever last used the canvas.
20920 this.parent.getFormattingValues(this.ctx, this.selected, this.hover, mod); // Still-present spaces are relevant, retain them
20921
20922 str = str.replace(/^( +)/g, "$1\r");
20923 str = str.replace(/([^\r][^ ]*)( +)/g, "$1\r$2\r");
20924 var words = str.split("\r");
20925
20926 while (words.length > 0) {
20927 var w = this.getLongestFit(words);
20928
20929 if (w === 0) {
20930 // Special case: the first word is already larger than the max width.
20931 var word = words[0]; // Break the word to the largest part that fits the line
20932
20933 var x = this.getLongestFitWord(word);
20934 this.lines.newLine(slice(word).call(word, 0, x), mod); // Adjust the word, so that the rest will be done next iteration
20935
20936 words[0] = slice(word).call(word, x);
20937 } else {
20938 // skip any space that is replaced by a newline
20939 var newW = w;
20940
20941 if (words[w - 1] === " ") {
20942 w--;
20943 } else if (words[newW] === " ") {
20944 newW++;
20945 }
20946
20947 var text = slice(words).call(words, 0, w).join("");
20948
20949 if (w == words.length && appendLast) {
20950 this.lines.append(text, mod);
20951 } else {
20952 this.lines.newLine(text, mod);
20953 } // Adjust the word, so that the rest will be done next iteration
20954
20955
20956 words = slice(words).call(words, newW);
20957 }
20958 }
20959 }
20960 }]);
20961
20962 return LabelSplitter;
20963 }();
20964
20965 /**
20966 * List of special styles for multi-fonts
20967 *
20968 * @private
20969 */
20970
20971 var multiFontStyle = ["bold", "ital", "boldital", "mono"];
20972 /**
20973 * A Label to be used for Nodes or Edges.
20974 */
20975
20976 var Label = /*#__PURE__*/function () {
20977 /**
20978 * @param {object} body
20979 * @param {object} options
20980 * @param {boolean} [edgelabel=false]
20981 */
20982 function Label(body, options) {
20983 var edgelabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
20984
20985 _classCallCheck(this, Label);
20986
20987 this.body = body;
20988 this.pointToSelf = false;
20989 this.baseSize = undefined;
20990 this.fontOptions = {}; // instance variable containing the *instance-local* font options
20991
20992 this.setOptions(options);
20993 this.size = {
20994 top: 0,
20995 left: 0,
20996 width: 0,
20997 height: 0,
20998 yLine: 0
20999 };
21000 this.isEdgeLabel = edgelabel;
21001 }
21002 /**
21003 * @param {object} options the options of the parent Node-instance
21004 */
21005
21006
21007 _createClass(Label, [{
21008 key: "setOptions",
21009 value: function setOptions(options) {
21010 this.elementOptions = options; // Reference to the options of the parent Node-instance
21011
21012 this.initFontOptions(options.font);
21013
21014 if (isValidLabel(options.label)) {
21015 this.labelDirty = true;
21016 } else {
21017 // Bad label! Change the option value to prevent bad stuff happening
21018 options.label = undefined;
21019 }
21020
21021 if (options.font !== undefined && options.font !== null) {
21022 // font options can be deleted at various levels
21023 if (typeof options.font === "string") {
21024 this.baseSize = this.fontOptions.size;
21025 } else if (_typeof(options.font) === "object") {
21026 var size = options.font.size;
21027
21028 if (size !== undefined) {
21029 this.baseSize = size;
21030 }
21031 }
21032 }
21033 }
21034 /**
21035 * Init the font Options structure.
21036 *
21037 * Member fontOptions serves as an accumulator for the current font options.
21038 * As such, it needs to be completely separated from the node options.
21039 *
21040 * @param {object} newFontOptions the new font options to process
21041 * @private
21042 */
21043
21044 }, {
21045 key: "initFontOptions",
21046 value: function initFontOptions(newFontOptions) {
21047 var _this = this;
21048
21049 // Prepare the multi-font option objects.
21050 // These will be filled in propagateFonts(), if required
21051 forEach$1(multiFontStyle, function (style) {
21052 _this.fontOptions[style] = {};
21053 }); // Handle shorthand option, if present
21054
21055 if (Label.parseFontString(this.fontOptions, newFontOptions)) {
21056 this.fontOptions.vadjust = 0;
21057 return;
21058 } // Copy over the non-multifont options, if specified
21059
21060
21061 forEach$1(newFontOptions, function (prop, n) {
21062 if (prop !== undefined && prop !== null && _typeof(prop) !== "object") {
21063 _this.fontOptions[n] = prop;
21064 }
21065 });
21066 }
21067 /**
21068 * If in-variable is a string, parse it as a font specifier.
21069 *
21070 * Note that following is not done here and have to be done after the call:
21071 * - Not all font options are set (vadjust, mod)
21072 *
21073 * @param {object} outOptions out-parameter, object in which to store the parse results (if any)
21074 * @param {object} inOptions font options to parse
21075 * @returns {boolean} true if font parsed as string, false otherwise
21076 * @static
21077 */
21078
21079 }, {
21080 key: "constrain",
21081 value:
21082 /**
21083 * Set the width and height constraints based on 'nearest' value
21084 *
21085 * @param {Array} pile array of option objects to consider
21086 * @returns {object} the actual constraint values to use
21087 * @private
21088 */
21089 function constrain(pile) {
21090 // NOTE: constrainWidth and constrainHeight never set!
21091 // NOTE: for edge labels, only 'maxWdt' set
21092 // Node labels can set all the fields
21093 var fontOptions = {
21094 constrainWidth: false,
21095 maxWdt: -1,
21096 minWdt: -1,
21097 constrainHeight: false,
21098 minHgt: -1,
21099 valign: "middle"
21100 };
21101 var widthConstraint = topMost(pile, "widthConstraint");
21102
21103 if (typeof widthConstraint === "number") {
21104 fontOptions.maxWdt = Number(widthConstraint);
21105 fontOptions.minWdt = Number(widthConstraint);
21106 } else if (_typeof(widthConstraint) === "object") {
21107 var widthConstraintMaximum = topMost(pile, ["widthConstraint", "maximum"]);
21108
21109 if (typeof widthConstraintMaximum === "number") {
21110 fontOptions.maxWdt = Number(widthConstraintMaximum);
21111 }
21112
21113 var widthConstraintMinimum = topMost(pile, ["widthConstraint", "minimum"]);
21114
21115 if (typeof widthConstraintMinimum === "number") {
21116 fontOptions.minWdt = Number(widthConstraintMinimum);
21117 }
21118 }
21119
21120 var heightConstraint = topMost(pile, "heightConstraint");
21121
21122 if (typeof heightConstraint === "number") {
21123 fontOptions.minHgt = Number(heightConstraint);
21124 } else if (_typeof(heightConstraint) === "object") {
21125 var heightConstraintMinimum = topMost(pile, ["heightConstraint", "minimum"]);
21126
21127 if (typeof heightConstraintMinimum === "number") {
21128 fontOptions.minHgt = Number(heightConstraintMinimum);
21129 }
21130
21131 var heightConstraintValign = topMost(pile, ["heightConstraint", "valign"]);
21132
21133 if (typeof heightConstraintValign === "string") {
21134 if (heightConstraintValign === "top" || heightConstraintValign === "bottom") {
21135 fontOptions.valign = heightConstraintValign;
21136 }
21137 }
21138 }
21139
21140 return fontOptions;
21141 }
21142 /**
21143 * Set options and update internal state
21144 *
21145 * @param {object} options options to set
21146 * @param {Array} pile array of option objects to consider for option 'chosen'
21147 */
21148
21149 }, {
21150 key: "update",
21151 value: function update(options, pile) {
21152 this.setOptions(options, true);
21153 this.propagateFonts(pile);
21154 deepExtend(this.fontOptions, this.constrain(pile));
21155 this.fontOptions.chooser = choosify("label", pile);
21156 }
21157 /**
21158 * When margins are set in an element, adjust sizes is called to remove them
21159 * from the width/height constraints. This must be done prior to label sizing.
21160 *
21161 * @param {{top: number, right: number, bottom: number, left: number}} margins
21162 */
21163
21164 }, {
21165 key: "adjustSizes",
21166 value: function adjustSizes(margins) {
21167 var widthBias = margins ? margins.right + margins.left : 0;
21168
21169 if (this.fontOptions.constrainWidth) {
21170 this.fontOptions.maxWdt -= widthBias;
21171 this.fontOptions.minWdt -= widthBias;
21172 }
21173
21174 var heightBias = margins ? margins.top + margins.bottom : 0;
21175
21176 if (this.fontOptions.constrainHeight) {
21177 this.fontOptions.minHgt -= heightBias;
21178 }
21179 } /////////////////////////////////////////////////////////
21180 // Methods for handling options piles
21181 // Eventually, these will be moved to a separate class
21182 /////////////////////////////////////////////////////////
21183
21184 /**
21185 * Add the font members of the passed list of option objects to the pile.
21186 *
21187 * @param {Pile} dstPile pile of option objects add to
21188 * @param {Pile} srcPile pile of option objects to take font options from
21189 * @private
21190 */
21191
21192 }, {
21193 key: "addFontOptionsToPile",
21194 value: function addFontOptionsToPile(dstPile, srcPile) {
21195 for (var i = 0; i < srcPile.length; ++i) {
21196 this.addFontToPile(dstPile, srcPile[i]);
21197 }
21198 }
21199 /**
21200 * Add given font option object to the list of objects (the 'pile') to consider for determining
21201 * multi-font option values.
21202 *
21203 * @param {Pile} pile pile of option objects to use
21204 * @param {object} options instance to add to pile
21205 * @private
21206 */
21207
21208 }, {
21209 key: "addFontToPile",
21210 value: function addFontToPile(pile, options) {
21211 if (options === undefined) return;
21212 if (options.font === undefined || options.font === null) return;
21213 var item = options.font;
21214 pile.push(item);
21215 }
21216 /**
21217 * Collect all own-property values from the font pile that aren't multi-font option objectss.
21218 *
21219 * @param {Pile} pile pile of option objects to use
21220 * @returns {object} object with all current own basic font properties
21221 * @private
21222 */
21223
21224 }, {
21225 key: "getBasicOptions",
21226 value: function getBasicOptions(pile) {
21227 var ret = {}; // Scans the whole pile to get all options present
21228
21229 for (var n = 0; n < pile.length; ++n) {
21230 var fontOptions = pile[n]; // Convert shorthand if necessary
21231
21232 var tmpShorthand = {};
21233
21234 if (Label.parseFontString(tmpShorthand, fontOptions)) {
21235 fontOptions = tmpShorthand;
21236 }
21237
21238 forEach$1(fontOptions, function (opt, name) {
21239 if (opt === undefined) return; // multi-font option need not be present
21240
21241 if (Object.prototype.hasOwnProperty.call(ret, name)) return; // Keep first value we encounter
21242
21243 if (indexOf(multiFontStyle).call(multiFontStyle, name) !== -1) {
21244 // Skip multi-font properties but we do need the structure
21245 ret[name] = {};
21246 } else {
21247 ret[name] = opt;
21248 }
21249 });
21250 }
21251
21252 return ret;
21253 }
21254 /**
21255 * Return the value for given option for the given multi-font.
21256 *
21257 * All available option objects are trawled in the set order to construct the option values.
21258 *
21259 * ---------------------------------------------------------------------
21260 * ## Traversal of pile for multi-fonts
21261 *
21262 * The determination of multi-font option values is a special case, because any values not
21263 * present in the multi-font options should by definition be taken from the main font options,
21264 * i.e. from the current 'parent' object of the multi-font option.
21265 *
21266 * ### Search order for multi-fonts
21267 *
21268 * 'bold' used as example:
21269 *
21270 * - search in option group 'bold' in local properties
21271 * - search in main font option group in local properties
21272 *
21273 * ---------------------------------------------------------------------
21274 *
21275 * @param {Pile} pile pile of option objects to use
21276 * @param {MultiFontStyle} multiName sub path for the multi-font
21277 * @param {string} option the option to search for, for the given multi-font
21278 * @returns {string|number} the value for the given option
21279 * @private
21280 */
21281
21282 }, {
21283 key: "getFontOption",
21284 value: function getFontOption(pile, multiName, option) {
21285 var multiFont; // Search multi font in local properties
21286
21287 for (var n = 0; n < pile.length; ++n) {
21288 var fontOptions = pile[n];
21289
21290 if (Object.prototype.hasOwnProperty.call(fontOptions, multiName)) {
21291 multiFont = fontOptions[multiName];
21292 if (multiFont === undefined || multiFont === null) continue; // Convert shorthand if necessary
21293 // TODO: inefficient to do this conversion every time; find a better way.
21294
21295 var tmpShorthand = {};
21296
21297 if (Label.parseFontString(tmpShorthand, multiFont)) {
21298 multiFont = tmpShorthand;
21299 }
21300
21301 if (Object.prototype.hasOwnProperty.call(multiFont, option)) {
21302 return multiFont[option];
21303 }
21304 }
21305 } // Option is not mentioned in the multi font options; take it from the parent font options.
21306 // These have already been converted with getBasicOptions(), so use the converted values.
21307
21308
21309 if (Object.prototype.hasOwnProperty.call(this.fontOptions, option)) {
21310 return this.fontOptions[option];
21311 } // A value **must** be found; you should never get here.
21312
21313
21314 throw new Error("Did not find value for multi-font for property: '" + option + "'");
21315 }
21316 /**
21317 * Return all options values for the given multi-font.
21318 *
21319 * All available option objects are trawled in the set order to construct the option values.
21320 *
21321 * @param {Pile} pile pile of option objects to use
21322 * @param {MultiFontStyle} multiName sub path for the mod-font
21323 * @returns {MultiFontOptions}
21324 * @private
21325 */
21326
21327 }, {
21328 key: "getFontOptions",
21329 value: function getFontOptions(pile, multiName) {
21330 var result = {};
21331 var optionNames = ["color", "size", "face", "mod", "vadjust"]; // List of allowed options per multi-font
21332
21333 for (var i = 0; i < optionNames.length; ++i) {
21334 var mod = optionNames[i];
21335 result[mod] = this.getFontOption(pile, multiName, mod);
21336 }
21337
21338 return result;
21339 } /////////////////////////////////////////////////////////
21340 // End methods for handling options piles
21341 /////////////////////////////////////////////////////////
21342
21343 /**
21344 * Collapse the font options for the multi-font to single objects, from
21345 * the chain of option objects passed (the 'pile').
21346 *
21347 * @param {Pile} pile sequence of option objects to consider.
21348 * First item in list assumed to be the newly set options.
21349 */
21350
21351 }, {
21352 key: "propagateFonts",
21353 value: function propagateFonts(pile) {
21354 var _this2 = this;
21355
21356 var fontPile = []; // sequence of font objects to consider, order important
21357 // Note that this.elementOptions is not used here.
21358
21359 this.addFontOptionsToPile(fontPile, pile);
21360 this.fontOptions = this.getBasicOptions(fontPile); // We set multifont values even if multi === false, for consistency (things break otherwise)
21361
21362 var _loop = function _loop(i) {
21363 var mod = multiFontStyle[i];
21364 var modOptions = _this2.fontOptions[mod];
21365
21366 var tmpMultiFontOptions = _this2.getFontOptions(fontPile, mod); // Copy over found values
21367
21368
21369 forEach$1(tmpMultiFontOptions, function (option, n) {
21370 modOptions[n] = option;
21371 });
21372 modOptions.size = Number(modOptions.size);
21373 modOptions.vadjust = Number(modOptions.vadjust);
21374 };
21375
21376 for (var i = 0; i < multiFontStyle.length; ++i) {
21377 _loop(i);
21378 }
21379 }
21380 /**
21381 * Main function. This is called from anything that wants to draw a label.
21382 *
21383 * @param {CanvasRenderingContext2D} ctx
21384 * @param {number} x
21385 * @param {number} y
21386 * @param {boolean} selected
21387 * @param {boolean} hover
21388 * @param {string} [baseline='middle']
21389 */
21390
21391 }, {
21392 key: "draw",
21393 value: function draw(ctx, x, y, selected, hover) {
21394 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : "middle";
21395 // if no label, return
21396 if (this.elementOptions.label === undefined) return; // check if we have to render the label
21397
21398 var viewFontSize = this.fontOptions.size * this.body.view.scale;
21399 if (this.elementOptions.label && viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) return; // This ensures that there will not be HUGE letters on screen
21400 // by setting an upper limit on the visible text size (regardless of zoomLevel)
21401
21402 if (viewFontSize >= this.elementOptions.scaling.label.maxVisible) {
21403 viewFontSize = Number(this.elementOptions.scaling.label.maxVisible) / this.body.view.scale;
21404 } // update the size cache if required
21405
21406
21407 this.calculateLabelSize(ctx, selected, hover, x, y, baseline);
21408
21409 this._drawBackground(ctx);
21410
21411 this._drawText(ctx, x, this.size.yLine, baseline, viewFontSize);
21412 }
21413 /**
21414 * Draws the label background
21415 *
21416 * @param {CanvasRenderingContext2D} ctx
21417 * @private
21418 */
21419
21420 }, {
21421 key: "_drawBackground",
21422 value: function _drawBackground(ctx) {
21423 if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") {
21424 ctx.fillStyle = this.fontOptions.background;
21425 var size = this.getSize();
21426 ctx.fillRect(size.left, size.top, size.width, size.height);
21427 }
21428 }
21429 /**
21430 *
21431 * @param {CanvasRenderingContext2D} ctx
21432 * @param {number} x
21433 * @param {number} y
21434 * @param {string} [baseline='middle']
21435 * @param {number} viewFontSize
21436 * @private
21437 */
21438
21439 }, {
21440 key: "_drawText",
21441 value: function _drawText(ctx, x, y) {
21442 var baseline = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "middle";
21443 var viewFontSize = arguments.length > 4 ? arguments[4] : undefined;
21444
21445 var _this$_setAlignment = this._setAlignment(ctx, x, y, baseline);
21446
21447 var _this$_setAlignment2 = _slicedToArray(_this$_setAlignment, 2);
21448
21449 x = _this$_setAlignment2[0];
21450 y = _this$_setAlignment2[1];
21451 ctx.textAlign = "left";
21452 x = x - this.size.width / 2; // Shift label 1/2-distance to the left
21453
21454 if (this.fontOptions.valign && this.size.height > this.size.labelHeight) {
21455 if (this.fontOptions.valign === "top") {
21456 y -= (this.size.height - this.size.labelHeight) / 2;
21457 }
21458
21459 if (this.fontOptions.valign === "bottom") {
21460 y += (this.size.height - this.size.labelHeight) / 2;
21461 }
21462 } // draw the text
21463
21464
21465 for (var i = 0; i < this.lineCount; i++) {
21466 var line = this.lines[i];
21467
21468 if (line && line.blocks) {
21469 var width = 0;
21470
21471 if (this.isEdgeLabel || this.fontOptions.align === "center") {
21472 width += (this.size.width - line.width) / 2;
21473 } else if (this.fontOptions.align === "right") {
21474 width += this.size.width - line.width;
21475 }
21476
21477 for (var j = 0; j < line.blocks.length; j++) {
21478 var block = line.blocks[j];
21479 ctx.font = block.font;
21480
21481 var _this$_getColor = this._getColor(block.color, viewFontSize, block.strokeColor),
21482 _this$_getColor2 = _slicedToArray(_this$_getColor, 2),
21483 fontColor = _this$_getColor2[0],
21484 strokeColor = _this$_getColor2[1];
21485
21486 if (block.strokeWidth > 0) {
21487 ctx.lineWidth = block.strokeWidth;
21488 ctx.strokeStyle = strokeColor;
21489 ctx.lineJoin = "round";
21490 }
21491
21492 ctx.fillStyle = fontColor;
21493
21494 if (block.strokeWidth > 0) {
21495 ctx.strokeText(block.text, x + width, y + block.vadjust);
21496 }
21497
21498 ctx.fillText(block.text, x + width, y + block.vadjust);
21499 width += block.width;
21500 }
21501
21502 y += line.height;
21503 }
21504 }
21505 }
21506 /**
21507 *
21508 * @param {CanvasRenderingContext2D} ctx
21509 * @param {number} x
21510 * @param {number} y
21511 * @param {string} baseline
21512 * @returns {Array.<number>}
21513 * @private
21514 */
21515
21516 }, {
21517 key: "_setAlignment",
21518 value: function _setAlignment(ctx, x, y, baseline) {
21519 // check for label alignment (for edges)
21520 // TODO: make alignment for nodes
21521 if (this.isEdgeLabel && this.fontOptions.align !== "horizontal" && this.pointToSelf === false) {
21522 x = 0;
21523 y = 0;
21524 var lineMargin = 2;
21525
21526 if (this.fontOptions.align === "top") {
21527 ctx.textBaseline = "alphabetic";
21528 y -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
21529 } else if (this.fontOptions.align === "bottom") {
21530 ctx.textBaseline = "hanging";
21531 y += 2 * lineMargin; // distance from edge, required because we use hanging. Hanging has less difference between browsers
21532 } else {
21533 ctx.textBaseline = "middle";
21534 }
21535 } else {
21536 ctx.textBaseline = baseline;
21537 }
21538
21539 return [x, y];
21540 }
21541 /**
21542 * fade in when relative scale is between threshold and threshold - 1.
21543 * If the relative scale would be smaller than threshold -1 the draw function would have returned before coming here.
21544 *
21545 * @param {string} color The font color to use
21546 * @param {number} viewFontSize
21547 * @param {string} initialStrokeColor
21548 * @returns {Array.<string>} An array containing the font color and stroke color
21549 * @private
21550 */
21551
21552 }, {
21553 key: "_getColor",
21554 value: function _getColor(color, viewFontSize, initialStrokeColor) {
21555 var fontColor = color || "#000000";
21556 var strokeColor = initialStrokeColor || "#ffffff";
21557
21558 if (viewFontSize <= this.elementOptions.scaling.label.drawThreshold) {
21559 var opacity = Math.max(0, Math.min(1, 1 - (this.elementOptions.scaling.label.drawThreshold - viewFontSize)));
21560 fontColor = overrideOpacity(fontColor, opacity);
21561 strokeColor = overrideOpacity(strokeColor, opacity);
21562 }
21563
21564 return [fontColor, strokeColor];
21565 }
21566 /**
21567 *
21568 * @param {CanvasRenderingContext2D} ctx
21569 * @param {boolean} selected
21570 * @param {boolean} hover
21571 * @returns {{width: number, height: number}}
21572 */
21573
21574 }, {
21575 key: "getTextSize",
21576 value: function getTextSize(ctx) {
21577 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
21578 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
21579
21580 this._processLabel(ctx, selected, hover);
21581
21582 return {
21583 width: this.size.width,
21584 height: this.size.height,
21585 lineCount: this.lineCount
21586 };
21587 }
21588 /**
21589 * Get the current dimensions of the label
21590 *
21591 * @returns {rect}
21592 */
21593
21594 }, {
21595 key: "getSize",
21596 value: function getSize() {
21597 var lineMargin = 2;
21598 var x = this.size.left; // default values which might be overridden below
21599
21600 var y = this.size.top - 0.5 * lineMargin; // idem
21601
21602 if (this.isEdgeLabel) {
21603 var x2 = -this.size.width * 0.5;
21604
21605 switch (this.fontOptions.align) {
21606 case "middle":
21607 x = x2;
21608 y = -this.size.height * 0.5;
21609 break;
21610
21611 case "top":
21612 x = x2;
21613 y = -(this.size.height + lineMargin);
21614 break;
21615
21616 case "bottom":
21617 x = x2;
21618 y = lineMargin;
21619 break;
21620 }
21621 }
21622
21623 var ret = {
21624 left: x,
21625 top: y,
21626 width: this.size.width,
21627 height: this.size.height
21628 };
21629 return ret;
21630 }
21631 /**
21632 *
21633 * @param {CanvasRenderingContext2D} ctx
21634 * @param {boolean} selected
21635 * @param {boolean} hover
21636 * @param {number} [x=0]
21637 * @param {number} [y=0]
21638 * @param {'middle'|'hanging'} [baseline='middle']
21639 */
21640
21641 }, {
21642 key: "calculateLabelSize",
21643 value: function calculateLabelSize(ctx, selected, hover) {
21644 var x = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
21645 var y = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
21646 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : "middle";
21647
21648 this._processLabel(ctx, selected, hover);
21649
21650 this.size.left = x - this.size.width * 0.5;
21651 this.size.top = y - this.size.height * 0.5;
21652 this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size;
21653
21654 if (baseline === "hanging") {
21655 this.size.top += 0.5 * this.fontOptions.size;
21656 this.size.top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
21657
21658 this.size.yLine += 4; // distance from node
21659 }
21660 }
21661 /**
21662 *
21663 * @param {CanvasRenderingContext2D} ctx
21664 * @param {boolean} selected
21665 * @param {boolean} hover
21666 * @param {string} mod
21667 * @returns {{color, size, face, mod, vadjust, strokeWidth: *, strokeColor: (*|string|allOptions.edges.font.strokeColor|{string}|allOptions.nodes.font.strokeColor|Array)}}
21668 */
21669
21670 }, {
21671 key: "getFormattingValues",
21672 value: function getFormattingValues(ctx, selected, hover, mod) {
21673 var getValue = function getValue(fontOptions, mod, option) {
21674 if (mod === "normal") {
21675 if (option === "mod") return "";
21676 return fontOptions[option];
21677 }
21678
21679 if (fontOptions[mod][option] !== undefined) {
21680 // Grumbl leaving out test on undefined equals false for ""
21681 return fontOptions[mod][option];
21682 } else {
21683 // Take from parent font option
21684 return fontOptions[option];
21685 }
21686 };
21687
21688 var values = {
21689 color: getValue(this.fontOptions, mod, "color"),
21690 size: getValue(this.fontOptions, mod, "size"),
21691 face: getValue(this.fontOptions, mod, "face"),
21692 mod: getValue(this.fontOptions, mod, "mod"),
21693 vadjust: getValue(this.fontOptions, mod, "vadjust"),
21694 strokeWidth: this.fontOptions.strokeWidth,
21695 strokeColor: this.fontOptions.strokeColor
21696 };
21697
21698 if (selected || hover) {
21699 if (mod === "normal" && this.fontOptions.chooser === true && this.elementOptions.labelHighlightBold) {
21700 values.mod = "bold";
21701 } else {
21702 if (typeof this.fontOptions.chooser === "function") {
21703 this.fontOptions.chooser(values, this.elementOptions.id, selected, hover);
21704 }
21705 }
21706 }
21707
21708 var fontString = "";
21709
21710 if (values.mod !== undefined && values.mod !== "") {
21711 // safeguard for undefined - this happened
21712 fontString += values.mod + " ";
21713 }
21714
21715 fontString += values.size + "px " + values.face;
21716 ctx.font = fontString.replace(/"/g, "");
21717 values.font = ctx.font;
21718 values.height = values.size;
21719 return values;
21720 }
21721 /**
21722 *
21723 * @param {boolean} selected
21724 * @param {boolean} hover
21725 * @returns {boolean}
21726 */
21727
21728 }, {
21729 key: "differentState",
21730 value: function differentState(selected, hover) {
21731 return selected !== this.selectedState || hover !== this.hoverState;
21732 }
21733 /**
21734 * This explodes the passed text into lines and determines the width, height and number of lines.
21735 *
21736 * @param {CanvasRenderingContext2D} ctx
21737 * @param {boolean} selected
21738 * @param {boolean} hover
21739 * @param {string} inText the text to explode
21740 * @returns {{width, height, lines}|*}
21741 * @private
21742 */
21743
21744 }, {
21745 key: "_processLabelText",
21746 value: function _processLabelText(ctx, selected, hover, inText) {
21747 var splitter = new LabelSplitter(ctx, this, selected, hover);
21748 return splitter.process(inText);
21749 }
21750 /**
21751 * This explodes the label string into lines and sets the width, height and number of lines.
21752 *
21753 * @param {CanvasRenderingContext2D} ctx
21754 * @param {boolean} selected
21755 * @param {boolean} hover
21756 * @private
21757 */
21758
21759 }, {
21760 key: "_processLabel",
21761 value: function _processLabel(ctx, selected, hover) {
21762 if (this.labelDirty === false && !this.differentState(selected, hover)) return;
21763
21764 var state = this._processLabelText(ctx, selected, hover, this.elementOptions.label);
21765
21766 if (this.fontOptions.minWdt > 0 && state.width < this.fontOptions.minWdt) {
21767 state.width = this.fontOptions.minWdt;
21768 }
21769
21770 this.size.labelHeight = state.height;
21771
21772 if (this.fontOptions.minHgt > 0 && state.height < this.fontOptions.minHgt) {
21773 state.height = this.fontOptions.minHgt;
21774 }
21775
21776 this.lines = state.lines;
21777 this.lineCount = state.lines.length;
21778 this.size.width = state.width;
21779 this.size.height = state.height;
21780 this.selectedState = selected;
21781 this.hoverState = hover;
21782 this.labelDirty = false;
21783 }
21784 /**
21785 * Check if this label is visible
21786 *
21787 * @returns {boolean} true if this label will be show, false otherwise
21788 */
21789
21790 }, {
21791 key: "visible",
21792 value: function visible() {
21793 if (this.size.width === 0 || this.size.height === 0 || this.elementOptions.label === undefined) {
21794 return false; // nothing to display
21795 }
21796
21797 var viewFontSize = this.fontOptions.size * this.body.view.scale;
21798
21799 if (viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) {
21800 return false; // Too small or too far away to show
21801 }
21802
21803 return true;
21804 }
21805 }], [{
21806 key: "parseFontString",
21807 value: function parseFontString(outOptions, inOptions) {
21808 if (!inOptions || typeof inOptions !== "string") return false;
21809 var newOptionsArray = inOptions.split(" ");
21810 outOptions.size = +newOptionsArray[0].replace("px", "");
21811 outOptions.face = newOptionsArray[1];
21812 outOptions.color = newOptionsArray[2];
21813 return true;
21814 }
21815 }]);
21816
21817 return Label;
21818 }();
21819
21820 /**
21821 * The Base class for all Nodes.
21822 */
21823 var NodeBase = /*#__PURE__*/function () {
21824 /**
21825 * @param {object} options
21826 * @param {object} body
21827 * @param {Label} labelModule
21828 */
21829 function NodeBase(options, body, labelModule) {
21830 _classCallCheck(this, NodeBase);
21831
21832 this.body = body;
21833 this.labelModule = labelModule;
21834 this.setOptions(options);
21835 this.top = undefined;
21836 this.left = undefined;
21837 this.height = undefined;
21838 this.width = undefined;
21839 this.radius = undefined;
21840 this.margin = undefined;
21841 this.refreshNeeded = true;
21842 this.boundingBox = {
21843 top: 0,
21844 left: 0,
21845 right: 0,
21846 bottom: 0
21847 };
21848 }
21849 /**
21850 *
21851 * @param {object} options
21852 */
21853
21854
21855 _createClass(NodeBase, [{
21856 key: "setOptions",
21857 value: function setOptions(options) {
21858 this.options = options;
21859 }
21860 /**
21861 *
21862 * @param {Label} labelModule
21863 * @private
21864 */
21865
21866 }, {
21867 key: "_setMargins",
21868 value: function _setMargins(labelModule) {
21869 this.margin = {};
21870
21871 if (this.options.margin) {
21872 if (_typeof(this.options.margin) == "object") {
21873 this.margin.top = this.options.margin.top;
21874 this.margin.right = this.options.margin.right;
21875 this.margin.bottom = this.options.margin.bottom;
21876 this.margin.left = this.options.margin.left;
21877 } else {
21878 this.margin.top = this.options.margin;
21879 this.margin.right = this.options.margin;
21880 this.margin.bottom = this.options.margin;
21881 this.margin.left = this.options.margin;
21882 }
21883 }
21884
21885 labelModule.adjustSizes(this.margin);
21886 }
21887 /**
21888 *
21889 * @param {CanvasRenderingContext2D} ctx
21890 * @param {number} angle
21891 * @returns {number}
21892 * @private
21893 */
21894
21895 }, {
21896 key: "_distanceToBorder",
21897 value: function _distanceToBorder(ctx, angle) {
21898 var borderWidth = this.options.borderWidth;
21899
21900 if (ctx) {
21901 this.resize(ctx);
21902 }
21903
21904 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
21905 }
21906 /**
21907 *
21908 * @param {CanvasRenderingContext2D} ctx
21909 * @param {ArrowOptions} values
21910 */
21911
21912 }, {
21913 key: "enableShadow",
21914 value: function enableShadow(ctx, values) {
21915 if (values.shadow) {
21916 ctx.shadowColor = values.shadowColor;
21917 ctx.shadowBlur = values.shadowSize;
21918 ctx.shadowOffsetX = values.shadowX;
21919 ctx.shadowOffsetY = values.shadowY;
21920 }
21921 }
21922 /**
21923 *
21924 * @param {CanvasRenderingContext2D} ctx
21925 * @param {ArrowOptions} values
21926 */
21927
21928 }, {
21929 key: "disableShadow",
21930 value: function disableShadow(ctx, values) {
21931 if (values.shadow) {
21932 ctx.shadowColor = "rgba(0,0,0,0)";
21933 ctx.shadowBlur = 0;
21934 ctx.shadowOffsetX = 0;
21935 ctx.shadowOffsetY = 0;
21936 }
21937 }
21938 /**
21939 *
21940 * @param {CanvasRenderingContext2D} ctx
21941 * @param {ArrowOptions} values
21942 */
21943
21944 }, {
21945 key: "enableBorderDashes",
21946 value: function enableBorderDashes(ctx, values) {
21947 if (values.borderDashes !== false) {
21948 if (ctx.setLineDash !== undefined) {
21949 var dashes = values.borderDashes;
21950
21951 if (dashes === true) {
21952 dashes = [5, 15];
21953 }
21954
21955 ctx.setLineDash(dashes);
21956 } else {
21957 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
21958 this.options.shapeProperties.borderDashes = false;
21959 values.borderDashes = false;
21960 }
21961 }
21962 }
21963 /**
21964 *
21965 * @param {CanvasRenderingContext2D} ctx
21966 * @param {ArrowOptions} values
21967 */
21968
21969 }, {
21970 key: "disableBorderDashes",
21971 value: function disableBorderDashes(ctx, values) {
21972 if (values.borderDashes !== false) {
21973 if (ctx.setLineDash !== undefined) {
21974 ctx.setLineDash([0]);
21975 } else {
21976 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
21977 this.options.shapeProperties.borderDashes = false;
21978 values.borderDashes = false;
21979 }
21980 }
21981 }
21982 /**
21983 * Determine if the shape of a node needs to be recalculated.
21984 *
21985 * @param {boolean} selected
21986 * @param {boolean} hover
21987 * @returns {boolean}
21988 * @protected
21989 */
21990
21991 }, {
21992 key: "needsRefresh",
21993 value: function needsRefresh(selected, hover) {
21994 if (this.refreshNeeded === true) {
21995 // This is probably not the best location to reset this member.
21996 // However, in the current logic, it is the most convenient one.
21997 this.refreshNeeded = false;
21998 return true;
21999 }
22000
22001 return this.width === undefined || this.labelModule.differentState(selected, hover);
22002 }
22003 /**
22004 *
22005 * @param {CanvasRenderingContext2D} ctx
22006 * @param {ArrowOptions} values
22007 */
22008
22009 }, {
22010 key: "initContextForDraw",
22011 value: function initContextForDraw(ctx, values) {
22012 var borderWidth = values.borderWidth / this.body.view.scale;
22013 ctx.lineWidth = Math.min(this.width, borderWidth);
22014 ctx.strokeStyle = values.borderColor;
22015 ctx.fillStyle = values.color;
22016 }
22017 /**
22018 *
22019 * @param {CanvasRenderingContext2D} ctx
22020 * @param {ArrowOptions} values
22021 */
22022
22023 }, {
22024 key: "performStroke",
22025 value: function performStroke(ctx, values) {
22026 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.
22027
22028 ctx.save(); // if borders are zero width, they will be drawn with width 1 by default. This prevents that
22029
22030 if (borderWidth > 0) {
22031 this.enableBorderDashes(ctx, values); //draw the border
22032
22033 ctx.stroke(); //disable dashed border for other elements
22034
22035 this.disableBorderDashes(ctx, values);
22036 }
22037
22038 ctx.restore();
22039 }
22040 /**
22041 *
22042 * @param {CanvasRenderingContext2D} ctx
22043 * @param {ArrowOptions} values
22044 */
22045
22046 }, {
22047 key: "performFill",
22048 value: function performFill(ctx, values) {
22049 ctx.save();
22050 ctx.fillStyle = values.color; // draw shadow if enabled
22051
22052 this.enableShadow(ctx, values); // draw the background
22053
22054 fill(ctx).call(ctx); // disable shadows for other elements.
22055
22056
22057 this.disableShadow(ctx, values);
22058 ctx.restore();
22059 this.performStroke(ctx, values);
22060 }
22061 /**
22062 *
22063 * @param {number} margin
22064 * @private
22065 */
22066
22067 }, {
22068 key: "_addBoundingBoxMargin",
22069 value: function _addBoundingBoxMargin(margin) {
22070 this.boundingBox.left -= margin;
22071 this.boundingBox.top -= margin;
22072 this.boundingBox.bottom += margin;
22073 this.boundingBox.right += margin;
22074 }
22075 /**
22076 * Actual implementation of this method call.
22077 *
22078 * Doing it like this makes it easier to override
22079 * in the child classes.
22080 *
22081 * @param {number} x width
22082 * @param {number} y height
22083 * @param {CanvasRenderingContext2D} ctx
22084 * @param {boolean} selected
22085 * @param {boolean} hover
22086 * @private
22087 */
22088
22089 }, {
22090 key: "_updateBoundingBox",
22091 value: function _updateBoundingBox(x, y, ctx, selected, hover) {
22092 if (ctx !== undefined) {
22093 this.resize(ctx, selected, hover);
22094 }
22095
22096 this.left = x - this.width / 2;
22097 this.top = y - this.height / 2;
22098 this.boundingBox.left = this.left;
22099 this.boundingBox.top = this.top;
22100 this.boundingBox.bottom = this.top + this.height;
22101 this.boundingBox.right = this.left + this.width;
22102 }
22103 /**
22104 * Default implementation of this method call.
22105 * This acts as a stub which can be overridden.
22106 *
22107 * @param {number} x width
22108 * @param {number} y height
22109 * @param {CanvasRenderingContext2D} ctx
22110 * @param {boolean} selected
22111 * @param {boolean} hover
22112 */
22113
22114 }, {
22115 key: "updateBoundingBox",
22116 value: function updateBoundingBox(x, y, ctx, selected, hover) {
22117 this._updateBoundingBox(x, y, ctx, selected, hover);
22118 }
22119 /**
22120 * Determine the dimensions to use for nodes with an internal label
22121 *
22122 * Currently, these are: Circle, Ellipse, Database, Box
22123 * The other nodes have external labels, and will not call this method
22124 *
22125 * If there is no label, decent default values are supplied.
22126 *
22127 * @param {CanvasRenderingContext2D} ctx
22128 * @param {boolean} [selected]
22129 * @param {boolean} [hover]
22130 * @returns {{width:number, height:number}}
22131 */
22132
22133 }, {
22134 key: "getDimensionsFromLabel",
22135 value: function getDimensionsFromLabel(ctx, selected, hover) {
22136 // NOTE: previously 'textSize' was not put in 'this' for Ellipse
22137 // TODO: examine the consequences.
22138 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
22139 var width = this.textSize.width;
22140 var height = this.textSize.height;
22141 var DEFAULT_SIZE = 14;
22142
22143 if (width === 0) {
22144 // This happens when there is no label text set
22145 width = DEFAULT_SIZE; // use a decent default
22146
22147 height = DEFAULT_SIZE; // if width zero, then height also always zero
22148 }
22149
22150 return {
22151 width: width,
22152 height: height
22153 };
22154 }
22155 }]);
22156
22157 return NodeBase;
22158 }();
22159
22160 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); }; }
22161
22162 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; } }
22163 /**
22164 * A Box Node/Cluster shape.
22165 *
22166 * @augments NodeBase
22167 */
22168
22169 var Box$1 = /*#__PURE__*/function (_NodeBase) {
22170 _inherits(Box, _NodeBase);
22171
22172 var _super = _createSuper$s(Box);
22173
22174 /**
22175 * @param {object} options
22176 * @param {object} body
22177 * @param {Label} labelModule
22178 */
22179 function Box(options, body, labelModule) {
22180 var _this;
22181
22182 _classCallCheck(this, Box);
22183
22184 _this = _super.call(this, options, body, labelModule);
22185
22186 _this._setMargins(labelModule);
22187
22188 return _this;
22189 }
22190 /**
22191 *
22192 * @param {CanvasRenderingContext2D} ctx
22193 * @param {boolean} [selected]
22194 * @param {boolean} [hover]
22195 */
22196
22197
22198 _createClass(Box, [{
22199 key: "resize",
22200 value: function resize(ctx) {
22201 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
22202 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
22203
22204 if (this.needsRefresh(selected, hover)) {
22205 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
22206 this.width = dimensions.width + this.margin.right + this.margin.left;
22207 this.height = dimensions.height + this.margin.top + this.margin.bottom;
22208 this.radius = this.width / 2;
22209 }
22210 }
22211 /**
22212 *
22213 * @param {CanvasRenderingContext2D} ctx
22214 * @param {number} x width
22215 * @param {number} y height
22216 * @param {boolean} selected
22217 * @param {boolean} hover
22218 * @param {ArrowOptions} values
22219 */
22220
22221 }, {
22222 key: "draw",
22223 value: function draw(ctx, x, y, selected, hover, values) {
22224 this.resize(ctx, selected, hover);
22225 this.left = x - this.width / 2;
22226 this.top = y - this.height / 2;
22227 this.initContextForDraw(ctx, values);
22228 drawRoundRect(ctx, this.left, this.top, this.width, this.height, values.borderRadius);
22229 this.performFill(ctx, values);
22230 this.updateBoundingBox(x, y, ctx, selected, hover);
22231 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
22232 }
22233 /**
22234 *
22235 * @param {number} x width
22236 * @param {number} y height
22237 * @param {CanvasRenderingContext2D} ctx
22238 * @param {boolean} selected
22239 * @param {boolean} hover
22240 */
22241
22242 }, {
22243 key: "updateBoundingBox",
22244 value: function updateBoundingBox(x, y, ctx, selected, hover) {
22245 this._updateBoundingBox(x, y, ctx, selected, hover);
22246
22247 var borderRadius = this.options.shapeProperties.borderRadius; // only effective for box
22248
22249 this._addBoundingBoxMargin(borderRadius);
22250 }
22251 /**
22252 *
22253 * @param {CanvasRenderingContext2D} ctx
22254 * @param {number} angle
22255 * @returns {number}
22256 */
22257
22258 }, {
22259 key: "distanceToBorder",
22260 value: function distanceToBorder(ctx, angle) {
22261 if (ctx) {
22262 this.resize(ctx);
22263 }
22264
22265 var borderWidth = this.options.borderWidth;
22266 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
22267 }
22268 }]);
22269
22270 return Box;
22271 }(NodeBase);
22272
22273 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); }; }
22274
22275 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; } }
22276 /**
22277 * NOTE: This is a bad base class
22278 *
22279 * Child classes are:
22280 *
22281 * Image - uses *only* image methods
22282 * Circle - uses *only* _drawRawCircle
22283 * CircleImage - uses all
22284 *
22285 * TODO: Refactor, move _drawRawCircle to different module, derive Circle from NodeBase
22286 * Rename this to ImageBase
22287 * Consolidate common code in Image and CircleImage to base class
22288 *
22289 * @augments NodeBase
22290 */
22291
22292 var CircleImageBase = /*#__PURE__*/function (_NodeBase) {
22293 _inherits(CircleImageBase, _NodeBase);
22294
22295 var _super = _createSuper$r(CircleImageBase);
22296
22297 /**
22298 * @param {object} options
22299 * @param {object} body
22300 * @param {Label} labelModule
22301 */
22302 function CircleImageBase(options, body, labelModule) {
22303 var _this;
22304
22305 _classCallCheck(this, CircleImageBase);
22306
22307 _this = _super.call(this, options, body, labelModule);
22308 _this.labelOffset = 0;
22309 _this.selected = false;
22310 return _this;
22311 }
22312 /**
22313 *
22314 * @param {object} options
22315 * @param {object} [imageObj]
22316 * @param {object} [imageObjAlt]
22317 */
22318
22319
22320 _createClass(CircleImageBase, [{
22321 key: "setOptions",
22322 value: function setOptions(options, imageObj, imageObjAlt) {
22323 this.options = options;
22324
22325 if (!(imageObj === undefined && imageObjAlt === undefined)) {
22326 this.setImages(imageObj, imageObjAlt);
22327 }
22328 }
22329 /**
22330 * Set the images for this node.
22331 *
22332 * The images can be updated after the initial setting of options;
22333 * therefore, this method needs to be reentrant.
22334 *
22335 * For correct working in error cases, it is necessary to properly set
22336 * field 'nodes.brokenImage' in the options.
22337 *
22338 * @param {Image} imageObj required; main image to show for this node
22339 * @param {Image|undefined} imageObjAlt optional; image to show when node is selected
22340 */
22341
22342 }, {
22343 key: "setImages",
22344 value: function setImages(imageObj, imageObjAlt) {
22345 if (imageObjAlt && this.selected) {
22346 this.imageObj = imageObjAlt;
22347 this.imageObjAlt = imageObj;
22348 } else {
22349 this.imageObj = imageObj;
22350 this.imageObjAlt = imageObjAlt;
22351 }
22352 }
22353 /**
22354 * Set selection and switch between the base and the selected image.
22355 *
22356 * Do the switch only if imageObjAlt exists.
22357 *
22358 * @param {boolean} selected value of new selected state for current node
22359 */
22360
22361 }, {
22362 key: "switchImages",
22363 value: function switchImages(selected) {
22364 var selection_changed = selected && !this.selected || !selected && this.selected;
22365 this.selected = selected; // Remember new selection
22366
22367 if (this.imageObjAlt !== undefined && selection_changed) {
22368 var imageTmp = this.imageObj;
22369 this.imageObj = this.imageObjAlt;
22370 this.imageObjAlt = imageTmp;
22371 }
22372 }
22373 /**
22374 * Returns Image Padding from node options
22375 *
22376 * @returns {{top: number,left: number,bottom: number,right: number}} image padding inside this shape
22377 * @private
22378 */
22379
22380 }, {
22381 key: "_getImagePadding",
22382 value: function _getImagePadding() {
22383 var imgPadding = {
22384 top: 0,
22385 right: 0,
22386 bottom: 0,
22387 left: 0
22388 };
22389
22390 if (this.options.imagePadding) {
22391 var optImgPadding = this.options.imagePadding;
22392
22393 if (_typeof(optImgPadding) == "object") {
22394 imgPadding.top = optImgPadding.top;
22395 imgPadding.right = optImgPadding.right;
22396 imgPadding.bottom = optImgPadding.bottom;
22397 imgPadding.left = optImgPadding.left;
22398 } else {
22399 imgPadding.top = optImgPadding;
22400 imgPadding.right = optImgPadding;
22401 imgPadding.bottom = optImgPadding;
22402 imgPadding.left = optImgPadding;
22403 }
22404 }
22405
22406 return imgPadding;
22407 }
22408 /**
22409 * Adjust the node dimensions for a loaded image.
22410 *
22411 * Pre: this.imageObj is valid
22412 */
22413
22414 }, {
22415 key: "_resizeImage",
22416 value: function _resizeImage() {
22417 var width, height;
22418
22419 if (this.options.shapeProperties.useImageSize === false) {
22420 // Use the size property
22421 var ratio_width = 1;
22422 var ratio_height = 1; // Only calculate the proper ratio if both width and height not zero
22423
22424 if (this.imageObj.width && this.imageObj.height) {
22425 if (this.imageObj.width > this.imageObj.height) {
22426 ratio_width = this.imageObj.width / this.imageObj.height;
22427 } else {
22428 ratio_height = this.imageObj.height / this.imageObj.width;
22429 }
22430 }
22431
22432 width = this.options.size * 2 * ratio_width;
22433 height = this.options.size * 2 * ratio_height;
22434 } else {
22435 // Use the image size with image padding
22436 var imgPadding = this._getImagePadding();
22437
22438 width = this.imageObj.width + imgPadding.left + imgPadding.right;
22439 height = this.imageObj.height + imgPadding.top + imgPadding.bottom;
22440 }
22441
22442 this.width = width;
22443 this.height = height;
22444 this.radius = 0.5 * this.width;
22445 }
22446 /**
22447 *
22448 * @param {CanvasRenderingContext2D} ctx
22449 * @param {number} x width
22450 * @param {number} y height
22451 * @param {ArrowOptions} values
22452 * @private
22453 */
22454
22455 }, {
22456 key: "_drawRawCircle",
22457 value: function _drawRawCircle(ctx, x, y, values) {
22458 this.initContextForDraw(ctx, values);
22459 drawCircle(ctx, x, y, values.size);
22460 this.performFill(ctx, values);
22461 }
22462 /**
22463 *
22464 * @param {CanvasRenderingContext2D} ctx
22465 * @param {ArrowOptions} values
22466 * @private
22467 */
22468
22469 }, {
22470 key: "_drawImageAtPosition",
22471 value: function _drawImageAtPosition(ctx, values) {
22472 if (this.imageObj.width != 0) {
22473 // draw the image
22474 ctx.globalAlpha = values.opacity !== undefined ? values.opacity : 1; // draw shadow if enabled
22475
22476 this.enableShadow(ctx, values);
22477 var factor = 1;
22478
22479 if (this.options.shapeProperties.interpolation === true) {
22480 factor = this.imageObj.width / this.width / this.body.view.scale;
22481 }
22482
22483 var imgPadding = this._getImagePadding();
22484
22485 var imgPosLeft = this.left + imgPadding.left;
22486 var imgPosTop = this.top + imgPadding.top;
22487 var imgWidth = this.width - imgPadding.left - imgPadding.right;
22488 var imgHeight = this.height - imgPadding.top - imgPadding.bottom;
22489 this.imageObj.drawImageAtPosition(ctx, factor, imgPosLeft, imgPosTop, imgWidth, imgHeight); // disable shadows for other elements.
22490
22491 this.disableShadow(ctx, values);
22492 }
22493 }
22494 /**
22495 *
22496 * @param {CanvasRenderingContext2D} ctx
22497 * @param {number} x width
22498 * @param {number} y height
22499 * @param {boolean} selected
22500 * @param {boolean} hover
22501 * @private
22502 */
22503
22504 }, {
22505 key: "_drawImageLabel",
22506 value: function _drawImageLabel(ctx, x, y, selected, hover) {
22507 var offset = 0;
22508
22509 if (this.height !== undefined) {
22510 offset = this.height * 0.5;
22511 var labelDimensions = this.labelModule.getTextSize(ctx, selected, hover);
22512
22513 if (labelDimensions.lineCount >= 1) {
22514 offset += labelDimensions.height / 2;
22515 }
22516 }
22517
22518 var yLabel = y + offset;
22519
22520 if (this.options.label) {
22521 this.labelOffset = offset;
22522 }
22523
22524 this.labelModule.draw(ctx, x, yLabel, selected, hover, "hanging");
22525 }
22526 }]);
22527
22528 return CircleImageBase;
22529 }(NodeBase);
22530
22531 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); }; }
22532
22533 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; } }
22534 /**
22535 * A Circle Node/Cluster shape.
22536 *
22537 * @augments CircleImageBase
22538 */
22539
22540 var Circle$1 = /*#__PURE__*/function (_CircleImageBase) {
22541 _inherits(Circle, _CircleImageBase);
22542
22543 var _super = _createSuper$q(Circle);
22544
22545 /**
22546 * @param {object} options
22547 * @param {object} body
22548 * @param {Label} labelModule
22549 */
22550 function Circle(options, body, labelModule) {
22551 var _this;
22552
22553 _classCallCheck(this, Circle);
22554
22555 _this = _super.call(this, options, body, labelModule);
22556
22557 _this._setMargins(labelModule);
22558
22559 return _this;
22560 }
22561 /**
22562 *
22563 * @param {CanvasRenderingContext2D} ctx
22564 * @param {boolean} [selected]
22565 * @param {boolean} [hover]
22566 */
22567
22568
22569 _createClass(Circle, [{
22570 key: "resize",
22571 value: function resize(ctx) {
22572 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
22573 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
22574
22575 if (this.needsRefresh(selected, hover)) {
22576 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
22577 var diameter = Math.max(dimensions.width + this.margin.right + this.margin.left, dimensions.height + this.margin.top + this.margin.bottom);
22578 this.options.size = diameter / 2; // NOTE: this size field only set here, not in Ellipse, Database, Box
22579
22580 this.width = diameter;
22581 this.height = diameter;
22582 this.radius = this.width / 2;
22583 }
22584 }
22585 /**
22586 *
22587 * @param {CanvasRenderingContext2D} ctx
22588 * @param {number} x width
22589 * @param {number} y height
22590 * @param {boolean} selected
22591 * @param {boolean} hover
22592 * @param {ArrowOptions} values
22593 */
22594
22595 }, {
22596 key: "draw",
22597 value: function draw(ctx, x, y, selected, hover, values) {
22598 this.resize(ctx, selected, hover);
22599 this.left = x - this.width / 2;
22600 this.top = y - this.height / 2;
22601
22602 this._drawRawCircle(ctx, x, y, values);
22603
22604 this.updateBoundingBox(x, y);
22605 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, y, selected, hover);
22606 }
22607 /**
22608 *
22609 * @param {number} x width
22610 * @param {number} y height
22611 */
22612
22613 }, {
22614 key: "updateBoundingBox",
22615 value: function updateBoundingBox(x, y) {
22616 this.boundingBox.top = y - this.options.size;
22617 this.boundingBox.left = x - this.options.size;
22618 this.boundingBox.right = x + this.options.size;
22619 this.boundingBox.bottom = y + this.options.size;
22620 }
22621 /**
22622 *
22623 * @param {CanvasRenderingContext2D} ctx
22624 * @returns {number}
22625 */
22626
22627 }, {
22628 key: "distanceToBorder",
22629 value: function distanceToBorder(ctx) {
22630 if (ctx) {
22631 this.resize(ctx);
22632 }
22633
22634 return this.width * 0.5;
22635 }
22636 }]);
22637
22638 return Circle;
22639 }(CircleImageBase);
22640
22641 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); }; }
22642
22643 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; } }
22644 /**
22645 * A CircularImage Node/Cluster shape.
22646 *
22647 * @augments CircleImageBase
22648 */
22649
22650 var CircularImage = /*#__PURE__*/function (_CircleImageBase) {
22651 _inherits(CircularImage, _CircleImageBase);
22652
22653 var _super = _createSuper$p(CircularImage);
22654
22655 /**
22656 * @param {object} options
22657 * @param {object} body
22658 * @param {Label} labelModule
22659 * @param {Image} imageObj
22660 * @param {Image} imageObjAlt
22661 */
22662 function CircularImage(options, body, labelModule, imageObj, imageObjAlt) {
22663 var _this;
22664
22665 _classCallCheck(this, CircularImage);
22666
22667 _this = _super.call(this, options, body, labelModule);
22668
22669 _this.setImages(imageObj, imageObjAlt);
22670
22671 return _this;
22672 }
22673 /**
22674 *
22675 * @param {CanvasRenderingContext2D} ctx
22676 * @param {boolean} [selected]
22677 * @param {boolean} [hover]
22678 */
22679
22680
22681 _createClass(CircularImage, [{
22682 key: "resize",
22683 value: function resize(ctx) {
22684 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
22685 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
22686 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
22687
22688 if (imageAbsent) {
22689 var diameter = this.options.size * 2;
22690 this.width = diameter;
22691 this.height = diameter;
22692 this.radius = 0.5 * this.width;
22693 return;
22694 } // At this point, an image is present, i.e. this.imageObj is valid.
22695
22696
22697 if (this.needsRefresh(selected, hover)) {
22698 this._resizeImage();
22699 }
22700 }
22701 /**
22702 *
22703 * @param {CanvasRenderingContext2D} ctx
22704 * @param {number} x width
22705 * @param {number} y height
22706 * @param {boolean} selected
22707 * @param {boolean} hover
22708 * @param {ArrowOptions} values
22709 */
22710
22711 }, {
22712 key: "draw",
22713 value: function draw(ctx, x, y, selected, hover, values) {
22714 this.switchImages(selected);
22715 this.resize();
22716 var labelX = x,
22717 labelY = y;
22718
22719 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
22720 this.left = x;
22721 this.top = y;
22722 labelX += this.width / 2;
22723 labelY += this.height / 2;
22724 } else {
22725 this.left = x - this.width / 2;
22726 this.top = y - this.height / 2;
22727 } // draw the background circle. IMPORTANT: the stroke in this method is used by the clip method below.
22728
22729
22730 this._drawRawCircle(ctx, labelX, labelY, values); // now we draw in the circle, we save so we can revert the clip operation after drawing.
22731
22732
22733 ctx.save(); // clip is used to use the stroke in drawRawCircle as an area that we can draw in.
22734
22735 ctx.clip(); // draw the image
22736
22737 this._drawImageAtPosition(ctx, values); // restore so we can again draw on the full canvas
22738
22739
22740 ctx.restore();
22741
22742 this._drawImageLabel(ctx, labelX, labelY, selected, hover);
22743
22744 this.updateBoundingBox(x, y);
22745 } // TODO: compare with Circle.updateBoundingBox(), consolidate? More stuff is happening here
22746
22747 /**
22748 *
22749 * @param {number} x width
22750 * @param {number} y height
22751 */
22752
22753 }, {
22754 key: "updateBoundingBox",
22755 value: function updateBoundingBox(x, y) {
22756 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
22757 this.boundingBox.top = y;
22758 this.boundingBox.left = x;
22759 this.boundingBox.right = x + this.options.size * 2;
22760 this.boundingBox.bottom = y + this.options.size * 2;
22761 } else {
22762 this.boundingBox.top = y - this.options.size;
22763 this.boundingBox.left = x - this.options.size;
22764 this.boundingBox.right = x + this.options.size;
22765 this.boundingBox.bottom = y + this.options.size;
22766 } // TODO: compare with Image.updateBoundingBox(), consolidate?
22767
22768
22769 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
22770 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
22771 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
22772 }
22773 /**
22774 *
22775 * @param {CanvasRenderingContext2D} ctx
22776 * @returns {number}
22777 */
22778
22779 }, {
22780 key: "distanceToBorder",
22781 value: function distanceToBorder(ctx) {
22782 if (ctx) {
22783 this.resize(ctx);
22784 }
22785
22786 return this.width * 0.5;
22787 }
22788 }]);
22789
22790 return CircularImage;
22791 }(CircleImageBase);
22792
22793 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); }; }
22794
22795 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; } }
22796 /**
22797 * Base class for constructing Node/Cluster Shapes.
22798 *
22799 * @augments NodeBase
22800 */
22801
22802 var ShapeBase = /*#__PURE__*/function (_NodeBase) {
22803 _inherits(ShapeBase, _NodeBase);
22804
22805 var _super = _createSuper$o(ShapeBase);
22806
22807 /**
22808 * @param {object} options
22809 * @param {object} body
22810 * @param {Label} labelModule
22811 */
22812 function ShapeBase(options, body, labelModule) {
22813 _classCallCheck(this, ShapeBase);
22814
22815 return _super.call(this, options, body, labelModule);
22816 }
22817 /**
22818 *
22819 * @param {CanvasRenderingContext2D} ctx
22820 * @param {boolean} [selected]
22821 * @param {boolean} [hover]
22822 * @param {object} [values={size: this.options.size}]
22823 */
22824
22825
22826 _createClass(ShapeBase, [{
22827 key: "resize",
22828 value: function resize(ctx) {
22829 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
22830 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
22831 var values = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {
22832 size: this.options.size
22833 };
22834
22835 if (this.needsRefresh(selected, hover)) {
22836 var _this$customSizeWidth, _this$customSizeHeigh;
22837
22838 this.labelModule.getTextSize(ctx, selected, hover);
22839 var size = 2 * values.size;
22840 this.width = (_this$customSizeWidth = this.customSizeWidth) !== null && _this$customSizeWidth !== void 0 ? _this$customSizeWidth : size;
22841 this.height = (_this$customSizeHeigh = this.customSizeHeight) !== null && _this$customSizeHeigh !== void 0 ? _this$customSizeHeigh : size;
22842 this.radius = 0.5 * this.width;
22843 }
22844 }
22845 /**
22846 *
22847 * @param {CanvasRenderingContext2D} ctx
22848 * @param {string} shape
22849 * @param {number} sizeMultiplier - Unused! TODO: Remove next major release
22850 * @param {number} x
22851 * @param {number} y
22852 * @param {boolean} selected
22853 * @param {boolean} hover
22854 * @param {ArrowOptions} values
22855 * @private
22856 * @returns {object} Callbacks to draw later on higher layers.
22857 */
22858
22859 }, {
22860 key: "_drawShape",
22861 value: function _drawShape(ctx, shape, sizeMultiplier, x, y, selected, hover, values) {
22862 var _this = this;
22863
22864 this.resize(ctx, selected, hover, values);
22865 this.left = x - this.width / 2;
22866 this.top = y - this.height / 2;
22867 this.initContextForDraw(ctx, values);
22868 getShape(shape)(ctx, x, y, values.size);
22869 this.performFill(ctx, values);
22870
22871 if (this.options.icon !== undefined) {
22872 if (this.options.icon.code !== undefined) {
22873 ctx.font = (selected ? "bold " : "") + this.height / 2 + "px " + (this.options.icon.face || "FontAwesome");
22874 ctx.fillStyle = this.options.icon.color || "black";
22875 ctx.textAlign = "center";
22876 ctx.textBaseline = "middle";
22877 ctx.fillText(this.options.icon.code, x, y);
22878 }
22879 }
22880
22881 return {
22882 drawExternalLabel: function drawExternalLabel() {
22883 if (_this.options.label !== undefined) {
22884 // Need to call following here in order to ensure value for
22885 // `this.labelModule.size.height`.
22886 _this.labelModule.calculateLabelSize(ctx, selected, hover, x, y, "hanging");
22887
22888 var yLabel = y + 0.5 * _this.height + 0.5 * _this.labelModule.size.height;
22889
22890 _this.labelModule.draw(ctx, x, yLabel, selected, hover, "hanging");
22891 }
22892
22893 _this.updateBoundingBox(x, y);
22894 }
22895 };
22896 }
22897 /**
22898 *
22899 * @param {number} x
22900 * @param {number} y
22901 */
22902
22903 }, {
22904 key: "updateBoundingBox",
22905 value: function updateBoundingBox(x, y) {
22906 this.boundingBox.top = y - this.options.size;
22907 this.boundingBox.left = x - this.options.size;
22908 this.boundingBox.right = x + this.options.size;
22909 this.boundingBox.bottom = y + this.options.size;
22910
22911 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
22912 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
22913 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
22914 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
22915 }
22916 }
22917 }]);
22918
22919 return ShapeBase;
22920 }(NodeBase);
22921
22922 function ownKeys$3(object, enumerableOnly) { var keys = keys$4(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); enumerableOnly && (symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$3(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
22923
22924 function _objectSpread$3(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? forEach$2(_context = ownKeys$3(Object(source), !0)).call(_context, function (key) { _defineProperty(target, key, source[key]); }) : getOwnPropertyDescriptors ? defineProperties(target, getOwnPropertyDescriptors(source)) : forEach$2(_context2 = ownKeys$3(Object(source))).call(_context2, function (key) { defineProperty$6(target, key, getOwnPropertyDescriptor$3(source, key)); }); } return target; }
22925
22926 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); }; }
22927
22928 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; } }
22929 /**
22930 * A CustomShape Node/Cluster shape.
22931 *
22932 * @augments ShapeBase
22933 */
22934
22935 var CustomShape = /*#__PURE__*/function (_ShapeBase) {
22936 _inherits(CustomShape, _ShapeBase);
22937
22938 var _super = _createSuper$n(CustomShape);
22939
22940 /**
22941 * @param {object} options
22942 * @param {object} body
22943 * @param {Label} labelModule
22944 * @param {Function} ctxRenderer
22945 */
22946 function CustomShape(options, body, labelModule, ctxRenderer) {
22947 var _this;
22948
22949 _classCallCheck(this, CustomShape);
22950
22951 _this = _super.call(this, options, body, labelModule, ctxRenderer);
22952 _this.ctxRenderer = ctxRenderer;
22953 return _this;
22954 }
22955 /**
22956 *
22957 * @param {CanvasRenderingContext2D} ctx
22958 * @param {number} x width
22959 * @param {number} y height
22960 * @param {boolean} selected
22961 * @param {boolean} hover
22962 * @param {ArrowOptions} values
22963 * @returns {object} Callbacks to draw later on different layers.
22964 */
22965
22966
22967 _createClass(CustomShape, [{
22968 key: "draw",
22969 value: function draw(ctx, x, y, selected, hover, values) {
22970 this.resize(ctx, selected, hover, values);
22971 this.left = x - this.width / 2;
22972 this.top = y - this.height / 2; // Guard right away because someone may just draw in the function itself.
22973
22974 ctx.save();
22975 var drawLater = this.ctxRenderer({
22976 ctx: ctx,
22977 id: this.options.id,
22978 x: x,
22979 y: y,
22980 state: {
22981 selected: selected,
22982 hover: hover
22983 },
22984 style: _objectSpread$3({}, values),
22985 label: this.options.label
22986 }); // Render the node shape bellow arrows.
22987
22988 if (drawLater.drawNode != null) {
22989 drawLater.drawNode();
22990 }
22991
22992 ctx.restore();
22993
22994 if (drawLater.drawExternalLabel) {
22995 // Guard the external label (above arrows) drawing function.
22996 var drawExternalLabel = drawLater.drawExternalLabel;
22997
22998 drawLater.drawExternalLabel = function () {
22999 ctx.save();
23000 drawExternalLabel();
23001 ctx.restore();
23002 };
23003 }
23004
23005 if (drawLater.nodeDimensions) {
23006 this.customSizeWidth = drawLater.nodeDimensions.width;
23007 this.customSizeHeight = drawLater.nodeDimensions.height;
23008 }
23009
23010 return drawLater;
23011 }
23012 /**
23013 *
23014 * @param {CanvasRenderingContext2D} ctx
23015 * @param {number} angle
23016 * @returns {number}
23017 */
23018
23019 }, {
23020 key: "distanceToBorder",
23021 value: function distanceToBorder(ctx, angle) {
23022 return this._distanceToBorder(ctx, angle);
23023 }
23024 }]);
23025
23026 return CustomShape;
23027 }(ShapeBase);
23028
23029 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); }; }
23030
23031 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; } }
23032 /**
23033 * A Database Node/Cluster shape.
23034 *
23035 * @augments NodeBase
23036 */
23037
23038 var Database = /*#__PURE__*/function (_NodeBase) {
23039 _inherits(Database, _NodeBase);
23040
23041 var _super = _createSuper$m(Database);
23042
23043 /**
23044 * @param {object} options
23045 * @param {object} body
23046 * @param {Label} labelModule
23047 */
23048 function Database(options, body, labelModule) {
23049 var _this;
23050
23051 _classCallCheck(this, Database);
23052
23053 _this = _super.call(this, options, body, labelModule);
23054
23055 _this._setMargins(labelModule);
23056
23057 return _this;
23058 }
23059 /**
23060 *
23061 * @param {CanvasRenderingContext2D} ctx
23062 * @param {boolean} selected
23063 * @param {boolean} hover
23064 */
23065
23066
23067 _createClass(Database, [{
23068 key: "resize",
23069 value: function resize(ctx, selected, hover) {
23070 if (this.needsRefresh(selected, hover)) {
23071 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
23072 var size = dimensions.width + this.margin.right + this.margin.left;
23073 this.width = size;
23074 this.height = size;
23075 this.radius = this.width / 2;
23076 }
23077 }
23078 /**
23079 *
23080 * @param {CanvasRenderingContext2D} ctx
23081 * @param {number} x width
23082 * @param {number} y height
23083 * @param {boolean} selected
23084 * @param {boolean} hover
23085 * @param {ArrowOptions} values
23086 */
23087
23088 }, {
23089 key: "draw",
23090 value: function draw(ctx, x, y, selected, hover, values) {
23091 this.resize(ctx, selected, hover);
23092 this.left = x - this.width / 2;
23093 this.top = y - this.height / 2;
23094 this.initContextForDraw(ctx, values);
23095 drawDatabase(ctx, x - this.width / 2, y - this.height / 2, this.width, this.height);
23096 this.performFill(ctx, values);
23097 this.updateBoundingBox(x, y, ctx, selected, hover);
23098 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
23099 }
23100 /**
23101 *
23102 * @param {CanvasRenderingContext2D} ctx
23103 * @param {number} angle
23104 * @returns {number}
23105 */
23106
23107 }, {
23108 key: "distanceToBorder",
23109 value: function distanceToBorder(ctx, angle) {
23110 return this._distanceToBorder(ctx, angle);
23111 }
23112 }]);
23113
23114 return Database;
23115 }(NodeBase);
23116
23117 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); }; }
23118
23119 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; } }
23120 /**
23121 * A Diamond Node/Cluster shape.
23122 *
23123 * @augments ShapeBase
23124 */
23125
23126 var Diamond$1 = /*#__PURE__*/function (_ShapeBase) {
23127 _inherits(Diamond, _ShapeBase);
23128
23129 var _super = _createSuper$l(Diamond);
23130
23131 /**
23132 * @param {object} options
23133 * @param {object} body
23134 * @param {Label} labelModule
23135 */
23136 function Diamond(options, body, labelModule) {
23137 _classCallCheck(this, Diamond);
23138
23139 return _super.call(this, options, body, labelModule);
23140 }
23141 /**
23142 *
23143 * @param {CanvasRenderingContext2D} ctx
23144 * @param {number} x width
23145 * @param {number} y height
23146 * @param {boolean} selected
23147 * @param {boolean} hover
23148 * @param {ArrowOptions} values
23149 * @returns {object} Callbacks to draw later on higher layers.
23150 */
23151
23152
23153 _createClass(Diamond, [{
23154 key: "draw",
23155 value: function draw(ctx, x, y, selected, hover, values) {
23156 return this._drawShape(ctx, "diamond", 4, x, y, selected, hover, values);
23157 }
23158 /**
23159 *
23160 * @param {CanvasRenderingContext2D} ctx
23161 * @param {number} angle
23162 * @returns {number}
23163 */
23164
23165 }, {
23166 key: "distanceToBorder",
23167 value: function distanceToBorder(ctx, angle) {
23168 return this._distanceToBorder(ctx, angle);
23169 }
23170 }]);
23171
23172 return Diamond;
23173 }(ShapeBase);
23174
23175 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); }; }
23176
23177 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; } }
23178 /**
23179 * A Dot Node/Cluster shape.
23180 *
23181 * @augments ShapeBase
23182 */
23183
23184 var Dot = /*#__PURE__*/function (_ShapeBase) {
23185 _inherits(Dot, _ShapeBase);
23186
23187 var _super = _createSuper$k(Dot);
23188
23189 /**
23190 * @param {object} options
23191 * @param {object} body
23192 * @param {Label} labelModule
23193 */
23194 function Dot(options, body, labelModule) {
23195 _classCallCheck(this, Dot);
23196
23197 return _super.call(this, options, body, labelModule);
23198 }
23199 /**
23200 *
23201 * @param {CanvasRenderingContext2D} ctx
23202 * @param {number} x width
23203 * @param {number} y height
23204 * @param {boolean} selected
23205 * @param {boolean} hover
23206 * @param {ArrowOptions} values
23207 * @returns {object} Callbacks to draw later on higher layers.
23208 */
23209
23210
23211 _createClass(Dot, [{
23212 key: "draw",
23213 value: function draw(ctx, x, y, selected, hover, values) {
23214 return this._drawShape(ctx, "circle", 2, x, y, selected, hover, values);
23215 }
23216 /**
23217 *
23218 * @param {CanvasRenderingContext2D} ctx
23219 * @returns {number}
23220 */
23221
23222 }, {
23223 key: "distanceToBorder",
23224 value: function distanceToBorder(ctx) {
23225 if (ctx) {
23226 this.resize(ctx);
23227 }
23228
23229 return this.options.size;
23230 }
23231 }]);
23232
23233 return Dot;
23234 }(ShapeBase);
23235
23236 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); }; }
23237
23238 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; } }
23239 /**
23240 * Am Ellipse Node/Cluster shape.
23241 *
23242 * @augments NodeBase
23243 */
23244
23245 var Ellipse = /*#__PURE__*/function (_NodeBase) {
23246 _inherits(Ellipse, _NodeBase);
23247
23248 var _super = _createSuper$j(Ellipse);
23249
23250 /**
23251 * @param {object} options
23252 * @param {object} body
23253 * @param {Label} labelModule
23254 */
23255 function Ellipse(options, body, labelModule) {
23256 _classCallCheck(this, Ellipse);
23257
23258 return _super.call(this, options, body, labelModule);
23259 }
23260 /**
23261 *
23262 * @param {CanvasRenderingContext2D} ctx
23263 * @param {boolean} [selected]
23264 * @param {boolean} [hover]
23265 */
23266
23267
23268 _createClass(Ellipse, [{
23269 key: "resize",
23270 value: function resize(ctx) {
23271 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
23272 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
23273
23274 if (this.needsRefresh(selected, hover)) {
23275 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
23276 this.height = dimensions.height * 2;
23277 this.width = dimensions.width + dimensions.height;
23278 this.radius = 0.5 * this.width;
23279 }
23280 }
23281 /**
23282 *
23283 * @param {CanvasRenderingContext2D} ctx
23284 * @param {number} x width
23285 * @param {number} y height
23286 * @param {boolean} selected
23287 * @param {boolean} hover
23288 * @param {ArrowOptions} values
23289 */
23290
23291 }, {
23292 key: "draw",
23293 value: function draw(ctx, x, y, selected, hover, values) {
23294 this.resize(ctx, selected, hover);
23295 this.left = x - this.width * 0.5;
23296 this.top = y - this.height * 0.5;
23297 this.initContextForDraw(ctx, values);
23298 drawEllipse(ctx, this.left, this.top, this.width, this.height);
23299 this.performFill(ctx, values);
23300 this.updateBoundingBox(x, y, ctx, selected, hover);
23301 this.labelModule.draw(ctx, x, y, selected, hover);
23302 }
23303 /**
23304 *
23305 * @param {CanvasRenderingContext2D} ctx
23306 * @param {number} angle
23307 * @returns {number}
23308 */
23309
23310 }, {
23311 key: "distanceToBorder",
23312 value: function distanceToBorder(ctx, angle) {
23313 if (ctx) {
23314 this.resize(ctx);
23315 }
23316
23317 var a = this.width * 0.5;
23318 var b = this.height * 0.5;
23319 var w = Math.sin(angle) * a;
23320 var h = Math.cos(angle) * b;
23321 return a * b / Math.sqrt(w * w + h * h);
23322 }
23323 }]);
23324
23325 return Ellipse;
23326 }(NodeBase);
23327
23328 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); }; }
23329
23330 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; } }
23331 /**
23332 * An icon replacement for the default Node shape.
23333 *
23334 * @augments NodeBase
23335 */
23336
23337 var Icon = /*#__PURE__*/function (_NodeBase) {
23338 _inherits(Icon, _NodeBase);
23339
23340 var _super = _createSuper$i(Icon);
23341
23342 /**
23343 * @param {object} options
23344 * @param {object} body
23345 * @param {Label} labelModule
23346 */
23347 function Icon(options, body, labelModule) {
23348 var _this;
23349
23350 _classCallCheck(this, Icon);
23351
23352 _this = _super.call(this, options, body, labelModule);
23353
23354 _this._setMargins(labelModule);
23355
23356 return _this;
23357 }
23358 /**
23359 *
23360 * @param {CanvasRenderingContext2D} ctx - Unused.
23361 * @param {boolean} [selected]
23362 * @param {boolean} [hover]
23363 */
23364
23365
23366 _createClass(Icon, [{
23367 key: "resize",
23368 value: function resize(ctx, selected, hover) {
23369 if (this.needsRefresh(selected, hover)) {
23370 this.iconSize = {
23371 width: Number(this.options.icon.size),
23372 height: Number(this.options.icon.size)
23373 };
23374 this.width = this.iconSize.width + this.margin.right + this.margin.left;
23375 this.height = this.iconSize.height + this.margin.top + this.margin.bottom;
23376 this.radius = 0.5 * this.width;
23377 }
23378 }
23379 /**
23380 *
23381 * @param {CanvasRenderingContext2D} ctx
23382 * @param {number} x width
23383 * @param {number} y height
23384 * @param {boolean} selected
23385 * @param {boolean} hover
23386 * @param {ArrowOptions} values
23387 * @returns {object} Callbacks to draw later on higher layers.
23388 */
23389
23390 }, {
23391 key: "draw",
23392 value: function draw(ctx, x, y, selected, hover, values) {
23393 var _this2 = this;
23394
23395 this.resize(ctx, selected, hover);
23396 this.options.icon.size = this.options.icon.size || 50;
23397 this.left = x - this.width / 2;
23398 this.top = y - this.height / 2;
23399
23400 this._icon(ctx, x, y, selected, hover, values);
23401
23402 return {
23403 drawExternalLabel: function drawExternalLabel() {
23404 if (_this2.options.label !== undefined) {
23405 var iconTextSpacing = 5;
23406
23407 _this2.labelModule.draw(ctx, _this2.left + _this2.iconSize.width / 2 + _this2.margin.left, y + _this2.height / 2 + iconTextSpacing, selected);
23408 }
23409
23410 _this2.updateBoundingBox(x, y);
23411 }
23412 };
23413 }
23414 /**
23415 *
23416 * @param {number} x
23417 * @param {number} y
23418 */
23419
23420 }, {
23421 key: "updateBoundingBox",
23422 value: function updateBoundingBox(x, y) {
23423 this.boundingBox.top = y - this.options.icon.size * 0.5;
23424 this.boundingBox.left = x - this.options.icon.size * 0.5;
23425 this.boundingBox.right = x + this.options.icon.size * 0.5;
23426 this.boundingBox.bottom = y + this.options.icon.size * 0.5;
23427
23428 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
23429 var iconTextSpacing = 5;
23430 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
23431 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
23432 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height + iconTextSpacing);
23433 }
23434 }
23435 /**
23436 *
23437 * @param {CanvasRenderingContext2D} ctx
23438 * @param {number} x width
23439 * @param {number} y height
23440 * @param {boolean} selected
23441 * @param {boolean} hover - Unused
23442 * @param {ArrowOptions} values
23443 */
23444
23445 }, {
23446 key: "_icon",
23447 value: function _icon(ctx, x, y, selected, hover, values) {
23448 var iconSize = Number(this.options.icon.size);
23449
23450 if (this.options.icon.code !== undefined) {
23451 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
23452 // properly) substitute slightly bigger size for bold font face.
23453 (this.options.icon.weight != null && selected ? 5 : 0) + iconSize + "px", this.options.icon.face].join(" "); // draw icon
23454
23455 ctx.fillStyle = this.options.icon.color || "black";
23456 ctx.textAlign = "center";
23457 ctx.textBaseline = "middle"; // draw shadow if enabled
23458
23459 this.enableShadow(ctx, values);
23460 ctx.fillText(this.options.icon.code, x, y); // disable shadows for other elements.
23461
23462 this.disableShadow(ctx, values);
23463 } else {
23464 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.");
23465 }
23466 }
23467 /**
23468 *
23469 * @param {CanvasRenderingContext2D} ctx
23470 * @param {number} angle
23471 * @returns {number}
23472 */
23473
23474 }, {
23475 key: "distanceToBorder",
23476 value: function distanceToBorder(ctx, angle) {
23477 return this._distanceToBorder(ctx, angle);
23478 }
23479 }]);
23480
23481 return Icon;
23482 }(NodeBase);
23483
23484 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); }; }
23485
23486 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; } }
23487 /**
23488 * An image-based replacement for the default Node shape.
23489 *
23490 * @augments CircleImageBase
23491 */
23492
23493 var Image$2 = /*#__PURE__*/function (_CircleImageBase) {
23494 _inherits(Image, _CircleImageBase);
23495
23496 var _super = _createSuper$h(Image);
23497
23498 /**
23499 * @param {object} options
23500 * @param {object} body
23501 * @param {Label} labelModule
23502 * @param {Image} imageObj
23503 * @param {Image} imageObjAlt
23504 */
23505 function Image(options, body, labelModule, imageObj, imageObjAlt) {
23506 var _this;
23507
23508 _classCallCheck(this, Image);
23509
23510 _this = _super.call(this, options, body, labelModule);
23511
23512 _this.setImages(imageObj, imageObjAlt);
23513
23514 return _this;
23515 }
23516 /**
23517 *
23518 * @param {CanvasRenderingContext2D} ctx - Unused.
23519 * @param {boolean} [selected]
23520 * @param {boolean} [hover]
23521 */
23522
23523
23524 _createClass(Image, [{
23525 key: "resize",
23526 value: function resize(ctx) {
23527 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
23528 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
23529 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
23530
23531 if (imageAbsent) {
23532 var side = this.options.size * 2;
23533 this.width = side;
23534 this.height = side;
23535 return;
23536 }
23537
23538 if (this.needsRefresh(selected, hover)) {
23539 this._resizeImage();
23540 }
23541 }
23542 /**
23543 *
23544 * @param {CanvasRenderingContext2D} ctx
23545 * @param {number} x width
23546 * @param {number} y height
23547 * @param {boolean} selected
23548 * @param {boolean} hover
23549 * @param {ArrowOptions} values
23550 */
23551
23552 }, {
23553 key: "draw",
23554 value: function draw(ctx, x, y, selected, hover, values) {
23555 ctx.save();
23556 this.switchImages(selected);
23557 this.resize();
23558 var labelX = x,
23559 labelY = y;
23560
23561 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
23562 this.left = x;
23563 this.top = y;
23564 labelX += this.width / 2;
23565 labelY += this.height / 2;
23566 } else {
23567 this.left = x - this.width / 2;
23568 this.top = y - this.height / 2;
23569 }
23570
23571 if (this.options.shapeProperties.useBorderWithImage === true) {
23572 var neutralborderWidth = this.options.borderWidth;
23573 var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
23574 var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
23575 ctx.lineWidth = Math.min(this.width, borderWidth);
23576 ctx.beginPath();
23577 var strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
23578 var fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
23579
23580 if (values.opacity !== undefined) {
23581 strokeStyle = overrideOpacity(strokeStyle, values.opacity);
23582 fillStyle = overrideOpacity(fillStyle, values.opacity);
23583 } // setup the line properties.
23584
23585
23586 ctx.strokeStyle = strokeStyle; // set a fillstyle
23587
23588 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
23589
23590 ctx.rect(this.left - 0.5 * ctx.lineWidth, this.top - 0.5 * ctx.lineWidth, this.width + ctx.lineWidth, this.height + ctx.lineWidth);
23591
23592 fill(ctx).call(ctx);
23593
23594 this.performStroke(ctx, values);
23595 ctx.closePath();
23596 }
23597
23598 this._drawImageAtPosition(ctx, values);
23599
23600 this._drawImageLabel(ctx, labelX, labelY, selected, hover);
23601
23602 this.updateBoundingBox(x, y);
23603 ctx.restore();
23604 }
23605 /**
23606 *
23607 * @param {number} x
23608 * @param {number} y
23609 */
23610
23611 }, {
23612 key: "updateBoundingBox",
23613 value: function updateBoundingBox(x, y) {
23614 this.resize();
23615
23616 if (this.options.shapeProperties.coordinateOrigin === "top-left") {
23617 this.left = x;
23618 this.top = y;
23619 } else {
23620 this.left = x - this.width / 2;
23621 this.top = y - this.height / 2;
23622 }
23623
23624 this.boundingBox.left = this.left;
23625 this.boundingBox.top = this.top;
23626 this.boundingBox.bottom = this.top + this.height;
23627 this.boundingBox.right = this.left + this.width;
23628
23629 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
23630 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
23631 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
23632 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
23633 }
23634 }
23635 /**
23636 *
23637 * @param {CanvasRenderingContext2D} ctx
23638 * @param {number} angle
23639 * @returns {number}
23640 */
23641
23642 }, {
23643 key: "distanceToBorder",
23644 value: function distanceToBorder(ctx, angle) {
23645 return this._distanceToBorder(ctx, angle);
23646 }
23647 }]);
23648
23649 return Image;
23650 }(CircleImageBase);
23651
23652 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); }; }
23653
23654 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; } }
23655 /**
23656 * A Square Node/Cluster shape.
23657 *
23658 * @augments ShapeBase
23659 */
23660
23661 var Square = /*#__PURE__*/function (_ShapeBase) {
23662 _inherits(Square, _ShapeBase);
23663
23664 var _super = _createSuper$g(Square);
23665
23666 /**
23667 * @param {object} options
23668 * @param {object} body
23669 * @param {Label} labelModule
23670 */
23671 function Square(options, body, labelModule) {
23672 _classCallCheck(this, Square);
23673
23674 return _super.call(this, options, body, labelModule);
23675 }
23676 /**
23677 *
23678 * @param {CanvasRenderingContext2D} ctx
23679 * @param {number} x width
23680 * @param {number} y height
23681 * @param {boolean} selected
23682 * @param {boolean} hover
23683 * @param {ArrowOptions} values
23684 * @returns {object} Callbacks to draw later on higher layers.
23685 */
23686
23687
23688 _createClass(Square, [{
23689 key: "draw",
23690 value: function draw(ctx, x, y, selected, hover, values) {
23691 return this._drawShape(ctx, "square", 2, x, y, selected, hover, values);
23692 }
23693 /**
23694 *
23695 * @param {CanvasRenderingContext2D} ctx
23696 * @param {number} angle
23697 * @returns {number}
23698 */
23699
23700 }, {
23701 key: "distanceToBorder",
23702 value: function distanceToBorder(ctx, angle) {
23703 return this._distanceToBorder(ctx, angle);
23704 }
23705 }]);
23706
23707 return Square;
23708 }(ShapeBase);
23709
23710 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); }; }
23711
23712 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; } }
23713 /**
23714 * A Hexagon Node/Cluster shape.
23715 *
23716 * @augments ShapeBase
23717 */
23718
23719 var Hexagon = /*#__PURE__*/function (_ShapeBase) {
23720 _inherits(Hexagon, _ShapeBase);
23721
23722 var _super = _createSuper$f(Hexagon);
23723
23724 /**
23725 * @param {object} options
23726 * @param {object} body
23727 * @param {Label} labelModule
23728 */
23729 function Hexagon(options, body, labelModule) {
23730 _classCallCheck(this, Hexagon);
23731
23732 return _super.call(this, options, body, labelModule);
23733 }
23734 /**
23735 *
23736 * @param {CanvasRenderingContext2D} ctx
23737 * @param {number} x width
23738 * @param {number} y height
23739 * @param {boolean} selected
23740 * @param {boolean} hover
23741 * @param {ArrowOptions} values
23742 * @returns {object} Callbacks to draw later on higher layers.
23743 */
23744
23745
23746 _createClass(Hexagon, [{
23747 key: "draw",
23748 value: function draw(ctx, x, y, selected, hover, values) {
23749 return this._drawShape(ctx, "hexagon", 4, x, y, selected, hover, values);
23750 }
23751 /**
23752 *
23753 * @param {CanvasRenderingContext2D} ctx
23754 * @param {number} angle
23755 * @returns {number}
23756 */
23757
23758 }, {
23759 key: "distanceToBorder",
23760 value: function distanceToBorder(ctx, angle) {
23761 return this._distanceToBorder(ctx, angle);
23762 }
23763 }]);
23764
23765 return Hexagon;
23766 }(ShapeBase);
23767
23768 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); }; }
23769
23770 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; } }
23771 /**
23772 * A Star Node/Cluster shape.
23773 *
23774 * @augments ShapeBase
23775 */
23776
23777 var Star = /*#__PURE__*/function (_ShapeBase) {
23778 _inherits(Star, _ShapeBase);
23779
23780 var _super = _createSuper$e(Star);
23781
23782 /**
23783 * @param {object} options
23784 * @param {object} body
23785 * @param {Label} labelModule
23786 */
23787 function Star(options, body, labelModule) {
23788 _classCallCheck(this, Star);
23789
23790 return _super.call(this, options, body, labelModule);
23791 }
23792 /**
23793 *
23794 * @param {CanvasRenderingContext2D} ctx
23795 * @param {number} x width
23796 * @param {number} y height
23797 * @param {boolean} selected
23798 * @param {boolean} hover
23799 * @param {ArrowOptions} values
23800 * @returns {object} Callbacks to draw later on higher layers.
23801 */
23802
23803
23804 _createClass(Star, [{
23805 key: "draw",
23806 value: function draw(ctx, x, y, selected, hover, values) {
23807 return this._drawShape(ctx, "star", 4, x, y, selected, hover, values);
23808 }
23809 /**
23810 *
23811 * @param {CanvasRenderingContext2D} ctx
23812 * @param {number} angle
23813 * @returns {number}
23814 */
23815
23816 }, {
23817 key: "distanceToBorder",
23818 value: function distanceToBorder(ctx, angle) {
23819 return this._distanceToBorder(ctx, angle);
23820 }
23821 }]);
23822
23823 return Star;
23824 }(ShapeBase);
23825
23826 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); }; }
23827
23828 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; } }
23829 /**
23830 * A text-based replacement for the default Node shape.
23831 *
23832 * @augments NodeBase
23833 */
23834
23835 var Text = /*#__PURE__*/function (_NodeBase) {
23836 _inherits(Text, _NodeBase);
23837
23838 var _super = _createSuper$d(Text);
23839
23840 /**
23841 * @param {object} options
23842 * @param {object} body
23843 * @param {Label} labelModule
23844 */
23845 function Text(options, body, labelModule) {
23846 var _this;
23847
23848 _classCallCheck(this, Text);
23849
23850 _this = _super.call(this, options, body, labelModule);
23851
23852 _this._setMargins(labelModule);
23853
23854 return _this;
23855 }
23856 /**
23857 *
23858 * @param {CanvasRenderingContext2D} ctx
23859 * @param {boolean} selected
23860 * @param {boolean} hover
23861 */
23862
23863
23864 _createClass(Text, [{
23865 key: "resize",
23866 value: function resize(ctx, selected, hover) {
23867 if (this.needsRefresh(selected, hover)) {
23868 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
23869 this.width = this.textSize.width + this.margin.right + this.margin.left;
23870 this.height = this.textSize.height + this.margin.top + this.margin.bottom;
23871 this.radius = 0.5 * this.width;
23872 }
23873 }
23874 /**
23875 *
23876 * @param {CanvasRenderingContext2D} ctx
23877 * @param {number} x width
23878 * @param {number} y height
23879 * @param {boolean} selected
23880 * @param {boolean} hover
23881 * @param {ArrowOptions} values
23882 */
23883
23884 }, {
23885 key: "draw",
23886 value: function draw(ctx, x, y, selected, hover, values) {
23887 this.resize(ctx, selected, hover);
23888 this.left = x - this.width / 2;
23889 this.top = y - this.height / 2; // draw shadow if enabled
23890
23891 this.enableShadow(ctx, values);
23892 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.
23893
23894 this.disableShadow(ctx, values);
23895 this.updateBoundingBox(x, y, ctx, selected, hover);
23896 }
23897 /**
23898 *
23899 * @param {CanvasRenderingContext2D} ctx
23900 * @param {number} angle
23901 * @returns {number}
23902 */
23903
23904 }, {
23905 key: "distanceToBorder",
23906 value: function distanceToBorder(ctx, angle) {
23907 return this._distanceToBorder(ctx, angle);
23908 }
23909 }]);
23910
23911 return Text;
23912 }(NodeBase);
23913
23914 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); }; }
23915
23916 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; } }
23917 /**
23918 * A Triangle Node/Cluster shape.
23919 *
23920 * @augments ShapeBase
23921 */
23922
23923 var Triangle$1 = /*#__PURE__*/function (_ShapeBase) {
23924 _inherits(Triangle, _ShapeBase);
23925
23926 var _super = _createSuper$c(Triangle);
23927
23928 /**
23929 * @param {object} options
23930 * @param {object} body
23931 * @param {Label} labelModule
23932 */
23933 function Triangle(options, body, labelModule) {
23934 _classCallCheck(this, Triangle);
23935
23936 return _super.call(this, options, body, labelModule);
23937 }
23938 /**
23939 *
23940 * @param {CanvasRenderingContext2D} ctx
23941 * @param {number} x
23942 * @param {number} y
23943 * @param {boolean} selected
23944 * @param {boolean} hover
23945 * @param {ArrowOptions} values
23946 * @returns {object} Callbacks to draw later on higher layers.
23947 */
23948
23949
23950 _createClass(Triangle, [{
23951 key: "draw",
23952 value: function draw(ctx, x, y, selected, hover, values) {
23953 return this._drawShape(ctx, "triangle", 3, x, y, selected, hover, values);
23954 }
23955 /**
23956 *
23957 * @param {CanvasRenderingContext2D} ctx
23958 * @param {number} angle
23959 * @returns {number}
23960 */
23961
23962 }, {
23963 key: "distanceToBorder",
23964 value: function distanceToBorder(ctx, angle) {
23965 return this._distanceToBorder(ctx, angle);
23966 }
23967 }]);
23968
23969 return Triangle;
23970 }(ShapeBase);
23971
23972 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); }; }
23973
23974 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; } }
23975 /**
23976 * A downward facing Triangle Node/Cluster shape.
23977 *
23978 * @augments ShapeBase
23979 */
23980
23981 var TriangleDown = /*#__PURE__*/function (_ShapeBase) {
23982 _inherits(TriangleDown, _ShapeBase);
23983
23984 var _super = _createSuper$b(TriangleDown);
23985
23986 /**
23987 * @param {object} options
23988 * @param {object} body
23989 * @param {Label} labelModule
23990 */
23991 function TriangleDown(options, body, labelModule) {
23992 _classCallCheck(this, TriangleDown);
23993
23994 return _super.call(this, options, body, labelModule);
23995 }
23996 /**
23997 *
23998 * @param {CanvasRenderingContext2D} ctx
23999 * @param {number} x
24000 * @param {number} y
24001 * @param {boolean} selected
24002 * @param {boolean} hover
24003 * @param {ArrowOptions} values
24004 * @returns {object} Callbacks to draw later on higher layers.
24005 */
24006
24007
24008 _createClass(TriangleDown, [{
24009 key: "draw",
24010 value: function draw(ctx, x, y, selected, hover, values) {
24011 return this._drawShape(ctx, "triangleDown", 3, x, y, selected, hover, values);
24012 }
24013 /**
24014 *
24015 * @param {CanvasRenderingContext2D} ctx
24016 * @param {number} angle
24017 * @returns {number}
24018 */
24019
24020 }, {
24021 key: "distanceToBorder",
24022 value: function distanceToBorder(ctx, angle) {
24023 return this._distanceToBorder(ctx, angle);
24024 }
24025 }]);
24026
24027 return TriangleDown;
24028 }(ShapeBase);
24029
24030 function ownKeys$2(object, enumerableOnly) { var keys = keys$4(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); enumerableOnly && (symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$3(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
24031
24032 function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var _context5, _context6; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? forEach$2(_context5 = ownKeys$2(Object(source), !0)).call(_context5, function (key) { _defineProperty(target, key, source[key]); }) : getOwnPropertyDescriptors ? defineProperties(target, getOwnPropertyDescriptors(source)) : forEach$2(_context6 = ownKeys$2(Object(source))).call(_context6, function (key) { defineProperty$6(target, key, getOwnPropertyDescriptor$3(source, key)); }); } return target; }
24033 /**
24034 * A node. A node can be connected to other nodes via one or multiple edges.
24035 */
24036
24037 var Node = /*#__PURE__*/function () {
24038 /**
24039 *
24040 * @param {object} options An object containing options for the node. All
24041 * options are optional, except for the id.
24042 * {number} id Id of the node. Required
24043 * {string} label Text label for the node
24044 * {number} x Horizontal position of the node
24045 * {number} y Vertical position of the node
24046 * {string} shape Node shape
24047 * {string} image An image url
24048 * {string} title A title text, can be HTML
24049 * {anytype} group A group name or number
24050 * @param {object} body Shared state of current network instance
24051 * @param {Network.Images} imagelist A list with images. Only needed when the node has an image
24052 * @param {Groups} grouplist A list with groups. Needed for retrieving group options
24053 * @param {object} globalOptions Current global node options; these serve as defaults for the node instance
24054 * @param {object} defaultOptions Global default options for nodes; note that this is also the prototype
24055 * for parameter `globalOptions`.
24056 */
24057 function Node(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
24058 _classCallCheck(this, Node);
24059
24060 this.options = bridgeObject(globalOptions);
24061 this.globalOptions = globalOptions;
24062 this.defaultOptions = defaultOptions;
24063 this.body = body;
24064 this.edges = []; // all edges connected to this node
24065 // set defaults for the options
24066
24067 this.id = undefined;
24068 this.imagelist = imagelist;
24069 this.grouplist = grouplist; // state options
24070
24071 this.x = undefined;
24072 this.y = undefined;
24073 this.baseSize = this.options.size;
24074 this.baseFontSize = this.options.font.size;
24075 this.predefinedPosition = false; // used to check if initial fit should just take the range or approximate
24076
24077 this.selected = false;
24078 this.hover = false;
24079 this.labelModule = new Label(this.body, this.options, false
24080 /* Not edge label */
24081 );
24082 this.setOptions(options);
24083 }
24084 /**
24085 * Attach a edge to the node
24086 *
24087 * @param {Edge} edge
24088 */
24089
24090
24091 _createClass(Node, [{
24092 key: "attachEdge",
24093 value: function attachEdge(edge) {
24094 var _context;
24095
24096 if (indexOf(_context = this.edges).call(_context, edge) === -1) {
24097 this.edges.push(edge);
24098 }
24099 }
24100 /**
24101 * Detach a edge from the node
24102 *
24103 * @param {Edge} edge
24104 */
24105
24106 }, {
24107 key: "detachEdge",
24108 value: function detachEdge(edge) {
24109 var _context2;
24110
24111 var index = indexOf(_context2 = this.edges).call(_context2, edge);
24112
24113 if (index != -1) {
24114 var _context3;
24115
24116 splice$1(_context3 = this.edges).call(_context3, index, 1);
24117 }
24118 }
24119 /**
24120 * Set or overwrite options for the node
24121 *
24122 * @param {object} options an object with options
24123 * @returns {null|boolean}
24124 */
24125
24126 }, {
24127 key: "setOptions",
24128 value: function setOptions(options) {
24129 var currentShape = this.options.shape;
24130
24131 if (!options) {
24132 return; // Note that the return value will be 'undefined'! This is OK.
24133 } // Save the color for later.
24134 // This is necessary in order to prevent local color from being overwritten by group color.
24135 // TODO: To prevent such workarounds the way options are handled should be rewritten from scratch.
24136 // This is not the only problem with current options handling.
24137
24138
24139 if (typeof options.color !== "undefined") {
24140 this._localColor = options.color;
24141 } // basic options
24142
24143
24144 if (options.id !== undefined) {
24145 this.id = options.id;
24146 }
24147
24148 if (this.id === undefined) {
24149 throw new Error("Node must have an id");
24150 }
24151
24152 Node.checkMass(options, this.id); // set these options locally
24153 // clear x and y positions
24154
24155 if (options.x !== undefined) {
24156 if (options.x === null) {
24157 this.x = undefined;
24158 this.predefinedPosition = false;
24159 } else {
24160 this.x = _parseInt(options.x);
24161 this.predefinedPosition = true;
24162 }
24163 }
24164
24165 if (options.y !== undefined) {
24166 if (options.y === null) {
24167 this.y = undefined;
24168 this.predefinedPosition = false;
24169 } else {
24170 this.y = _parseInt(options.y);
24171 this.predefinedPosition = true;
24172 }
24173 }
24174
24175 if (options.size !== undefined) {
24176 this.baseSize = options.size;
24177 }
24178
24179 if (options.value !== undefined) {
24180 options.value = _parseFloat(options.value);
24181 } // this transforms all shorthands into fully defined options
24182
24183
24184 Node.parseOptions(this.options, options, true, this.globalOptions, this.grouplist);
24185 var pile = [options, this.options, this.defaultOptions];
24186 this.chooser = choosify("node", pile);
24187
24188 this._load_images();
24189
24190 this.updateLabelModule(options); // Need to set local opacity after `this.updateLabelModule(options);` because `this.updateLabelModule(options);` overrites local opacity with group opacity
24191
24192 if (options.opacity !== undefined && Node.checkOpacity(options.opacity)) {
24193 this.options.opacity = options.opacity;
24194 }
24195
24196 this.updateShape(currentShape);
24197 return options.hidden !== undefined || options.physics !== undefined;
24198 }
24199 /**
24200 * Load the images from the options, for the nodes that need them.
24201 *
24202 * Images are always loaded, even if they are not used in the current shape.
24203 * The user may switch to an image shape later on.
24204 *
24205 * @private
24206 */
24207
24208 }, {
24209 key: "_load_images",
24210 value: function _load_images() {
24211 if (this.options.shape === "circularImage" || this.options.shape === "image") {
24212 if (this.options.image === undefined) {
24213 throw new Error("Option image must be defined for node type '" + this.options.shape + "'");
24214 }
24215 }
24216
24217 if (this.options.image === undefined) {
24218 return;
24219 }
24220
24221 if (this.imagelist === undefined) {
24222 throw new Error("Internal Error: No images provided");
24223 }
24224
24225 if (typeof this.options.image === "string") {
24226 this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
24227 } else {
24228 if (this.options.image.unselected === undefined) {
24229 throw new Error("No unselected image provided");
24230 }
24231
24232 this.imageObj = this.imagelist.load(this.options.image.unselected, this.options.brokenImage, this.id);
24233
24234 if (this.options.image.selected !== undefined) {
24235 this.imageObjAlt = this.imagelist.load(this.options.image.selected, this.options.brokenImage, this.id);
24236 } else {
24237 this.imageObjAlt = undefined;
24238 }
24239 }
24240 }
24241 /**
24242 * Check that opacity is only between 0 and 1
24243 *
24244 * @param {number} opacity
24245 * @returns {boolean}
24246 */
24247
24248 }, {
24249 key: "getFormattingValues",
24250 value:
24251 /**
24252 *
24253 * @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: *}}
24254 */
24255 function getFormattingValues() {
24256 var values = {
24257 color: this.options.color.background,
24258 opacity: this.options.opacity,
24259 borderWidth: this.options.borderWidth,
24260 borderColor: this.options.color.border,
24261 size: this.options.size,
24262 borderDashes: this.options.shapeProperties.borderDashes,
24263 borderRadius: this.options.shapeProperties.borderRadius,
24264 shadow: this.options.shadow.enabled,
24265 shadowColor: this.options.shadow.color,
24266 shadowSize: this.options.shadow.size,
24267 shadowX: this.options.shadow.x,
24268 shadowY: this.options.shadow.y
24269 };
24270
24271 if (this.selected || this.hover) {
24272 if (this.chooser === true) {
24273 if (this.selected) {
24274 if (this.options.borderWidthSelected != null) {
24275 values.borderWidth = this.options.borderWidthSelected;
24276 } else {
24277 values.borderWidth *= 2;
24278 }
24279
24280 values.color = this.options.color.highlight.background;
24281 values.borderColor = this.options.color.highlight.border;
24282 values.shadow = this.options.shadow.enabled;
24283 } else if (this.hover) {
24284 values.color = this.options.color.hover.background;
24285 values.borderColor = this.options.color.hover.border;
24286 values.shadow = this.options.shadow.enabled;
24287 }
24288 } else if (typeof this.chooser === "function") {
24289 this.chooser(values, this.options.id, this.selected, this.hover);
24290
24291 if (values.shadow === false) {
24292 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) {
24293 values.shadow = true;
24294 }
24295 }
24296 }
24297 } else {
24298 values.shadow = this.options.shadow.enabled;
24299 }
24300
24301 if (this.options.opacity !== undefined) {
24302 var opacity = this.options.opacity;
24303 values.borderColor = overrideOpacity(values.borderColor, opacity);
24304 values.color = overrideOpacity(values.color, opacity);
24305 values.shadowColor = overrideOpacity(values.shadowColor, opacity);
24306 }
24307
24308 return values;
24309 }
24310 /**
24311 *
24312 * @param {object} options
24313 */
24314
24315 }, {
24316 key: "updateLabelModule",
24317 value: function updateLabelModule(options) {
24318 if (this.options.label === undefined || this.options.label === null) {
24319 this.options.label = "";
24320 }
24321
24322 Node.updateGroupOptions(this.options, _objectSpread$2(_objectSpread$2({}, options), {}, {
24323 color: options && options.color || this._localColor || undefined
24324 }), this.grouplist); //
24325 // Note:The prototype chain for this.options is:
24326 //
24327 // this.options -> NodesHandler.options -> NodesHandler.defaultOptions
24328 // (also: this.globalOptions)
24329 //
24330 // Note that the prototypes are mentioned explicitly in the pile list below;
24331 // WE DON'T WANT THE ORDER OF THE PROTOTYPES!!!! At least, not for font handling of labels.
24332 // This is a good indication that the prototype usage of options is deficient.
24333 //
24334
24335 var currentGroup = this.grouplist.get(this.options.group, false);
24336 var pile = [options, // new options
24337 this.options, // current node options, see comment above for prototype
24338 currentGroup, // group options, if any
24339 this.globalOptions, // Currently set global node options
24340 this.defaultOptions // Default global node options
24341 ];
24342 this.labelModule.update(this.options, pile);
24343
24344 if (this.labelModule.baseSize !== undefined) {
24345 this.baseFontSize = this.labelModule.baseSize;
24346 }
24347 }
24348 /**
24349 *
24350 * @param {string} currentShape
24351 */
24352
24353 }, {
24354 key: "updateShape",
24355 value: function updateShape(currentShape) {
24356 if (currentShape === this.options.shape && this.shape) {
24357 this.shape.setOptions(this.options, this.imageObj, this.imageObjAlt);
24358 } else {
24359 // choose draw method depending on the shape
24360 switch (this.options.shape) {
24361 case "box":
24362 this.shape = new Box$1(this.options, this.body, this.labelModule);
24363 break;
24364
24365 case "circle":
24366 this.shape = new Circle$1(this.options, this.body, this.labelModule);
24367 break;
24368
24369 case "circularImage":
24370 this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
24371 break;
24372
24373 case "custom":
24374 this.shape = new CustomShape(this.options, this.body, this.labelModule, this.options.ctxRenderer);
24375 break;
24376
24377 case "database":
24378 this.shape = new Database(this.options, this.body, this.labelModule);
24379 break;
24380
24381 case "diamond":
24382 this.shape = new Diamond$1(this.options, this.body, this.labelModule);
24383 break;
24384
24385 case "dot":
24386 this.shape = new Dot(this.options, this.body, this.labelModule);
24387 break;
24388
24389 case "ellipse":
24390 this.shape = new Ellipse(this.options, this.body, this.labelModule);
24391 break;
24392
24393 case "icon":
24394 this.shape = new Icon(this.options, this.body, this.labelModule);
24395 break;
24396
24397 case "image":
24398 this.shape = new Image$2(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
24399 break;
24400
24401 case "square":
24402 this.shape = new Square(this.options, this.body, this.labelModule);
24403 break;
24404
24405 case "hexagon":
24406 this.shape = new Hexagon(this.options, this.body, this.labelModule);
24407 break;
24408
24409 case "star":
24410 this.shape = new Star(this.options, this.body, this.labelModule);
24411 break;
24412
24413 case "text":
24414 this.shape = new Text(this.options, this.body, this.labelModule);
24415 break;
24416
24417 case "triangle":
24418 this.shape = new Triangle$1(this.options, this.body, this.labelModule);
24419 break;
24420
24421 case "triangleDown":
24422 this.shape = new TriangleDown(this.options, this.body, this.labelModule);
24423 break;
24424
24425 default:
24426 this.shape = new Ellipse(this.options, this.body, this.labelModule);
24427 break;
24428 }
24429 }
24430
24431 this.needsRefresh();
24432 }
24433 /**
24434 * select this node
24435 */
24436
24437 }, {
24438 key: "select",
24439 value: function select() {
24440 this.selected = true;
24441 this.needsRefresh();
24442 }
24443 /**
24444 * unselect this node
24445 */
24446
24447 }, {
24448 key: "unselect",
24449 value: function unselect() {
24450 this.selected = false;
24451 this.needsRefresh();
24452 }
24453 /**
24454 * Reset the calculated size of the node, forces it to recalculate its size
24455 */
24456
24457 }, {
24458 key: "needsRefresh",
24459 value: function needsRefresh() {
24460 this.shape.refreshNeeded = true;
24461 }
24462 /**
24463 * get the title of this node.
24464 *
24465 * @returns {string} title The title of the node, or undefined when no title
24466 * has been set.
24467 */
24468
24469 }, {
24470 key: "getTitle",
24471 value: function getTitle() {
24472 return this.options.title;
24473 }
24474 /**
24475 * Calculate the distance to the border of the Node
24476 *
24477 * @param {CanvasRenderingContext2D} ctx
24478 * @param {number} angle Angle in radians
24479 * @returns {number} distance Distance to the border in pixels
24480 */
24481
24482 }, {
24483 key: "distanceToBorder",
24484 value: function distanceToBorder(ctx, angle) {
24485 return this.shape.distanceToBorder(ctx, angle);
24486 }
24487 /**
24488 * Check if this node has a fixed x and y position
24489 *
24490 * @returns {boolean} true if fixed, false if not
24491 */
24492
24493 }, {
24494 key: "isFixed",
24495 value: function isFixed() {
24496 return this.options.fixed.x && this.options.fixed.y;
24497 }
24498 /**
24499 * check if this node is selecte
24500 *
24501 * @returns {boolean} selected True if node is selected, else false
24502 */
24503
24504 }, {
24505 key: "isSelected",
24506 value: function isSelected() {
24507 return this.selected;
24508 }
24509 /**
24510 * Retrieve the value of the node. Can be undefined
24511 *
24512 * @returns {number} value
24513 */
24514
24515 }, {
24516 key: "getValue",
24517 value: function getValue() {
24518 return this.options.value;
24519 }
24520 /**
24521 * Get the current dimensions of the label
24522 *
24523 * @returns {rect}
24524 */
24525
24526 }, {
24527 key: "getLabelSize",
24528 value: function getLabelSize() {
24529 return this.labelModule.size();
24530 }
24531 /**
24532 * Adjust the value range of the node. The node will adjust it's size
24533 * based on its value.
24534 *
24535 * @param {number} min
24536 * @param {number} max
24537 * @param {number} total
24538 */
24539
24540 }, {
24541 key: "setValueRange",
24542 value: function setValueRange(min, max, total) {
24543 if (this.options.value !== undefined) {
24544 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
24545 var sizeDiff = this.options.scaling.max - this.options.scaling.min;
24546
24547 if (this.options.scaling.label.enabled === true) {
24548 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
24549 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
24550 }
24551
24552 this.options.size = this.options.scaling.min + scale * sizeDiff;
24553 } else {
24554 this.options.size = this.baseSize;
24555 this.options.font.size = this.baseFontSize;
24556 }
24557
24558 this.updateLabelModule();
24559 }
24560 /**
24561 * Draw this node in the given canvas
24562 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
24563 *
24564 * @param {CanvasRenderingContext2D} ctx
24565 * @returns {object} Callbacks to draw later on higher layers.
24566 */
24567
24568 }, {
24569 key: "draw",
24570 value: function draw(ctx) {
24571 var values = this.getFormattingValues();
24572 return this.shape.draw(ctx, this.x, this.y, this.selected, this.hover, values) || {};
24573 }
24574 /**
24575 * Update the bounding box of the shape
24576 *
24577 * @param {CanvasRenderingContext2D} ctx
24578 */
24579
24580 }, {
24581 key: "updateBoundingBox",
24582 value: function updateBoundingBox(ctx) {
24583 this.shape.updateBoundingBox(this.x, this.y, ctx);
24584 }
24585 /**
24586 * Recalculate the size of this node in the given canvas
24587 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
24588 *
24589 * @param {CanvasRenderingContext2D} ctx
24590 */
24591
24592 }, {
24593 key: "resize",
24594 value: function resize(ctx) {
24595 var values = this.getFormattingValues();
24596 this.shape.resize(ctx, this.selected, this.hover, values);
24597 }
24598 /**
24599 * Determine all visual elements of this node instance, in which the given
24600 * point falls within the bounding shape.
24601 *
24602 * @param {point} point
24603 * @returns {Array.<nodeClickItem|nodeLabelClickItem>} list with the items which are on the point
24604 */
24605
24606 }, {
24607 key: "getItemsOnPoint",
24608 value: function getItemsOnPoint(point) {
24609 var ret = [];
24610
24611 if (this.labelModule.visible()) {
24612 if (pointInRect(this.labelModule.getSize(), point)) {
24613 ret.push({
24614 nodeId: this.id,
24615 labelId: 0
24616 });
24617 }
24618 }
24619
24620 if (pointInRect(this.shape.boundingBox, point)) {
24621 ret.push({
24622 nodeId: this.id
24623 });
24624 }
24625
24626 return ret;
24627 }
24628 /**
24629 * Check if this object is overlapping with the provided object
24630 *
24631 * @param {object} obj an object with parameters left, top, right, bottom
24632 * @returns {boolean} True if location is located on node
24633 */
24634
24635 }, {
24636 key: "isOverlappingWith",
24637 value: function isOverlappingWith(obj) {
24638 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;
24639 }
24640 /**
24641 * Check if this object is overlapping with the provided object
24642 *
24643 * @param {object} obj an object with parameters left, top, right, bottom
24644 * @returns {boolean} True if location is located on node
24645 */
24646
24647 }, {
24648 key: "isBoundingBoxOverlappingWith",
24649 value: function isBoundingBoxOverlappingWith(obj) {
24650 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;
24651 }
24652 /**
24653 * Check valid values for mass
24654 *
24655 * The mass may not be negative or zero. If it is, reset to 1
24656 *
24657 * @param {object} options
24658 * @param {Node.id} id
24659 * @static
24660 */
24661
24662 }], [{
24663 key: "checkOpacity",
24664 value: function checkOpacity(opacity) {
24665 return 0 <= opacity && opacity <= 1;
24666 }
24667 /**
24668 * Check that origin is 'center' or 'top-left'
24669 *
24670 * @param {string} origin
24671 * @returns {boolean}
24672 */
24673
24674 }, {
24675 key: "checkCoordinateOrigin",
24676 value: function checkCoordinateOrigin(origin) {
24677 return origin === undefined || origin === "center" || origin === "top-left";
24678 }
24679 /**
24680 * Copy group option values into the node options.
24681 *
24682 * The group options override the global node options, so the copy of group options
24683 * must happen *after* the global node options have been set.
24684 *
24685 * This method must also be called also if the global node options have changed and the group options did not.
24686 *
24687 * @param {object} parentOptions
24688 * @param {object} newOptions new values for the options, currently only passed in for check
24689 * @param {object} groupList
24690 */
24691
24692 }, {
24693 key: "updateGroupOptions",
24694 value: function updateGroupOptions(parentOptions, newOptions, groupList) {
24695 var _context4;
24696
24697 if (groupList === undefined) return; // No groups, nothing to do
24698
24699 var group = parentOptions.group; // paranoia: the selected group is already merged into node options, check.
24700
24701 if (newOptions !== undefined && newOptions.group !== undefined && group !== newOptions.group) {
24702 throw new Error("updateGroupOptions: group values in options don't match.");
24703 }
24704
24705 var hasGroup = typeof group === "number" || typeof group === "string" && group != "";
24706 if (!hasGroup) return; // current node has no group, no need to merge
24707
24708 var groupObj = groupList.get(group);
24709
24710 if (groupObj.opacity !== undefined && newOptions.opacity === undefined) {
24711 if (!Node.checkOpacity(groupObj.opacity)) {
24712 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + groupObj.opacity);
24713 groupObj.opacity = undefined;
24714 }
24715 } // Skip any new option to avoid them being overridden by the group options.
24716
24717
24718 var skipProperties = filter(_context4 = getOwnPropertyNames(newOptions)).call(_context4, function (p) {
24719 return newOptions[p] != null;
24720 }); // Always skip merging group font options into parent; these are required to be distinct for labels
24721
24722
24723 skipProperties.push("font");
24724 selectiveNotDeepExtend(skipProperties, parentOptions, groupObj); // the color object needs to be completely defined.
24725 // Since groups can partially overwrite the colors, we parse it again, just in case.
24726
24727 parentOptions.color = parseColor(parentOptions.color);
24728 }
24729 /**
24730 * This process all possible shorthands in the new options and makes sure that the parentOptions are fully defined.
24731 * Static so it can also be used by the handler.
24732 *
24733 * @param {object} parentOptions
24734 * @param {object} newOptions
24735 * @param {boolean} [allowDeletion=false]
24736 * @param {object} [globalOptions={}]
24737 * @param {object} [groupList]
24738 * @static
24739 */
24740
24741 }, {
24742 key: "parseOptions",
24743 value: function parseOptions(parentOptions, newOptions) {
24744 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
24745 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
24746 var groupList = arguments.length > 4 ? arguments[4] : undefined;
24747 var fields = ["color", "fixed", "shadow"];
24748 selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);
24749 Node.checkMass(newOptions);
24750
24751 if (parentOptions.opacity !== undefined) {
24752 if (!Node.checkOpacity(parentOptions.opacity)) {
24753 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + parentOptions.opacity);
24754 parentOptions.opacity = undefined;
24755 }
24756 }
24757
24758 if (newOptions.opacity !== undefined) {
24759 if (!Node.checkOpacity(newOptions.opacity)) {
24760 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + newOptions.opacity);
24761 newOptions.opacity = undefined;
24762 }
24763 }
24764
24765 if (newOptions.shapeProperties && !Node.checkCoordinateOrigin(newOptions.shapeProperties.coordinateOrigin)) {
24766 console.error("Invalid option for node coordinateOrigin, found: " + newOptions.shapeProperties.coordinateOrigin);
24767 } // merge the shadow options into the parent.
24768
24769
24770 mergeOptions(parentOptions, newOptions, "shadow", globalOptions); // individual shape newOptions
24771
24772 if (newOptions.color !== undefined && newOptions.color !== null) {
24773 var parsedColor = parseColor(newOptions.color);
24774 fillIfDefined(parentOptions.color, parsedColor);
24775 } else if (allowDeletion === true && newOptions.color === null) {
24776 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
24777 } // handle the fixed options
24778
24779
24780 if (newOptions.fixed !== undefined && newOptions.fixed !== null) {
24781 if (typeof newOptions.fixed === "boolean") {
24782 parentOptions.fixed.x = newOptions.fixed;
24783 parentOptions.fixed.y = newOptions.fixed;
24784 } else {
24785 if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === "boolean") {
24786 parentOptions.fixed.x = newOptions.fixed.x;
24787 }
24788
24789 if (newOptions.fixed.y !== undefined && typeof newOptions.fixed.y === "boolean") {
24790 parentOptions.fixed.y = newOptions.fixed.y;
24791 }
24792 }
24793 }
24794
24795 if (allowDeletion === true && newOptions.font === null) {
24796 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
24797 }
24798
24799 Node.updateGroupOptions(parentOptions, newOptions, groupList); // handle the scaling options, specifically the label part
24800
24801 if (newOptions.scaling !== undefined) {
24802 mergeOptions(parentOptions.scaling, newOptions.scaling, "label", globalOptions.scaling);
24803 }
24804 }
24805 }, {
24806 key: "checkMass",
24807 value: function checkMass(options, id) {
24808 if (options.mass !== undefined && options.mass <= 0) {
24809 var strId = "";
24810
24811 if (id !== undefined) {
24812 strId = " in node id: " + id;
24813 }
24814
24815 console.error("%cNegative or zero mass disallowed" + strId + ", setting mass to 1.", VALIDATOR_PRINT_STYLE);
24816 options.mass = 1;
24817 }
24818 }
24819 }]);
24820
24821 return Node;
24822 }();
24823
24824 function _createForOfIteratorHelper$6(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$2(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; } } }; }
24825
24826 function _unsupportedIterableToArray$6(o, minLen) { var _context4; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$6(o, minLen); var n = slice(_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$3(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$6(o, minLen); }
24827
24828 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; }
24829 /**
24830 * Handler for Nodes
24831 */
24832
24833 var NodesHandler = /*#__PURE__*/function () {
24834 /**
24835 * @param {object} body
24836 * @param {Images} images
24837 * @param {Array.<Group>} groups
24838 * @param {LayoutEngine} layoutEngine
24839 */
24840 function NodesHandler(body, images, groups, layoutEngine) {
24841 var _context,
24842 _this = this;
24843
24844 _classCallCheck(this, NodesHandler);
24845
24846 this.body = body;
24847 this.images = images;
24848 this.groups = groups;
24849 this.layoutEngine = layoutEngine; // create the node API in the body container
24850
24851 this.body.functions.createNode = bind$6(_context = this.create).call(_context, this);
24852 this.nodesListeners = {
24853 add: function add(event, params) {
24854 _this.add(params.items);
24855 },
24856 update: function update(event, params) {
24857 _this.update(params.items, params.data, params.oldData);
24858 },
24859 remove: function remove(event, params) {
24860 _this.remove(params.items);
24861 }
24862 };
24863 this.defaultOptions = {
24864 borderWidth: 1,
24865 borderWidthSelected: undefined,
24866 brokenImage: undefined,
24867 color: {
24868 border: "#2B7CE9",
24869 background: "#97C2FC",
24870 highlight: {
24871 border: "#2B7CE9",
24872 background: "#D2E5FF"
24873 },
24874 hover: {
24875 border: "#2B7CE9",
24876 background: "#D2E5FF"
24877 }
24878 },
24879 opacity: undefined,
24880 // number between 0 and 1
24881 fixed: {
24882 x: false,
24883 y: false
24884 },
24885 font: {
24886 color: "#343434",
24887 size: 14,
24888 // px
24889 face: "arial",
24890 background: "none",
24891 strokeWidth: 0,
24892 // px
24893 strokeColor: "#ffffff",
24894 align: "center",
24895 vadjust: 0,
24896 multi: false,
24897 bold: {
24898 mod: "bold"
24899 },
24900 boldital: {
24901 mod: "bold italic"
24902 },
24903 ital: {
24904 mod: "italic"
24905 },
24906 mono: {
24907 mod: "",
24908 size: 15,
24909 // px
24910 face: "monospace",
24911 vadjust: 2
24912 }
24913 },
24914 group: undefined,
24915 hidden: false,
24916 icon: {
24917 face: "FontAwesome",
24918 //'FontAwesome',
24919 code: undefined,
24920 //'\uf007',
24921 size: 50,
24922 //50,
24923 color: "#2B7CE9" //'#aa00ff'
24924
24925 },
24926 image: undefined,
24927 // --> URL
24928 imagePadding: {
24929 // only for image shape
24930 top: 0,
24931 right: 0,
24932 bottom: 0,
24933 left: 0
24934 },
24935 label: undefined,
24936 labelHighlightBold: true,
24937 level: undefined,
24938 margin: {
24939 top: 5,
24940 right: 5,
24941 bottom: 5,
24942 left: 5
24943 },
24944 mass: 1,
24945 physics: true,
24946 scaling: {
24947 min: 10,
24948 max: 30,
24949 label: {
24950 enabled: false,
24951 min: 14,
24952 max: 30,
24953 maxVisible: 30,
24954 drawThreshold: 5
24955 },
24956 customScalingFunction: function customScalingFunction(min, max, total, value) {
24957 if (max === min) {
24958 return 0.5;
24959 } else {
24960 var scale = 1 / (max - min);
24961 return Math.max(0, (value - min) * scale);
24962 }
24963 }
24964 },
24965 shadow: {
24966 enabled: false,
24967 color: "rgba(0,0,0,0.5)",
24968 size: 10,
24969 x: 5,
24970 y: 5
24971 },
24972 shape: "ellipse",
24973 shapeProperties: {
24974 borderDashes: false,
24975 // only for borders
24976 borderRadius: 6,
24977 // only for box shape
24978 interpolation: true,
24979 // only for image and circularImage shapes
24980 useImageSize: false,
24981 // only for image and circularImage shapes
24982 useBorderWithImage: false,
24983 // only for image shape
24984 coordinateOrigin: "center" // only for image and circularImage shapes
24985
24986 },
24987 size: 25,
24988 title: undefined,
24989 value: undefined,
24990 x: undefined,
24991 y: undefined
24992 }; // Protect from idiocy
24993
24994 if (this.defaultOptions.mass <= 0) {
24995 throw "Internal error: mass in defaultOptions of NodesHandler may not be zero or negative";
24996 }
24997
24998 this.options = bridgeObject(this.defaultOptions);
24999 this.bindEventListeners();
25000 }
25001 /**
25002 * Binds event listeners
25003 */
25004
25005
25006 _createClass(NodesHandler, [{
25007 key: "bindEventListeners",
25008 value: function bindEventListeners() {
25009 var _context2,
25010 _context3,
25011 _this2 = this;
25012
25013 // refresh the nodes. Used when reverting from hierarchical layout
25014 this.body.emitter.on("refreshNodes", bind$6(_context2 = this.refresh).call(_context2, this));
25015 this.body.emitter.on("refresh", bind$6(_context3 = this.refresh).call(_context3, this));
25016 this.body.emitter.on("destroy", function () {
25017 forEach$1(_this2.nodesListeners, function (callback, event) {
25018 if (_this2.body.data.nodes) _this2.body.data.nodes.off(event, callback);
25019 });
25020 delete _this2.body.functions.createNode;
25021 delete _this2.nodesListeners.add;
25022 delete _this2.nodesListeners.update;
25023 delete _this2.nodesListeners.remove;
25024 delete _this2.nodesListeners;
25025 });
25026 }
25027 /**
25028 *
25029 * @param {object} options
25030 */
25031
25032 }, {
25033 key: "setOptions",
25034 value: function setOptions(options) {
25035 if (options !== undefined) {
25036 Node.parseOptions(this.options, options); // Need to set opacity here because Node.parseOptions is also used for groups,
25037 // if you set opacity in Node.parseOptions it overwrites group opacity.
25038
25039 if (options.opacity !== undefined) {
25040 if (isNan(options.opacity) || !_isFinite(options.opacity) || options.opacity < 0 || options.opacity > 1) {
25041 console.error("Invalid option for node opacity. Value must be between 0 and 1, found: " + options.opacity);
25042 } else {
25043 this.options.opacity = options.opacity;
25044 }
25045 } // update the shape in all nodes
25046
25047
25048 if (options.shape !== undefined) {
25049 for (var nodeId in this.body.nodes) {
25050 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
25051 this.body.nodes[nodeId].updateShape();
25052 }
25053 }
25054 } // Update the labels of nodes if any relevant options changed.
25055
25056
25057 if (typeof options.font !== "undefined" || typeof options.widthConstraint !== "undefined" || typeof options.heightConstraint !== "undefined") {
25058 for (var _i = 0, _Object$keys = keys$4(this.body.nodes); _i < _Object$keys.length; _i++) {
25059 var _nodeId = _Object$keys[_i];
25060
25061 this.body.nodes[_nodeId].updateLabelModule();
25062
25063 this.body.nodes[_nodeId].needsRefresh();
25064 }
25065 } // update the shape size in all nodes
25066
25067
25068 if (options.size !== undefined) {
25069 for (var _nodeId2 in this.body.nodes) {
25070 if (Object.prototype.hasOwnProperty.call(this.body.nodes, _nodeId2)) {
25071 this.body.nodes[_nodeId2].needsRefresh();
25072 }
25073 }
25074 } // update the state of the variables if needed
25075
25076
25077 if (options.hidden !== undefined || options.physics !== undefined) {
25078 this.body.emitter.emit("_dataChanged");
25079 }
25080 }
25081 }
25082 /**
25083 * Set a data set with nodes for the network
25084 *
25085 * @param {Array | DataSet | DataView} nodes The data containing the nodes.
25086 * @param {boolean} [doNotEmit=false] - Suppress data changed event.
25087 * @private
25088 */
25089
25090 }, {
25091 key: "setData",
25092 value: function setData(nodes) {
25093 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
25094 var oldNodesData = this.body.data.nodes;
25095
25096 if (isDataViewLike("id", nodes)) {
25097 this.body.data.nodes = nodes;
25098 } else if (isArray$2(nodes)) {
25099 this.body.data.nodes = new DataSet();
25100 this.body.data.nodes.add(nodes);
25101 } else if (!nodes) {
25102 this.body.data.nodes = new DataSet();
25103 } else {
25104 throw new TypeError("Array or DataSet expected");
25105 }
25106
25107 if (oldNodesData) {
25108 // unsubscribe from old dataset
25109 forEach$1(this.nodesListeners, function (callback, event) {
25110 oldNodesData.off(event, callback);
25111 });
25112 } // remove drawn nodes
25113
25114
25115 this.body.nodes = {};
25116
25117 if (this.body.data.nodes) {
25118 // subscribe to new dataset
25119 var me = this;
25120 forEach$1(this.nodesListeners, function (callback, event) {
25121 me.body.data.nodes.on(event, callback);
25122 }); // draw all new nodes
25123
25124 var ids = this.body.data.nodes.getIds();
25125 this.add(ids, true);
25126 }
25127
25128 if (doNotEmit === false) {
25129 this.body.emitter.emit("_dataChanged");
25130 }
25131 }
25132 /**
25133 * Add nodes
25134 *
25135 * @param {number[] | string[]} ids
25136 * @param {boolean} [doNotEmit=false]
25137 * @private
25138 */
25139
25140 }, {
25141 key: "add",
25142 value: function add(ids) {
25143 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
25144 var id;
25145 var newNodes = [];
25146
25147 for (var i = 0; i < ids.length; i++) {
25148 id = ids[i];
25149 var properties = this.body.data.nodes.get(id);
25150 var node = this.create(properties);
25151 newNodes.push(node);
25152 this.body.nodes[id] = node; // note: this may replace an existing node
25153 }
25154
25155 this.layoutEngine.positionInitially(newNodes);
25156
25157 if (doNotEmit === false) {
25158 this.body.emitter.emit("_dataChanged");
25159 }
25160 }
25161 /**
25162 * Update existing nodes, or create them when not yet existing
25163 *
25164 * @param {number[] | string[]} ids id's of changed nodes
25165 * @param {Array} changedData array with changed data
25166 * @param {Array|undefined} oldData optional; array with previous data
25167 * @private
25168 */
25169
25170 }, {
25171 key: "update",
25172 value: function update(ids, changedData, oldData) {
25173 var nodes = this.body.nodes;
25174 var dataChanged = false;
25175
25176 for (var i = 0; i < ids.length; i++) {
25177 var id = ids[i];
25178 var node = nodes[id];
25179 var data = changedData[i];
25180
25181 if (node !== undefined) {
25182 // update node
25183 if (node.setOptions(data)) {
25184 dataChanged = true;
25185 }
25186 } else {
25187 dataChanged = true; // create node
25188
25189 node = this.create(data);
25190 nodes[id] = node;
25191 }
25192 }
25193
25194 if (!dataChanged && oldData !== undefined) {
25195 // Check for any changes which should trigger a layout recalculation
25196 // For now, this is just 'level' for hierarchical layout
25197 // Assumption: old and new data arranged in same order; at time of writing, this holds.
25198 dataChanged = some(changedData).call(changedData, function (newValue, index) {
25199 var oldValue = oldData[index];
25200 return oldValue && oldValue.level !== newValue.level;
25201 });
25202 }
25203
25204 if (dataChanged === true) {
25205 this.body.emitter.emit("_dataChanged");
25206 } else {
25207 this.body.emitter.emit("_dataUpdated");
25208 }
25209 }
25210 /**
25211 * Remove existing nodes. If nodes do not exist, the method will just ignore it.
25212 *
25213 * @param {number[] | string[]} ids
25214 * @private
25215 */
25216
25217 }, {
25218 key: "remove",
25219 value: function remove(ids) {
25220 var nodes = this.body.nodes;
25221
25222 for (var i = 0; i < ids.length; i++) {
25223 var id = ids[i];
25224 delete nodes[id];
25225 }
25226
25227 this.body.emitter.emit("_dataChanged");
25228 }
25229 /**
25230 * create a node
25231 *
25232 * @param {object} properties
25233 * @param {class} [constructorClass=Node.default]
25234 * @returns {*}
25235 */
25236
25237 }, {
25238 key: "create",
25239 value: function create(properties) {
25240 var constructorClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Node;
25241 return new constructorClass(properties, this.body, this.images, this.groups, this.options, this.defaultOptions);
25242 }
25243 /**
25244 *
25245 * @param {boolean} [clearPositions=false]
25246 */
25247
25248 }, {
25249 key: "refresh",
25250 value: function refresh() {
25251 var _this3 = this;
25252
25253 var clearPositions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
25254 forEach$1(this.body.nodes, function (node, nodeId) {
25255 var data = _this3.body.data.nodes.get(nodeId);
25256
25257 if (data !== undefined) {
25258 if (clearPositions === true) {
25259 node.setOptions({
25260 x: null,
25261 y: null
25262 });
25263 }
25264
25265 node.setOptions({
25266 fixed: false
25267 });
25268 node.setOptions(data);
25269 }
25270 });
25271 }
25272 /**
25273 * Returns the positions of the nodes.
25274 *
25275 * @param {Array.<Node.id> | string} [ids] --> optional, can be array of nodeIds, can be string
25276 * @returns {{}}
25277 */
25278
25279 }, {
25280 key: "getPositions",
25281 value: function getPositions(ids) {
25282 var dataArray = {};
25283
25284 if (ids !== undefined) {
25285 if (isArray$2(ids) === true) {
25286 for (var i = 0; i < ids.length; i++) {
25287 if (this.body.nodes[ids[i]] !== undefined) {
25288 var node = this.body.nodes[ids[i]];
25289 dataArray[ids[i]] = {
25290 x: Math.round(node.x),
25291 y: Math.round(node.y)
25292 };
25293 }
25294 }
25295 } else {
25296 if (this.body.nodes[ids] !== undefined) {
25297 var _node = this.body.nodes[ids];
25298 dataArray[ids] = {
25299 x: Math.round(_node.x),
25300 y: Math.round(_node.y)
25301 };
25302 }
25303 }
25304 } else {
25305 for (var _i2 = 0; _i2 < this.body.nodeIndices.length; _i2++) {
25306 var _node2 = this.body.nodes[this.body.nodeIndices[_i2]];
25307 dataArray[this.body.nodeIndices[_i2]] = {
25308 x: Math.round(_node2.x),
25309 y: Math.round(_node2.y)
25310 };
25311 }
25312 }
25313
25314 return dataArray;
25315 }
25316 /**
25317 * Retrieves the x y position of a specific id.
25318 *
25319 * @param {string} id The id to retrieve.
25320 * @throws {TypeError} If no id is included.
25321 * @throws {ReferenceError} If an invalid id is provided.
25322 * @returns {{ x: number, y: number }} Returns X, Y canvas position of the node with given id.
25323 */
25324
25325 }, {
25326 key: "getPosition",
25327 value: function getPosition(id) {
25328 if (id == undefined) {
25329 throw new TypeError("No id was specified for getPosition method.");
25330 } else if (this.body.nodes[id] == undefined) {
25331 throw new ReferenceError("NodeId provided for getPosition does not exist. Provided: ".concat(id));
25332 } else {
25333 return {
25334 x: Math.round(this.body.nodes[id].x),
25335 y: Math.round(this.body.nodes[id].y)
25336 };
25337 }
25338 }
25339 /**
25340 * Load the XY positions of the nodes into the dataset.
25341 */
25342
25343 }, {
25344 key: "storePositions",
25345 value: function storePositions() {
25346 // todo: add support for clusters and hierarchical.
25347 var dataArray = [];
25348 var dataset = this.body.data.nodes.getDataSet();
25349
25350 var _iterator = _createForOfIteratorHelper$6(dataset.get()),
25351 _step;
25352
25353 try {
25354 for (_iterator.s(); !(_step = _iterator.n()).done;) {
25355 var dsNode = _step.value;
25356 var id = dsNode.id;
25357 var bodyNode = this.body.nodes[id];
25358 var x = Math.round(bodyNode.x);
25359 var y = Math.round(bodyNode.y);
25360
25361 if (dsNode.x !== x || dsNode.y !== y) {
25362 dataArray.push({
25363 id: id,
25364 x: x,
25365 y: y
25366 });
25367 }
25368 }
25369 } catch (err) {
25370 _iterator.e(err);
25371 } finally {
25372 _iterator.f();
25373 }
25374
25375 dataset.update(dataArray);
25376 }
25377 /**
25378 * get the bounding box of a node.
25379 *
25380 * @param {Node.id} nodeId
25381 * @returns {j|*}
25382 */
25383
25384 }, {
25385 key: "getBoundingBox",
25386 value: function getBoundingBox(nodeId) {
25387 if (this.body.nodes[nodeId] !== undefined) {
25388 return this.body.nodes[nodeId].shape.boundingBox;
25389 }
25390 }
25391 /**
25392 * Get the Ids of nodes connected to this node.
25393 *
25394 * @param {Node.id} nodeId
25395 * @param {'to'|'from'|undefined} direction values 'from' and 'to' select respectively parent and child nodes only.
25396 * Any other value returns both parent and child nodes.
25397 * @returns {Array}
25398 */
25399
25400 }, {
25401 key: "getConnectedNodes",
25402 value: function getConnectedNodes(nodeId, direction) {
25403 var nodeList = [];
25404
25405 if (this.body.nodes[nodeId] !== undefined) {
25406 var node = this.body.nodes[nodeId];
25407 var nodeObj = {}; // used to quickly check if node already exists
25408
25409 for (var i = 0; i < node.edges.length; i++) {
25410 var edge = node.edges[i];
25411
25412 if (direction !== "to" && edge.toId == node.id) {
25413 // these are double equals since ids can be numeric or string
25414 if (nodeObj[edge.fromId] === undefined) {
25415 nodeList.push(edge.fromId);
25416 nodeObj[edge.fromId] = true;
25417 }
25418 } else if (direction !== "from" && edge.fromId == node.id) {
25419 // these are double equals since ids can be numeric or string
25420 if (nodeObj[edge.toId] === undefined) {
25421 nodeList.push(edge.toId);
25422 nodeObj[edge.toId] = true;
25423 }
25424 }
25425 }
25426 }
25427
25428 return nodeList;
25429 }
25430 /**
25431 * Get the ids of the edges connected to this node.
25432 *
25433 * @param {Node.id} nodeId
25434 * @returns {*}
25435 */
25436
25437 }, {
25438 key: "getConnectedEdges",
25439 value: function getConnectedEdges(nodeId) {
25440 var edgeList = [];
25441
25442 if (this.body.nodes[nodeId] !== undefined) {
25443 var node = this.body.nodes[nodeId];
25444
25445 for (var i = 0; i < node.edges.length; i++) {
25446 edgeList.push(node.edges[i].id);
25447 }
25448 } else {
25449 console.error("NodeId provided for getConnectedEdges does not exist. Provided: ", nodeId);
25450 }
25451
25452 return edgeList;
25453 }
25454 /**
25455 * Move a node.
25456 *
25457 * @param {Node.id} nodeId
25458 * @param {number} x
25459 * @param {number} y
25460 */
25461
25462 }, {
25463 key: "moveNode",
25464 value: function moveNode(nodeId, x, y) {
25465 var _this4 = this;
25466
25467 if (this.body.nodes[nodeId] !== undefined) {
25468 this.body.nodes[nodeId].x = Number(x);
25469 this.body.nodes[nodeId].y = Number(y);
25470
25471 setTimeout$1(function () {
25472 _this4.body.emitter.emit("startSimulation");
25473 }, 0);
25474 } else {
25475 console.error("Node id supplied to moveNode does not exist. Provided: ", nodeId);
25476 }
25477 }
25478 }]);
25479
25480 return NodesHandler;
25481 }();
25482
25483 var hasOwn$1 = hasOwnProperty_1;
25484
25485 var isDataDescriptor$1 = function (descriptor) {
25486 return descriptor !== undefined && (hasOwn$1(descriptor, 'value') || hasOwn$1(descriptor, 'writable'));
25487 };
25488
25489 var $$2 = _export;
25490 var call = functionCall;
25491 var isObject$2 = isObject$j;
25492 var anObject$1 = anObject$d;
25493 var isDataDescriptor = isDataDescriptor$1;
25494 var getOwnPropertyDescriptorModule = objectGetOwnPropertyDescriptor;
25495 var getPrototypeOf = objectGetPrototypeOf; // `Reflect.get` method
25496 // https://tc39.es/ecma262/#sec-reflect.get
25497
25498 function get$5(target, propertyKey
25499 /* , receiver */
25500 ) {
25501 var receiver = arguments.length < 3 ? target : arguments[2];
25502 var descriptor, prototype;
25503 if (anObject$1(target) === receiver) return target[propertyKey];
25504 descriptor = getOwnPropertyDescriptorModule.f(target, propertyKey);
25505 if (descriptor) return isDataDescriptor(descriptor) ? descriptor.value : descriptor.get === undefined ? undefined : call(descriptor.get, receiver);
25506 if (isObject$2(prototype = getPrototypeOf(target))) return get$5(prototype, propertyKey, receiver);
25507 }
25508
25509 $$2({
25510 target: 'Reflect',
25511 stat: true
25512 }, {
25513 get: get$5
25514 });
25515
25516 var path$3 = path$y;
25517 var get$4 = path$3.Reflect.get;
25518
25519 var parent$7 = get$4;
25520 var get$3 = parent$7;
25521
25522 var parent$6 = get$3;
25523 var get$2 = parent$6;
25524
25525 var parent$5 = get$2;
25526 var get$1 = parent$5;
25527
25528 var get = get$1;
25529
25530 var parent$4 = getOwnPropertyDescriptor$4;
25531 var getOwnPropertyDescriptor$2 = parent$4;
25532
25533 var parent$3 = getOwnPropertyDescriptor$2;
25534 var getOwnPropertyDescriptor$1 = parent$3;
25535
25536 var getOwnPropertyDescriptor = getOwnPropertyDescriptor$1;
25537
25538 function _superPropBase(object, property) {
25539 while (!Object.prototype.hasOwnProperty.call(object, property)) {
25540 object = _getPrototypeOf(object);
25541 if (object === null) break;
25542 }
25543
25544 return object;
25545 }
25546
25547 function _get() {
25548 if (typeof Reflect !== "undefined" && get) {
25549 _get = get;
25550 } else {
25551 _get = function _get(target, property, receiver) {
25552 var base = _superPropBase(target, property);
25553 if (!base) return;
25554
25555 var desc = getOwnPropertyDescriptor(base, property);
25556
25557 if (desc.get) {
25558 return desc.get.call(arguments.length < 3 ? target : receiver);
25559 }
25560
25561 return desc.value;
25562 };
25563 }
25564
25565 return _get.apply(this, arguments);
25566 }
25567
25568 var $$1 = _export; // eslint-disable-next-line es/no-math-hypot -- required for testing
25569
25570 var $hypot = Math.hypot;
25571 var abs = Math.abs;
25572 var sqrt = Math.sqrt; // Chrome 77 bug
25573 // https://bugs.chromium.org/p/v8/issues/detail?id=9546
25574
25575 var BUGGY = !!$hypot && $hypot(Infinity, NaN) !== Infinity; // `Math.hypot` method
25576 // https://tc39.es/ecma262/#sec-math.hypot
25577
25578 $$1({
25579 target: 'Math',
25580 stat: true,
25581 forced: BUGGY
25582 }, {
25583 // eslint-disable-next-line no-unused-vars -- required for `.length`
25584 hypot: function hypot(value1, value2) {
25585 var sum = 0;
25586 var i = 0;
25587 var aLen = arguments.length;
25588 var larg = 0;
25589 var arg, div;
25590
25591 while (i < aLen) {
25592 arg = abs(arguments[i++]);
25593
25594 if (larg < arg) {
25595 div = larg / arg;
25596 sum = sum * div * div + 1;
25597 larg = arg;
25598 } else if (arg > 0) {
25599 div = arg / larg;
25600 sum += div * div;
25601 } else sum += arg;
25602 }
25603
25604 return larg === Infinity ? Infinity : larg * sqrt(sum);
25605 }
25606 });
25607
25608 var path$2 = path$y;
25609 var hypot$2 = path$2.Math.hypot;
25610
25611 var parent$2 = hypot$2;
25612 var hypot$1 = parent$2;
25613
25614 var hypot = hypot$1;
25615
25616 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); }; }
25617
25618 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; } }
25619 /**
25620 * Common methods for endpoints
25621 *
25622 * @class
25623 */
25624
25625 var EndPoint = /*#__PURE__*/function () {
25626 function EndPoint() {
25627 _classCallCheck(this, EndPoint);
25628 }
25629
25630 _createClass(EndPoint, null, [{
25631 key: "transform",
25632 value:
25633 /**
25634 * Apply transformation on points for display.
25635 *
25636 * The following is done:
25637 * - rotate by the specified angle
25638 * - multiply the (normalized) coordinates by the passed length
25639 * - offset by the target coordinates
25640 *
25641 * @param points - The point(s) to be transformed.
25642 * @param arrowData - The data determining the result of the transformation.
25643 */
25644 function transform(points, arrowData) {
25645 if (!isArray$2(points)) {
25646 points = [points];
25647 }
25648
25649 var x = arrowData.point.x;
25650 var y = arrowData.point.y;
25651 var angle = arrowData.angle;
25652 var length = arrowData.length;
25653
25654 for (var i = 0; i < points.length; ++i) {
25655 var p = points[i];
25656 var xt = p.x * Math.cos(angle) - p.y * Math.sin(angle);
25657 var yt = p.x * Math.sin(angle) + p.y * Math.cos(angle);
25658 p.x = x + length * xt;
25659 p.y = y + length * yt;
25660 }
25661 }
25662 /**
25663 * Draw a closed path using the given real coordinates.
25664 *
25665 * @param ctx - The path will be rendered into this context.
25666 * @param points - The points of the path.
25667 */
25668
25669 }, {
25670 key: "drawPath",
25671 value: function drawPath(ctx, points) {
25672 ctx.beginPath();
25673 ctx.moveTo(points[0].x, points[0].y);
25674
25675 for (var i = 1; i < points.length; ++i) {
25676 ctx.lineTo(points[i].x, points[i].y);
25677 }
25678
25679 ctx.closePath();
25680 }
25681 }]);
25682
25683 return EndPoint;
25684 }();
25685 /**
25686 * Drawing methods for the arrow endpoint.
25687 */
25688
25689
25690 var Image$1 = /*#__PURE__*/function (_EndPoint) {
25691 _inherits(Image, _EndPoint);
25692
25693 var _super = _createSuper$a(Image);
25694
25695 function Image() {
25696 _classCallCheck(this, Image);
25697
25698 return _super.apply(this, arguments);
25699 }
25700
25701 _createClass(Image, null, [{
25702 key: "draw",
25703 value:
25704 /**
25705 * Draw this shape at the end of a line.
25706 *
25707 * @param ctx - The shape will be rendered into this context.
25708 * @param arrowData - The data determining the shape.
25709 * @returns False as there is no way to fill an image.
25710 */
25711 function draw(ctx, arrowData) {
25712 if (arrowData.image) {
25713 ctx.save();
25714 ctx.translate(arrowData.point.x, arrowData.point.y);
25715 ctx.rotate(Math.PI / 2 + arrowData.angle);
25716 var width = arrowData.imageWidth != null ? arrowData.imageWidth : arrowData.image.width;
25717 var height = arrowData.imageHeight != null ? arrowData.imageHeight : arrowData.image.height;
25718 arrowData.image.drawImageAtPosition(ctx, 1, // scale
25719 -width / 2, // x
25720 0, // y
25721 width, height);
25722 ctx.restore();
25723 }
25724
25725 return false;
25726 }
25727 }]);
25728
25729 return Image;
25730 }(EndPoint);
25731 /**
25732 * Drawing methods for the arrow endpoint.
25733 */
25734
25735
25736 var Arrow = /*#__PURE__*/function (_EndPoint2) {
25737 _inherits(Arrow, _EndPoint2);
25738
25739 var _super2 = _createSuper$a(Arrow);
25740
25741 function Arrow() {
25742 _classCallCheck(this, Arrow);
25743
25744 return _super2.apply(this, arguments);
25745 }
25746
25747 _createClass(Arrow, null, [{
25748 key: "draw",
25749 value:
25750 /**
25751 * Draw this shape at the end of a line.
25752 *
25753 * @param ctx - The shape will be rendered into this context.
25754 * @param arrowData - The data determining the shape.
25755 * @returns True because ctx.fill() can be used to fill the arrow.
25756 */
25757 function draw(ctx, arrowData) {
25758 // Normalized points of closed path, in the order that they should be drawn.
25759 // (0, 0) is the attachment point, and the point around which should be rotated
25760 var points = [{
25761 x: 0,
25762 y: 0
25763 }, {
25764 x: -1,
25765 y: 0.3
25766 }, {
25767 x: -0.9,
25768 y: 0
25769 }, {
25770 x: -1,
25771 y: -0.3
25772 }];
25773 EndPoint.transform(points, arrowData);
25774 EndPoint.drawPath(ctx, points);
25775 return true;
25776 }
25777 }]);
25778
25779 return Arrow;
25780 }(EndPoint);
25781 /**
25782 * Drawing methods for the crow endpoint.
25783 */
25784
25785
25786 var Crow = /*#__PURE__*/function () {
25787 function Crow() {
25788 _classCallCheck(this, Crow);
25789 }
25790
25791 _createClass(Crow, null, [{
25792 key: "draw",
25793 value:
25794 /**
25795 * Draw this shape at the end of a line.
25796 *
25797 * @param ctx - The shape will be rendered into this context.
25798 * @param arrowData - The data determining the shape.
25799 * @returns True because ctx.fill() can be used to fill the arrow.
25800 */
25801 function draw(ctx, arrowData) {
25802 // Normalized points of closed path, in the order that they should be drawn.
25803 // (0, 0) is the attachment point, and the point around which should be rotated
25804 var points = [{
25805 x: -1,
25806 y: 0
25807 }, {
25808 x: 0,
25809 y: 0.3
25810 }, {
25811 x: -0.4,
25812 y: 0
25813 }, {
25814 x: 0,
25815 y: -0.3
25816 }];
25817 EndPoint.transform(points, arrowData);
25818 EndPoint.drawPath(ctx, points);
25819 return true;
25820 }
25821 }]);
25822
25823 return Crow;
25824 }();
25825 /**
25826 * Drawing methods for the curve endpoint.
25827 */
25828
25829
25830 var Curve = /*#__PURE__*/function () {
25831 function Curve() {
25832 _classCallCheck(this, Curve);
25833 }
25834
25835 _createClass(Curve, null, [{
25836 key: "draw",
25837 value:
25838 /**
25839 * Draw this shape at the end of a line.
25840 *
25841 * @param ctx - The shape will be rendered into this context.
25842 * @param arrowData - The data determining the shape.
25843 * @returns True because ctx.fill() can be used to fill the arrow.
25844 */
25845 function draw(ctx, arrowData) {
25846 // Normalized points of closed path, in the order that they should be drawn.
25847 // (0, 0) is the attachment point, and the point around which should be rotated
25848 var point = {
25849 x: -0.4,
25850 y: 0
25851 };
25852 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
25853
25854 ctx.strokeStyle = ctx.fillStyle;
25855 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define curve endpoint as semicircle.
25856
25857 var pi = Math.PI;
25858 var startAngle = arrowData.angle - pi / 2;
25859 var endAngle = arrowData.angle + pi / 2;
25860 ctx.beginPath();
25861 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
25862 ctx.stroke();
25863 return true;
25864 }
25865 }]);
25866
25867 return Curve;
25868 }();
25869 /**
25870 * Drawing methods for the inverted curve endpoint.
25871 */
25872
25873
25874 var InvertedCurve = /*#__PURE__*/function () {
25875 function InvertedCurve() {
25876 _classCallCheck(this, InvertedCurve);
25877 }
25878
25879 _createClass(InvertedCurve, null, [{
25880 key: "draw",
25881 value:
25882 /**
25883 * Draw this shape at the end of a line.
25884 *
25885 * @param ctx - The shape will be rendered into this context.
25886 * @param arrowData - The data determining the shape.
25887 * @returns True because ctx.fill() can be used to fill the arrow.
25888 */
25889 function draw(ctx, arrowData) {
25890 // Normalized points of closed path, in the order that they should be drawn.
25891 // (0, 0) is the attachment point, and the point around which should be rotated
25892 var point = {
25893 x: -0.3,
25894 y: 0
25895 };
25896 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
25897
25898 ctx.strokeStyle = ctx.fillStyle;
25899 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define inverted curve endpoint as semicircle.
25900
25901 var pi = Math.PI;
25902 var startAngle = arrowData.angle + pi / 2;
25903 var endAngle = arrowData.angle + 3 * pi / 2;
25904 ctx.beginPath();
25905 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
25906 ctx.stroke();
25907 return true;
25908 }
25909 }]);
25910
25911 return InvertedCurve;
25912 }();
25913 /**
25914 * Drawing methods for the trinagle endpoint.
25915 */
25916
25917
25918 var Triangle = /*#__PURE__*/function () {
25919 function Triangle() {
25920 _classCallCheck(this, Triangle);
25921 }
25922
25923 _createClass(Triangle, null, [{
25924 key: "draw",
25925 value:
25926 /**
25927 * Draw this shape at the end of a line.
25928 *
25929 * @param ctx - The shape will be rendered into this context.
25930 * @param arrowData - The data determining the shape.
25931 * @returns True because ctx.fill() can be used to fill the arrow.
25932 */
25933 function draw(ctx, arrowData) {
25934 // Normalized points of closed path, in the order that they should be drawn.
25935 // (0, 0) is the attachment point, and the point around which should be rotated
25936 var points = [{
25937 x: 0.02,
25938 y: 0
25939 }, {
25940 x: -1,
25941 y: 0.3
25942 }, {
25943 x: -1,
25944 y: -0.3
25945 }];
25946 EndPoint.transform(points, arrowData);
25947 EndPoint.drawPath(ctx, points);
25948 return true;
25949 }
25950 }]);
25951
25952 return Triangle;
25953 }();
25954 /**
25955 * Drawing methods for the inverted trinagle endpoint.
25956 */
25957
25958
25959 var InvertedTriangle = /*#__PURE__*/function () {
25960 function InvertedTriangle() {
25961 _classCallCheck(this, InvertedTriangle);
25962 }
25963
25964 _createClass(InvertedTriangle, null, [{
25965 key: "draw",
25966 value:
25967 /**
25968 * Draw this shape at the end of a line.
25969 *
25970 * @param ctx - The shape will be rendered into this context.
25971 * @param arrowData - The data determining the shape.
25972 * @returns True because ctx.fill() can be used to fill the arrow.
25973 */
25974 function draw(ctx, arrowData) {
25975 // Normalized points of closed path, in the order that they should be drawn.
25976 // (0, 0) is the attachment point, and the point around which should be rotated
25977 var points = [{
25978 x: 0,
25979 y: 0.3
25980 }, {
25981 x: 0,
25982 y: -0.3
25983 }, {
25984 x: -1,
25985 y: 0
25986 }];
25987 EndPoint.transform(points, arrowData);
25988 EndPoint.drawPath(ctx, points);
25989 return true;
25990 }
25991 }]);
25992
25993 return InvertedTriangle;
25994 }();
25995 /**
25996 * Drawing methods for the circle endpoint.
25997 */
25998
25999
26000 var Circle = /*#__PURE__*/function () {
26001 function Circle() {
26002 _classCallCheck(this, Circle);
26003 }
26004
26005 _createClass(Circle, null, [{
26006 key: "draw",
26007 value:
26008 /**
26009 * Draw this shape at the end of a line.
26010 *
26011 * @param ctx - The shape will be rendered into this context.
26012 * @param arrowData - The data determining the shape.
26013 * @returns True because ctx.fill() can be used to fill the arrow.
26014 */
26015 function draw(ctx, arrowData) {
26016 var point = {
26017 x: -0.4,
26018 y: 0
26019 };
26020 EndPoint.transform(point, arrowData);
26021 drawCircle(ctx, point.x, point.y, arrowData.length * 0.4);
26022 return true;
26023 }
26024 }]);
26025
26026 return Circle;
26027 }();
26028 /**
26029 * Drawing methods for the bar endpoint.
26030 */
26031
26032
26033 var Bar = /*#__PURE__*/function () {
26034 function Bar() {
26035 _classCallCheck(this, Bar);
26036 }
26037
26038 _createClass(Bar, null, [{
26039 key: "draw",
26040 value:
26041 /**
26042 * Draw this shape at the end of a line.
26043 *
26044 * @param ctx - The shape will be rendered into this context.
26045 * @param arrowData - The data determining the shape.
26046 * @returns True because ctx.fill() can be used to fill the arrow.
26047 */
26048 function draw(ctx, arrowData) {
26049 /*
26050 var points = [
26051 {x:0, y:0.5},
26052 {x:0, y:-0.5}
26053 ];
26054 EndPoint.transform(points, arrowData);
26055 ctx.beginPath();
26056 ctx.moveTo(points[0].x, points[0].y);
26057 ctx.lineTo(points[1].x, points[1].y);
26058 ctx.stroke();
26059 */
26060 var points = [{
26061 x: 0,
26062 y: 0.5
26063 }, {
26064 x: 0,
26065 y: -0.5
26066 }, {
26067 x: -0.15,
26068 y: -0.5
26069 }, {
26070 x: -0.15,
26071 y: 0.5
26072 }];
26073 EndPoint.transform(points, arrowData);
26074 EndPoint.drawPath(ctx, points);
26075 return true;
26076 }
26077 }]);
26078
26079 return Bar;
26080 }();
26081 /**
26082 * Drawing methods for the box endpoint.
26083 */
26084
26085
26086 var Box = /*#__PURE__*/function () {
26087 function Box() {
26088 _classCallCheck(this, Box);
26089 }
26090
26091 _createClass(Box, null, [{
26092 key: "draw",
26093 value:
26094 /**
26095 * Draw this shape at the end of a line.
26096 *
26097 * @param ctx - The shape will be rendered into this context.
26098 * @param arrowData - The data determining the shape.
26099 * @returns True because ctx.fill() can be used to fill the arrow.
26100 */
26101 function draw(ctx, arrowData) {
26102 var points = [{
26103 x: 0,
26104 y: 0.3
26105 }, {
26106 x: 0,
26107 y: -0.3
26108 }, {
26109 x: -0.6,
26110 y: -0.3
26111 }, {
26112 x: -0.6,
26113 y: 0.3
26114 }];
26115 EndPoint.transform(points, arrowData);
26116 EndPoint.drawPath(ctx, points);
26117 return true;
26118 }
26119 }]);
26120
26121 return Box;
26122 }();
26123 /**
26124 * Drawing methods for the diamond endpoint.
26125 */
26126
26127
26128 var Diamond = /*#__PURE__*/function () {
26129 function Diamond() {
26130 _classCallCheck(this, Diamond);
26131 }
26132
26133 _createClass(Diamond, null, [{
26134 key: "draw",
26135 value:
26136 /**
26137 * Draw this shape at the end of a line.
26138 *
26139 * @param ctx - The shape will be rendered into this context.
26140 * @param arrowData - The data determining the shape.
26141 * @returns True because ctx.fill() can be used to fill the arrow.
26142 */
26143 function draw(ctx, arrowData) {
26144 var points = [{
26145 x: 0,
26146 y: 0
26147 }, {
26148 x: -0.5,
26149 y: -0.3
26150 }, {
26151 x: -1,
26152 y: 0
26153 }, {
26154 x: -0.5,
26155 y: 0.3
26156 }];
26157 EndPoint.transform(points, arrowData);
26158 EndPoint.drawPath(ctx, points);
26159 return true;
26160 }
26161 }]);
26162
26163 return Diamond;
26164 }();
26165 /**
26166 * Drawing methods for the vee endpoint.
26167 */
26168
26169
26170 var Vee = /*#__PURE__*/function () {
26171 function Vee() {
26172 _classCallCheck(this, Vee);
26173 }
26174
26175 _createClass(Vee, null, [{
26176 key: "draw",
26177 value:
26178 /**
26179 * Draw this shape at the end of a line.
26180 *
26181 * @param ctx - The shape will be rendered into this context.
26182 * @param arrowData - The data determining the shape.
26183 * @returns True because ctx.fill() can be used to fill the arrow.
26184 */
26185 function draw(ctx, arrowData) {
26186 // Normalized points of closed path, in the order that they should be drawn.
26187 // (0, 0) is the attachment point, and the point around which should be rotated
26188 var points = [{
26189 x: -1,
26190 y: 0.3
26191 }, {
26192 x: -0.5,
26193 y: 0
26194 }, {
26195 x: -1,
26196 y: -0.3
26197 }, {
26198 x: 0,
26199 y: 0
26200 }];
26201 EndPoint.transform(points, arrowData);
26202 EndPoint.drawPath(ctx, points);
26203 return true;
26204 }
26205 }]);
26206
26207 return Vee;
26208 }();
26209 /**
26210 * Drawing methods for the endpoints.
26211 */
26212
26213
26214 var EndPoints = /*#__PURE__*/function () {
26215 function EndPoints() {
26216 _classCallCheck(this, EndPoints);
26217 }
26218
26219 _createClass(EndPoints, null, [{
26220 key: "draw",
26221 value:
26222 /**
26223 * Draw an endpoint.
26224 *
26225 * @param ctx - The shape will be rendered into this context.
26226 * @param arrowData - The data determining the shape.
26227 * @returns True if ctx.fill() can be used to fill the arrow, false otherwise.
26228 */
26229 function draw(ctx, arrowData) {
26230 var type;
26231
26232 if (arrowData.type) {
26233 type = arrowData.type.toLowerCase();
26234 }
26235
26236 switch (type) {
26237 case "image":
26238 return Image$1.draw(ctx, arrowData);
26239
26240 case "circle":
26241 return Circle.draw(ctx, arrowData);
26242
26243 case "box":
26244 return Box.draw(ctx, arrowData);
26245
26246 case "crow":
26247 return Crow.draw(ctx, arrowData);
26248
26249 case "curve":
26250 return Curve.draw(ctx, arrowData);
26251
26252 case "diamond":
26253 return Diamond.draw(ctx, arrowData);
26254
26255 case "inv_curve":
26256 return InvertedCurve.draw(ctx, arrowData);
26257
26258 case "triangle":
26259 return Triangle.draw(ctx, arrowData);
26260
26261 case "inv_triangle":
26262 return InvertedTriangle.draw(ctx, arrowData);
26263
26264 case "bar":
26265 return Bar.draw(ctx, arrowData);
26266
26267 case "vee":
26268 return Vee.draw(ctx, arrowData);
26269
26270 case "arrow": // fall-through
26271
26272 default:
26273 return Arrow.draw(ctx, arrowData);
26274 }
26275 }
26276 }]);
26277
26278 return EndPoints;
26279 }();
26280
26281 function ownKeys$1(object, enumerableOnly) { var keys = keys$4(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); enumerableOnly && (symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$3(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
26282
26283 function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var _context2, _context3; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? forEach$2(_context2 = ownKeys$1(Object(source), !0)).call(_context2, function (key) { _defineProperty(target, key, source[key]); }) : getOwnPropertyDescriptors ? defineProperties(target, getOwnPropertyDescriptors(source)) : forEach$2(_context3 = ownKeys$1(Object(source))).call(_context3, function (key) { defineProperty$6(target, key, getOwnPropertyDescriptor$3(source, key)); }); } return target; }
26284 /**
26285 * The Base Class for all edges.
26286 */
26287
26288 var EdgeBase = /*#__PURE__*/function () {
26289 /**
26290 * Create a new instance.
26291 *
26292 * @param options - The options object of given edge.
26293 * @param _body - The body of the network.
26294 * @param _labelModule - Label module.
26295 */
26296 function EdgeBase(options, _body, _labelModule) {
26297 _classCallCheck(this, EdgeBase);
26298
26299 this._body = _body;
26300 this._labelModule = _labelModule;
26301 this.color = {};
26302 this.colorDirty = true;
26303 this.hoverWidth = 1.5;
26304 this.selectionWidth = 2;
26305 this.setOptions(options);
26306 this.fromPoint = this.from;
26307 this.toPoint = this.to;
26308 }
26309 /** @inheritDoc */
26310
26311
26312 _createClass(EdgeBase, [{
26313 key: "connect",
26314 value: function connect() {
26315 this.from = this._body.nodes[this.options.from];
26316 this.to = this._body.nodes[this.options.to];
26317 }
26318 /** @inheritDoc */
26319
26320 }, {
26321 key: "cleanup",
26322 value: function cleanup() {
26323 return false;
26324 }
26325 /**
26326 * Set new edge options.
26327 *
26328 * @param options - The new edge options object.
26329 */
26330
26331 }, {
26332 key: "setOptions",
26333 value: function setOptions(options) {
26334 this.options = options;
26335 this.from = this._body.nodes[this.options.from];
26336 this.to = this._body.nodes[this.options.to];
26337 this.id = this.options.id;
26338 }
26339 /** @inheritDoc */
26340
26341 }, {
26342 key: "drawLine",
26343 value: function drawLine(ctx, values, _selected, _hover) {
26344 var viaNode = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : this.getViaNode();
26345 // set style
26346 ctx.strokeStyle = this.getColor(ctx, values);
26347 ctx.lineWidth = values.width;
26348
26349 if (values.dashes !== false) {
26350 this._drawDashedLine(ctx, values, viaNode);
26351 } else {
26352 this._drawLine(ctx, values, viaNode);
26353 }
26354 }
26355 /**
26356 * Draw a line with given style between two nodes through supplied node(s).
26357 *
26358 * @param ctx - The context that will be used for rendering.
26359 * @param values - Formatting values like color, opacity or shadow.
26360 * @param viaNode - Additional control point(s) for the edge.
26361 * @param fromPoint - TODO: Seems ignored, remove?
26362 * @param toPoint - TODO: Seems ignored, remove?
26363 */
26364
26365 }, {
26366 key: "_drawLine",
26367 value: function _drawLine(ctx, values, viaNode, fromPoint, toPoint) {
26368 if (this.from != this.to) {
26369 // draw line
26370 this._line(ctx, values, viaNode, fromPoint, toPoint);
26371 } else {
26372 var _this$_getCircleData = this._getCircleData(ctx),
26373 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
26374 x = _this$_getCircleData2[0],
26375 y = _this$_getCircleData2[1],
26376 radius = _this$_getCircleData2[2];
26377
26378 this._circle(ctx, values, x, y, radius);
26379 }
26380 }
26381 /**
26382 * Draw a dashed line with given style between two nodes through supplied node(s).
26383 *
26384 * @param ctx - The context that will be used for rendering.
26385 * @param values - Formatting values like color, opacity or shadow.
26386 * @param viaNode - Additional control point(s) for the edge.
26387 * @param _fromPoint - Ignored (TODO: remove in the future).
26388 * @param _toPoint - Ignored (TODO: remove in the future).
26389 */
26390
26391 }, {
26392 key: "_drawDashedLine",
26393 value: function _drawDashedLine(ctx, values, viaNode, _fromPoint, _toPoint) {
26394 ctx.lineCap = "round";
26395 var pattern = isArray$2(values.dashes) ? values.dashes : [5, 5]; // only firefox and chrome support this method, else we use the legacy one.
26396
26397 if (ctx.setLineDash !== undefined) {
26398 ctx.save(); // set dash settings for chrome or firefox
26399
26400 ctx.setLineDash(pattern);
26401 ctx.lineDashOffset = 0; // draw the line
26402
26403 if (this.from != this.to) {
26404 // draw line
26405 this._line(ctx, values, viaNode);
26406 } else {
26407 var _this$_getCircleData3 = this._getCircleData(ctx),
26408 _this$_getCircleData4 = _slicedToArray(_this$_getCircleData3, 3),
26409 x = _this$_getCircleData4[0],
26410 y = _this$_getCircleData4[1],
26411 radius = _this$_getCircleData4[2];
26412
26413 this._circle(ctx, values, x, y, radius);
26414 } // restore the dash settings.
26415
26416
26417 ctx.setLineDash([0]);
26418 ctx.lineDashOffset = 0;
26419 ctx.restore();
26420 } else {
26421 // unsupporting smooth lines
26422 if (this.from != this.to) {
26423 // draw line
26424 drawDashedLine(ctx, this.from.x, this.from.y, this.to.x, this.to.y, pattern);
26425 } else {
26426 var _this$_getCircleData5 = this._getCircleData(ctx),
26427 _this$_getCircleData6 = _slicedToArray(_this$_getCircleData5, 3),
26428 _x = _this$_getCircleData6[0],
26429 _y = _this$_getCircleData6[1],
26430 _radius = _this$_getCircleData6[2];
26431
26432 this._circle(ctx, values, _x, _y, _radius);
26433 } // draw shadow if enabled
26434
26435
26436 this.enableShadow(ctx, values);
26437 ctx.stroke(); // disable shadows for other elements.
26438
26439 this.disableShadow(ctx, values);
26440 }
26441 }
26442 /**
26443 * Find the intersection between the border of the node and the edge.
26444 *
26445 * @param node - The node (either from or to node of the edge).
26446 * @param ctx - The context that will be used for rendering.
26447 * @param options - Additional options.
26448 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
26449 */
26450
26451 }, {
26452 key: "findBorderPosition",
26453 value: function findBorderPosition(node, ctx, options) {
26454 if (this.from != this.to) {
26455 return this._findBorderPosition(node, ctx, options);
26456 } else {
26457 return this._findBorderPositionCircle(node, ctx, options);
26458 }
26459 }
26460 /** @inheritDoc */
26461
26462 }, {
26463 key: "findBorderPositions",
26464 value: function findBorderPositions(ctx) {
26465 if (this.from != this.to) {
26466 return {
26467 from: this._findBorderPosition(this.from, ctx),
26468 to: this._findBorderPosition(this.to, ctx)
26469 };
26470 } else {
26471 var _context;
26472
26473 var _this$_getCircleData$ = slice(_context = this._getCircleData(ctx)).call(_context, 0, 2),
26474 _this$_getCircleData$2 = _slicedToArray(_this$_getCircleData$, 2),
26475 x = _this$_getCircleData$2[0],
26476 y = _this$_getCircleData$2[1];
26477
26478 return {
26479 from: this._findBorderPositionCircle(this.from, ctx, {
26480 x: x,
26481 y: y,
26482 low: 0.25,
26483 high: 0.6,
26484 direction: -1
26485 }),
26486 to: this._findBorderPositionCircle(this.from, ctx, {
26487 x: x,
26488 y: y,
26489 low: 0.6,
26490 high: 0.8,
26491 direction: 1
26492 })
26493 };
26494 }
26495 }
26496 /**
26497 * Compute the center point and radius of an edge connected to the same node at both ends.
26498 *
26499 * @param ctx - The context that will be used for rendering.
26500 * @returns `[x, y, radius]`
26501 */
26502
26503 }, {
26504 key: "_getCircleData",
26505 value: function _getCircleData(ctx) {
26506 var radius = this.options.selfReference.size;
26507
26508 if (ctx !== undefined) {
26509 if (this.from.shape.width === undefined) {
26510 this.from.shape.resize(ctx);
26511 }
26512 } // get circle coordinates
26513
26514
26515 var coordinates = getSelfRefCoordinates(ctx, this.options.selfReference.angle, radius, this.from);
26516 return [coordinates.x, coordinates.y, radius];
26517 }
26518 /**
26519 * Get a point on a circle.
26520 *
26521 * @param x - Center of the circle on the x axis.
26522 * @param y - Center of the circle on the y axis.
26523 * @param radius - Radius of the circle.
26524 * @param position - Value between 0 (line start) and 1 (line end).
26525 * @returns Cartesian coordinates of requested point on the circle.
26526 */
26527
26528 }, {
26529 key: "_pointOnCircle",
26530 value: function _pointOnCircle(x, y, radius, position) {
26531 var angle = position * 2 * Math.PI;
26532 return {
26533 x: x + radius * Math.cos(angle),
26534 y: y - radius * Math.sin(angle)
26535 };
26536 }
26537 /**
26538 * Find the intersection between the border of the node and the edge.
26539 *
26540 * @remarks
26541 * This function uses binary search to look for the point where the circle crosses the border of the node.
26542 * @param nearNode - The node (either from or to node of the edge).
26543 * @param ctx - The context that will be used for rendering.
26544 * @param options - Additional options.
26545 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
26546 */
26547
26548 }, {
26549 key: "_findBorderPositionCircle",
26550 value: function _findBorderPositionCircle(nearNode, ctx, options) {
26551 var x = options.x;
26552 var y = options.y;
26553 var low = options.low;
26554 var high = options.high;
26555 var direction = options.direction;
26556 var maxIterations = 10;
26557 var radius = this.options.selfReference.size;
26558 var threshold = 0.05;
26559 var pos;
26560 var middle = (low + high) * 0.5;
26561 var endPointOffset = 0;
26562
26563 if (this.options.arrowStrikethrough === true) {
26564 if (direction === -1) {
26565 endPointOffset = this.options.endPointOffset.from;
26566 } else if (direction === 1) {
26567 endPointOffset = this.options.endPointOffset.to;
26568 }
26569 }
26570
26571 var iteration = 0;
26572
26573 do {
26574 middle = (low + high) * 0.5;
26575 pos = this._pointOnCircle(x, y, radius, middle);
26576 var angle = Math.atan2(nearNode.y - pos.y, nearNode.x - pos.x);
26577 var distanceToBorder = nearNode.distanceToBorder(ctx, angle) + endPointOffset;
26578 var distanceToPoint = Math.sqrt(Math.pow(pos.x - nearNode.x, 2) + Math.pow(pos.y - nearNode.y, 2));
26579 var difference = distanceToBorder - distanceToPoint;
26580
26581 if (Math.abs(difference) < threshold) {
26582 break; // found
26583 } else if (difference > 0) {
26584 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
26585 if (direction > 0) {
26586 low = middle;
26587 } else {
26588 high = middle;
26589 }
26590 } else {
26591 if (direction > 0) {
26592 high = middle;
26593 } else {
26594 low = middle;
26595 }
26596 }
26597
26598 ++iteration;
26599 } while (low <= high && iteration < maxIterations);
26600
26601 return _objectSpread$1(_objectSpread$1({}, pos), {}, {
26602 t: middle
26603 });
26604 }
26605 /**
26606 * Get the line width of the edge. Depends on width and whether one of the connected nodes is selected.
26607 *
26608 * @param selected - Determines wheter the line is selected.
26609 * @param hover - Determines wheter the line is being hovered, only applies if selected is false.
26610 * @returns The width of the line.
26611 */
26612
26613 }, {
26614 key: "getLineWidth",
26615 value: function getLineWidth(selected, hover) {
26616 if (selected === true) {
26617 return Math.max(this.selectionWidth, 0.3 / this._body.view.scale);
26618 } else if (hover === true) {
26619 return Math.max(this.hoverWidth, 0.3 / this._body.view.scale);
26620 } else {
26621 return Math.max(this.options.width, 0.3 / this._body.view.scale);
26622 }
26623 }
26624 /**
26625 * Compute the color or gradient for given edge.
26626 *
26627 * @param ctx - The context that will be used for rendering.
26628 * @param values - Formatting values like color, opacity or shadow.
26629 * @param _selected - Ignored (TODO: remove in the future).
26630 * @param _hover - Ignored (TODO: remove in the future).
26631 * @returns Color string if single color is inherited or gradient if two.
26632 */
26633
26634 }, {
26635 key: "getColor",
26636 value: function getColor(ctx, values) {
26637 if (values.inheritsColor !== false) {
26638 // when this is a loop edge, just use the 'from' method
26639 if (values.inheritsColor === "both" && this.from.id !== this.to.id) {
26640 var grd = ctx.createLinearGradient(this.from.x, this.from.y, this.to.x, this.to.y);
26641 var fromColor = this.from.options.color.highlight.border;
26642 var toColor = this.to.options.color.highlight.border;
26643
26644 if (this.from.selected === false && this.to.selected === false) {
26645 fromColor = overrideOpacity(this.from.options.color.border, values.opacity);
26646 toColor = overrideOpacity(this.to.options.color.border, values.opacity);
26647 } else if (this.from.selected === true && this.to.selected === false) {
26648 toColor = this.to.options.color.border;
26649 } else if (this.from.selected === false && this.to.selected === true) {
26650 fromColor = this.from.options.color.border;
26651 }
26652
26653 grd.addColorStop(0, fromColor);
26654 grd.addColorStop(1, toColor); // -------------------- this returns -------------------- //
26655
26656 return grd;
26657 }
26658
26659 if (values.inheritsColor === "to") {
26660 return overrideOpacity(this.to.options.color.border, values.opacity);
26661 } else {
26662 // "from"
26663 return overrideOpacity(this.from.options.color.border, values.opacity);
26664 }
26665 } else {
26666 return overrideOpacity(values.color, values.opacity);
26667 }
26668 }
26669 /**
26670 * Draw a line from a node to itself, a circle.
26671 *
26672 * @param ctx - The context that will be used for rendering.
26673 * @param values - Formatting values like color, opacity or shadow.
26674 * @param x - Center of the circle on the x axis.
26675 * @param y - Center of the circle on the y axis.
26676 * @param radius - Radius of the circle.
26677 */
26678
26679 }, {
26680 key: "_circle",
26681 value: function _circle(ctx, values, x, y, radius) {
26682 // draw shadow if enabled
26683 this.enableShadow(ctx, values); //full circle
26684
26685 var angleFrom = 0;
26686 var angleTo = Math.PI * 2;
26687
26688 if (!this.options.selfReference.renderBehindTheNode) {
26689 //render only parts which are not overlaping with parent node
26690 //need to find x,y of from point and x,y to point
26691 //calculating radians
26692 var low = this.options.selfReference.angle;
26693 var high = this.options.selfReference.angle + Math.PI;
26694
26695 var pointTFrom = this._findBorderPositionCircle(this.from, ctx, {
26696 x: x,
26697 y: y,
26698 low: low,
26699 high: high,
26700 direction: -1
26701 });
26702
26703 var pointTTo = this._findBorderPositionCircle(this.from, ctx, {
26704 x: x,
26705 y: y,
26706 low: low,
26707 high: high,
26708 direction: 1
26709 });
26710
26711 angleFrom = Math.atan2(pointTFrom.y - y, pointTFrom.x - x);
26712 angleTo = Math.atan2(pointTTo.y - y, pointTTo.x - x);
26713 } // draw a circle
26714
26715
26716 ctx.beginPath();
26717 ctx.arc(x, y, radius, angleFrom, angleTo, false);
26718 ctx.stroke(); // disable shadows for other elements.
26719
26720 this.disableShadow(ctx, values);
26721 }
26722 /**
26723 * @inheritDoc
26724 * @remarks
26725 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
26726 */
26727
26728 }, {
26729 key: "getDistanceToEdge",
26730 value: function getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
26731 if (this.from != this.to) {
26732 return this._getDistanceToEdge(x1, y1, x2, y2, x3, y3);
26733 } else {
26734 var _this$_getCircleData7 = this._getCircleData(undefined),
26735 _this$_getCircleData8 = _slicedToArray(_this$_getCircleData7, 3),
26736 x = _this$_getCircleData8[0],
26737 y = _this$_getCircleData8[1],
26738 radius = _this$_getCircleData8[2];
26739
26740 var dx = x - x3;
26741 var dy = y - y3;
26742 return Math.abs(Math.sqrt(dx * dx + dy * dy) - radius);
26743 }
26744 }
26745 /**
26746 * Calculate the distance between a point (x3, y3) and a line segment from (x1, y1) to (x2, y2).
26747 *
26748 * @param x1 - First end of the line segment on the x axis.
26749 * @param y1 - First end of the line segment on the y axis.
26750 * @param x2 - Second end of the line segment on the x axis.
26751 * @param y2 - Second end of the line segment on the y axis.
26752 * @param x3 - Position of the point on the x axis.
26753 * @param y3 - Position of the point on the y axis.
26754 * @returns The distance between the line segment and the point.
26755 */
26756
26757 }, {
26758 key: "_getDistanceToLine",
26759 value: function _getDistanceToLine(x1, y1, x2, y2, x3, y3) {
26760 var px = x2 - x1;
26761 var py = y2 - y1;
26762 var something = px * px + py * py;
26763 var u = ((x3 - x1) * px + (y3 - y1) * py) / something;
26764
26765 if (u > 1) {
26766 u = 1;
26767 } else if (u < 0) {
26768 u = 0;
26769 }
26770
26771 var x = x1 + u * px;
26772 var y = y1 + u * py;
26773 var dx = x - x3;
26774 var dy = y - y3; //# Note: If the actual distance does not matter,
26775 //# if you only want to compare what this function
26776 //# returns to other results of this function, you
26777 //# can just return the squared distance instead
26778 //# (i.e. remove the sqrt) to gain a little performance
26779
26780 return Math.sqrt(dx * dx + dy * dy);
26781 }
26782 /** @inheritDoc */
26783
26784 }, {
26785 key: "getArrowData",
26786 value: function getArrowData(ctx, position, viaNode, _selected, _hover, values) {
26787 // set lets
26788 var angle;
26789 var arrowPoint;
26790 var node1;
26791 var node2;
26792 var reversed;
26793 var scaleFactor;
26794 var type;
26795 var lineWidth = values.width;
26796
26797 if (position === "from") {
26798 node1 = this.from;
26799 node2 = this.to;
26800 reversed = values.fromArrowScale < 0;
26801 scaleFactor = Math.abs(values.fromArrowScale);
26802 type = values.fromArrowType;
26803 } else if (position === "to") {
26804 node1 = this.to;
26805 node2 = this.from;
26806 reversed = values.toArrowScale < 0;
26807 scaleFactor = Math.abs(values.toArrowScale);
26808 type = values.toArrowType;
26809 } else {
26810 node1 = this.to;
26811 node2 = this.from;
26812 reversed = values.middleArrowScale < 0;
26813 scaleFactor = Math.abs(values.middleArrowScale);
26814 type = values.middleArrowType;
26815 }
26816
26817 var length = 15 * scaleFactor + 3 * lineWidth; // 3* lineWidth is the width of the edge.
26818 // if not connected to itself
26819
26820 if (node1 != node2) {
26821 var approximateEdgeLength = hypot(node1.x - node2.x, node1.y - node2.y);
26822
26823 var relativeLength = length / approximateEdgeLength;
26824
26825 if (position !== "middle") {
26826 // draw arrow head
26827 if (this.options.smooth.enabled === true) {
26828 var pointT = this._findBorderPosition(node1, ctx, {
26829 via: viaNode
26830 });
26831
26832 var guidePos = this.getPoint(pointT.t + relativeLength * (position === "from" ? 1 : -1), viaNode);
26833 angle = Math.atan2(pointT.y - guidePos.y, pointT.x - guidePos.x);
26834 arrowPoint = pointT;
26835 } else {
26836 angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
26837 arrowPoint = this._findBorderPosition(node1, ctx);
26838 }
26839 } else {
26840 // Negative half length reverses arrow direction.
26841 var halfLength = (reversed ? -relativeLength : relativeLength) / 2;
26842 var guidePos1 = this.getPoint(0.5 + halfLength, viaNode);
26843 var guidePos2 = this.getPoint(0.5 - halfLength, viaNode);
26844 angle = Math.atan2(guidePos1.y - guidePos2.y, guidePos1.x - guidePos2.x);
26845 arrowPoint = this.getPoint(0.5, viaNode);
26846 }
26847 } else {
26848 // draw circle
26849 var _this$_getCircleData9 = this._getCircleData(ctx),
26850 _this$_getCircleData10 = _slicedToArray(_this$_getCircleData9, 3),
26851 x = _this$_getCircleData10[0],
26852 y = _this$_getCircleData10[1],
26853 radius = _this$_getCircleData10[2];
26854
26855 if (position === "from") {
26856 var low = this.options.selfReference.angle;
26857 var high = this.options.selfReference.angle + Math.PI;
26858
26859 var _pointT = this._findBorderPositionCircle(this.from, ctx, {
26860 x: x,
26861 y: y,
26862 low: low,
26863 high: high,
26864 direction: -1
26865 });
26866
26867 angle = _pointT.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
26868 arrowPoint = _pointT;
26869 } else if (position === "to") {
26870 var _low = this.options.selfReference.angle;
26871
26872 var _high = this.options.selfReference.angle + Math.PI;
26873
26874 var _pointT2 = this._findBorderPositionCircle(this.from, ctx, {
26875 x: x,
26876 y: y,
26877 low: _low,
26878 high: _high,
26879 direction: 1
26880 });
26881
26882 angle = _pointT2.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI;
26883 arrowPoint = _pointT2;
26884 } else {
26885 var pos = this.options.selfReference.angle / (2 * Math.PI);
26886 arrowPoint = this._pointOnCircle(x, y, radius, pos);
26887 angle = pos * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
26888 }
26889 }
26890
26891 var xi = arrowPoint.x - length * 0.9 * Math.cos(angle);
26892 var yi = arrowPoint.y - length * 0.9 * Math.sin(angle);
26893 var arrowCore = {
26894 x: xi,
26895 y: yi
26896 };
26897 return {
26898 point: arrowPoint,
26899 core: arrowCore,
26900 angle: angle,
26901 length: length,
26902 type: type
26903 };
26904 }
26905 /** @inheritDoc */
26906
26907 }, {
26908 key: "drawArrowHead",
26909 value: function drawArrowHead(ctx, values, _selected, _hover, arrowData) {
26910 // set style
26911 ctx.strokeStyle = this.getColor(ctx, values);
26912 ctx.fillStyle = ctx.strokeStyle;
26913 ctx.lineWidth = values.width;
26914 var canFill = EndPoints.draw(ctx, arrowData);
26915
26916 if (canFill) {
26917 // draw shadow if enabled
26918 this.enableShadow(ctx, values);
26919
26920 fill(ctx).call(ctx); // disable shadows for other elements.
26921
26922
26923 this.disableShadow(ctx, values);
26924 }
26925 }
26926 /**
26927 * Set the shadow formatting values in the context if enabled, do nothing otherwise.
26928 *
26929 * @param ctx - The context that will be used for rendering.
26930 * @param values - Formatting values for the shadow.
26931 */
26932
26933 }, {
26934 key: "enableShadow",
26935 value: function enableShadow(ctx, values) {
26936 if (values.shadow === true) {
26937 ctx.shadowColor = values.shadowColor;
26938 ctx.shadowBlur = values.shadowSize;
26939 ctx.shadowOffsetX = values.shadowX;
26940 ctx.shadowOffsetY = values.shadowY;
26941 }
26942 }
26943 /**
26944 * Reset the shadow formatting values in the context if enabled, do nothing otherwise.
26945 *
26946 * @param ctx - The context that will be used for rendering.
26947 * @param values - Formatting values for the shadow.
26948 */
26949
26950 }, {
26951 key: "disableShadow",
26952 value: function disableShadow(ctx, values) {
26953 if (values.shadow === true) {
26954 ctx.shadowColor = "rgba(0,0,0,0)";
26955 ctx.shadowBlur = 0;
26956 ctx.shadowOffsetX = 0;
26957 ctx.shadowOffsetY = 0;
26958 }
26959 }
26960 /**
26961 * Render the background according to the formatting values.
26962 *
26963 * @param ctx - The context that will be used for rendering.
26964 * @param values - Formatting values for the background.
26965 */
26966
26967 }, {
26968 key: "drawBackground",
26969 value: function drawBackground(ctx, values) {
26970 if (values.background !== false) {
26971 // save original line attrs
26972 var origCtxAttr = {
26973 strokeStyle: ctx.strokeStyle,
26974 lineWidth: ctx.lineWidth,
26975 dashes: ctx.dashes
26976 };
26977 ctx.strokeStyle = values.backgroundColor;
26978 ctx.lineWidth = values.backgroundSize;
26979 this.setStrokeDashed(ctx, values.backgroundDashes);
26980 ctx.stroke(); // restore original line attrs
26981
26982 ctx.strokeStyle = origCtxAttr.strokeStyle;
26983 ctx.lineWidth = origCtxAttr.lineWidth;
26984 ctx.dashes = origCtxAttr.dashes;
26985 this.setStrokeDashed(ctx, values.dashes);
26986 }
26987 }
26988 /**
26989 * Set the line dash pattern if supported. Logs a warning to the console if it isn't supported.
26990 *
26991 * @param ctx - The context that will be used for rendering.
26992 * @param dashes - The pattern [line, space, line…], true for default dashed line or false for normal line.
26993 */
26994
26995 }, {
26996 key: "setStrokeDashed",
26997 value: function setStrokeDashed(ctx, dashes) {
26998 if (dashes !== false) {
26999 if (ctx.setLineDash !== undefined) {
27000 var pattern = isArray$2(dashes) ? dashes : [5, 5];
27001 ctx.setLineDash(pattern);
27002 } else {
27003 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
27004 }
27005 } else {
27006 if (ctx.setLineDash !== undefined) {
27007 ctx.setLineDash([]);
27008 } else {
27009 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
27010 }
27011 }
27012 }
27013 }]);
27014
27015 return EdgeBase;
27016 }();
27017
27018 function ownKeys(object, enumerableOnly) { var keys = keys$4(object); if (getOwnPropertySymbols) { var symbols = getOwnPropertySymbols(object); enumerableOnly && (symbols = filter(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$3(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
27019
27020 function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? forEach$2(_context = ownKeys(Object(source), !0)).call(_context, function (key) { _defineProperty(target, key, source[key]); }) : getOwnPropertyDescriptors ? defineProperties(target, getOwnPropertyDescriptors(source)) : forEach$2(_context2 = ownKeys(Object(source))).call(_context2, function (key) { defineProperty$6(target, key, getOwnPropertyDescriptor$3(source, key)); }); } return target; }
27021
27022 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); }; }
27023
27024 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; } }
27025 /**
27026 * The Base Class for all Bezier edges.
27027 * Bezier curves are used to model smooth gradual curves in paths between nodes.
27028 */
27029
27030 var BezierEdgeBase = /*#__PURE__*/function (_EdgeBase) {
27031 _inherits(BezierEdgeBase, _EdgeBase);
27032
27033 var _super = _createSuper$9(BezierEdgeBase);
27034
27035 /**
27036 * Create a new instance.
27037 *
27038 * @param options - The options object of given edge.
27039 * @param body - The body of the network.
27040 * @param labelModule - Label module.
27041 */
27042 function BezierEdgeBase(options, body, labelModule) {
27043 _classCallCheck(this, BezierEdgeBase);
27044
27045 return _super.call(this, options, body, labelModule);
27046 }
27047 /**
27048 * Find the intersection between the border of the node and the edge.
27049 *
27050 * @remarks
27051 * This function uses binary search to look for the point where the bezier curve crosses the border of the node.
27052 * @param nearNode - The node (either from or to node of the edge).
27053 * @param ctx - The context that will be used for rendering.
27054 * @param viaNode - Additional node(s) the edge passes through.
27055 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
27056 */
27057
27058
27059 _createClass(BezierEdgeBase, [{
27060 key: "_findBorderPositionBezier",
27061 value: function _findBorderPositionBezier(nearNode, ctx) {
27062 var viaNode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this._getViaCoordinates();
27063 var maxIterations = 10;
27064 var threshold = 0.2;
27065 var from = false;
27066 var high = 1;
27067 var low = 0;
27068 var node = this.to;
27069 var pos;
27070 var middle;
27071 var endPointOffset = this.options.endPointOffset ? this.options.endPointOffset.to : 0;
27072
27073 if (nearNode.id === this.from.id) {
27074 node = this.from;
27075 from = true;
27076 endPointOffset = this.options.endPointOffset ? this.options.endPointOffset.from : 0;
27077 }
27078
27079 if (this.options.arrowStrikethrough === false) {
27080 endPointOffset = 0;
27081 }
27082
27083 var iteration = 0;
27084
27085 do {
27086 middle = (low + high) * 0.5;
27087 pos = this.getPoint(middle, viaNode);
27088 var angle = Math.atan2(node.y - pos.y, node.x - pos.x);
27089 var distanceToBorder = node.distanceToBorder(ctx, angle) + endPointOffset;
27090 var distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2));
27091 var difference = distanceToBorder - distanceToPoint;
27092
27093 if (Math.abs(difference) < threshold) {
27094 break; // found
27095 } else if (difference < 0) {
27096 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
27097 if (from === false) {
27098 low = middle;
27099 } else {
27100 high = middle;
27101 }
27102 } else {
27103 if (from === false) {
27104 high = middle;
27105 } else {
27106 low = middle;
27107 }
27108 }
27109
27110 ++iteration;
27111 } while (low <= high && iteration < maxIterations);
27112
27113 return _objectSpread(_objectSpread({}, pos), {}, {
27114 t: middle
27115 });
27116 }
27117 /**
27118 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
27119 *
27120 * @remarks
27121 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
27122 * @param x1 - First end of the line segment on the x axis.
27123 * @param y1 - First end of the line segment on the y axis.
27124 * @param x2 - Second end of the line segment on the x axis.
27125 * @param y2 - Second end of the line segment on the y axis.
27126 * @param x3 - Position of the point on the x axis.
27127 * @param y3 - Position of the point on the y axis.
27128 * @param via - The control point for the edge.
27129 * @returns The distance between the line segment and the point.
27130 */
27131
27132 }, {
27133 key: "_getDistanceToBezierEdge",
27134 value: function _getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via) {
27135 // x3,y3 is the point
27136 var minDistance = 1e9;
27137 var distance;
27138 var i, t, x, y;
27139 var lastX = x1;
27140 var lastY = y1;
27141
27142 for (i = 1; i < 10; i++) {
27143 t = 0.1 * i;
27144 x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * via.x + Math.pow(t, 2) * x2;
27145 y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * via.y + Math.pow(t, 2) * y2;
27146
27147 if (i > 0) {
27148 distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
27149 minDistance = distance < minDistance ? distance : minDistance;
27150 }
27151
27152 lastX = x;
27153 lastY = y;
27154 }
27155
27156 return minDistance;
27157 }
27158 /**
27159 * Render a bezier curve between two nodes.
27160 *
27161 * @remarks
27162 * The method accepts zero, one or two control points.
27163 * Passing zero control points just draws a straight line.
27164 * @param ctx - The context that will be used for rendering.
27165 * @param values - Style options for edge drawing.
27166 * @param viaNode1 - First control point for curve drawing.
27167 * @param viaNode2 - Second control point for curve drawing.
27168 */
27169
27170 }, {
27171 key: "_bezierCurve",
27172 value: function _bezierCurve(ctx, values, viaNode1, viaNode2) {
27173 ctx.beginPath();
27174 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
27175
27176 if (viaNode1 != null && viaNode1.x != null) {
27177 if (viaNode2 != null && viaNode2.x != null) {
27178 ctx.bezierCurveTo(viaNode1.x, viaNode1.y, viaNode2.x, viaNode2.y, this.toPoint.x, this.toPoint.y);
27179 } else {
27180 ctx.quadraticCurveTo(viaNode1.x, viaNode1.y, this.toPoint.x, this.toPoint.y);
27181 }
27182 } else {
27183 // fallback to normal straight edge
27184 ctx.lineTo(this.toPoint.x, this.toPoint.y);
27185 } // draw a background
27186
27187
27188 this.drawBackground(ctx, values); // draw shadow if enabled
27189
27190 this.enableShadow(ctx, values);
27191 ctx.stroke();
27192 this.disableShadow(ctx, values);
27193 }
27194 /** @inheritDoc */
27195
27196 }, {
27197 key: "getViaNode",
27198 value: function getViaNode() {
27199 return this._getViaCoordinates();
27200 }
27201 }]);
27202
27203 return BezierEdgeBase;
27204 }(EdgeBase);
27205
27206 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); }; }
27207
27208 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; } }
27209 /**
27210 * A Dynamic Bezier Edge. Bezier curves are used to model smooth gradual
27211 * curves in paths between nodes. The Dynamic piece refers to how the curve
27212 * reacts to physics changes.
27213 *
27214 * @augments BezierEdgeBase
27215 */
27216
27217 var BezierEdgeDynamic = /*#__PURE__*/function (_BezierEdgeBase) {
27218 _inherits(BezierEdgeDynamic, _BezierEdgeBase);
27219
27220 var _super = _createSuper$8(BezierEdgeDynamic);
27221
27222 /**
27223 * Create a new instance.
27224 *
27225 * @param options - The options object of given edge.
27226 * @param body - The body of the network.
27227 * @param labelModule - Label module.
27228 */
27229 function BezierEdgeDynamic(options, body, labelModule) {
27230 var _this;
27231
27232 _classCallCheck(this, BezierEdgeDynamic);
27233
27234 //this.via = undefined; // Here for completeness but not allowed to defined before super() is invoked.
27235 _this = _super.call(this, options, body, labelModule); // --> this calls the setOptions below
27236
27237 _this.via = _this.via; // constructor → super → super → setOptions → setupSupportNode
27238
27239 _this._boundFunction = function () {
27240 _this.positionBezierNode();
27241 };
27242
27243 _this._body.emitter.on("_repositionBezierNodes", _this._boundFunction);
27244
27245 return _this;
27246 }
27247 /** @inheritDoc */
27248
27249
27250 _createClass(BezierEdgeDynamic, [{
27251 key: "setOptions",
27252 value: function setOptions(options) {
27253 _get(_getPrototypeOf(BezierEdgeDynamic.prototype), "setOptions", this).call(this, options); // check if the physics has changed.
27254
27255
27256 var physicsChange = false;
27257
27258 if (this.options.physics !== options.physics) {
27259 physicsChange = true;
27260 } // set the options and the to and from nodes
27261
27262
27263 this.options = options;
27264 this.id = this.options.id;
27265 this.from = this._body.nodes[this.options.from];
27266 this.to = this._body.nodes[this.options.to]; // setup the support node and connect
27267
27268 this.setupSupportNode();
27269 this.connect(); // when we change the physics state of the edge, we reposition the support node.
27270
27271 if (physicsChange === true) {
27272 this.via.setOptions({
27273 physics: this.options.physics
27274 });
27275 this.positionBezierNode();
27276 }
27277 }
27278 /** @inheritDoc */
27279
27280 }, {
27281 key: "connect",
27282 value: function connect() {
27283 this.from = this._body.nodes[this.options.from];
27284 this.to = this._body.nodes[this.options.to];
27285
27286 if (this.from === undefined || this.to === undefined || this.options.physics === false) {
27287 this.via.setOptions({
27288 physics: false
27289 });
27290 } else {
27291 // fix weird behaviour where a self referencing node has physics enabled
27292 if (this.from.id === this.to.id) {
27293 this.via.setOptions({
27294 physics: false
27295 });
27296 } else {
27297 this.via.setOptions({
27298 physics: true
27299 });
27300 }
27301 }
27302 }
27303 /** @inheritDoc */
27304
27305 }, {
27306 key: "cleanup",
27307 value: function cleanup() {
27308 this._body.emitter.off("_repositionBezierNodes", this._boundFunction);
27309
27310 if (this.via !== undefined) {
27311 delete this._body.nodes[this.via.id];
27312 this.via = undefined;
27313 return true;
27314 }
27315
27316 return false;
27317 }
27318 /**
27319 * Create and add a support node if not already present.
27320 *
27321 * @remarks
27322 * Bezier curves require an anchor point to calculate the smooth flow.
27323 * These points are nodes.
27324 * These nodes are invisible but are used for the force calculation.
27325 *
27326 * The changed data is not called, if needed, it is returned by the main edge constructor.
27327 */
27328
27329 }, {
27330 key: "setupSupportNode",
27331 value: function setupSupportNode() {
27332 if (this.via === undefined) {
27333 var nodeId = "edgeId:" + this.id;
27334
27335 var node = this._body.functions.createNode({
27336 id: nodeId,
27337 shape: "circle",
27338 physics: true,
27339 hidden: true
27340 });
27341
27342 this._body.nodes[nodeId] = node;
27343 this.via = node;
27344 this.via.parentEdgeId = this.id;
27345 this.positionBezierNode();
27346 }
27347 }
27348 /**
27349 * Position bezier node.
27350 */
27351
27352 }, {
27353 key: "positionBezierNode",
27354 value: function positionBezierNode() {
27355 if (this.via !== undefined && this.from !== undefined && this.to !== undefined) {
27356 this.via.x = 0.5 * (this.from.x + this.to.x);
27357 this.via.y = 0.5 * (this.from.y + this.to.y);
27358 } else if (this.via !== undefined) {
27359 this.via.x = 0;
27360 this.via.y = 0;
27361 }
27362 }
27363 /** @inheritDoc */
27364
27365 }, {
27366 key: "_line",
27367 value: function _line(ctx, values, viaNode) {
27368 this._bezierCurve(ctx, values, viaNode);
27369 }
27370 /** @inheritDoc */
27371
27372 }, {
27373 key: "_getViaCoordinates",
27374 value: function _getViaCoordinates() {
27375 return this.via;
27376 }
27377 /** @inheritDoc */
27378
27379 }, {
27380 key: "getViaNode",
27381 value: function getViaNode() {
27382 return this.via;
27383 }
27384 /** @inheritDoc */
27385
27386 }, {
27387 key: "getPoint",
27388 value: function getPoint(position) {
27389 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.via;
27390
27391 if (this.from === this.to) {
27392 var _this$_getCircleData = this._getCircleData(),
27393 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
27394 cx = _this$_getCircleData2[0],
27395 cy = _this$_getCircleData2[1],
27396 cr = _this$_getCircleData2[2];
27397
27398 var a = 2 * Math.PI * (1 - position);
27399 return {
27400 x: cx + cr * Math.sin(a),
27401 y: cy + cr - cr * (1 - Math.cos(a))
27402 };
27403 } else {
27404 return {
27405 x: Math.pow(1 - position, 2) * this.fromPoint.x + 2 * position * (1 - position) * viaNode.x + Math.pow(position, 2) * this.toPoint.x,
27406 y: Math.pow(1 - position, 2) * this.fromPoint.y + 2 * position * (1 - position) * viaNode.y + Math.pow(position, 2) * this.toPoint.y
27407 };
27408 }
27409 }
27410 /** @inheritDoc */
27411
27412 }, {
27413 key: "_findBorderPosition",
27414 value: function _findBorderPosition(nearNode, ctx) {
27415 return this._findBorderPositionBezier(nearNode, ctx, this.via);
27416 }
27417 /** @inheritDoc */
27418
27419 }, {
27420 key: "_getDistanceToEdge",
27421 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
27422 // x3,y3 is the point
27423 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, this.via);
27424 }
27425 }]);
27426
27427 return BezierEdgeDynamic;
27428 }(BezierEdgeBase);
27429
27430 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); }; }
27431
27432 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; } }
27433 /**
27434 * A Static Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
27435 */
27436
27437 var BezierEdgeStatic = /*#__PURE__*/function (_BezierEdgeBase) {
27438 _inherits(BezierEdgeStatic, _BezierEdgeBase);
27439
27440 var _super = _createSuper$7(BezierEdgeStatic);
27441
27442 /**
27443 * Create a new instance.
27444 *
27445 * @param options - The options object of given edge.
27446 * @param body - The body of the network.
27447 * @param labelModule - Label module.
27448 */
27449 function BezierEdgeStatic(options, body, labelModule) {
27450 _classCallCheck(this, BezierEdgeStatic);
27451
27452 return _super.call(this, options, body, labelModule);
27453 }
27454 /** @inheritDoc */
27455
27456
27457 _createClass(BezierEdgeStatic, [{
27458 key: "_line",
27459 value: function _line(ctx, values, viaNode) {
27460 this._bezierCurve(ctx, values, viaNode);
27461 }
27462 /** @inheritDoc */
27463
27464 }, {
27465 key: "getViaNode",
27466 value: function getViaNode() {
27467 return this._getViaCoordinates();
27468 }
27469 /**
27470 * Compute the coordinates of the via node.
27471 *
27472 * @remarks
27473 * We do not use the to and fromPoints here to make the via nodes the same as edges without arrows.
27474 * @returns Cartesian coordinates of the via node.
27475 */
27476
27477 }, {
27478 key: "_getViaCoordinates",
27479 value: function _getViaCoordinates() {
27480 // Assumption: x/y coordinates in from/to always defined
27481 var factor = this.options.smooth.roundness;
27482 var type = this.options.smooth.type;
27483 var dx = Math.abs(this.from.x - this.to.x);
27484 var dy = Math.abs(this.from.y - this.to.y);
27485
27486 if (type === "discrete" || type === "diagonalCross") {
27487 var stepX;
27488 var stepY;
27489
27490 if (dx <= dy) {
27491 stepX = stepY = factor * dy;
27492 } else {
27493 stepX = stepY = factor * dx;
27494 }
27495
27496 if (this.from.x > this.to.x) {
27497 stepX = -stepX;
27498 }
27499
27500 if (this.from.y >= this.to.y) {
27501 stepY = -stepY;
27502 }
27503
27504 var xVia = this.from.x + stepX;
27505 var yVia = this.from.y + stepY;
27506
27507 if (type === "discrete") {
27508 if (dx <= dy) {
27509 xVia = dx < factor * dy ? this.from.x : xVia;
27510 } else {
27511 yVia = dy < factor * dx ? this.from.y : yVia;
27512 }
27513 }
27514
27515 return {
27516 x: xVia,
27517 y: yVia
27518 };
27519 } else if (type === "straightCross") {
27520 var _stepX = (1 - factor) * dx;
27521
27522 var _stepY = (1 - factor) * dy;
27523
27524 if (dx <= dy) {
27525 // up - down
27526 _stepX = 0;
27527
27528 if (this.from.y < this.to.y) {
27529 _stepY = -_stepY;
27530 }
27531 } else {
27532 // left - right
27533 if (this.from.x < this.to.x) {
27534 _stepX = -_stepX;
27535 }
27536
27537 _stepY = 0;
27538 }
27539
27540 return {
27541 x: this.to.x + _stepX,
27542 y: this.to.y + _stepY
27543 };
27544 } else if (type === "horizontal") {
27545 var _stepX2 = (1 - factor) * dx;
27546
27547 if (this.from.x < this.to.x) {
27548 _stepX2 = -_stepX2;
27549 }
27550
27551 return {
27552 x: this.to.x + _stepX2,
27553 y: this.from.y
27554 };
27555 } else if (type === "vertical") {
27556 var _stepY2 = (1 - factor) * dy;
27557
27558 if (this.from.y < this.to.y) {
27559 _stepY2 = -_stepY2;
27560 }
27561
27562 return {
27563 x: this.from.x,
27564 y: this.to.y + _stepY2
27565 };
27566 } else if (type === "curvedCW") {
27567 dx = this.to.x - this.from.x;
27568 dy = this.from.y - this.to.y;
27569 var radius = Math.sqrt(dx * dx + dy * dy);
27570 var pi = Math.PI;
27571 var originalAngle = Math.atan2(dy, dx);
27572 var myAngle = (originalAngle + (factor * 0.5 + 0.5) * pi) % (2 * pi);
27573 return {
27574 x: this.from.x + (factor * 0.5 + 0.5) * radius * Math.sin(myAngle),
27575 y: this.from.y + (factor * 0.5 + 0.5) * radius * Math.cos(myAngle)
27576 };
27577 } else if (type === "curvedCCW") {
27578 dx = this.to.x - this.from.x;
27579 dy = this.from.y - this.to.y;
27580
27581 var _radius = Math.sqrt(dx * dx + dy * dy);
27582
27583 var _pi = Math.PI;
27584
27585 var _originalAngle = Math.atan2(dy, dx);
27586
27587 var _myAngle = (_originalAngle + (-factor * 0.5 + 0.5) * _pi) % (2 * _pi);
27588
27589 return {
27590 x: this.from.x + (factor * 0.5 + 0.5) * _radius * Math.sin(_myAngle),
27591 y: this.from.y + (factor * 0.5 + 0.5) * _radius * Math.cos(_myAngle)
27592 };
27593 } else {
27594 // continuous
27595 var _stepX3;
27596
27597 var _stepY3;
27598
27599 if (dx <= dy) {
27600 _stepX3 = _stepY3 = factor * dy;
27601 } else {
27602 _stepX3 = _stepY3 = factor * dx;
27603 }
27604
27605 if (this.from.x > this.to.x) {
27606 _stepX3 = -_stepX3;
27607 }
27608
27609 if (this.from.y >= this.to.y) {
27610 _stepY3 = -_stepY3;
27611 }
27612
27613 var _xVia = this.from.x + _stepX3;
27614
27615 var _yVia = this.from.y + _stepY3;
27616
27617 if (dx <= dy) {
27618 if (this.from.x <= this.to.x) {
27619 _xVia = this.to.x < _xVia ? this.to.x : _xVia;
27620 } else {
27621 _xVia = this.to.x > _xVia ? this.to.x : _xVia;
27622 }
27623 } else {
27624 if (this.from.y >= this.to.y) {
27625 _yVia = this.to.y > _yVia ? this.to.y : _yVia;
27626 } else {
27627 _yVia = this.to.y < _yVia ? this.to.y : _yVia;
27628 }
27629 }
27630
27631 return {
27632 x: _xVia,
27633 y: _yVia
27634 };
27635 }
27636 }
27637 /** @inheritDoc */
27638
27639 }, {
27640 key: "_findBorderPosition",
27641 value: function _findBorderPosition(nearNode, ctx) {
27642 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
27643 return this._findBorderPositionBezier(nearNode, ctx, options.via);
27644 }
27645 /** @inheritDoc */
27646
27647 }, {
27648 key: "_getDistanceToEdge",
27649 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
27650 var viaNode = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates();
27651 // x3,y3 is the point
27652 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, viaNode);
27653 }
27654 /** @inheritDoc */
27655
27656 }, {
27657 key: "getPoint",
27658 value: function getPoint(position) {
27659 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates();
27660 var t = position;
27661 var x = Math.pow(1 - t, 2) * this.fromPoint.x + 2 * t * (1 - t) * viaNode.x + Math.pow(t, 2) * this.toPoint.x;
27662 var y = Math.pow(1 - t, 2) * this.fromPoint.y + 2 * t * (1 - t) * viaNode.y + Math.pow(t, 2) * this.toPoint.y;
27663 return {
27664 x: x,
27665 y: y
27666 };
27667 }
27668 }]);
27669
27670 return BezierEdgeStatic;
27671 }(BezierEdgeBase);
27672
27673 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); }; }
27674
27675 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; } }
27676 /**
27677 * A Base Class for all Cubic Bezier Edges. Bezier curves are used to model
27678 * smooth gradual curves in paths between nodes.
27679 *
27680 * @augments BezierEdgeBase
27681 */
27682
27683 var CubicBezierEdgeBase = /*#__PURE__*/function (_BezierEdgeBase) {
27684 _inherits(CubicBezierEdgeBase, _BezierEdgeBase);
27685
27686 var _super = _createSuper$6(CubicBezierEdgeBase);
27687
27688 /**
27689 * Create a new instance.
27690 *
27691 * @param options - The options object of given edge.
27692 * @param body - The body of the network.
27693 * @param labelModule - Label module.
27694 */
27695 function CubicBezierEdgeBase(options, body, labelModule) {
27696 _classCallCheck(this, CubicBezierEdgeBase);
27697
27698 return _super.call(this, options, body, labelModule);
27699 }
27700 /**
27701 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
27702 *
27703 * @remarks
27704 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
27705 * https://en.wikipedia.org/wiki/B%C3%A9zier_curve
27706 * @param x1 - First end of the line segment on the x axis.
27707 * @param y1 - First end of the line segment on the y axis.
27708 * @param x2 - Second end of the line segment on the x axis.
27709 * @param y2 - Second end of the line segment on the y axis.
27710 * @param x3 - Position of the point on the x axis.
27711 * @param y3 - Position of the point on the y axis.
27712 * @param via1 - The first point this edge passes through.
27713 * @param via2 - The second point this edge passes through.
27714 * @returns The distance between the line segment and the point.
27715 */
27716
27717
27718 _createClass(CubicBezierEdgeBase, [{
27719 key: "_getDistanceToBezierEdge2",
27720 value: function _getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2) {
27721 // x3,y3 is the point
27722 var minDistance = 1e9;
27723 var lastX = x1;
27724 var lastY = y1;
27725 var vec = [0, 0, 0, 0];
27726
27727 for (var i = 1; i < 10; i++) {
27728 var t = 0.1 * i;
27729 vec[0] = Math.pow(1 - t, 3);
27730 vec[1] = 3 * t * Math.pow(1 - t, 2);
27731 vec[2] = 3 * Math.pow(t, 2) * (1 - t);
27732 vec[3] = Math.pow(t, 3);
27733 var x = vec[0] * x1 + vec[1] * via1.x + vec[2] * via2.x + vec[3] * x2;
27734 var y = vec[0] * y1 + vec[1] * via1.y + vec[2] * via2.y + vec[3] * y2;
27735
27736 if (i > 0) {
27737 var distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
27738
27739 minDistance = distance < minDistance ? distance : minDistance;
27740 }
27741
27742 lastX = x;
27743 lastY = y;
27744 }
27745
27746 return minDistance;
27747 }
27748 }]);
27749
27750 return CubicBezierEdgeBase;
27751 }(BezierEdgeBase);
27752
27753 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); }; }
27754
27755 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; } }
27756 /**
27757 * A Cubic Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
27758 */
27759
27760 var CubicBezierEdge = /*#__PURE__*/function (_CubicBezierEdgeBase) {
27761 _inherits(CubicBezierEdge, _CubicBezierEdgeBase);
27762
27763 var _super = _createSuper$5(CubicBezierEdge);
27764
27765 /**
27766 * Create a new instance.
27767 *
27768 * @param options - The options object of given edge.
27769 * @param body - The body of the network.
27770 * @param labelModule - Label module.
27771 */
27772 function CubicBezierEdge(options, body, labelModule) {
27773 _classCallCheck(this, CubicBezierEdge);
27774
27775 return _super.call(this, options, body, labelModule);
27776 }
27777 /** @inheritDoc */
27778
27779
27780 _createClass(CubicBezierEdge, [{
27781 key: "_line",
27782 value: function _line(ctx, values, viaNodes) {
27783 // get the coordinates of the support points.
27784 var via1 = viaNodes[0];
27785 var via2 = viaNodes[1];
27786
27787 this._bezierCurve(ctx, values, via1, via2);
27788 }
27789 /**
27790 * Compute the additional points the edge passes through.
27791 *
27792 * @returns Cartesian coordinates of the points the edge passes through.
27793 */
27794
27795 }, {
27796 key: "_getViaCoordinates",
27797 value: function _getViaCoordinates() {
27798 var dx = this.from.x - this.to.x;
27799 var dy = this.from.y - this.to.y;
27800 var x1;
27801 var y1;
27802 var x2;
27803 var y2;
27804 var roundness = this.options.smooth.roundness; // horizontal if x > y or if direction is forced or if direction is horizontal
27805
27806 if ((Math.abs(dx) > Math.abs(dy) || this.options.smooth.forceDirection === true || this.options.smooth.forceDirection === "horizontal") && this.options.smooth.forceDirection !== "vertical") {
27807 y1 = this.from.y;
27808 y2 = this.to.y;
27809 x1 = this.from.x - roundness * dx;
27810 x2 = this.to.x + roundness * dx;
27811 } else {
27812 y1 = this.from.y - roundness * dy;
27813 y2 = this.to.y + roundness * dy;
27814 x1 = this.from.x;
27815 x2 = this.to.x;
27816 }
27817
27818 return [{
27819 x: x1,
27820 y: y1
27821 }, {
27822 x: x2,
27823 y: y2
27824 }];
27825 }
27826 /** @inheritDoc */
27827
27828 }, {
27829 key: "getViaNode",
27830 value: function getViaNode() {
27831 return this._getViaCoordinates();
27832 }
27833 /** @inheritDoc */
27834
27835 }, {
27836 key: "_findBorderPosition",
27837 value: function _findBorderPosition(nearNode, ctx) {
27838 return this._findBorderPositionBezier(nearNode, ctx);
27839 }
27840 /** @inheritDoc */
27841
27842 }, {
27843 key: "_getDistanceToEdge",
27844 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
27845 var _ref = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates(),
27846 _ref2 = _slicedToArray(_ref, 2),
27847 via1 = _ref2[0],
27848 via2 = _ref2[1];
27849
27850 // x3,y3 is the point
27851 return this._getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2);
27852 }
27853 /** @inheritDoc */
27854
27855 }, {
27856 key: "getPoint",
27857 value: function getPoint(position) {
27858 var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates(),
27859 _ref4 = _slicedToArray(_ref3, 2),
27860 via1 = _ref4[0],
27861 via2 = _ref4[1];
27862
27863 var t = position;
27864 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)];
27865 var x = vec[0] * this.fromPoint.x + vec[1] * via1.x + vec[2] * via2.x + vec[3] * this.toPoint.x;
27866 var y = vec[0] * this.fromPoint.y + vec[1] * via1.y + vec[2] * via2.y + vec[3] * this.toPoint.y;
27867 return {
27868 x: x,
27869 y: y
27870 };
27871 }
27872 }]);
27873
27874 return CubicBezierEdge;
27875 }(CubicBezierEdgeBase);
27876
27877 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); }; }
27878
27879 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; } }
27880 /**
27881 * A Straight Edge.
27882 */
27883
27884 var StraightEdge = /*#__PURE__*/function (_EdgeBase) {
27885 _inherits(StraightEdge, _EdgeBase);
27886
27887 var _super = _createSuper$4(StraightEdge);
27888
27889 /**
27890 * Create a new instance.
27891 *
27892 * @param options - The options object of given edge.
27893 * @param body - The body of the network.
27894 * @param labelModule - Label module.
27895 */
27896 function StraightEdge(options, body, labelModule) {
27897 _classCallCheck(this, StraightEdge);
27898
27899 return _super.call(this, options, body, labelModule);
27900 }
27901 /** @inheritDoc */
27902
27903
27904 _createClass(StraightEdge, [{
27905 key: "_line",
27906 value: function _line(ctx, values) {
27907 // draw a straight line
27908 ctx.beginPath();
27909 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
27910 ctx.lineTo(this.toPoint.x, this.toPoint.y); // draw shadow if enabled
27911
27912 this.enableShadow(ctx, values);
27913 ctx.stroke();
27914 this.disableShadow(ctx, values);
27915 }
27916 /** @inheritDoc */
27917
27918 }, {
27919 key: "getViaNode",
27920 value: function getViaNode() {
27921 return undefined;
27922 }
27923 /** @inheritDoc */
27924
27925 }, {
27926 key: "getPoint",
27927 value: function getPoint(position) {
27928 return {
27929 x: (1 - position) * this.fromPoint.x + position * this.toPoint.x,
27930 y: (1 - position) * this.fromPoint.y + position * this.toPoint.y
27931 };
27932 }
27933 /** @inheritDoc */
27934
27935 }, {
27936 key: "_findBorderPosition",
27937 value: function _findBorderPosition(nearNode, ctx) {
27938 var node1 = this.to;
27939 var node2 = this.from;
27940
27941 if (nearNode.id === this.from.id) {
27942 node1 = this.from;
27943 node2 = this.to;
27944 }
27945
27946 var angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
27947 var dx = node1.x - node2.x;
27948 var dy = node1.y - node2.y;
27949 var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
27950 var toBorderDist = nearNode.distanceToBorder(ctx, angle);
27951 var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
27952 return {
27953 x: (1 - toBorderPoint) * node2.x + toBorderPoint * node1.x,
27954 y: (1 - toBorderPoint) * node2.y + toBorderPoint * node1.y,
27955 t: 0
27956 };
27957 }
27958 /** @inheritDoc */
27959
27960 }, {
27961 key: "_getDistanceToEdge",
27962 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
27963 // x3,y3 is the point
27964 return this._getDistanceToLine(x1, y1, x2, y2, x3, y3);
27965 }
27966 }]);
27967
27968 return StraightEdge;
27969 }(EdgeBase);
27970
27971 /**
27972 * An edge connects two nodes and has a specific direction.
27973 */
27974
27975 var Edge = /*#__PURE__*/function () {
27976 /**
27977 * @param {object} options values specific to this edge, must contain at least 'from' and 'to'
27978 * @param {object} body shared state from Network instance
27979 * @param {Network.Images} imagelist A list with images. Only needed when the edge has image arrows.
27980 * @param {object} globalOptions options from the EdgesHandler instance
27981 * @param {object} defaultOptions default options from the EdgeHandler instance. Value and reference are constant
27982 */
27983 function Edge(options, body, imagelist, globalOptions, defaultOptions) {
27984 _classCallCheck(this, Edge);
27985
27986 if (body === undefined) {
27987 throw new Error("No body provided");
27988 } // Since globalOptions is constant in values as well as reference,
27989 // Following needs to be done only once.
27990
27991
27992 this.options = bridgeObject(globalOptions);
27993 this.globalOptions = globalOptions;
27994 this.defaultOptions = defaultOptions;
27995 this.body = body;
27996 this.imagelist = imagelist; // initialize variables
27997
27998 this.id = undefined;
27999 this.fromId = undefined;
28000 this.toId = undefined;
28001 this.selected = false;
28002 this.hover = false;
28003 this.labelDirty = true;
28004 this.baseWidth = this.options.width;
28005 this.baseFontSize = this.options.font.size;
28006 this.from = undefined; // a node
28007
28008 this.to = undefined; // a node
28009
28010 this.edgeType = undefined;
28011 this.connected = false;
28012 this.labelModule = new Label(this.body, this.options, true
28013 /* It's an edge label */
28014 );
28015 this.setOptions(options);
28016 }
28017 /**
28018 * Set or overwrite options for the edge
28019 *
28020 * @param {object} options an object with options
28021 * @returns {undefined|boolean} undefined if no options, true if layout affecting data changed, false otherwise.
28022 */
28023
28024
28025 _createClass(Edge, [{
28026 key: "setOptions",
28027 value: function setOptions(options) {
28028 if (!options) {
28029 return;
28030 } // Following options if changed affect the layout.
28031
28032
28033 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;
28034 Edge.parseOptions(this.options, options, true, this.globalOptions);
28035
28036 if (options.id !== undefined) {
28037 this.id = options.id;
28038 }
28039
28040 if (options.from !== undefined) {
28041 this.fromId = options.from;
28042 }
28043
28044 if (options.to !== undefined) {
28045 this.toId = options.to;
28046 }
28047
28048 if (options.title !== undefined) {
28049 this.title = options.title;
28050 }
28051
28052 if (options.value !== undefined) {
28053 options.value = _parseFloat(options.value);
28054 }
28055
28056 var pile = [options, this.options, this.defaultOptions];
28057 this.chooser = choosify("edge", pile); // update label Module
28058
28059 this.updateLabelModule(options); // Update edge type, this if changed affects the layout.
28060
28061 affectsLayout = this.updateEdgeType() || affectsLayout; // if anything has been updates, reset the selection width and the hover width
28062
28063 this._setInteractionWidths(); // A node is connected when it has a from and to node that both exist in the network.body.nodes.
28064
28065
28066 this.connect();
28067 return affectsLayout;
28068 }
28069 /**
28070 *
28071 * @param {object} parentOptions
28072 * @param {object} newOptions
28073 * @param {boolean} [allowDeletion=false]
28074 * @param {object} [globalOptions={}]
28075 * @param {boolean} [copyFromGlobals=false]
28076 */
28077
28078 }, {
28079 key: "getFormattingValues",
28080 value:
28081 /**
28082 *
28083 * @returns {ArrowOptions}
28084 */
28085 function getFormattingValues() {
28086 var toArrow = this.options.arrows.to === true || this.options.arrows.to.enabled === true;
28087 var fromArrow = this.options.arrows.from === true || this.options.arrows.from.enabled === true;
28088 var middleArrow = this.options.arrows.middle === true || this.options.arrows.middle.enabled === true;
28089 var inheritsColor = this.options.color.inherit;
28090 var values = {
28091 toArrow: toArrow,
28092 toArrowScale: this.options.arrows.to.scaleFactor,
28093 toArrowType: this.options.arrows.to.type,
28094 toArrowSrc: this.options.arrows.to.src,
28095 toArrowImageWidth: this.options.arrows.to.imageWidth,
28096 toArrowImageHeight: this.options.arrows.to.imageHeight,
28097 middleArrow: middleArrow,
28098 middleArrowScale: this.options.arrows.middle.scaleFactor,
28099 middleArrowType: this.options.arrows.middle.type,
28100 middleArrowSrc: this.options.arrows.middle.src,
28101 middleArrowImageWidth: this.options.arrows.middle.imageWidth,
28102 middleArrowImageHeight: this.options.arrows.middle.imageHeight,
28103 fromArrow: fromArrow,
28104 fromArrowScale: this.options.arrows.from.scaleFactor,
28105 fromArrowType: this.options.arrows.from.type,
28106 fromArrowSrc: this.options.arrows.from.src,
28107 fromArrowImageWidth: this.options.arrows.from.imageWidth,
28108 fromArrowImageHeight: this.options.arrows.from.imageHeight,
28109 arrowStrikethrough: this.options.arrowStrikethrough,
28110 color: inheritsColor ? undefined : this.options.color.color,
28111 inheritsColor: inheritsColor,
28112 opacity: this.options.color.opacity,
28113 hidden: this.options.hidden,
28114 length: this.options.length,
28115 shadow: this.options.shadow.enabled,
28116 shadowColor: this.options.shadow.color,
28117 shadowSize: this.options.shadow.size,
28118 shadowX: this.options.shadow.x,
28119 shadowY: this.options.shadow.y,
28120 dashes: this.options.dashes,
28121 width: this.options.width,
28122 background: this.options.background.enabled,
28123 backgroundColor: this.options.background.color,
28124 backgroundSize: this.options.background.size,
28125 backgroundDashes: this.options.background.dashes
28126 };
28127
28128 if (this.selected || this.hover) {
28129 if (this.chooser === true) {
28130 if (this.selected) {
28131 var selectedWidth = this.options.selectionWidth;
28132
28133 if (typeof selectedWidth === "function") {
28134 values.width = selectedWidth(values.width);
28135 } else if (typeof selectedWidth === "number") {
28136 values.width += selectedWidth;
28137 }
28138
28139 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
28140 values.color = this.options.color.highlight;
28141 values.shadow = this.options.shadow.enabled;
28142 } else if (this.hover) {
28143 var hoverWidth = this.options.hoverWidth;
28144
28145 if (typeof hoverWidth === "function") {
28146 values.width = hoverWidth(values.width);
28147 } else if (typeof hoverWidth === "number") {
28148 values.width += hoverWidth;
28149 }
28150
28151 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
28152 values.color = this.options.color.hover;
28153 values.shadow = this.options.shadow.enabled;
28154 }
28155 } else if (typeof this.chooser === "function") {
28156 this.chooser(values, this.options.id, this.selected, this.hover);
28157
28158 if (values.color !== undefined) {
28159 values.inheritsColor = false;
28160 }
28161
28162 if (values.shadow === false) {
28163 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) {
28164 values.shadow = true;
28165 }
28166 }
28167 }
28168 } else {
28169 values.shadow = this.options.shadow.enabled;
28170 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
28171 }
28172
28173 return values;
28174 }
28175 /**
28176 * update the options in the label module
28177 *
28178 * @param {object} options
28179 */
28180
28181 }, {
28182 key: "updateLabelModule",
28183 value: function updateLabelModule(options) {
28184 var pile = [options, this.options, this.globalOptions, // Currently set global edge options
28185 this.defaultOptions];
28186 this.labelModule.update(this.options, pile);
28187
28188 if (this.labelModule.baseSize !== undefined) {
28189 this.baseFontSize = this.labelModule.baseSize;
28190 }
28191 }
28192 /**
28193 * update the edge type, set the options
28194 *
28195 * @returns {boolean}
28196 */
28197
28198 }, {
28199 key: "updateEdgeType",
28200 value: function updateEdgeType() {
28201 var smooth = this.options.smooth;
28202 var dataChanged = false;
28203 var changeInType = true;
28204
28205 if (this.edgeType !== undefined) {
28206 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) {
28207 changeInType = false;
28208 }
28209
28210 if (changeInType === true) {
28211 dataChanged = this.cleanup();
28212 }
28213 }
28214
28215 if (changeInType === true) {
28216 if (smooth.enabled === true) {
28217 if (smooth.type === "dynamic") {
28218 dataChanged = true;
28219 this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
28220 } else if (smooth.type === "cubicBezier") {
28221 this.edgeType = new CubicBezierEdge(this.options, this.body, this.labelModule);
28222 } else {
28223 this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
28224 }
28225 } else {
28226 this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
28227 }
28228 } else {
28229 // if nothing changes, we just set the options.
28230 this.edgeType.setOptions(this.options);
28231 }
28232
28233 return dataChanged;
28234 }
28235 /**
28236 * Connect an edge to its nodes
28237 */
28238
28239 }, {
28240 key: "connect",
28241 value: function connect() {
28242 this.disconnect();
28243 this.from = this.body.nodes[this.fromId] || undefined;
28244 this.to = this.body.nodes[this.toId] || undefined;
28245 this.connected = this.from !== undefined && this.to !== undefined;
28246
28247 if (this.connected === true) {
28248 this.from.attachEdge(this);
28249 this.to.attachEdge(this);
28250 } else {
28251 if (this.from) {
28252 this.from.detachEdge(this);
28253 }
28254
28255 if (this.to) {
28256 this.to.detachEdge(this);
28257 }
28258 }
28259
28260 this.edgeType.connect();
28261 }
28262 /**
28263 * Disconnect an edge from its nodes
28264 */
28265
28266 }, {
28267 key: "disconnect",
28268 value: function disconnect() {
28269 if (this.from) {
28270 this.from.detachEdge(this);
28271 this.from = undefined;
28272 }
28273
28274 if (this.to) {
28275 this.to.detachEdge(this);
28276 this.to = undefined;
28277 }
28278
28279 this.connected = false;
28280 }
28281 /**
28282 * get the title of this edge.
28283 *
28284 * @returns {string} title The title of the edge, or undefined when no title
28285 * has been set.
28286 */
28287
28288 }, {
28289 key: "getTitle",
28290 value: function getTitle() {
28291 return this.title;
28292 }
28293 /**
28294 * check if this node is selecte
28295 *
28296 * @returns {boolean} selected True if node is selected, else false
28297 */
28298
28299 }, {
28300 key: "isSelected",
28301 value: function isSelected() {
28302 return this.selected;
28303 }
28304 /**
28305 * Retrieve the value of the edge. Can be undefined
28306 *
28307 * @returns {number} value
28308 */
28309
28310 }, {
28311 key: "getValue",
28312 value: function getValue() {
28313 return this.options.value;
28314 }
28315 /**
28316 * Adjust the value range of the edge. The edge will adjust it's width
28317 * based on its value.
28318 *
28319 * @param {number} min
28320 * @param {number} max
28321 * @param {number} total
28322 */
28323
28324 }, {
28325 key: "setValueRange",
28326 value: function setValueRange(min, max, total) {
28327 if (this.options.value !== undefined) {
28328 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
28329 var widthDiff = this.options.scaling.max - this.options.scaling.min;
28330
28331 if (this.options.scaling.label.enabled === true) {
28332 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
28333 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
28334 }
28335
28336 this.options.width = this.options.scaling.min + scale * widthDiff;
28337 } else {
28338 this.options.width = this.baseWidth;
28339 this.options.font.size = this.baseFontSize;
28340 }
28341
28342 this._setInteractionWidths();
28343
28344 this.updateLabelModule();
28345 }
28346 /**
28347 *
28348 * @private
28349 */
28350
28351 }, {
28352 key: "_setInteractionWidths",
28353 value: function _setInteractionWidths() {
28354 if (typeof this.options.hoverWidth === "function") {
28355 this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
28356 } else {
28357 this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
28358 }
28359
28360 if (typeof this.options.selectionWidth === "function") {
28361 this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
28362 } else {
28363 this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
28364 }
28365 }
28366 /**
28367 * Redraw a edge
28368 * Draw this edge in the given canvas
28369 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
28370 *
28371 * @param {CanvasRenderingContext2D} ctx
28372 */
28373
28374 }, {
28375 key: "draw",
28376 value: function draw(ctx) {
28377 var values = this.getFormattingValues();
28378
28379 if (values.hidden) {
28380 return;
28381 } // get the via node from the edge type
28382
28383
28384 var viaNode = this.edgeType.getViaNode(); // draw line and label
28385
28386 this.edgeType.drawLine(ctx, values, this.selected, this.hover, viaNode);
28387 this.drawLabel(ctx, viaNode);
28388 }
28389 /**
28390 * Redraw arrows
28391 * Draw this arrows in the given canvas
28392 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
28393 *
28394 * @param {CanvasRenderingContext2D} ctx
28395 */
28396
28397 }, {
28398 key: "drawArrows",
28399 value: function drawArrows(ctx) {
28400 var values = this.getFormattingValues();
28401
28402 if (values.hidden) {
28403 return;
28404 } // get the via node from the edge type
28405
28406
28407 var viaNode = this.edgeType.getViaNode();
28408 var arrowData = {}; // restore edge targets to defaults
28409
28410 this.edgeType.fromPoint = this.edgeType.from;
28411 this.edgeType.toPoint = this.edgeType.to; // from and to arrows give a different end point for edges. we set them here
28412
28413 if (values.fromArrow) {
28414 arrowData.from = this.edgeType.getArrowData(ctx, "from", viaNode, this.selected, this.hover, values);
28415 if (values.arrowStrikethrough === false) this.edgeType.fromPoint = arrowData.from.core;
28416
28417 if (values.fromArrowSrc) {
28418 arrowData.from.image = this.imagelist.load(values.fromArrowSrc);
28419 }
28420
28421 if (values.fromArrowImageWidth) {
28422 arrowData.from.imageWidth = values.fromArrowImageWidth;
28423 }
28424
28425 if (values.fromArrowImageHeight) {
28426 arrowData.from.imageHeight = values.fromArrowImageHeight;
28427 }
28428 }
28429
28430 if (values.toArrow) {
28431 arrowData.to = this.edgeType.getArrowData(ctx, "to", viaNode, this.selected, this.hover, values);
28432 if (values.arrowStrikethrough === false) this.edgeType.toPoint = arrowData.to.core;
28433
28434 if (values.toArrowSrc) {
28435 arrowData.to.image = this.imagelist.load(values.toArrowSrc);
28436 }
28437
28438 if (values.toArrowImageWidth) {
28439 arrowData.to.imageWidth = values.toArrowImageWidth;
28440 }
28441
28442 if (values.toArrowImageHeight) {
28443 arrowData.to.imageHeight = values.toArrowImageHeight;
28444 }
28445 } // the middle arrow depends on the line, which can depend on the to and from arrows so we do this one lastly.
28446
28447
28448 if (values.middleArrow) {
28449 arrowData.middle = this.edgeType.getArrowData(ctx, "middle", viaNode, this.selected, this.hover, values);
28450
28451 if (values.middleArrowSrc) {
28452 arrowData.middle.image = this.imagelist.load(values.middleArrowSrc);
28453 }
28454
28455 if (values.middleArrowImageWidth) {
28456 arrowData.middle.imageWidth = values.middleArrowImageWidth;
28457 }
28458
28459 if (values.middleArrowImageHeight) {
28460 arrowData.middle.imageHeight = values.middleArrowImageHeight;
28461 }
28462 }
28463
28464 if (values.fromArrow) {
28465 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.from);
28466 }
28467
28468 if (values.middleArrow) {
28469 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.middle);
28470 }
28471
28472 if (values.toArrow) {
28473 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.to);
28474 }
28475 }
28476 /**
28477 *
28478 * @param {CanvasRenderingContext2D} ctx
28479 * @param {Node} viaNode
28480 */
28481
28482 }, {
28483 key: "drawLabel",
28484 value: function drawLabel(ctx, viaNode) {
28485 if (this.options.label !== undefined) {
28486 // set style
28487 var node1 = this.from;
28488 var node2 = this.to;
28489
28490 if (this.labelModule.differentState(this.selected, this.hover)) {
28491 this.labelModule.getTextSize(ctx, this.selected, this.hover);
28492 }
28493
28494 var point;
28495
28496 if (node1.id != node2.id) {
28497 this.labelModule.pointToSelf = false;
28498 point = this.edgeType.getPoint(0.5, viaNode);
28499 ctx.save();
28500
28501 var rotationPoint = this._getRotation(ctx);
28502
28503 if (rotationPoint.angle != 0) {
28504 ctx.translate(rotationPoint.x, rotationPoint.y);
28505 ctx.rotate(rotationPoint.angle);
28506 } // draw the label
28507
28508
28509 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
28510 /*
28511 // Useful debug code: draw a border around the label
28512 // This should **not** be enabled in production!
28513 var size = this.labelModule.getSize();; // ;; intentional so lint catches it
28514 ctx.strokeStyle = "#ff0000";
28515 ctx.strokeRect(size.left, size.top, size.width, size.height);
28516 // End debug code
28517 */
28518
28519 ctx.restore();
28520 } else {
28521 // Ignore the orientations.
28522 this.labelModule.pointToSelf = true; // get circle coordinates
28523
28524 var coordinates = getSelfRefCoordinates(ctx, this.options.selfReference.angle, this.options.selfReference.size, node1);
28525 point = this._pointOnCircle(coordinates.x, coordinates.y, this.options.selfReference.size, this.options.selfReference.angle);
28526 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
28527 }
28528 }
28529 }
28530 /**
28531 * Determine all visual elements of this edge instance, in which the given
28532 * point falls within the bounding shape.
28533 *
28534 * @param {point} point
28535 * @returns {Array.<edgeClickItem|edgeLabelClickItem>} list with the items which are on the point
28536 */
28537
28538 }, {
28539 key: "getItemsOnPoint",
28540 value: function getItemsOnPoint(point) {
28541 var ret = [];
28542
28543 if (this.labelModule.visible()) {
28544 var rotationPoint = this._getRotation();
28545
28546 if (pointInRect(this.labelModule.getSize(), point, rotationPoint)) {
28547 ret.push({
28548 edgeId: this.id,
28549 labelId: 0
28550 });
28551 }
28552 }
28553
28554 var obj = {
28555 left: point.x,
28556 top: point.y
28557 };
28558
28559 if (this.isOverlappingWith(obj)) {
28560 ret.push({
28561 edgeId: this.id
28562 });
28563 }
28564
28565 return ret;
28566 }
28567 /**
28568 * Check if this object is overlapping with the provided object
28569 *
28570 * @param {object} obj an object with parameters left, top
28571 * @returns {boolean} True if location is located on the edge
28572 */
28573
28574 }, {
28575 key: "isOverlappingWith",
28576 value: function isOverlappingWith(obj) {
28577 if (this.connected) {
28578 var distMax = 10;
28579 var xFrom = this.from.x;
28580 var yFrom = this.from.y;
28581 var xTo = this.to.x;
28582 var yTo = this.to.y;
28583 var xObj = obj.left;
28584 var yObj = obj.top;
28585 var dist = this.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);
28586 return dist < distMax;
28587 } else {
28588 return false;
28589 }
28590 }
28591 /**
28592 * Determine the rotation point, if any.
28593 *
28594 * @param {CanvasRenderingContext2D} [ctx] if passed, do a recalculation of the label size
28595 * @returns {rotationPoint} the point to rotate around and the angle in radians to rotate
28596 * @private
28597 */
28598
28599 }, {
28600 key: "_getRotation",
28601 value: function _getRotation(ctx) {
28602 var viaNode = this.edgeType.getViaNode();
28603 var point = this.edgeType.getPoint(0.5, viaNode);
28604
28605 if (ctx !== undefined) {
28606 this.labelModule.calculateLabelSize(ctx, this.selected, this.hover, point.x, point.y);
28607 }
28608
28609 var ret = {
28610 x: point.x,
28611 y: this.labelModule.size.yLine,
28612 angle: 0
28613 };
28614
28615 if (!this.labelModule.visible()) {
28616 return ret; // Don't even bother doing the atan2, there's nothing to draw
28617 }
28618
28619 if (this.options.font.align === "horizontal") {
28620 return ret; // No need to calculate angle
28621 }
28622
28623 var dy = this.from.y - this.to.y;
28624 var dx = this.from.x - this.to.x;
28625 var angle = Math.atan2(dy, dx); // radians
28626 // rotate so that label is readable
28627
28628 if (angle < -1 && dx < 0 || angle > 0 && dx < 0) {
28629 angle += Math.PI;
28630 }
28631
28632 ret.angle = angle;
28633 return ret;
28634 }
28635 /**
28636 * Get a point on a circle
28637 *
28638 * @param {number} x
28639 * @param {number} y
28640 * @param {number} radius
28641 * @param {number} angle
28642 * @returns {object} point
28643 * @private
28644 */
28645
28646 }, {
28647 key: "_pointOnCircle",
28648 value: function _pointOnCircle(x, y, radius, angle) {
28649 return {
28650 x: x + radius * Math.cos(angle),
28651 y: y - radius * Math.sin(angle)
28652 };
28653 }
28654 /**
28655 * Sets selected state to true
28656 */
28657
28658 }, {
28659 key: "select",
28660 value: function select() {
28661 this.selected = true;
28662 }
28663 /**
28664 * Sets selected state to false
28665 */
28666
28667 }, {
28668 key: "unselect",
28669 value: function unselect() {
28670 this.selected = false;
28671 }
28672 /**
28673 * cleans all required things on delete
28674 *
28675 * @returns {*}
28676 */
28677
28678 }, {
28679 key: "cleanup",
28680 value: function cleanup() {
28681 return this.edgeType.cleanup();
28682 }
28683 /**
28684 * Remove edge from the list and perform necessary cleanup.
28685 */
28686
28687 }, {
28688 key: "remove",
28689 value: function remove() {
28690 this.cleanup();
28691 this.disconnect();
28692 delete this.body.edges[this.id];
28693 }
28694 /**
28695 * Check if both connecting nodes exist
28696 *
28697 * @returns {boolean}
28698 */
28699
28700 }, {
28701 key: "endPointsValid",
28702 value: function endPointsValid() {
28703 return this.body.nodes[this.fromId] !== undefined && this.body.nodes[this.toId] !== undefined;
28704 }
28705 }], [{
28706 key: "parseOptions",
28707 value: function parseOptions(parentOptions, newOptions) {
28708 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
28709 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
28710 var copyFromGlobals = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
28711 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.
28712
28713 selectiveDeepExtend(fields, parentOptions, newOptions, allowDeletion); // Only use endPointOffset values (from and to) if it's valid values
28714
28715 if (newOptions.endPointOffset !== undefined && newOptions.endPointOffset.from !== undefined) {
28716 if (_isFinite(newOptions.endPointOffset.from)) {
28717 parentOptions.endPointOffset.from = newOptions.endPointOffset.from;
28718 } else {
28719 parentOptions.endPointOffset.from = globalOptions.endPointOffset.from !== undefined ? globalOptions.endPointOffset.from : 0;
28720 console.error("endPointOffset.from is not a valid number");
28721 }
28722 }
28723
28724 if (newOptions.endPointOffset !== undefined && newOptions.endPointOffset.to !== undefined) {
28725 if (_isFinite(newOptions.endPointOffset.to)) {
28726 parentOptions.endPointOffset.to = newOptions.endPointOffset.to;
28727 } else {
28728 parentOptions.endPointOffset.to = globalOptions.endPointOffset.to !== undefined ? globalOptions.endPointOffset.to : 0;
28729 console.error("endPointOffset.to is not a valid number");
28730 }
28731 } // Only copy label if it's a legal value.
28732
28733
28734 if (isValidLabel(newOptions.label)) {
28735 parentOptions.label = newOptions.label;
28736 } else if (!isValidLabel(parentOptions.label)) {
28737 parentOptions.label = undefined;
28738 }
28739
28740 mergeOptions(parentOptions, newOptions, "smooth", globalOptions);
28741 mergeOptions(parentOptions, newOptions, "shadow", globalOptions);
28742 mergeOptions(parentOptions, newOptions, "background", globalOptions);
28743
28744 if (newOptions.dashes !== undefined && newOptions.dashes !== null) {
28745 parentOptions.dashes = newOptions.dashes;
28746 } else if (allowDeletion === true && newOptions.dashes === null) {
28747 parentOptions.dashes = create$5(globalOptions.dashes); // this sets the pointer of the option back to the global option.
28748 } // set the scaling newOptions
28749
28750
28751 if (newOptions.scaling !== undefined && newOptions.scaling !== null) {
28752 if (newOptions.scaling.min !== undefined) {
28753 parentOptions.scaling.min = newOptions.scaling.min;
28754 }
28755
28756 if (newOptions.scaling.max !== undefined) {
28757 parentOptions.scaling.max = newOptions.scaling.max;
28758 }
28759
28760 mergeOptions(parentOptions.scaling, newOptions.scaling, "label", globalOptions.scaling);
28761 } else if (allowDeletion === true && newOptions.scaling === null) {
28762 parentOptions.scaling = create$5(globalOptions.scaling); // this sets the pointer of the option back to the global option.
28763 } // handle multiple input cases for arrows
28764
28765
28766 if (newOptions.arrows !== undefined && newOptions.arrows !== null) {
28767 if (typeof newOptions.arrows === "string") {
28768 var arrows = newOptions.arrows.toLowerCase();
28769 parentOptions.arrows.to.enabled = indexOf(arrows).call(arrows, "to") != -1;
28770 parentOptions.arrows.middle.enabled = indexOf(arrows).call(arrows, "middle") != -1;
28771 parentOptions.arrows.from.enabled = indexOf(arrows).call(arrows, "from") != -1;
28772 } else if (_typeof(newOptions.arrows) === "object") {
28773 mergeOptions(parentOptions.arrows, newOptions.arrows, "to", globalOptions.arrows);
28774 mergeOptions(parentOptions.arrows, newOptions.arrows, "middle", globalOptions.arrows);
28775 mergeOptions(parentOptions.arrows, newOptions.arrows, "from", globalOptions.arrows);
28776 } else {
28777 throw new Error("The arrow newOptions can only be an object or a string. Refer to the documentation. You used:" + stringify$1(newOptions.arrows));
28778 }
28779 } else if (allowDeletion === true && newOptions.arrows === null) {
28780 parentOptions.arrows = create$5(globalOptions.arrows); // this sets the pointer of the option back to the global option.
28781 } // handle multiple input cases for color
28782
28783
28784 if (newOptions.color !== undefined && newOptions.color !== null) {
28785 var fromColor = isString(newOptions.color) ? {
28786 color: newOptions.color,
28787 highlight: newOptions.color,
28788 hover: newOptions.color,
28789 inherit: false,
28790 opacity: 1
28791 } : newOptions.color;
28792 var toColor = parentOptions.color; // If passed, fill in values from default options - required in the case of no prototype bridging
28793
28794 if (copyFromGlobals) {
28795 deepExtend(toColor, globalOptions.color, false, allowDeletion);
28796 } else {
28797 // Clear local properties - need to do it like this in order to retain prototype bridges
28798 for (var i in toColor) {
28799 if (Object.prototype.hasOwnProperty.call(toColor, i)) {
28800 delete toColor[i];
28801 }
28802 }
28803 }
28804
28805 if (isString(toColor)) {
28806 toColor.color = toColor;
28807 toColor.highlight = toColor;
28808 toColor.hover = toColor;
28809 toColor.inherit = false;
28810
28811 if (fromColor.opacity === undefined) {
28812 toColor.opacity = 1.0; // set default
28813 }
28814 } else {
28815 var colorsDefined = false;
28816
28817 if (fromColor.color !== undefined) {
28818 toColor.color = fromColor.color;
28819 colorsDefined = true;
28820 }
28821
28822 if (fromColor.highlight !== undefined) {
28823 toColor.highlight = fromColor.highlight;
28824 colorsDefined = true;
28825 }
28826
28827 if (fromColor.hover !== undefined) {
28828 toColor.hover = fromColor.hover;
28829 colorsDefined = true;
28830 }
28831
28832 if (fromColor.inherit !== undefined) {
28833 toColor.inherit = fromColor.inherit;
28834 }
28835
28836 if (fromColor.opacity !== undefined) {
28837 toColor.opacity = Math.min(1, Math.max(0, fromColor.opacity));
28838 }
28839
28840 if (colorsDefined === true) {
28841 toColor.inherit = false;
28842 } else {
28843 if (toColor.inherit === undefined) {
28844 toColor.inherit = "from"; // Set default
28845 }
28846 }
28847 }
28848 } else if (allowDeletion === true && newOptions.color === null) {
28849 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
28850 }
28851
28852 if (allowDeletion === true && newOptions.font === null) {
28853 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
28854 }
28855
28856 if (Object.prototype.hasOwnProperty.call(newOptions, "selfReferenceSize")) {
28857 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}");
28858 parentOptions.selfReference.size = newOptions.selfReferenceSize;
28859 }
28860 }
28861 }]);
28862
28863 return Edge;
28864 }();
28865
28866 /**
28867 * Handler for Edges
28868 */
28869
28870 var EdgesHandler = /*#__PURE__*/function () {
28871 /**
28872 * @param {object} body
28873 * @param {Array.<Image>} images
28874 * @param {Array.<Group>} groups
28875 */
28876 function EdgesHandler(body, images, groups) {
28877 var _context,
28878 _this = this;
28879
28880 _classCallCheck(this, EdgesHandler);
28881
28882 this.body = body;
28883 this.images = images;
28884 this.groups = groups; // create the edge API in the body container
28885
28886 this.body.functions.createEdge = bind$6(_context = this.create).call(_context, this);
28887 this.edgesListeners = {
28888 add: function add(event, params) {
28889 _this.add(params.items);
28890 },
28891 update: function update(event, params) {
28892 _this.update(params.items);
28893 },
28894 remove: function remove(event, params) {
28895 _this.remove(params.items);
28896 }
28897 };
28898 this.options = {};
28899 this.defaultOptions = {
28900 arrows: {
28901 to: {
28902 enabled: false,
28903 scaleFactor: 1,
28904 type: "arrow"
28905 },
28906 // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
28907 middle: {
28908 enabled: false,
28909 scaleFactor: 1,
28910 type: "arrow"
28911 },
28912 from: {
28913 enabled: false,
28914 scaleFactor: 1,
28915 type: "arrow"
28916 }
28917 },
28918 endPointOffset: {
28919 from: 0,
28920 to: 0
28921 },
28922 arrowStrikethrough: true,
28923 color: {
28924 color: "#848484",
28925 highlight: "#848484",
28926 hover: "#848484",
28927 inherit: "from",
28928 opacity: 1.0
28929 },
28930 dashes: false,
28931 font: {
28932 color: "#343434",
28933 size: 14,
28934 // px
28935 face: "arial",
28936 background: "none",
28937 strokeWidth: 2,
28938 // px
28939 strokeColor: "#ffffff",
28940 align: "horizontal",
28941 multi: false,
28942 vadjust: 0,
28943 bold: {
28944 mod: "bold"
28945 },
28946 boldital: {
28947 mod: "bold italic"
28948 },
28949 ital: {
28950 mod: "italic"
28951 },
28952 mono: {
28953 mod: "",
28954 size: 15,
28955 // px
28956 face: "courier new",
28957 vadjust: 2
28958 }
28959 },
28960 hidden: false,
28961 hoverWidth: 1.5,
28962 label: undefined,
28963 labelHighlightBold: true,
28964 length: undefined,
28965 physics: true,
28966 scaling: {
28967 min: 1,
28968 max: 15,
28969 label: {
28970 enabled: true,
28971 min: 14,
28972 max: 30,
28973 maxVisible: 30,
28974 drawThreshold: 5
28975 },
28976 customScalingFunction: function customScalingFunction(min, max, total, value) {
28977 if (max === min) {
28978 return 0.5;
28979 } else {
28980 var scale = 1 / (max - min);
28981 return Math.max(0, (value - min) * scale);
28982 }
28983 }
28984 },
28985 selectionWidth: 1.5,
28986 selfReference: {
28987 size: 20,
28988 angle: Math.PI / 4,
28989 renderBehindTheNode: true
28990 },
28991 shadow: {
28992 enabled: false,
28993 color: "rgba(0,0,0,0.5)",
28994 size: 10,
28995 x: 5,
28996 y: 5
28997 },
28998 background: {
28999 enabled: false,
29000 color: "rgba(111,111,111,1)",
29001 size: 10,
29002 dashes: false
29003 },
29004 smooth: {
29005 enabled: true,
29006 type: "dynamic",
29007 forceDirection: "none",
29008 roundness: 0.5
29009 },
29010 title: undefined,
29011 width: 1,
29012 value: undefined
29013 };
29014 deepExtend(this.options, this.defaultOptions);
29015 this.bindEventListeners();
29016 }
29017 /**
29018 * Binds event listeners
29019 */
29020
29021
29022 _createClass(EdgesHandler, [{
29023 key: "bindEventListeners",
29024 value: function bindEventListeners() {
29025 var _this2 = this,
29026 _context2,
29027 _context3;
29028
29029 // this allows external modules to force all dynamic curves to turn static.
29030 this.body.emitter.on("_forceDisableDynamicCurves", function (type) {
29031 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
29032
29033 if (type === "dynamic") {
29034 type = "continuous";
29035 }
29036
29037 var dataChanged = false;
29038
29039 for (var edgeId in _this2.body.edges) {
29040 if (Object.prototype.hasOwnProperty.call(_this2.body.edges, edgeId)) {
29041 var edge = _this2.body.edges[edgeId];
29042
29043 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.
29044 // this is because a change in the global would not affect these curves.
29045
29046
29047 if (edgeData != null) {
29048 var smoothOptions = edgeData.smooth;
29049
29050 if (smoothOptions !== undefined) {
29051 if (smoothOptions.enabled === true && smoothOptions.type === "dynamic") {
29052 if (type === undefined) {
29053 edge.setOptions({
29054 smooth: false
29055 });
29056 } else {
29057 edge.setOptions({
29058 smooth: {
29059 type: type
29060 }
29061 });
29062 }
29063
29064 dataChanged = true;
29065 }
29066 }
29067 }
29068 }
29069 }
29070
29071 if (emit === true && dataChanged === true) {
29072 _this2.body.emitter.emit("_dataChanged");
29073 }
29074 }); // this is called when options of EXISTING nodes or edges have changed.
29075 //
29076 // NOTE: Not true, called when options have NOT changed, for both existing as well as new nodes.
29077 // See update() for logic.
29078 // TODO: Verify and examine the consequences of this. It might still trigger when
29079 // non-option fields have changed, but then reconnecting edges is still useless.
29080 // Alternatively, it might also be called when edges are removed.
29081 //
29082
29083 this.body.emitter.on("_dataUpdated", function () {
29084 _this2.reconnectEdges();
29085 }); // refresh the edges. Used when reverting from hierarchical layout
29086
29087 this.body.emitter.on("refreshEdges", bind$6(_context2 = this.refresh).call(_context2, this));
29088 this.body.emitter.on("refresh", bind$6(_context3 = this.refresh).call(_context3, this));
29089 this.body.emitter.on("destroy", function () {
29090 forEach$1(_this2.edgesListeners, function (callback, event) {
29091 if (_this2.body.data.edges) _this2.body.data.edges.off(event, callback);
29092 });
29093 delete _this2.body.functions.createEdge;
29094 delete _this2.edgesListeners.add;
29095 delete _this2.edgesListeners.update;
29096 delete _this2.edgesListeners.remove;
29097 delete _this2.edgesListeners;
29098 });
29099 }
29100 /**
29101 *
29102 * @param {object} options
29103 */
29104
29105 }, {
29106 key: "setOptions",
29107 value: function setOptions(options) {
29108 if (options !== undefined) {
29109 // use the parser from the Edge class to fill in all shorthand notations
29110 Edge.parseOptions(this.options, options, true, this.defaultOptions, true); // update smooth settings in all edges
29111
29112 var dataChanged = false;
29113
29114 if (options.smooth !== undefined) {
29115 for (var edgeId in this.body.edges) {
29116 if (Object.prototype.hasOwnProperty.call(this.body.edges, edgeId)) {
29117 dataChanged = this.body.edges[edgeId].updateEdgeType() || dataChanged;
29118 }
29119 }
29120 } // update fonts in all edges
29121
29122
29123 if (options.font !== undefined) {
29124 for (var _edgeId in this.body.edges) {
29125 if (Object.prototype.hasOwnProperty.call(this.body.edges, _edgeId)) {
29126 this.body.edges[_edgeId].updateLabelModule();
29127 }
29128 }
29129 } // update the state of the variables if needed
29130
29131
29132 if (options.hidden !== undefined || options.physics !== undefined || dataChanged === true) {
29133 this.body.emitter.emit("_dataChanged");
29134 }
29135 }
29136 }
29137 /**
29138 * Load edges by reading the data table
29139 *
29140 * @param {Array | DataSet | DataView} edges The data containing the edges.
29141 * @param {boolean} [doNotEmit=false] - Suppress data changed event.
29142 * @private
29143 */
29144
29145 }, {
29146 key: "setData",
29147 value: function setData(edges) {
29148 var _this3 = this;
29149
29150 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
29151 var oldEdgesData = this.body.data.edges;
29152
29153 if (isDataViewLike("id", edges)) {
29154 this.body.data.edges = edges;
29155 } else if (isArray$2(edges)) {
29156 this.body.data.edges = new DataSet();
29157 this.body.data.edges.add(edges);
29158 } else if (!edges) {
29159 this.body.data.edges = new DataSet();
29160 } else {
29161 throw new TypeError("Array or DataSet expected");
29162 } // TODO: is this null or undefined or false?
29163
29164
29165 if (oldEdgesData) {
29166 // unsubscribe from old dataset
29167 forEach$1(this.edgesListeners, function (callback, event) {
29168 oldEdgesData.off(event, callback);
29169 });
29170 } // remove drawn edges
29171
29172
29173 this.body.edges = {}; // TODO: is this null or undefined or false?
29174
29175 if (this.body.data.edges) {
29176 // subscribe to new dataset
29177 forEach$1(this.edgesListeners, function (callback, event) {
29178 _this3.body.data.edges.on(event, callback);
29179 }); // draw all new nodes
29180
29181 var ids = this.body.data.edges.getIds();
29182 this.add(ids, true);
29183 }
29184
29185 this.body.emitter.emit("_adjustEdgesForHierarchicalLayout");
29186
29187 if (doNotEmit === false) {
29188 this.body.emitter.emit("_dataChanged");
29189 }
29190 }
29191 /**
29192 * Add edges
29193 *
29194 * @param {number[] | string[]} ids
29195 * @param {boolean} [doNotEmit=false]
29196 * @private
29197 */
29198
29199 }, {
29200 key: "add",
29201 value: function add(ids) {
29202 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
29203 var edges = this.body.edges;
29204 var edgesData = this.body.data.edges;
29205
29206 for (var i = 0; i < ids.length; i++) {
29207 var id = ids[i];
29208 var oldEdge = edges[id];
29209
29210 if (oldEdge) {
29211 oldEdge.disconnect();
29212 }
29213
29214 var data = edgesData.get(id, {
29215 showInternalIds: true
29216 });
29217 edges[id] = this.create(data);
29218 }
29219
29220 this.body.emitter.emit("_adjustEdgesForHierarchicalLayout");
29221
29222 if (doNotEmit === false) {
29223 this.body.emitter.emit("_dataChanged");
29224 }
29225 }
29226 /**
29227 * Update existing edges, or create them when not yet existing
29228 *
29229 * @param {number[] | string[]} ids
29230 * @private
29231 */
29232
29233 }, {
29234 key: "update",
29235 value: function update(ids) {
29236 var edges = this.body.edges;
29237 var edgesData = this.body.data.edges;
29238 var dataChanged = false;
29239
29240 for (var i = 0; i < ids.length; i++) {
29241 var id = ids[i];
29242 var data = edgesData.get(id);
29243 var edge = edges[id];
29244
29245 if (edge !== undefined) {
29246 // update edge
29247 edge.disconnect();
29248 dataChanged = edge.setOptions(data) || dataChanged; // if a support node is added, data can be changed.
29249
29250 edge.connect();
29251 } else {
29252 // create edge
29253 this.body.edges[id] = this.create(data);
29254 dataChanged = true;
29255 }
29256 }
29257
29258 if (dataChanged === true) {
29259 this.body.emitter.emit("_adjustEdgesForHierarchicalLayout");
29260 this.body.emitter.emit("_dataChanged");
29261 } else {
29262 this.body.emitter.emit("_dataUpdated");
29263 }
29264 }
29265 /**
29266 * Remove existing edges. Non existing ids will be ignored
29267 *
29268 * @param {number[] | string[]} ids
29269 * @param {boolean} [emit=true]
29270 * @private
29271 */
29272
29273 }, {
29274 key: "remove",
29275 value: function remove(ids) {
29276 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
29277 if (ids.length === 0) return; // early out
29278
29279 var edges = this.body.edges;
29280 forEach$1(ids, function (id) {
29281 var edge = edges[id];
29282
29283 if (edge !== undefined) {
29284 edge.remove();
29285 }
29286 });
29287
29288 if (emit) {
29289 this.body.emitter.emit("_dataChanged");
29290 }
29291 }
29292 /**
29293 * Refreshes Edge Handler
29294 */
29295
29296 }, {
29297 key: "refresh",
29298 value: function refresh() {
29299 var _this4 = this;
29300
29301 forEach$1(this.body.edges, function (edge, edgeId) {
29302 var data = _this4.body.data.edges.get(edgeId);
29303
29304 if (data !== undefined) {
29305 edge.setOptions(data);
29306 }
29307 });
29308 }
29309 /**
29310 *
29311 * @param {object} properties
29312 * @returns {Edge}
29313 */
29314
29315 }, {
29316 key: "create",
29317 value: function create(properties) {
29318 return new Edge(properties, this.body, this.images, this.options, this.defaultOptions);
29319 }
29320 /**
29321 * Reconnect all edges
29322 *
29323 * @private
29324 */
29325
29326 }, {
29327 key: "reconnectEdges",
29328 value: function reconnectEdges() {
29329 var id;
29330 var nodes = this.body.nodes;
29331 var edges = this.body.edges;
29332
29333 for (id in nodes) {
29334 if (Object.prototype.hasOwnProperty.call(nodes, id)) {
29335 nodes[id].edges = [];
29336 }
29337 }
29338
29339 for (id in edges) {
29340 if (Object.prototype.hasOwnProperty.call(edges, id)) {
29341 var edge = edges[id];
29342 edge.from = null;
29343 edge.to = null;
29344 edge.connect();
29345 }
29346 }
29347 }
29348 /**
29349 *
29350 * @param {Edge.id} edgeId
29351 * @returns {Array}
29352 */
29353
29354 }, {
29355 key: "getConnectedNodes",
29356 value: function getConnectedNodes(edgeId) {
29357 var nodeList = [];
29358
29359 if (this.body.edges[edgeId] !== undefined) {
29360 var edge = this.body.edges[edgeId];
29361
29362 if (edge.fromId !== undefined) {
29363 nodeList.push(edge.fromId);
29364 }
29365
29366 if (edge.toId !== undefined) {
29367 nodeList.push(edge.toId);
29368 }
29369 }
29370
29371 return nodeList;
29372 }
29373 /**
29374 * There is no direct relation between the nodes and the edges DataSet,
29375 * so the right place to do call this is in the handler for event `_dataUpdated`.
29376 */
29377
29378 }, {
29379 key: "_updateState",
29380 value: function _updateState() {
29381 this._addMissingEdges();
29382
29383 this._removeInvalidEdges();
29384 }
29385 /**
29386 * Scan for missing nodes and remove corresponding edges, if any.
29387 *
29388 * @private
29389 */
29390
29391 }, {
29392 key: "_removeInvalidEdges",
29393 value: function _removeInvalidEdges() {
29394 var _this5 = this;
29395
29396 var edgesToDelete = [];
29397 forEach$1(this.body.edges, function (edge, id) {
29398 var toNode = _this5.body.nodes[edge.toId];
29399 var fromNode = _this5.body.nodes[edge.fromId]; // Skip clustering edges here, let the Clustering module handle those
29400
29401 if (toNode !== undefined && toNode.isCluster === true || fromNode !== undefined && fromNode.isCluster === true) {
29402 return;
29403 }
29404
29405 if (toNode === undefined || fromNode === undefined) {
29406 edgesToDelete.push(id);
29407 }
29408 });
29409 this.remove(edgesToDelete, false);
29410 }
29411 /**
29412 * add all edges from dataset that are not in the cached state
29413 *
29414 * @private
29415 */
29416
29417 }, {
29418 key: "_addMissingEdges",
29419 value: function _addMissingEdges() {
29420 var edgesData = this.body.data.edges;
29421
29422 if (edgesData === undefined || edgesData === null) {
29423 return; // No edges DataSet yet; can happen on startup
29424 }
29425
29426 var edges = this.body.edges;
29427 var addIds = [];
29428
29429 forEach$2(edgesData).call(edgesData, function (edgeData, edgeId) {
29430 var edge = edges[edgeId];
29431
29432 if (edge === undefined) {
29433 addIds.push(edgeId);
29434 }
29435 });
29436
29437 this.add(addIds, true);
29438 }
29439 }]);
29440
29441 return EdgesHandler;
29442 }();
29443
29444 /**
29445 * Barnes Hut Solver
29446 */
29447
29448 var BarnesHutSolver = /*#__PURE__*/function () {
29449 /**
29450 * @param {object} body
29451 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
29452 * @param {object} options
29453 */
29454 function BarnesHutSolver(body, physicsBody, options) {
29455 _classCallCheck(this, BarnesHutSolver);
29456
29457 this.body = body;
29458 this.physicsBody = physicsBody;
29459 this.barnesHutTree;
29460 this.setOptions(options);
29461 this._rng = Alea("BARNES HUT SOLVER"); // debug: show grid
29462 // this.body.emitter.on("afterDrawing", (ctx) => {this._debug(ctx,'#ff0000')})
29463 }
29464 /**
29465 *
29466 * @param {object} options
29467 */
29468
29469
29470 _createClass(BarnesHutSolver, [{
29471 key: "setOptions",
29472 value: function setOptions(options) {
29473 this.options = options;
29474 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
29475
29476 this.overlapAvoidanceFactor = 1 - Math.max(0, Math.min(1, this.options.avoidOverlap));
29477 }
29478 /**
29479 * This function calculates the forces the nodes apply on each other based on a gravitational model.
29480 * The Barnes Hut method is used to speed up this N-body simulation.
29481 *
29482 * @private
29483 */
29484
29485 }, {
29486 key: "solve",
29487 value: function solve() {
29488 if (this.options.gravitationalConstant !== 0 && this.physicsBody.physicsNodeIndices.length > 0) {
29489 var node;
29490 var nodes = this.body.nodes;
29491 var nodeIndices = this.physicsBody.physicsNodeIndices;
29492 var nodeCount = nodeIndices.length; // create the tree
29493
29494 var barnesHutTree = this._formBarnesHutTree(nodes, nodeIndices); // for debugging
29495
29496
29497 this.barnesHutTree = barnesHutTree; // place the nodes one by one recursively
29498
29499 for (var i = 0; i < nodeCount; i++) {
29500 node = nodes[nodeIndices[i]];
29501
29502 if (node.options.mass > 0) {
29503 // starting with root is irrelevant, it never passes the BarnesHutSolver condition
29504 this._getForceContributions(barnesHutTree.root, node);
29505 }
29506 }
29507 }
29508 }
29509 /**
29510 * @param {object} parentBranch
29511 * @param {Node} node
29512 * @private
29513 */
29514
29515 }, {
29516 key: "_getForceContributions",
29517 value: function _getForceContributions(parentBranch, node) {
29518 this._getForceContribution(parentBranch.children.NW, node);
29519
29520 this._getForceContribution(parentBranch.children.NE, node);
29521
29522 this._getForceContribution(parentBranch.children.SW, node);
29523
29524 this._getForceContribution(parentBranch.children.SE, node);
29525 }
29526 /**
29527 * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass.
29528 * If a region contains a single node, we check if it is not itself, then we apply the force.
29529 *
29530 * @param {object} parentBranch
29531 * @param {Node} node
29532 * @private
29533 */
29534
29535 }, {
29536 key: "_getForceContribution",
29537 value: function _getForceContribution(parentBranch, node) {
29538 // we get no force contribution from an empty region
29539 if (parentBranch.childrenCount > 0) {
29540 // get the distance from the center of mass to the node.
29541 var dx = parentBranch.centerOfMass.x - node.x;
29542 var dy = parentBranch.centerOfMass.y - node.y;
29543 var distance = Math.sqrt(dx * dx + dy * dy); // BarnesHutSolver condition
29544 // original condition : s/d < theta = passed === d/s > 1/theta = passed
29545 // calcSize = 1/s --> d * 1/s > 1/theta = passed
29546
29547 if (distance * parentBranch.calcSize > this.thetaInversed) {
29548 this._calculateForces(distance, dx, dy, node, parentBranch);
29549 } else {
29550 // Did not pass the condition, go into children if available
29551 if (parentBranch.childrenCount === 4) {
29552 this._getForceContributions(parentBranch, node);
29553 } else {
29554 // parentBranch must have only one node, if it was empty we wouldnt be here
29555 if (parentBranch.children.data.id != node.id) {
29556 // if it is not self
29557 this._calculateForces(distance, dx, dy, node, parentBranch);
29558 }
29559 }
29560 }
29561 }
29562 }
29563 /**
29564 * Calculate the forces based on the distance.
29565 *
29566 * @param {number} distance
29567 * @param {number} dx
29568 * @param {number} dy
29569 * @param {Node} node
29570 * @param {object} parentBranch
29571 * @private
29572 */
29573
29574 }, {
29575 key: "_calculateForces",
29576 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
29577 if (distance === 0) {
29578 distance = 0.1;
29579 dx = distance;
29580 }
29581
29582 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
29583 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
29584 } // the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
29585 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
29586
29587
29588 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass / Math.pow(distance, 3);
29589 var fx = dx * gravityForce;
29590 var fy = dy * gravityForce;
29591 this.physicsBody.forces[node.id].x += fx;
29592 this.physicsBody.forces[node.id].y += fy;
29593 }
29594 /**
29595 * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes.
29596 *
29597 * @param {Array.<Node>} nodes
29598 * @param {Array.<number>} nodeIndices
29599 * @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
29600 * @private
29601 */
29602
29603 }, {
29604 key: "_formBarnesHutTree",
29605 value: function _formBarnesHutTree(nodes, nodeIndices) {
29606 var node;
29607 var nodeCount = nodeIndices.length;
29608 var minX = nodes[nodeIndices[0]].x;
29609 var minY = nodes[nodeIndices[0]].y;
29610 var maxX = nodes[nodeIndices[0]].x;
29611 var maxY = nodes[nodeIndices[0]].y; // get the range of the nodes
29612
29613 for (var i = 1; i < nodeCount; i++) {
29614 var _node = nodes[nodeIndices[i]];
29615 var x = _node.x;
29616 var y = _node.y;
29617
29618 if (_node.options.mass > 0) {
29619 if (x < minX) {
29620 minX = x;
29621 }
29622
29623 if (x > maxX) {
29624 maxX = x;
29625 }
29626
29627 if (y < minY) {
29628 minY = y;
29629 }
29630
29631 if (y > maxY) {
29632 maxY = y;
29633 }
29634 }
29635 } // make the range a square
29636
29637
29638 var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
29639
29640 if (sizeDiff > 0) {
29641 minY -= 0.5 * sizeDiff;
29642 maxY += 0.5 * sizeDiff;
29643 } // xSize > ySize
29644 else {
29645 minX += 0.5 * sizeDiff;
29646 maxX -= 0.5 * sizeDiff;
29647 } // xSize < ySize
29648
29649
29650 var minimumTreeSize = 1e-5;
29651 var rootSize = Math.max(minimumTreeSize, Math.abs(maxX - minX));
29652 var halfRootSize = 0.5 * rootSize;
29653 var centerX = 0.5 * (minX + maxX),
29654 centerY = 0.5 * (minY + maxY); // construct the barnesHutTree
29655
29656 var barnesHutTree = {
29657 root: {
29658 centerOfMass: {
29659 x: 0,
29660 y: 0
29661 },
29662 mass: 0,
29663 range: {
29664 minX: centerX - halfRootSize,
29665 maxX: centerX + halfRootSize,
29666 minY: centerY - halfRootSize,
29667 maxY: centerY + halfRootSize
29668 },
29669 size: rootSize,
29670 calcSize: 1 / rootSize,
29671 children: {
29672 data: null
29673 },
29674 maxWidth: 0,
29675 level: 0,
29676 childrenCount: 4
29677 }
29678 };
29679
29680 this._splitBranch(barnesHutTree.root); // place the nodes one by one recursively
29681
29682
29683 for (var _i = 0; _i < nodeCount; _i++) {
29684 node = nodes[nodeIndices[_i]];
29685
29686 if (node.options.mass > 0) {
29687 this._placeInTree(barnesHutTree.root, node);
29688 }
29689 } // make global
29690
29691
29692 return barnesHutTree;
29693 }
29694 /**
29695 * this updates the mass of a branch. this is increased by adding a node.
29696 *
29697 * @param {object} parentBranch
29698 * @param {Node} node
29699 * @private
29700 */
29701
29702 }, {
29703 key: "_updateBranchMass",
29704 value: function _updateBranchMass(parentBranch, node) {
29705 var centerOfMass = parentBranch.centerOfMass;
29706 var totalMass = parentBranch.mass + node.options.mass;
29707 var totalMassInv = 1 / totalMass;
29708 centerOfMass.x = centerOfMass.x * parentBranch.mass + node.x * node.options.mass;
29709 centerOfMass.x *= totalMassInv;
29710 centerOfMass.y = centerOfMass.y * parentBranch.mass + node.y * node.options.mass;
29711 centerOfMass.y *= totalMassInv;
29712 parentBranch.mass = totalMass;
29713 var biggestSize = Math.max(Math.max(node.height, node.radius), node.width);
29714 parentBranch.maxWidth = parentBranch.maxWidth < biggestSize ? biggestSize : parentBranch.maxWidth;
29715 }
29716 /**
29717 * determine in which branch the node will be placed.
29718 *
29719 * @param {object} parentBranch
29720 * @param {Node} node
29721 * @param {boolean} skipMassUpdate
29722 * @private
29723 */
29724
29725 }, {
29726 key: "_placeInTree",
29727 value: function _placeInTree(parentBranch, node, skipMassUpdate) {
29728 if (skipMassUpdate != true || skipMassUpdate === undefined) {
29729 // update the mass of the branch.
29730 this._updateBranchMass(parentBranch, node);
29731 }
29732
29733 var range = parentBranch.children.NW.range;
29734 var region;
29735
29736 if (range.maxX > node.x) {
29737 // in NW or SW
29738 if (range.maxY > node.y) {
29739 region = "NW";
29740 } else {
29741 region = "SW";
29742 }
29743 } else {
29744 // in NE or SE
29745 if (range.maxY > node.y) {
29746 region = "NE";
29747 } else {
29748 region = "SE";
29749 }
29750 }
29751
29752 this._placeInRegion(parentBranch, node, region);
29753 }
29754 /**
29755 * actually place the node in a region (or branch)
29756 *
29757 * @param {object} parentBranch
29758 * @param {Node} node
29759 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
29760 * @private
29761 */
29762
29763 }, {
29764 key: "_placeInRegion",
29765 value: function _placeInRegion(parentBranch, node, region) {
29766 var children = parentBranch.children[region];
29767
29768 switch (children.childrenCount) {
29769 case 0:
29770 // place node here
29771 children.children.data = node;
29772 children.childrenCount = 1;
29773
29774 this._updateBranchMass(children, node);
29775
29776 break;
29777
29778 case 1:
29779 // convert into children
29780 // if there are two nodes exactly overlapping (on init, on opening of cluster etc.)
29781 // we move one node a little bit and we do not put it in the tree.
29782 if (children.children.data.x === node.x && children.children.data.y === node.y) {
29783 node.x += this._rng();
29784 node.y += this._rng();
29785 } else {
29786 this._splitBranch(children);
29787
29788 this._placeInTree(children, node);
29789 }
29790
29791 break;
29792
29793 case 4:
29794 // place in branch
29795 this._placeInTree(children, node);
29796
29797 break;
29798 }
29799 }
29800 /**
29801 * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch
29802 * after the split is complete.
29803 *
29804 * @param {object} parentBranch
29805 * @private
29806 */
29807
29808 }, {
29809 key: "_splitBranch",
29810 value: function _splitBranch(parentBranch) {
29811 // if the branch is shaded with a node, replace the node in the new subset.
29812 var containedNode = null;
29813
29814 if (parentBranch.childrenCount === 1) {
29815 containedNode = parentBranch.children.data;
29816 parentBranch.mass = 0;
29817 parentBranch.centerOfMass.x = 0;
29818 parentBranch.centerOfMass.y = 0;
29819 }
29820
29821 parentBranch.childrenCount = 4;
29822 parentBranch.children.data = null;
29823
29824 this._insertRegion(parentBranch, "NW");
29825
29826 this._insertRegion(parentBranch, "NE");
29827
29828 this._insertRegion(parentBranch, "SW");
29829
29830 this._insertRegion(parentBranch, "SE");
29831
29832 if (containedNode != null) {
29833 this._placeInTree(parentBranch, containedNode);
29834 }
29835 }
29836 /**
29837 * This function subdivides the region into four new segments.
29838 * Specifically, this inserts a single new segment.
29839 * It fills the children section of the parentBranch
29840 *
29841 * @param {object} parentBranch
29842 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
29843 * @private
29844 */
29845
29846 }, {
29847 key: "_insertRegion",
29848 value: function _insertRegion(parentBranch, region) {
29849 var minX, maxX, minY, maxY;
29850 var childSize = 0.5 * parentBranch.size;
29851
29852 switch (region) {
29853 case "NW":
29854 minX = parentBranch.range.minX;
29855 maxX = parentBranch.range.minX + childSize;
29856 minY = parentBranch.range.minY;
29857 maxY = parentBranch.range.minY + childSize;
29858 break;
29859
29860 case "NE":
29861 minX = parentBranch.range.minX + childSize;
29862 maxX = parentBranch.range.maxX;
29863 minY = parentBranch.range.minY;
29864 maxY = parentBranch.range.minY + childSize;
29865 break;
29866
29867 case "SW":
29868 minX = parentBranch.range.minX;
29869 maxX = parentBranch.range.minX + childSize;
29870 minY = parentBranch.range.minY + childSize;
29871 maxY = parentBranch.range.maxY;
29872 break;
29873
29874 case "SE":
29875 minX = parentBranch.range.minX + childSize;
29876 maxX = parentBranch.range.maxX;
29877 minY = parentBranch.range.minY + childSize;
29878 maxY = parentBranch.range.maxY;
29879 break;
29880 }
29881
29882 parentBranch.children[region] = {
29883 centerOfMass: {
29884 x: 0,
29885 y: 0
29886 },
29887 mass: 0,
29888 range: {
29889 minX: minX,
29890 maxX: maxX,
29891 minY: minY,
29892 maxY: maxY
29893 },
29894 size: 0.5 * parentBranch.size,
29895 calcSize: 2 * parentBranch.calcSize,
29896 children: {
29897 data: null
29898 },
29899 maxWidth: 0,
29900 level: parentBranch.level + 1,
29901 childrenCount: 0
29902 };
29903 } //--------------------------- DEBUGGING BELOW ---------------------------//
29904
29905 /**
29906 * This function is for debugging purposed, it draws the tree.
29907 *
29908 * @param {CanvasRenderingContext2D} ctx
29909 * @param {string} color
29910 * @private
29911 */
29912
29913 }, {
29914 key: "_debug",
29915 value: function _debug(ctx, color) {
29916 if (this.barnesHutTree !== undefined) {
29917 ctx.lineWidth = 1;
29918
29919 this._drawBranch(this.barnesHutTree.root, ctx, color);
29920 }
29921 }
29922 /**
29923 * This function is for debugging purposes. It draws the branches recursively.
29924 *
29925 * @param {object} branch
29926 * @param {CanvasRenderingContext2D} ctx
29927 * @param {string} color
29928 * @private
29929 */
29930
29931 }, {
29932 key: "_drawBranch",
29933 value: function _drawBranch(branch, ctx, color) {
29934 if (color === undefined) {
29935 color = "#FF0000";
29936 }
29937
29938 if (branch.childrenCount === 4) {
29939 this._drawBranch(branch.children.NW, ctx);
29940
29941 this._drawBranch(branch.children.NE, ctx);
29942
29943 this._drawBranch(branch.children.SE, ctx);
29944
29945 this._drawBranch(branch.children.SW, ctx);
29946 }
29947
29948 ctx.strokeStyle = color;
29949 ctx.beginPath();
29950 ctx.moveTo(branch.range.minX, branch.range.minY);
29951 ctx.lineTo(branch.range.maxX, branch.range.minY);
29952 ctx.stroke();
29953 ctx.beginPath();
29954 ctx.moveTo(branch.range.maxX, branch.range.minY);
29955 ctx.lineTo(branch.range.maxX, branch.range.maxY);
29956 ctx.stroke();
29957 ctx.beginPath();
29958 ctx.moveTo(branch.range.maxX, branch.range.maxY);
29959 ctx.lineTo(branch.range.minX, branch.range.maxY);
29960 ctx.stroke();
29961 ctx.beginPath();
29962 ctx.moveTo(branch.range.minX, branch.range.maxY);
29963 ctx.lineTo(branch.range.minX, branch.range.minY);
29964 ctx.stroke();
29965 /*
29966 if (branch.mass > 0) {
29967 ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass);
29968 ctx.stroke();
29969 }
29970 */
29971 }
29972 }]);
29973
29974 return BarnesHutSolver;
29975 }();
29976
29977 /**
29978 * Repulsion Solver
29979 */
29980
29981 var RepulsionSolver = /*#__PURE__*/function () {
29982 /**
29983 * @param {object} body
29984 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
29985 * @param {object} options
29986 */
29987 function RepulsionSolver(body, physicsBody, options) {
29988 _classCallCheck(this, RepulsionSolver);
29989
29990 this._rng = Alea("REPULSION SOLVER");
29991 this.body = body;
29992 this.physicsBody = physicsBody;
29993 this.setOptions(options);
29994 }
29995 /**
29996 *
29997 * @param {object} options
29998 */
29999
30000
30001 _createClass(RepulsionSolver, [{
30002 key: "setOptions",
30003 value: function setOptions(options) {
30004 this.options = options;
30005 }
30006 /**
30007 * Calculate the forces the nodes apply on each other based on a repulsion field.
30008 * This field is linearly approximated.
30009 *
30010 * @private
30011 */
30012
30013 }, {
30014 key: "solve",
30015 value: function solve() {
30016 var dx, dy, distance, fx, fy, repulsingForce, node1, node2;
30017 var nodes = this.body.nodes;
30018 var nodeIndices = this.physicsBody.physicsNodeIndices;
30019 var forces = this.physicsBody.forces; // repulsing forces between nodes
30020
30021 var nodeDistance = this.options.nodeDistance; // approximation constants
30022
30023 var a = -2 / 3 / nodeDistance;
30024 var b = 4 / 3; // we loop from i over all but the last entree in the array
30025 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
30026
30027 for (var i = 0; i < nodeIndices.length - 1; i++) {
30028 node1 = nodes[nodeIndices[i]];
30029
30030 for (var j = i + 1; j < nodeIndices.length; j++) {
30031 node2 = nodes[nodeIndices[j]];
30032 dx = node2.x - node1.x;
30033 dy = node2.y - node1.y;
30034 distance = Math.sqrt(dx * dx + dy * dy); // same condition as BarnesHutSolver, making sure nodes are never 100% overlapping.
30035
30036 if (distance === 0) {
30037 distance = 0.1 * this._rng();
30038 dx = distance;
30039 }
30040
30041 if (distance < 2 * nodeDistance) {
30042 if (distance < 0.5 * nodeDistance) {
30043 repulsingForce = 1.0;
30044 } else {
30045 repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / nodeDistance - 1) * steepness))
30046 }
30047
30048 repulsingForce = repulsingForce / distance;
30049 fx = dx * repulsingForce;
30050 fy = dy * repulsingForce;
30051 forces[node1.id].x -= fx;
30052 forces[node1.id].y -= fy;
30053 forces[node2.id].x += fx;
30054 forces[node2.id].y += fy;
30055 }
30056 }
30057 }
30058 }
30059 }]);
30060
30061 return RepulsionSolver;
30062 }();
30063
30064 /**
30065 * Hierarchical Repulsion Solver
30066 */
30067 var HierarchicalRepulsionSolver = /*#__PURE__*/function () {
30068 /**
30069 * @param {object} body
30070 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
30071 * @param {object} options
30072 */
30073 function HierarchicalRepulsionSolver(body, physicsBody, options) {
30074 _classCallCheck(this, HierarchicalRepulsionSolver);
30075
30076 this.body = body;
30077 this.physicsBody = physicsBody;
30078 this.setOptions(options);
30079 }
30080 /**
30081 *
30082 * @param {object} options
30083 */
30084
30085
30086 _createClass(HierarchicalRepulsionSolver, [{
30087 key: "setOptions",
30088 value: function setOptions(options) {
30089 this.options = options;
30090 this.overlapAvoidanceFactor = Math.max(0, Math.min(1, this.options.avoidOverlap || 0));
30091 }
30092 /**
30093 * Calculate the forces the nodes apply on each other based on a repulsion field.
30094 * This field is linearly approximated.
30095 *
30096 * @private
30097 */
30098
30099 }, {
30100 key: "solve",
30101 value: function solve() {
30102 var nodes = this.body.nodes;
30103 var nodeIndices = this.physicsBody.physicsNodeIndices;
30104 var forces = this.physicsBody.forces; // repulsing forces between nodes
30105
30106 var nodeDistance = this.options.nodeDistance; // we loop from i over all but the last entree in the array
30107 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
30108
30109 for (var i = 0; i < nodeIndices.length - 1; i++) {
30110 var node1 = nodes[nodeIndices[i]];
30111
30112 for (var j = i + 1; j < nodeIndices.length; j++) {
30113 var node2 = nodes[nodeIndices[j]]; // nodes only affect nodes on their level
30114
30115 if (node1.level === node2.level) {
30116 var theseNodesDistance = nodeDistance + this.overlapAvoidanceFactor * ((node1.shape.radius || 0) / 2 + (node2.shape.radius || 0) / 2);
30117 var dx = node2.x - node1.x;
30118 var dy = node2.y - node1.y;
30119 var distance = Math.sqrt(dx * dx + dy * dy);
30120 var steepness = 0.05;
30121 var repulsingForce = void 0;
30122
30123 if (distance < theseNodesDistance) {
30124 repulsingForce = -Math.pow(steepness * distance, 2) + Math.pow(steepness * theseNodesDistance, 2);
30125 } else {
30126 repulsingForce = 0;
30127 } // normalize force with
30128
30129
30130 if (distance !== 0) {
30131 repulsingForce = repulsingForce / distance;
30132 }
30133
30134 var fx = dx * repulsingForce;
30135 var fy = dy * repulsingForce;
30136 forces[node1.id].x -= fx;
30137 forces[node1.id].y -= fy;
30138 forces[node2.id].x += fx;
30139 forces[node2.id].y += fy;
30140 }
30141 }
30142 }
30143 }
30144 }]);
30145
30146 return HierarchicalRepulsionSolver;
30147 }();
30148
30149 /**
30150 * Spring Solver
30151 */
30152 var SpringSolver = /*#__PURE__*/function () {
30153 /**
30154 * @param {object} body
30155 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
30156 * @param {object} options
30157 */
30158 function SpringSolver(body, physicsBody, options) {
30159 _classCallCheck(this, SpringSolver);
30160
30161 this.body = body;
30162 this.physicsBody = physicsBody;
30163 this.setOptions(options);
30164 }
30165 /**
30166 *
30167 * @param {object} options
30168 */
30169
30170
30171 _createClass(SpringSolver, [{
30172 key: "setOptions",
30173 value: function setOptions(options) {
30174 this.options = options;
30175 }
30176 /**
30177 * This function calculates the springforces on the nodes, accounting for the support nodes.
30178 *
30179 * @private
30180 */
30181
30182 }, {
30183 key: "solve",
30184 value: function solve() {
30185 var edgeLength, edge;
30186 var edgeIndices = this.physicsBody.physicsEdgeIndices;
30187 var edges = this.body.edges;
30188 var node1, node2, node3; // forces caused by the edges, modelled as springs
30189
30190 for (var i = 0; i < edgeIndices.length; i++) {
30191 edge = edges[edgeIndices[i]];
30192
30193 if (edge.connected === true && edge.toId !== edge.fromId) {
30194 // only calculate forces if nodes are in the same sector
30195 if (this.body.nodes[edge.toId] !== undefined && this.body.nodes[edge.fromId] !== undefined) {
30196 if (edge.edgeType.via !== undefined) {
30197 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
30198 node1 = edge.to;
30199 node2 = edge.edgeType.via;
30200 node3 = edge.from;
30201
30202 this._calculateSpringForce(node1, node2, 0.5 * edgeLength);
30203
30204 this._calculateSpringForce(node2, node3, 0.5 * edgeLength);
30205 } else {
30206 // the * 1.5 is here so the edge looks as large as a smooth edge. It does not initially because the smooth edges use
30207 // the support nodes which exert a repulsive force on the to and from nodes, making the edge appear larger.
30208 edgeLength = edge.options.length === undefined ? this.options.springLength * 1.5 : edge.options.length;
30209
30210 this._calculateSpringForce(edge.from, edge.to, edgeLength);
30211 }
30212 }
30213 }
30214 }
30215 }
30216 /**
30217 * This is the code actually performing the calculation for the function above.
30218 *
30219 * @param {Node} node1
30220 * @param {Node} node2
30221 * @param {number} edgeLength
30222 * @private
30223 */
30224
30225 }, {
30226 key: "_calculateSpringForce",
30227 value: function _calculateSpringForce(node1, node2, edgeLength) {
30228 var dx = node1.x - node2.x;
30229 var dy = node1.y - node2.y;
30230 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.
30231
30232 var springForce = this.options.springConstant * (edgeLength - distance) / distance;
30233 var fx = dx * springForce;
30234 var fy = dy * springForce; // handle the case where one node is not part of the physcis
30235
30236 if (this.physicsBody.forces[node1.id] !== undefined) {
30237 this.physicsBody.forces[node1.id].x += fx;
30238 this.physicsBody.forces[node1.id].y += fy;
30239 }
30240
30241 if (this.physicsBody.forces[node2.id] !== undefined) {
30242 this.physicsBody.forces[node2.id].x -= fx;
30243 this.physicsBody.forces[node2.id].y -= fy;
30244 }
30245 }
30246 }]);
30247
30248 return SpringSolver;
30249 }();
30250
30251 /**
30252 * Hierarchical Spring Solver
30253 */
30254 var HierarchicalSpringSolver = /*#__PURE__*/function () {
30255 /**
30256 * @param {object} body
30257 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
30258 * @param {object} options
30259 */
30260 function HierarchicalSpringSolver(body, physicsBody, options) {
30261 _classCallCheck(this, HierarchicalSpringSolver);
30262
30263 this.body = body;
30264 this.physicsBody = physicsBody;
30265 this.setOptions(options);
30266 }
30267 /**
30268 *
30269 * @param {object} options
30270 */
30271
30272
30273 _createClass(HierarchicalSpringSolver, [{
30274 key: "setOptions",
30275 value: function setOptions(options) {
30276 this.options = options;
30277 }
30278 /**
30279 * This function calculates the springforces on the nodes, accounting for the support nodes.
30280 *
30281 * @private
30282 */
30283
30284 }, {
30285 key: "solve",
30286 value: function solve() {
30287 var edgeLength, edge;
30288 var dx, dy, fx, fy, springForce, distance;
30289 var edges = this.body.edges;
30290 var factor = 0.5;
30291 var edgeIndices = this.physicsBody.physicsEdgeIndices;
30292 var nodeIndices = this.physicsBody.physicsNodeIndices;
30293 var forces = this.physicsBody.forces; // initialize the spring force counters
30294
30295 for (var i = 0; i < nodeIndices.length; i++) {
30296 var nodeId = nodeIndices[i];
30297 forces[nodeId].springFx = 0;
30298 forces[nodeId].springFy = 0;
30299 } // forces caused by the edges, modelled as springs
30300
30301
30302 for (var _i = 0; _i < edgeIndices.length; _i++) {
30303 edge = edges[edgeIndices[_i]];
30304
30305 if (edge.connected === true) {
30306 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
30307 dx = edge.from.x - edge.to.x;
30308 dy = edge.from.y - edge.to.y;
30309 distance = Math.sqrt(dx * dx + dy * dy);
30310 distance = distance === 0 ? 0.01 : distance; // the 1/distance is so the fx and fy can be calculated without sine or cosine.
30311
30312 springForce = this.options.springConstant * (edgeLength - distance) / distance;
30313 fx = dx * springForce;
30314 fy = dy * springForce;
30315
30316 if (edge.to.level != edge.from.level) {
30317 if (forces[edge.toId] !== undefined) {
30318 forces[edge.toId].springFx -= fx;
30319 forces[edge.toId].springFy -= fy;
30320 }
30321
30322 if (forces[edge.fromId] !== undefined) {
30323 forces[edge.fromId].springFx += fx;
30324 forces[edge.fromId].springFy += fy;
30325 }
30326 } else {
30327 if (forces[edge.toId] !== undefined) {
30328 forces[edge.toId].x -= factor * fx;
30329 forces[edge.toId].y -= factor * fy;
30330 }
30331
30332 if (forces[edge.fromId] !== undefined) {
30333 forces[edge.fromId].x += factor * fx;
30334 forces[edge.fromId].y += factor * fy;
30335 }
30336 }
30337 }
30338 } // normalize spring forces
30339
30340
30341 springForce = 1;
30342 var springFx, springFy;
30343
30344 for (var _i2 = 0; _i2 < nodeIndices.length; _i2++) {
30345 var _nodeId = nodeIndices[_i2];
30346 springFx = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFx));
30347 springFy = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFy));
30348 forces[_nodeId].x += springFx;
30349 forces[_nodeId].y += springFy;
30350 } // retain energy balance
30351
30352
30353 var totalFx = 0;
30354 var totalFy = 0;
30355
30356 for (var _i3 = 0; _i3 < nodeIndices.length; _i3++) {
30357 var _nodeId2 = nodeIndices[_i3];
30358 totalFx += forces[_nodeId2].x;
30359 totalFy += forces[_nodeId2].y;
30360 }
30361
30362 var correctionFx = totalFx / nodeIndices.length;
30363 var correctionFy = totalFy / nodeIndices.length;
30364
30365 for (var _i4 = 0; _i4 < nodeIndices.length; _i4++) {
30366 var _nodeId3 = nodeIndices[_i4];
30367 forces[_nodeId3].x -= correctionFx;
30368 forces[_nodeId3].y -= correctionFy;
30369 }
30370 }
30371 }]);
30372
30373 return HierarchicalSpringSolver;
30374 }();
30375
30376 /**
30377 * Central Gravity Solver
30378 */
30379 var CentralGravitySolver = /*#__PURE__*/function () {
30380 /**
30381 * @param {object} body
30382 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
30383 * @param {object} options
30384 */
30385 function CentralGravitySolver(body, physicsBody, options) {
30386 _classCallCheck(this, CentralGravitySolver);
30387
30388 this.body = body;
30389 this.physicsBody = physicsBody;
30390 this.setOptions(options);
30391 }
30392 /**
30393 *
30394 * @param {object} options
30395 */
30396
30397
30398 _createClass(CentralGravitySolver, [{
30399 key: "setOptions",
30400 value: function setOptions(options) {
30401 this.options = options;
30402 }
30403 /**
30404 * Calculates forces for each node
30405 */
30406
30407 }, {
30408 key: "solve",
30409 value: function solve() {
30410 var dx, dy, distance, node;
30411 var nodes = this.body.nodes;
30412 var nodeIndices = this.physicsBody.physicsNodeIndices;
30413 var forces = this.physicsBody.forces;
30414
30415 for (var i = 0; i < nodeIndices.length; i++) {
30416 var nodeId = nodeIndices[i];
30417 node = nodes[nodeId];
30418 dx = -node.x;
30419 dy = -node.y;
30420 distance = Math.sqrt(dx * dx + dy * dy);
30421
30422 this._calculateForces(distance, dx, dy, forces, node);
30423 }
30424 }
30425 /**
30426 * Calculate the forces based on the distance.
30427 *
30428 * @param {number} distance
30429 * @param {number} dx
30430 * @param {number} dy
30431 * @param {object<Node.id, vis.Node>} forces
30432 * @param {Node} node
30433 * @private
30434 */
30435
30436 }, {
30437 key: "_calculateForces",
30438 value: function _calculateForces(distance, dx, dy, forces, node) {
30439 var gravityForce = distance === 0 ? 0 : this.options.centralGravity / distance;
30440 forces[node.id].x = dx * gravityForce;
30441 forces[node.id].y = dy * gravityForce;
30442 }
30443 }]);
30444
30445 return CentralGravitySolver;
30446 }();
30447
30448 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); }; }
30449
30450 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; } }
30451 /**
30452 * @augments BarnesHutSolver
30453 */
30454
30455 var ForceAtlas2BasedRepulsionSolver = /*#__PURE__*/function (_BarnesHutSolver) {
30456 _inherits(ForceAtlas2BasedRepulsionSolver, _BarnesHutSolver);
30457
30458 var _super = _createSuper$3(ForceAtlas2BasedRepulsionSolver);
30459
30460 /**
30461 * @param {object} body
30462 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
30463 * @param {object} options
30464 */
30465 function ForceAtlas2BasedRepulsionSolver(body, physicsBody, options) {
30466 var _this;
30467
30468 _classCallCheck(this, ForceAtlas2BasedRepulsionSolver);
30469
30470 _this = _super.call(this, body, physicsBody, options);
30471 _this._rng = Alea("FORCE ATLAS 2 BASED REPULSION SOLVER");
30472 return _this;
30473 }
30474 /**
30475 * Calculate the forces based on the distance.
30476 *
30477 * @param {number} distance
30478 * @param {number} dx
30479 * @param {number} dy
30480 * @param {Node} node
30481 * @param {object} parentBranch
30482 * @private
30483 */
30484
30485
30486 _createClass(ForceAtlas2BasedRepulsionSolver, [{
30487 key: "_calculateForces",
30488 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
30489 if (distance === 0) {
30490 distance = 0.1 * this._rng();
30491 dx = distance;
30492 }
30493
30494 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
30495 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
30496 }
30497
30498 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
30499 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
30500
30501 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass * degree / Math.pow(distance, 2);
30502 var fx = dx * gravityForce;
30503 var fy = dy * gravityForce;
30504 this.physicsBody.forces[node.id].x += fx;
30505 this.physicsBody.forces[node.id].y += fy;
30506 }
30507 }]);
30508
30509 return ForceAtlas2BasedRepulsionSolver;
30510 }(BarnesHutSolver);
30511
30512 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); }; }
30513
30514 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; } }
30515 /**
30516 * @augments CentralGravitySolver
30517 */
30518
30519 var ForceAtlas2BasedCentralGravitySolver = /*#__PURE__*/function (_CentralGravitySolver) {
30520 _inherits(ForceAtlas2BasedCentralGravitySolver, _CentralGravitySolver);
30521
30522 var _super = _createSuper$2(ForceAtlas2BasedCentralGravitySolver);
30523
30524 /**
30525 * @param {object} body
30526 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
30527 * @param {object} options
30528 */
30529 function ForceAtlas2BasedCentralGravitySolver(body, physicsBody, options) {
30530 _classCallCheck(this, ForceAtlas2BasedCentralGravitySolver);
30531
30532 return _super.call(this, body, physicsBody, options);
30533 }
30534 /**
30535 * Calculate the forces based on the distance.
30536 *
30537 * @param {number} distance
30538 * @param {number} dx
30539 * @param {number} dy
30540 * @param {object<Node.id, Node>} forces
30541 * @param {Node} node
30542 * @private
30543 */
30544
30545
30546 _createClass(ForceAtlas2BasedCentralGravitySolver, [{
30547 key: "_calculateForces",
30548 value: function _calculateForces(distance, dx, dy, forces, node) {
30549 if (distance > 0) {
30550 var degree = node.edges.length + 1;
30551 var gravityForce = this.options.centralGravity * degree * node.options.mass;
30552 forces[node.id].x = dx * gravityForce;
30553 forces[node.id].y = dy * gravityForce;
30554 }
30555 }
30556 }]);
30557
30558 return ForceAtlas2BasedCentralGravitySolver;
30559 }(CentralGravitySolver);
30560
30561 /**
30562 * The physics engine
30563 */
30564
30565 var PhysicsEngine = /*#__PURE__*/function () {
30566 /**
30567 * @param {object} body
30568 */
30569 function PhysicsEngine(body) {
30570 _classCallCheck(this, PhysicsEngine);
30571
30572 this.body = body;
30573 this.physicsBody = {
30574 physicsNodeIndices: [],
30575 physicsEdgeIndices: [],
30576 forces: {},
30577 velocities: {}
30578 };
30579 this.physicsEnabled = true;
30580 this.simulationInterval = 1000 / 60;
30581 this.requiresTimeout = true;
30582 this.previousStates = {};
30583 this.referenceState = {};
30584 this.freezeCache = {};
30585 this.renderTimer = undefined; // parameters for the adaptive timestep
30586
30587 this.adaptiveTimestep = false;
30588 this.adaptiveTimestepEnabled = false;
30589 this.adaptiveCounter = 0;
30590 this.adaptiveInterval = 3;
30591 this.stabilized = false;
30592 this.startedStabilization = false;
30593 this.stabilizationIterations = 0;
30594 this.ready = false; // will be set to true if the stabilize
30595 // default options
30596
30597 this.options = {};
30598 this.defaultOptions = {
30599 enabled: true,
30600 barnesHut: {
30601 theta: 0.5,
30602 gravitationalConstant: -2000,
30603 centralGravity: 0.3,
30604 springLength: 95,
30605 springConstant: 0.04,
30606 damping: 0.09,
30607 avoidOverlap: 0
30608 },
30609 forceAtlas2Based: {
30610 theta: 0.5,
30611 gravitationalConstant: -50,
30612 centralGravity: 0.01,
30613 springConstant: 0.08,
30614 springLength: 100,
30615 damping: 0.4,
30616 avoidOverlap: 0
30617 },
30618 repulsion: {
30619 centralGravity: 0.2,
30620 springLength: 200,
30621 springConstant: 0.05,
30622 nodeDistance: 100,
30623 damping: 0.09,
30624 avoidOverlap: 0
30625 },
30626 hierarchicalRepulsion: {
30627 centralGravity: 0.0,
30628 springLength: 100,
30629 springConstant: 0.01,
30630 nodeDistance: 120,
30631 damping: 0.09
30632 },
30633 maxVelocity: 50,
30634 minVelocity: 0.75,
30635 // px/s
30636 solver: "barnesHut",
30637 stabilization: {
30638 enabled: true,
30639 iterations: 1000,
30640 // maximum number of iteration to stabilize
30641 updateInterval: 50,
30642 onlyDynamicEdges: false,
30643 fit: true
30644 },
30645 timestep: 0.5,
30646 adaptiveTimestep: true,
30647 wind: {
30648 x: 0,
30649 y: 0
30650 }
30651 };
30652
30653 assign$2(this.options, this.defaultOptions);
30654
30655 this.timestep = 0.5;
30656 this.layoutFailed = false;
30657 this.bindEventListeners();
30658 }
30659 /**
30660 * Binds event listeners
30661 */
30662
30663
30664 _createClass(PhysicsEngine, [{
30665 key: "bindEventListeners",
30666 value: function bindEventListeners() {
30667 var _this = this;
30668
30669 this.body.emitter.on("initPhysics", function () {
30670 _this.initPhysics();
30671 });
30672 this.body.emitter.on("_layoutFailed", function () {
30673 _this.layoutFailed = true;
30674 });
30675 this.body.emitter.on("resetPhysics", function () {
30676 _this.stopSimulation();
30677
30678 _this.ready = false;
30679 });
30680 this.body.emitter.on("disablePhysics", function () {
30681 _this.physicsEnabled = false;
30682
30683 _this.stopSimulation();
30684 });
30685 this.body.emitter.on("restorePhysics", function () {
30686 _this.setOptions(_this.options);
30687
30688 if (_this.ready === true) {
30689 _this.startSimulation();
30690 }
30691 });
30692 this.body.emitter.on("startSimulation", function () {
30693 if (_this.ready === true) {
30694 _this.startSimulation();
30695 }
30696 });
30697 this.body.emitter.on("stopSimulation", function () {
30698 _this.stopSimulation();
30699 });
30700 this.body.emitter.on("destroy", function () {
30701 _this.stopSimulation(false);
30702
30703 _this.body.emitter.off();
30704 });
30705 this.body.emitter.on("_dataChanged", function () {
30706 // Nodes and/or edges have been added or removed, update shortcut lists.
30707 _this.updatePhysicsData();
30708 }); // debug: show forces
30709 // this.body.emitter.on("afterDrawing", (ctx) => {this._drawForces(ctx);});
30710 }
30711 /**
30712 * set the physics options
30713 *
30714 * @param {object} options
30715 */
30716
30717 }, {
30718 key: "setOptions",
30719 value: function setOptions(options) {
30720 if (options !== undefined) {
30721 if (options === false) {
30722 this.options.enabled = false;
30723 this.physicsEnabled = false;
30724 this.stopSimulation();
30725 } else if (options === true) {
30726 this.options.enabled = true;
30727 this.physicsEnabled = true;
30728 this.startSimulation();
30729 } else {
30730 this.physicsEnabled = true;
30731 selectiveNotDeepExtend(["stabilization"], this.options, options);
30732 mergeOptions(this.options, options, "stabilization");
30733
30734 if (options.enabled === undefined) {
30735 this.options.enabled = true;
30736 }
30737
30738 if (this.options.enabled === false) {
30739 this.physicsEnabled = false;
30740 this.stopSimulation();
30741 }
30742
30743 var wind = this.options.wind;
30744
30745 if (wind) {
30746 if (typeof wind.x !== "number" || isNan(wind.x)) {
30747 wind.x = 0;
30748 }
30749
30750 if (typeof wind.y !== "number" || isNan(wind.y)) {
30751 wind.y = 0;
30752 }
30753 } // set the timestep
30754
30755
30756 this.timestep = this.options.timestep;
30757 }
30758 }
30759
30760 this.init();
30761 }
30762 /**
30763 * configure the engine.
30764 */
30765
30766 }, {
30767 key: "init",
30768 value: function init() {
30769 var options;
30770
30771 if (this.options.solver === "forceAtlas2Based") {
30772 options = this.options.forceAtlas2Based;
30773 this.nodesSolver = new ForceAtlas2BasedRepulsionSolver(this.body, this.physicsBody, options);
30774 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
30775 this.gravitySolver = new ForceAtlas2BasedCentralGravitySolver(this.body, this.physicsBody, options);
30776 } else if (this.options.solver === "repulsion") {
30777 options = this.options.repulsion;
30778 this.nodesSolver = new RepulsionSolver(this.body, this.physicsBody, options);
30779 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
30780 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
30781 } else if (this.options.solver === "hierarchicalRepulsion") {
30782 options = this.options.hierarchicalRepulsion;
30783 this.nodesSolver = new HierarchicalRepulsionSolver(this.body, this.physicsBody, options);
30784 this.edgesSolver = new HierarchicalSpringSolver(this.body, this.physicsBody, options);
30785 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
30786 } else {
30787 // barnesHut
30788 options = this.options.barnesHut;
30789 this.nodesSolver = new BarnesHutSolver(this.body, this.physicsBody, options);
30790 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
30791 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
30792 }
30793
30794 this.modelOptions = options;
30795 }
30796 /**
30797 * initialize the engine
30798 */
30799
30800 }, {
30801 key: "initPhysics",
30802 value: function initPhysics() {
30803 if (this.physicsEnabled === true && this.options.enabled === true) {
30804 if (this.options.stabilization.enabled === true) {
30805 this.stabilize();
30806 } else {
30807 this.stabilized = false;
30808 this.ready = true;
30809 this.body.emitter.emit("fit", {}, this.layoutFailed); // if the layout failed, we use the approximation for the zoom
30810
30811 this.startSimulation();
30812 }
30813 } else {
30814 this.ready = true;
30815 this.body.emitter.emit("fit");
30816 }
30817 }
30818 /**
30819 * Start the simulation
30820 */
30821
30822 }, {
30823 key: "startSimulation",
30824 value: function startSimulation() {
30825 if (this.physicsEnabled === true && this.options.enabled === true) {
30826 this.stabilized = false; // when visible, adaptivity is disabled.
30827
30828 this.adaptiveTimestep = false; // this sets the width of all nodes initially which could be required for the avoidOverlap
30829
30830 this.body.emitter.emit("_resizeNodes");
30831
30832 if (this.viewFunction === undefined) {
30833 var _context;
30834
30835 this.viewFunction = bind$6(_context = this.simulationStep).call(_context, this);
30836 this.body.emitter.on("initRedraw", this.viewFunction);
30837 this.body.emitter.emit("_startRendering");
30838 }
30839 } else {
30840 this.body.emitter.emit("_redraw");
30841 }
30842 }
30843 /**
30844 * Stop the simulation, force stabilization.
30845 *
30846 * @param {boolean} [emit=true]
30847 */
30848
30849 }, {
30850 key: "stopSimulation",
30851 value: function stopSimulation() {
30852 var emit = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
30853 this.stabilized = true;
30854
30855 if (emit === true) {
30856 this._emitStabilized();
30857 }
30858
30859 if (this.viewFunction !== undefined) {
30860 this.body.emitter.off("initRedraw", this.viewFunction);
30861 this.viewFunction = undefined;
30862
30863 if (emit === true) {
30864 this.body.emitter.emit("_stopRendering");
30865 }
30866 }
30867 }
30868 /**
30869 * The viewFunction inserts this step into each render loop. It calls the physics tick and handles the cleanup at stabilized.
30870 *
30871 */
30872
30873 }, {
30874 key: "simulationStep",
30875 value: function simulationStep() {
30876 // check if the physics have settled
30877 var startTime = now$1();
30878
30879 this.physicsTick();
30880 var physicsTime = now$1() - startTime; // run double speed if it is a little graph
30881
30882 if ((physicsTime < 0.4 * this.simulationInterval || this.runDoubleSpeed === true) && this.stabilized === false) {
30883 this.physicsTick(); // this makes sure there is no jitter. The decision is taken once to run it at double speed.
30884
30885 this.runDoubleSpeed = true;
30886 }
30887
30888 if (this.stabilized === true) {
30889 this.stopSimulation();
30890 }
30891 }
30892 /**
30893 * trigger the stabilized event.
30894 *
30895 * @param {number} [amountOfIterations=this.stabilizationIterations]
30896 * @private
30897 */
30898
30899 }, {
30900 key: "_emitStabilized",
30901 value: function _emitStabilized() {
30902 var _this2 = this;
30903
30904 var amountOfIterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.stabilizationIterations;
30905
30906 if (this.stabilizationIterations > 1 || this.startedStabilization === true) {
30907 setTimeout$1(function () {
30908 _this2.body.emitter.emit("stabilized", {
30909 iterations: amountOfIterations
30910 });
30911
30912 _this2.startedStabilization = false;
30913 _this2.stabilizationIterations = 0;
30914 }, 0);
30915 }
30916 }
30917 /**
30918 * Calculate the forces for one physics iteration and move the nodes.
30919 *
30920 * @private
30921 */
30922
30923 }, {
30924 key: "physicsStep",
30925 value: function physicsStep() {
30926 this.gravitySolver.solve();
30927 this.nodesSolver.solve();
30928 this.edgesSolver.solve();
30929 this.moveNodes();
30930 }
30931 /**
30932 * Make dynamic adjustments to the timestep, based on current state.
30933 *
30934 * Helper function for physicsTick().
30935 *
30936 * @private
30937 */
30938
30939 }, {
30940 key: "adjustTimeStep",
30941 value: function adjustTimeStep() {
30942 var factor = 1.2; // Factor for increasing the timestep on success.
30943 // we compare the two steps. if it is acceptable we double the step.
30944
30945 if (this._evaluateStepQuality() === true) {
30946 this.timestep = factor * this.timestep;
30947 } else {
30948 // if not, we decrease the step to a minimum of the options timestep.
30949 // if the decreased timestep is smaller than the options step, we do not reset the counter
30950 // we assume that the options timestep is stable enough.
30951 if (this.timestep / factor < this.options.timestep) {
30952 this.timestep = this.options.timestep;
30953 } else {
30954 // if the timestep was larger than 2 times the option one we check the adaptivity again to ensure
30955 // that large instabilities do not form.
30956 this.adaptiveCounter = -1; // check again next iteration
30957
30958 this.timestep = Math.max(this.options.timestep, this.timestep / factor);
30959 }
30960 }
30961 }
30962 /**
30963 * A single simulation step (or 'tick') in the physics simulation
30964 *
30965 * @private
30966 */
30967
30968 }, {
30969 key: "physicsTick",
30970 value: function physicsTick() {
30971 this._startStabilizing(); // this ensures that there is no start event when the network is already stable.
30972
30973
30974 if (this.stabilized === true) return; // adaptivity means the timestep adapts to the situation, only applicable for stabilization
30975
30976 if (this.adaptiveTimestep === true && this.adaptiveTimestepEnabled === true) {
30977 // timestep remains stable for "interval" iterations.
30978 var doAdaptive = this.adaptiveCounter % this.adaptiveInterval === 0;
30979
30980 if (doAdaptive) {
30981 // first the big step and revert.
30982 this.timestep = 2 * this.timestep;
30983 this.physicsStep();
30984 this.revert(); // saves the reference state
30985 // now the normal step. Since this is the last step, it is the more stable one and we will take this.
30986
30987 this.timestep = 0.5 * this.timestep; // since it's half the step, we do it twice.
30988
30989 this.physicsStep();
30990 this.physicsStep();
30991 this.adjustTimeStep();
30992 } else {
30993 this.physicsStep(); // normal step, keeping timestep constant
30994 }
30995
30996 this.adaptiveCounter += 1;
30997 } else {
30998 // case for the static timestep, we reset it to the one in options and take a normal step.
30999 this.timestep = this.options.timestep;
31000 this.physicsStep();
31001 }
31002
31003 if (this.stabilized === true) this.revert();
31004 this.stabilizationIterations++;
31005 }
31006 /**
31007 * 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.
31008 *
31009 * @private
31010 */
31011
31012 }, {
31013 key: "updatePhysicsData",
31014 value: function updatePhysicsData() {
31015 this.physicsBody.forces = {};
31016 this.physicsBody.physicsNodeIndices = [];
31017 this.physicsBody.physicsEdgeIndices = [];
31018 var nodes = this.body.nodes;
31019 var edges = this.body.edges; // get node indices for physics
31020
31021 for (var nodeId in nodes) {
31022 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
31023 if (nodes[nodeId].options.physics === true) {
31024 this.physicsBody.physicsNodeIndices.push(nodes[nodeId].id);
31025 }
31026 }
31027 } // get edge indices for physics
31028
31029
31030 for (var edgeId in edges) {
31031 if (Object.prototype.hasOwnProperty.call(edges, edgeId)) {
31032 if (edges[edgeId].options.physics === true) {
31033 this.physicsBody.physicsEdgeIndices.push(edges[edgeId].id);
31034 }
31035 }
31036 } // get the velocity and the forces vector
31037
31038
31039 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
31040 var _nodeId = this.physicsBody.physicsNodeIndices[i];
31041 this.physicsBody.forces[_nodeId] = {
31042 x: 0,
31043 y: 0
31044 }; // forces can be reset because they are recalculated. Velocities have to persist.
31045
31046 if (this.physicsBody.velocities[_nodeId] === undefined) {
31047 this.physicsBody.velocities[_nodeId] = {
31048 x: 0,
31049 y: 0
31050 };
31051 }
31052 } // clean deleted nodes from the velocity vector
31053
31054
31055 for (var _nodeId2 in this.physicsBody.velocities) {
31056 if (nodes[_nodeId2] === undefined) {
31057 delete this.physicsBody.velocities[_nodeId2];
31058 }
31059 }
31060 }
31061 /**
31062 * Revert the simulation one step. This is done so after stabilization, every new start of the simulation will also say stabilized.
31063 */
31064
31065 }, {
31066 key: "revert",
31067 value: function revert() {
31068 var nodeIds = keys$4(this.previousStates);
31069
31070 var nodes = this.body.nodes;
31071 var velocities = this.physicsBody.velocities;
31072 this.referenceState = {};
31073
31074 for (var i = 0; i < nodeIds.length; i++) {
31075 var nodeId = nodeIds[i];
31076
31077 if (nodes[nodeId] !== undefined) {
31078 if (nodes[nodeId].options.physics === true) {
31079 this.referenceState[nodeId] = {
31080 positions: {
31081 x: nodes[nodeId].x,
31082 y: nodes[nodeId].y
31083 }
31084 };
31085 velocities[nodeId].x = this.previousStates[nodeId].vx;
31086 velocities[nodeId].y = this.previousStates[nodeId].vy;
31087 nodes[nodeId].x = this.previousStates[nodeId].x;
31088 nodes[nodeId].y = this.previousStates[nodeId].y;
31089 }
31090 } else {
31091 delete this.previousStates[nodeId];
31092 }
31093 }
31094 }
31095 /**
31096 * This compares the reference state to the current state
31097 *
31098 * @returns {boolean}
31099 * @private
31100 */
31101
31102 }, {
31103 key: "_evaluateStepQuality",
31104 value: function _evaluateStepQuality() {
31105 var dx, dy, dpos;
31106 var nodes = this.body.nodes;
31107 var reference = this.referenceState;
31108 var posThreshold = 0.3;
31109
31110 for (var nodeId in this.referenceState) {
31111 if (Object.prototype.hasOwnProperty.call(this.referenceState, nodeId) && nodes[nodeId] !== undefined) {
31112 dx = nodes[nodeId].x - reference[nodeId].positions.x;
31113 dy = nodes[nodeId].y - reference[nodeId].positions.y;
31114 dpos = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
31115
31116 if (dpos > posThreshold) {
31117 return false;
31118 }
31119 }
31120 }
31121
31122 return true;
31123 }
31124 /**
31125 * move the nodes one timestep and check if they are stabilized
31126 */
31127
31128 }, {
31129 key: "moveNodes",
31130 value: function moveNodes() {
31131 var nodeIndices = this.physicsBody.physicsNodeIndices;
31132 var maxNodeVelocity = 0;
31133 var averageNodeVelocity = 0; // the velocity threshold (energy in the system) for the adaptivity toggle
31134
31135 var velocityAdaptiveThreshold = 5;
31136
31137 for (var i = 0; i < nodeIndices.length; i++) {
31138 var nodeId = nodeIndices[i];
31139
31140 var nodeVelocity = this._performStep(nodeId); // stabilized is true if stabilized is true and velocity is smaller than vmin --> all nodes must be stabilized
31141
31142
31143 maxNodeVelocity = Math.max(maxNodeVelocity, nodeVelocity);
31144 averageNodeVelocity += nodeVelocity;
31145 } // evaluating the stabilized and adaptiveTimestepEnabled conditions
31146
31147
31148 this.adaptiveTimestepEnabled = averageNodeVelocity / nodeIndices.length < velocityAdaptiveThreshold;
31149 this.stabilized = maxNodeVelocity < this.options.minVelocity;
31150 }
31151 /**
31152 * Calculate new velocity for a coordinate direction
31153 *
31154 * @param {number} v velocity for current coordinate
31155 * @param {number} f regular force for current coordinate
31156 * @param {number} m mass of current node
31157 * @returns {number} new velocity for current coordinate
31158 * @private
31159 */
31160
31161 }, {
31162 key: "calculateComponentVelocity",
31163 value: function calculateComponentVelocity(v, f, m) {
31164 var df = this.modelOptions.damping * v; // damping force
31165
31166 var a = (f - df) / m; // acceleration
31167
31168 v += a * this.timestep; // Put a limit on the velocities if it is really high
31169
31170 var maxV = this.options.maxVelocity || 1e9;
31171
31172 if (Math.abs(v) > maxV) {
31173 v = v > 0 ? maxV : -maxV;
31174 }
31175
31176 return v;
31177 }
31178 /**
31179 * Perform the actual step
31180 *
31181 * @param {Node.id} nodeId
31182 * @returns {number} the new velocity of given node
31183 * @private
31184 */
31185
31186 }, {
31187 key: "_performStep",
31188 value: function _performStep(nodeId) {
31189 var node = this.body.nodes[nodeId];
31190 var force = this.physicsBody.forces[nodeId];
31191
31192 if (this.options.wind) {
31193 force.x += this.options.wind.x;
31194 force.y += this.options.wind.y;
31195 }
31196
31197 var velocity = this.physicsBody.velocities[nodeId]; // store the state so we can revert
31198
31199 this.previousStates[nodeId] = {
31200 x: node.x,
31201 y: node.y,
31202 vx: velocity.x,
31203 vy: velocity.y
31204 };
31205
31206 if (node.options.fixed.x === false) {
31207 velocity.x = this.calculateComponentVelocity(velocity.x, force.x, node.options.mass);
31208 node.x += velocity.x * this.timestep;
31209 } else {
31210 force.x = 0;
31211 velocity.x = 0;
31212 }
31213
31214 if (node.options.fixed.y === false) {
31215 velocity.y = this.calculateComponentVelocity(velocity.y, force.y, node.options.mass);
31216 node.y += velocity.y * this.timestep;
31217 } else {
31218 force.y = 0;
31219 velocity.y = 0;
31220 }
31221
31222 var totalVelocity = Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(velocity.y, 2));
31223 return totalVelocity;
31224 }
31225 /**
31226 * When initializing and stabilizing, we can freeze nodes with a predefined position.
31227 * This greatly speeds up stabilization because only the supportnodes for the smoothCurves have to settle.
31228 *
31229 * @private
31230 */
31231
31232 }, {
31233 key: "_freezeNodes",
31234 value: function _freezeNodes() {
31235 var nodes = this.body.nodes;
31236
31237 for (var id in nodes) {
31238 if (Object.prototype.hasOwnProperty.call(nodes, id)) {
31239 if (nodes[id].x && nodes[id].y) {
31240 var fixed = nodes[id].options.fixed;
31241 this.freezeCache[id] = {
31242 x: fixed.x,
31243 y: fixed.y
31244 };
31245 fixed.x = true;
31246 fixed.y = true;
31247 }
31248 }
31249 }
31250 }
31251 /**
31252 * Unfreezes the nodes that have been frozen by _freezeDefinedNodes.
31253 *
31254 * @private
31255 */
31256
31257 }, {
31258 key: "_restoreFrozenNodes",
31259 value: function _restoreFrozenNodes() {
31260 var nodes = this.body.nodes;
31261
31262 for (var id in nodes) {
31263 if (Object.prototype.hasOwnProperty.call(nodes, id)) {
31264 if (this.freezeCache[id] !== undefined) {
31265 nodes[id].options.fixed.x = this.freezeCache[id].x;
31266 nodes[id].options.fixed.y = this.freezeCache[id].y;
31267 }
31268 }
31269 }
31270
31271 this.freezeCache = {};
31272 }
31273 /**
31274 * Find a stable position for all nodes
31275 *
31276 * @param {number} [iterations=this.options.stabilization.iterations]
31277 */
31278
31279 }, {
31280 key: "stabilize",
31281 value: function stabilize() {
31282 var _this3 = this;
31283
31284 var iterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.stabilization.iterations;
31285
31286 if (typeof iterations !== "number") {
31287 iterations = this.options.stabilization.iterations;
31288 console.error("The stabilize method needs a numeric amount of iterations. Switching to default: ", iterations);
31289 }
31290
31291 if (this.physicsBody.physicsNodeIndices.length === 0) {
31292 this.ready = true;
31293 return;
31294 } // enable adaptive timesteps
31295
31296
31297 this.adaptiveTimestep = this.options.adaptiveTimestep; // this sets the width of all nodes initially which could be required for the avoidOverlap
31298
31299 this.body.emitter.emit("_resizeNodes");
31300 this.stopSimulation(); // stop the render loop
31301
31302 this.stabilized = false; // block redraw requests
31303
31304 this.body.emitter.emit("_blockRedraw");
31305 this.targetIterations = iterations; // start the stabilization
31306
31307 if (this.options.stabilization.onlyDynamicEdges === true) {
31308 this._freezeNodes();
31309 }
31310
31311 this.stabilizationIterations = 0;
31312
31313 setTimeout$1(function () {
31314 return _this3._stabilizationBatch();
31315 }, 0);
31316 }
31317 /**
31318 * If not already stabilizing, start it and emit a start event.
31319 *
31320 * @returns {boolean} true if stabilization started with this call
31321 * @private
31322 */
31323
31324 }, {
31325 key: "_startStabilizing",
31326 value: function _startStabilizing() {
31327 if (this.startedStabilization === true) return false;
31328 this.body.emitter.emit("startStabilizing");
31329 this.startedStabilization = true;
31330 return true;
31331 }
31332 /**
31333 * One batch of stabilization
31334 *
31335 * @private
31336 */
31337
31338 }, {
31339 key: "_stabilizationBatch",
31340 value: function _stabilizationBatch() {
31341 var _this4 = this;
31342
31343 var running = function running() {
31344 return _this4.stabilized === false && _this4.stabilizationIterations < _this4.targetIterations;
31345 };
31346
31347 var sendProgress = function sendProgress() {
31348 _this4.body.emitter.emit("stabilizationProgress", {
31349 iterations: _this4.stabilizationIterations,
31350 total: _this4.targetIterations
31351 });
31352 };
31353
31354 if (this._startStabilizing()) {
31355 sendProgress(); // Ensure that there is at least one start event.
31356 }
31357
31358 var count = 0;
31359
31360 while (running() && count < this.options.stabilization.updateInterval) {
31361 this.physicsTick();
31362 count++;
31363 }
31364
31365 sendProgress();
31366
31367 if (running()) {
31368 var _context2;
31369
31370 setTimeout$1(bind$6(_context2 = this._stabilizationBatch).call(_context2, this), 0);
31371 } else {
31372 this._finalizeStabilization();
31373 }
31374 }
31375 /**
31376 * Wrap up the stabilization, fit and emit the events.
31377 *
31378 * @private
31379 */
31380
31381 }, {
31382 key: "_finalizeStabilization",
31383 value: function _finalizeStabilization() {
31384 this.body.emitter.emit("_allowRedraw");
31385
31386 if (this.options.stabilization.fit === true) {
31387 this.body.emitter.emit("fit");
31388 }
31389
31390 if (this.options.stabilization.onlyDynamicEdges === true) {
31391 this._restoreFrozenNodes();
31392 }
31393
31394 this.body.emitter.emit("stabilizationIterationsDone");
31395 this.body.emitter.emit("_requestRedraw");
31396
31397 if (this.stabilized === true) {
31398 this._emitStabilized();
31399 } else {
31400 this.startSimulation();
31401 }
31402
31403 this.ready = true;
31404 } //--------------------------- DEBUGGING BELOW ---------------------------//
31405
31406 /**
31407 * Debug function that display arrows for the forces currently active in the network.
31408 *
31409 * Use this when debugging only.
31410 *
31411 * @param {CanvasRenderingContext2D} ctx
31412 * @private
31413 */
31414
31415 }, {
31416 key: "_drawForces",
31417 value: function _drawForces(ctx) {
31418 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
31419 var index = this.physicsBody.physicsNodeIndices[i];
31420 var node = this.body.nodes[index];
31421 var force = this.physicsBody.forces[index];
31422 var factor = 20;
31423 var colorFactor = 0.03;
31424 var forceSize = Math.sqrt(Math.pow(force.x, 2) + Math.pow(force.x, 2));
31425 var size = Math.min(Math.max(5, forceSize), 15);
31426 var arrowSize = 3 * size;
31427 var color = HSVToHex((180 - Math.min(1, Math.max(0, colorFactor * forceSize)) * 180) / 360, 1, 1);
31428 var point = {
31429 x: node.x + factor * force.x,
31430 y: node.y + factor * force.y
31431 };
31432 ctx.lineWidth = size;
31433 ctx.strokeStyle = color;
31434 ctx.beginPath();
31435 ctx.moveTo(node.x, node.y);
31436 ctx.lineTo(point.x, point.y);
31437 ctx.stroke();
31438 var angle = Math.atan2(force.y, force.x);
31439 ctx.fillStyle = color;
31440 EndPoints.draw(ctx, {
31441 type: "arrow",
31442 point: point,
31443 angle: angle,
31444 length: arrowSize
31445 });
31446
31447 fill(ctx).call(ctx);
31448 }
31449 }
31450 }]);
31451
31452 return PhysicsEngine;
31453 }();
31454
31455 /**
31456 * Utility Class
31457 */
31458
31459 var NetworkUtil = /*#__PURE__*/function () {
31460 /**
31461 * @ignore
31462 */
31463 function NetworkUtil() {
31464 _classCallCheck(this, NetworkUtil);
31465 }
31466 /**
31467 * Find the center position of the network considering the bounding boxes
31468 *
31469 * @param {Array.<Node>} allNodes
31470 * @param {Array.<Node>} [specificNodes=[]]
31471 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
31472 * @static
31473 */
31474
31475
31476 _createClass(NetworkUtil, null, [{
31477 key: "getRange",
31478 value: function getRange(allNodes) {
31479 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
31480 var minY = 1e9,
31481 maxY = -1e9,
31482 minX = 1e9,
31483 maxX = -1e9,
31484 node;
31485
31486 if (specificNodes.length > 0) {
31487 for (var i = 0; i < specificNodes.length; i++) {
31488 node = allNodes[specificNodes[i]];
31489
31490 if (minX > node.shape.boundingBox.left) {
31491 minX = node.shape.boundingBox.left;
31492 }
31493
31494 if (maxX < node.shape.boundingBox.right) {
31495 maxX = node.shape.boundingBox.right;
31496 }
31497
31498 if (minY > node.shape.boundingBox.top) {
31499 minY = node.shape.boundingBox.top;
31500 } // top is negative, bottom is positive
31501
31502
31503 if (maxY < node.shape.boundingBox.bottom) {
31504 maxY = node.shape.boundingBox.bottom;
31505 } // top is negative, bottom is positive
31506
31507 }
31508 }
31509
31510 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
31511 minY = 0, maxY = 0, minX = 0, maxX = 0;
31512 }
31513
31514 return {
31515 minX: minX,
31516 maxX: maxX,
31517 minY: minY,
31518 maxY: maxY
31519 };
31520 }
31521 /**
31522 * Find the center position of the network
31523 *
31524 * @param {Array.<Node>} allNodes
31525 * @param {Array.<Node>} [specificNodes=[]]
31526 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
31527 * @static
31528 */
31529
31530 }, {
31531 key: "getRangeCore",
31532 value: function getRangeCore(allNodes) {
31533 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
31534 var minY = 1e9,
31535 maxY = -1e9,
31536 minX = 1e9,
31537 maxX = -1e9,
31538 node;
31539
31540 if (specificNodes.length > 0) {
31541 for (var i = 0; i < specificNodes.length; i++) {
31542 node = allNodes[specificNodes[i]];
31543
31544 if (minX > node.x) {
31545 minX = node.x;
31546 }
31547
31548 if (maxX < node.x) {
31549 maxX = node.x;
31550 }
31551
31552 if (minY > node.y) {
31553 minY = node.y;
31554 } // top is negative, bottom is positive
31555
31556
31557 if (maxY < node.y) {
31558 maxY = node.y;
31559 } // top is negative, bottom is positive
31560
31561 }
31562 }
31563
31564 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
31565 minY = 0, maxY = 0, minX = 0, maxX = 0;
31566 }
31567
31568 return {
31569 minX: minX,
31570 maxX: maxX,
31571 minY: minY,
31572 maxY: maxY
31573 };
31574 }
31575 /**
31576 * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY};
31577 * @returns {{x: number, y: number}}
31578 * @static
31579 */
31580
31581 }, {
31582 key: "findCenter",
31583 value: function findCenter(range) {
31584 return {
31585 x: 0.5 * (range.maxX + range.minX),
31586 y: 0.5 * (range.maxY + range.minY)
31587 };
31588 }
31589 /**
31590 * 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.
31591 *
31592 * @param {vis.Item} item
31593 * @param {'node'|undefined} type
31594 * @returns {{}}
31595 * @static
31596 */
31597
31598 }, {
31599 key: "cloneOptions",
31600 value: function cloneOptions(item, type) {
31601 var clonedOptions = {};
31602
31603 if (type === undefined || type === "node") {
31604 deepExtend(clonedOptions, item.options, true);
31605 clonedOptions.x = item.x;
31606 clonedOptions.y = item.y;
31607 clonedOptions.amountOfConnections = item.edges.length;
31608 } else {
31609 deepExtend(clonedOptions, item.options, true);
31610 }
31611
31612 return clonedOptions;
31613 }
31614 }]);
31615
31616 return NetworkUtil;
31617 }();
31618
31619 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); }; }
31620
31621 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; } }
31622 /**
31623 * A Cluster is a special Node that allows a group of Nodes positioned closely together
31624 * to be represented by a single Cluster Node.
31625 *
31626 * @augments Node
31627 */
31628
31629 var Cluster = /*#__PURE__*/function (_Node) {
31630 _inherits(Cluster, _Node);
31631
31632 var _super = _createSuper$1(Cluster);
31633
31634 /**
31635 * @param {object} options
31636 * @param {object} body
31637 * @param {Array.<HTMLImageElement>}imagelist
31638 * @param {Array} grouplist
31639 * @param {object} globalOptions
31640 * @param {object} defaultOptions Global default options for nodes
31641 */
31642 function Cluster(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
31643 var _this;
31644
31645 _classCallCheck(this, Cluster);
31646
31647 _this = _super.call(this, options, body, imagelist, grouplist, globalOptions, defaultOptions);
31648 _this.isCluster = true;
31649 _this.containedNodes = {};
31650 _this.containedEdges = {};
31651 return _this;
31652 }
31653 /**
31654 * Transfer child cluster data to current and disconnect the child cluster.
31655 *
31656 * Please consult the header comment in 'Clustering.js' for the fields set here.
31657 *
31658 * @param {string|number} childClusterId id of child cluster to open
31659 */
31660
31661
31662 _createClass(Cluster, [{
31663 key: "_openChildCluster",
31664 value: function _openChildCluster(childClusterId) {
31665 var _this2 = this;
31666
31667 var childCluster = this.body.nodes[childClusterId];
31668
31669 if (this.containedNodes[childClusterId] === undefined) {
31670 throw new Error("node with id: " + childClusterId + " not in current cluster");
31671 }
31672
31673 if (!childCluster.isCluster) {
31674 throw new Error("node with id: " + childClusterId + " is not a cluster");
31675 } // Disconnect child cluster from current cluster
31676
31677
31678 delete this.containedNodes[childClusterId];
31679 forEach$1(childCluster.edges, function (edge) {
31680 delete _this2.containedEdges[edge.id];
31681 }); // Transfer nodes and edges
31682
31683 forEach$1(childCluster.containedNodes, function (node, nodeId) {
31684 _this2.containedNodes[nodeId] = node;
31685 });
31686 childCluster.containedNodes = {};
31687 forEach$1(childCluster.containedEdges, function (edge, edgeId) {
31688 _this2.containedEdges[edgeId] = edge;
31689 });
31690 childCluster.containedEdges = {}; // Transfer edges within cluster edges which are clustered
31691
31692 forEach$1(childCluster.edges, function (clusterEdge) {
31693 forEach$1(_this2.edges, function (parentClusterEdge) {
31694 var _context, _context2;
31695
31696 // Assumption: a clustered edge can only be present in a single clustering edge
31697 // Not tested here
31698 var index = indexOf(_context = parentClusterEdge.clusteringEdgeReplacingIds).call(_context, clusterEdge.id);
31699
31700 if (index === -1) return;
31701 forEach$1(clusterEdge.clusteringEdgeReplacingIds, function (srcId) {
31702 parentClusterEdge.clusteringEdgeReplacingIds.push(srcId); // Maintain correct bookkeeping for transferred edge
31703
31704 _this2.body.edges[srcId].edgeReplacedById = parentClusterEdge.id;
31705 }); // Remove cluster edge from parent cluster edge
31706
31707 splice$1(_context2 = parentClusterEdge.clusteringEdgeReplacingIds).call(_context2, index, 1);
31708 });
31709 });
31710 childCluster.edges = [];
31711 }
31712 }]);
31713
31714 return Cluster;
31715 }(Node);
31716
31717 /**
31718 * The clustering engine
31719 */
31720
31721 var ClusterEngine = /*#__PURE__*/function () {
31722 /**
31723 * @param {object} body
31724 */
31725 function ClusterEngine(body) {
31726 var _this = this;
31727
31728 _classCallCheck(this, ClusterEngine);
31729
31730 this.body = body;
31731 this.clusteredNodes = {}; // key: node id, value: { clusterId: <id of cluster>, node: <node instance>}
31732
31733 this.clusteredEdges = {}; // key: edge id, value: restore information for given edge
31734
31735 this.options = {};
31736 this.defaultOptions = {};
31737
31738 assign$2(this.options, this.defaultOptions);
31739
31740 this.body.emitter.on("_resetData", function () {
31741 _this.clusteredNodes = {};
31742 _this.clusteredEdges = {};
31743 });
31744 }
31745 /**
31746 *
31747 * @param {number} hubsize
31748 * @param {object} options
31749 */
31750
31751
31752 _createClass(ClusterEngine, [{
31753 key: "clusterByHubsize",
31754 value: function clusterByHubsize(hubsize, options) {
31755 if (hubsize === undefined) {
31756 hubsize = this._getHubSize();
31757 } else if (_typeof(hubsize) === "object") {
31758 options = this._checkOptions(hubsize);
31759 hubsize = this._getHubSize();
31760 }
31761
31762 var nodesToCluster = [];
31763
31764 for (var i = 0; i < this.body.nodeIndices.length; i++) {
31765 var node = this.body.nodes[this.body.nodeIndices[i]];
31766
31767 if (node.edges.length >= hubsize) {
31768 nodesToCluster.push(node.id);
31769 }
31770 }
31771
31772 for (var _i = 0; _i < nodesToCluster.length; _i++) {
31773 this.clusterByConnection(nodesToCluster[_i], options, true);
31774 }
31775
31776 this.body.emitter.emit("_dataChanged");
31777 }
31778 /**
31779 * loop over all nodes, check if they adhere to the condition and cluster if needed.
31780 *
31781 * @param {object} options
31782 * @param {boolean} [refreshData=true]
31783 */
31784
31785 }, {
31786 key: "cluster",
31787 value: function cluster() {
31788 var _this2 = this;
31789
31790 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
31791 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
31792
31793 if (options.joinCondition === undefined) {
31794 throw new Error("Cannot call clusterByNodeData without a joinCondition function in the options.");
31795 } // check if the options object is fine, append if needed
31796
31797
31798 options = this._checkOptions(options);
31799 var childNodesObj = {};
31800 var childEdgesObj = {}; // collect the nodes that will be in the cluster
31801
31802 forEach$1(this.body.nodes, function (node, nodeId) {
31803 if (node.options && options.joinCondition(node.options) === true) {
31804 childNodesObj[nodeId] = node; // collect the edges that will be in the cluster
31805
31806 forEach$1(node.edges, function (edge) {
31807 if (_this2.clusteredEdges[edge.id] === undefined) {
31808 childEdgesObj[edge.id] = edge;
31809 }
31810 });
31811 }
31812 });
31813
31814 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
31815 }
31816 /**
31817 * Cluster all nodes in the network that have only X edges
31818 *
31819 * @param {number} edgeCount
31820 * @param {object} options
31821 * @param {boolean} [refreshData=true]
31822 */
31823
31824 }, {
31825 key: "clusterByEdgeCount",
31826 value: function clusterByEdgeCount(edgeCount, options) {
31827 var _this3 = this;
31828
31829 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
31830 options = this._checkOptions(options);
31831 var clusters = [];
31832 var usedNodes = {};
31833 var edge, edges, relevantEdgeCount; // collect the nodes that will be in the cluster
31834
31835 var _loop = function _loop(i) {
31836 var childNodesObj = {};
31837 var childEdgesObj = {};
31838 var nodeId = _this3.body.nodeIndices[i];
31839 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.
31840
31841 if (usedNodes[nodeId] === undefined) {
31842 relevantEdgeCount = 0;
31843 edges = [];
31844
31845 for (var j = 0; j < node.edges.length; j++) {
31846 edge = node.edges[j];
31847
31848 if (_this3.clusteredEdges[edge.id] === undefined) {
31849 if (edge.toId !== edge.fromId) {
31850 relevantEdgeCount++;
31851 }
31852
31853 edges.push(edge);
31854 }
31855 } // this node qualifies, we collect its neighbours to start the clustering process.
31856
31857
31858 if (relevantEdgeCount === edgeCount) {
31859 var checkJoinCondition = function checkJoinCondition(node) {
31860 if (options.joinCondition === undefined || options.joinCondition === null) {
31861 return true;
31862 }
31863
31864 var clonedOptions = NetworkUtil.cloneOptions(node);
31865 return options.joinCondition(clonedOptions);
31866 };
31867
31868 var gatheringSuccessful = true;
31869
31870 for (var _j = 0; _j < edges.length; _j++) {
31871 edge = edges[_j];
31872
31873 var childNodeId = _this3._getConnectedId(edge, nodeId); // add the nodes to the list by the join condition.
31874
31875
31876 if (checkJoinCondition(node)) {
31877 childEdgesObj[edge.id] = edge;
31878 childNodesObj[nodeId] = node;
31879 childNodesObj[childNodeId] = _this3.body.nodes[childNodeId];
31880 usedNodes[nodeId] = true;
31881 } else {
31882 // this node does not qualify after all.
31883 gatheringSuccessful = false;
31884 break;
31885 }
31886 } // add to the cluster queue
31887
31888
31889 if (keys$4(childNodesObj).length > 0 && keys$4(childEdgesObj).length > 0 && gatheringSuccessful === true) {
31890 /**
31891 * Search for cluster data that contains any of the node id's
31892 *
31893 * @returns {boolean} true if no joinCondition, otherwise return value of joinCondition
31894 */
31895 var findClusterData = function findClusterData() {
31896 for (var n = 0; n < clusters.length; ++n) {
31897 // Search for a cluster containing any of the node id's
31898 for (var m in childNodesObj) {
31899 if (clusters[n].nodes[m] !== undefined) {
31900 return clusters[n];
31901 }
31902 }
31903 }
31904
31905 return undefined;
31906 }; // If any of the found nodes is part of a cluster found in this method,
31907 // add the current values to that cluster
31908
31909
31910 var foundCluster = findClusterData();
31911
31912 if (foundCluster !== undefined) {
31913 // Add nodes to found cluster if not present
31914 for (var m in childNodesObj) {
31915 if (foundCluster.nodes[m] === undefined) {
31916 foundCluster.nodes[m] = childNodesObj[m];
31917 }
31918 } // Add edges to found cluster, if not present
31919
31920
31921 for (var _m in childEdgesObj) {
31922 if (foundCluster.edges[_m] === undefined) {
31923 foundCluster.edges[_m] = childEdgesObj[_m];
31924 }
31925 }
31926 } else {
31927 // Create a new cluster group
31928 clusters.push({
31929 nodes: childNodesObj,
31930 edges: childEdgesObj
31931 });
31932 }
31933 }
31934 }
31935 }
31936 };
31937
31938 for (var i = 0; i < this.body.nodeIndices.length; i++) {
31939 _loop(i);
31940 }
31941
31942 for (var _i2 = 0; _i2 < clusters.length; _i2++) {
31943 this._cluster(clusters[_i2].nodes, clusters[_i2].edges, options, false);
31944 }
31945
31946 if (refreshData === true) {
31947 this.body.emitter.emit("_dataChanged");
31948 }
31949 }
31950 /**
31951 * Cluster all nodes in the network that have only 1 edge
31952 *
31953 * @param {object} options
31954 * @param {boolean} [refreshData=true]
31955 */
31956
31957 }, {
31958 key: "clusterOutliers",
31959 value: function clusterOutliers(options) {
31960 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
31961 this.clusterByEdgeCount(1, options, refreshData);
31962 }
31963 /**
31964 * Cluster all nodes in the network that have only 2 edge
31965 *
31966 * @param {object} options
31967 * @param {boolean} [refreshData=true]
31968 */
31969
31970 }, {
31971 key: "clusterBridges",
31972 value: function clusterBridges(options) {
31973 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
31974 this.clusterByEdgeCount(2, options, refreshData);
31975 }
31976 /**
31977 * suck all connected nodes of a node into the node.
31978 *
31979 * @param {Node.id} nodeId
31980 * @param {object} options
31981 * @param {boolean} [refreshData=true]
31982 */
31983
31984 }, {
31985 key: "clusterByConnection",
31986 value: function clusterByConnection(nodeId, options) {
31987 var _context;
31988
31989 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
31990
31991 // kill conditions
31992 if (nodeId === undefined) {
31993 throw new Error("No nodeId supplied to clusterByConnection!");
31994 }
31995
31996 if (this.body.nodes[nodeId] === undefined) {
31997 throw new Error("The nodeId given to clusterByConnection does not exist!");
31998 }
31999
32000 var node = this.body.nodes[nodeId];
32001 options = this._checkOptions(options, node);
32002
32003 if (options.clusterNodeProperties.x === undefined) {
32004 options.clusterNodeProperties.x = node.x;
32005 }
32006
32007 if (options.clusterNodeProperties.y === undefined) {
32008 options.clusterNodeProperties.y = node.y;
32009 }
32010
32011 if (options.clusterNodeProperties.fixed === undefined) {
32012 options.clusterNodeProperties.fixed = {};
32013 options.clusterNodeProperties.fixed.x = node.options.fixed.x;
32014 options.clusterNodeProperties.fixed.y = node.options.fixed.y;
32015 }
32016
32017 var childNodesObj = {};
32018 var childEdgesObj = {};
32019 var parentNodeId = node.id;
32020 var parentClonedOptions = NetworkUtil.cloneOptions(node);
32021 childNodesObj[parentNodeId] = node; // collect the nodes that will be in the cluster
32022
32023 for (var i = 0; i < node.edges.length; i++) {
32024 var edge = node.edges[i];
32025
32026 if (this.clusteredEdges[edge.id] === undefined) {
32027 var childNodeId = this._getConnectedId(edge, parentNodeId); // if the child node is not in a cluster
32028
32029
32030 if (this.clusteredNodes[childNodeId] === undefined) {
32031 if (childNodeId !== parentNodeId) {
32032 if (options.joinCondition === undefined) {
32033 childEdgesObj[edge.id] = edge;
32034 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
32035 } else {
32036 // clone the options and insert some additional parameters that could be interesting.
32037 var childClonedOptions = NetworkUtil.cloneOptions(this.body.nodes[childNodeId]);
32038
32039 if (options.joinCondition(parentClonedOptions, childClonedOptions) === true) {
32040 childEdgesObj[edge.id] = edge;
32041 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
32042 }
32043 }
32044 } else {
32045 // swallow the edge if it is self-referencing.
32046 childEdgesObj[edge.id] = edge;
32047 }
32048 }
32049 }
32050 }
32051
32052 var childNodeIDs = map$3(_context = keys$4(childNodesObj)).call(_context, function (childNode) {
32053 return childNodesObj[childNode].id;
32054 });
32055
32056 for (var childNodeKey in childNodesObj) {
32057 if (!Object.prototype.hasOwnProperty.call(childNodesObj, childNodeKey)) continue;
32058 var childNode = childNodesObj[childNodeKey];
32059
32060 for (var y = 0; y < childNode.edges.length; y++) {
32061 var childEdge = childNode.edges[y];
32062
32063 if (indexOf(childNodeIDs).call(childNodeIDs, this._getConnectedId(childEdge, childNode.id)) > -1) {
32064 childEdgesObj[childEdge.id] = childEdge;
32065 }
32066 }
32067 }
32068
32069 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
32070 }
32071 /**
32072 * This function creates the edges that will be attached to the cluster
32073 * It looks for edges that are connected to the nodes from the "outside' of the cluster.
32074 *
32075 * @param {{Node.id: vis.Node}} childNodesObj
32076 * @param {{vis.Edge.id: vis.Edge}} childEdgesObj
32077 * @param {object} clusterNodeProperties
32078 * @param {object} clusterEdgeProperties
32079 * @private
32080 */
32081
32082 }, {
32083 key: "_createClusterEdges",
32084 value: function _createClusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, clusterEdgeProperties) {
32085 var edge, childNodeId, childNode, toId, fromId, otherNodeId; // loop over all child nodes and their edges to find edges going out of the cluster
32086 // these edges will be replaced by clusterEdges.
32087
32088 var childKeys = keys$4(childNodesObj);
32089
32090 var createEdges = [];
32091
32092 for (var i = 0; i < childKeys.length; i++) {
32093 childNodeId = childKeys[i];
32094 childNode = childNodesObj[childNodeId]; // construct new edges from the cluster to others
32095
32096 for (var j = 0; j < childNode.edges.length; j++) {
32097 edge = childNode.edges[j]; // we only handle edges that are visible to the system, not the disabled ones from the clustering process.
32098
32099 if (this.clusteredEdges[edge.id] === undefined) {
32100 // self-referencing edges will be added to the "hidden" list
32101 if (edge.toId == edge.fromId) {
32102 childEdgesObj[edge.id] = edge;
32103 } else {
32104 // set up the from and to.
32105 if (edge.toId == childNodeId) {
32106 // this is a double equals because ints and strings can be interchanged here.
32107 toId = clusterNodeProperties.id;
32108 fromId = edge.fromId;
32109 otherNodeId = fromId;
32110 } else {
32111 toId = edge.toId;
32112 fromId = clusterNodeProperties.id;
32113 otherNodeId = toId;
32114 }
32115 } // Only edges from the cluster outwards are being replaced.
32116
32117
32118 if (childNodesObj[otherNodeId] === undefined) {
32119 createEdges.push({
32120 edge: edge,
32121 fromId: fromId,
32122 toId: toId
32123 });
32124 }
32125 }
32126 }
32127 } //
32128 // Here we actually create the replacement edges.
32129 //
32130 // We could not do this in the loop above as the creation process
32131 // would add an edge to the edges array we are iterating over.
32132 //
32133 // NOTE: a clustered edge can have multiple base edges!
32134 //
32135
32136
32137 var newEdges = [];
32138 /**
32139 * Find a cluster edge which matches the given created edge.
32140 *
32141 * @param {vis.Edge} createdEdge
32142 * @returns {vis.Edge}
32143 */
32144
32145 var getNewEdge = function getNewEdge(createdEdge) {
32146 for (var _j2 = 0; _j2 < newEdges.length; _j2++) {
32147 var newEdge = newEdges[_j2]; // We replace both to and from edges with a single cluster edge
32148
32149 var matchToDirection = createdEdge.fromId === newEdge.fromId && createdEdge.toId === newEdge.toId;
32150 var matchFromDirection = createdEdge.fromId === newEdge.toId && createdEdge.toId === newEdge.fromId;
32151
32152 if (matchToDirection || matchFromDirection) {
32153 return newEdge;
32154 }
32155 }
32156
32157 return null;
32158 };
32159
32160 for (var _j3 = 0; _j3 < createEdges.length; _j3++) {
32161 var createdEdge = createEdges[_j3];
32162 var _edge = createdEdge.edge;
32163 var newEdge = getNewEdge(createdEdge);
32164
32165 if (newEdge === null) {
32166 // Create a clustered edge for this connection
32167 newEdge = this._createClusteredEdge(createdEdge.fromId, createdEdge.toId, _edge, clusterEdgeProperties);
32168 newEdges.push(newEdge);
32169 } else {
32170 newEdge.clusteringEdgeReplacingIds.push(_edge.id);
32171 } // also reference the new edge in the old edge
32172
32173
32174 this.body.edges[_edge.id].edgeReplacedById = newEdge.id; // hide the replaced edge
32175
32176 this._backupEdgeOptions(_edge);
32177
32178 _edge.setOptions({
32179 physics: false
32180 });
32181 }
32182 }
32183 /**
32184 * This function checks the options that can be supplied to the different cluster functions
32185 * for certain fields and inserts defaults if needed
32186 *
32187 * @param {object} options
32188 * @returns {*}
32189 * @private
32190 */
32191
32192 }, {
32193 key: "_checkOptions",
32194 value: function _checkOptions() {
32195 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
32196
32197 if (options.clusterEdgeProperties === undefined) {
32198 options.clusterEdgeProperties = {};
32199 }
32200
32201 if (options.clusterNodeProperties === undefined) {
32202 options.clusterNodeProperties = {};
32203 }
32204
32205 return options;
32206 }
32207 /**
32208 *
32209 * @param {object} childNodesObj | object with node objects, id as keys, same as childNodes except it also contains a source node
32210 * @param {object} childEdgesObj | object with edge objects, id as keys
32211 * @param {Array} options | object with {clusterNodeProperties, clusterEdgeProperties, processProperties}
32212 * @param {boolean} refreshData | when true, do not wrap up
32213 * @private
32214 */
32215
32216 }, {
32217 key: "_cluster",
32218 value: function _cluster(childNodesObj, childEdgesObj, options) {
32219 var refreshData = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
32220 // Remove nodes which are already clustered
32221 var tmpNodesToRemove = [];
32222
32223 for (var nodeId in childNodesObj) {
32224 if (Object.prototype.hasOwnProperty.call(childNodesObj, nodeId)) {
32225 if (this.clusteredNodes[nodeId] !== undefined) {
32226 tmpNodesToRemove.push(nodeId);
32227 }
32228 }
32229 }
32230
32231 for (var n = 0; n < tmpNodesToRemove.length; ++n) {
32232 delete childNodesObj[tmpNodesToRemove[n]];
32233 } // kill condition: no nodes don't bother
32234
32235
32236 if (keys$4(childNodesObj).length == 0) {
32237 return;
32238 } // allow clusters of 1 if options allow
32239
32240
32241 if (keys$4(childNodesObj).length == 1 && options.clusterNodeProperties.allowSingleNodeCluster != true) {
32242 return;
32243 }
32244
32245 var clusterNodeProperties = deepExtend({}, options.clusterNodeProperties); // construct the clusterNodeProperties
32246
32247 if (options.processProperties !== undefined) {
32248 // get the childNode options
32249 var childNodesOptions = [];
32250
32251 for (var _nodeId in childNodesObj) {
32252 if (Object.prototype.hasOwnProperty.call(childNodesObj, _nodeId)) {
32253 var clonedOptions = NetworkUtil.cloneOptions(childNodesObj[_nodeId]);
32254 childNodesOptions.push(clonedOptions);
32255 }
32256 } // get cluster properties based on childNodes
32257
32258
32259 var childEdgesOptions = [];
32260
32261 for (var edgeId in childEdgesObj) {
32262 if (Object.prototype.hasOwnProperty.call(childEdgesObj, edgeId)) {
32263 // these cluster edges will be removed on creation of the cluster.
32264 if (edgeId.substr(0, 12) !== "clusterEdge:") {
32265 var _clonedOptions = NetworkUtil.cloneOptions(childEdgesObj[edgeId], "edge");
32266
32267 childEdgesOptions.push(_clonedOptions);
32268 }
32269 }
32270 }
32271
32272 clusterNodeProperties = options.processProperties(clusterNodeProperties, childNodesOptions, childEdgesOptions);
32273
32274 if (!clusterNodeProperties) {
32275 throw new Error("The processProperties function does not return properties!");
32276 }
32277 } // check if we have an unique id;
32278
32279
32280 if (clusterNodeProperties.id === undefined) {
32281 clusterNodeProperties.id = "cluster:" + v4();
32282 }
32283
32284 var clusterId = clusterNodeProperties.id;
32285
32286 if (clusterNodeProperties.label === undefined) {
32287 clusterNodeProperties.label = "cluster";
32288 } // give the clusterNode a position if it does not have one.
32289
32290
32291 var pos = undefined;
32292
32293 if (clusterNodeProperties.x === undefined) {
32294 pos = this._getClusterPosition(childNodesObj);
32295 clusterNodeProperties.x = pos.x;
32296 }
32297
32298 if (clusterNodeProperties.y === undefined) {
32299 if (pos === undefined) {
32300 pos = this._getClusterPosition(childNodesObj);
32301 }
32302
32303 clusterNodeProperties.y = pos.y;
32304 } // force the ID to remain the same
32305
32306
32307 clusterNodeProperties.id = clusterId; // create the cluster Node
32308 // Note that allowSingleNodeCluster, if present, is stored in the options as well
32309
32310 var clusterNode = this.body.functions.createNode(clusterNodeProperties, Cluster);
32311 clusterNode.containedNodes = childNodesObj;
32312 clusterNode.containedEdges = childEdgesObj; // cache a copy from the cluster edge properties if we have to reconnect others later on
32313
32314 clusterNode.clusterEdgeProperties = options.clusterEdgeProperties; // finally put the cluster node into global
32315
32316 this.body.nodes[clusterNodeProperties.id] = clusterNode;
32317
32318 this._clusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, options.clusterEdgeProperties); // set ID to undefined so no duplicates arise
32319
32320
32321 clusterNodeProperties.id = undefined; // wrap up
32322
32323 if (refreshData === true) {
32324 this.body.emitter.emit("_dataChanged");
32325 }
32326 }
32327 /**
32328 *
32329 * @param {Edge} edge
32330 * @private
32331 */
32332
32333 }, {
32334 key: "_backupEdgeOptions",
32335 value: function _backupEdgeOptions(edge) {
32336 if (this.clusteredEdges[edge.id] === undefined) {
32337 this.clusteredEdges[edge.id] = {
32338 physics: edge.options.physics
32339 };
32340 }
32341 }
32342 /**
32343 *
32344 * @param {Edge} edge
32345 * @private
32346 */
32347
32348 }, {
32349 key: "_restoreEdge",
32350 value: function _restoreEdge(edge) {
32351 var originalOptions = this.clusteredEdges[edge.id];
32352
32353 if (originalOptions !== undefined) {
32354 edge.setOptions({
32355 physics: originalOptions.physics
32356 });
32357 delete this.clusteredEdges[edge.id];
32358 }
32359 }
32360 /**
32361 * Check if a node is a cluster.
32362 *
32363 * @param {Node.id} nodeId
32364 * @returns {*}
32365 */
32366
32367 }, {
32368 key: "isCluster",
32369 value: function isCluster(nodeId) {
32370 if (this.body.nodes[nodeId] !== undefined) {
32371 return this.body.nodes[nodeId].isCluster === true;
32372 } else {
32373 console.error("Node does not exist.");
32374 return false;
32375 }
32376 }
32377 /**
32378 * get the position of the cluster node based on what's inside
32379 *
32380 * @param {object} childNodesObj | object with node objects, id as keys
32381 * @returns {{x: number, y: number}}
32382 * @private
32383 */
32384
32385 }, {
32386 key: "_getClusterPosition",
32387 value: function _getClusterPosition(childNodesObj) {
32388 var childKeys = keys$4(childNodesObj);
32389
32390 var minX = childNodesObj[childKeys[0]].x;
32391 var maxX = childNodesObj[childKeys[0]].x;
32392 var minY = childNodesObj[childKeys[0]].y;
32393 var maxY = childNodesObj[childKeys[0]].y;
32394 var node;
32395
32396 for (var i = 1; i < childKeys.length; i++) {
32397 node = childNodesObj[childKeys[i]];
32398 minX = node.x < minX ? node.x : minX;
32399 maxX = node.x > maxX ? node.x : maxX;
32400 minY = node.y < minY ? node.y : minY;
32401 maxY = node.y > maxY ? node.y : maxY;
32402 }
32403
32404 return {
32405 x: 0.5 * (minX + maxX),
32406 y: 0.5 * (minY + maxY)
32407 };
32408 }
32409 /**
32410 * Open a cluster by calling this function.
32411 *
32412 * @param {vis.Edge.id} clusterNodeId | the ID of the cluster node
32413 * @param {object} options
32414 * @param {boolean} refreshData | wrap up afterwards if not true
32415 */
32416
32417 }, {
32418 key: "openCluster",
32419 value: function openCluster(clusterNodeId, options) {
32420 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
32421
32422 // kill conditions
32423 if (clusterNodeId === undefined) {
32424 throw new Error("No clusterNodeId supplied to openCluster.");
32425 }
32426
32427 var clusterNode = this.body.nodes[clusterNodeId];
32428
32429 if (clusterNode === undefined) {
32430 throw new Error("The clusterNodeId supplied to openCluster does not exist.");
32431 }
32432
32433 if (clusterNode.isCluster !== true || clusterNode.containedNodes === undefined || clusterNode.containedEdges === undefined) {
32434 throw new Error("The node:" + clusterNodeId + " is not a valid cluster.");
32435 } // Check if current cluster is clustered itself
32436
32437
32438 var stack = this.findNode(clusterNodeId);
32439 var parentIndex = indexOf(stack).call(stack, clusterNodeId) - 1;
32440
32441 if (parentIndex >= 0) {
32442 // Current cluster is clustered; transfer contained nodes and edges to parent
32443 var parentClusterNodeId = stack[parentIndex];
32444 var parentClusterNode = this.body.nodes[parentClusterNodeId]; // clustering.clusteredNodes and clustering.clusteredEdges remain unchanged
32445
32446 parentClusterNode._openChildCluster(clusterNodeId); // All components of child cluster node have been transferred. It can die now.
32447
32448
32449 delete this.body.nodes[clusterNodeId];
32450
32451 if (refreshData === true) {
32452 this.body.emitter.emit("_dataChanged");
32453 }
32454
32455 return;
32456 } // main body
32457
32458
32459 var containedNodes = clusterNode.containedNodes;
32460 var containedEdges = clusterNode.containedEdges; // allow the user to position the nodes after release.
32461
32462 if (options !== undefined && options.releaseFunction !== undefined && typeof options.releaseFunction === "function") {
32463 var positions = {};
32464 var clusterPosition = {
32465 x: clusterNode.x,
32466 y: clusterNode.y
32467 };
32468
32469 for (var nodeId in containedNodes) {
32470 if (Object.prototype.hasOwnProperty.call(containedNodes, nodeId)) {
32471 var containedNode = this.body.nodes[nodeId];
32472 positions[nodeId] = {
32473 x: containedNode.x,
32474 y: containedNode.y
32475 };
32476 }
32477 }
32478
32479 var newPositions = options.releaseFunction(clusterPosition, positions);
32480
32481 for (var _nodeId2 in containedNodes) {
32482 if (Object.prototype.hasOwnProperty.call(containedNodes, _nodeId2)) {
32483 var _containedNode = this.body.nodes[_nodeId2];
32484
32485 if (newPositions[_nodeId2] !== undefined) {
32486 _containedNode.x = newPositions[_nodeId2].x === undefined ? clusterNode.x : newPositions[_nodeId2].x;
32487 _containedNode.y = newPositions[_nodeId2].y === undefined ? clusterNode.y : newPositions[_nodeId2].y;
32488 }
32489 }
32490 }
32491 } else {
32492 // copy the position from the cluster
32493 forEach$1(containedNodes, function (containedNode) {
32494 // inherit position
32495 if (containedNode.options.fixed.x === false) {
32496 containedNode.x = clusterNode.x;
32497 }
32498
32499 if (containedNode.options.fixed.y === false) {
32500 containedNode.y = clusterNode.y;
32501 }
32502 });
32503 } // release nodes
32504
32505
32506 for (var _nodeId3 in containedNodes) {
32507 if (Object.prototype.hasOwnProperty.call(containedNodes, _nodeId3)) {
32508 var _containedNode2 = this.body.nodes[_nodeId3]; // inherit speed
32509
32510 _containedNode2.vx = clusterNode.vx;
32511 _containedNode2.vy = clusterNode.vy;
32512
32513 _containedNode2.setOptions({
32514 physics: true
32515 });
32516
32517 delete this.clusteredNodes[_nodeId3];
32518 }
32519 } // copy the clusterNode edges because we cannot iterate over an object that we add or remove from.
32520
32521
32522 var edgesToBeDeleted = [];
32523
32524 for (var i = 0; i < clusterNode.edges.length; i++) {
32525 edgesToBeDeleted.push(clusterNode.edges[i]);
32526 } // actually handling the deleting.
32527
32528
32529 for (var _i3 = 0; _i3 < edgesToBeDeleted.length; _i3++) {
32530 var edge = edgesToBeDeleted[_i3];
32531
32532 var otherNodeId = this._getConnectedId(edge, clusterNodeId);
32533
32534 var otherNode = this.clusteredNodes[otherNodeId];
32535
32536 for (var j = 0; j < edge.clusteringEdgeReplacingIds.length; j++) {
32537 var transferId = edge.clusteringEdgeReplacingIds[j];
32538 var transferEdge = this.body.edges[transferId];
32539 if (transferEdge === undefined) continue; // if the other node is in another cluster, we transfer ownership of this edge to the other cluster
32540
32541 if (otherNode !== undefined) {
32542 // transfer ownership:
32543 var otherCluster = this.body.nodes[otherNode.clusterId];
32544 otherCluster.containedEdges[transferEdge.id] = transferEdge; // delete local reference
32545
32546 delete containedEdges[transferEdge.id]; // get to and from
32547
32548 var fromId = transferEdge.fromId;
32549 var toId = transferEdge.toId;
32550
32551 if (transferEdge.toId == otherNodeId) {
32552 toId = otherNode.clusterId;
32553 } else {
32554 fromId = otherNode.clusterId;
32555 } // create new cluster edge from the otherCluster
32556
32557
32558 this._createClusteredEdge(fromId, toId, transferEdge, otherCluster.clusterEdgeProperties, {
32559 hidden: false,
32560 physics: true
32561 });
32562 } else {
32563 this._restoreEdge(transferEdge);
32564 }
32565 }
32566
32567 edge.remove();
32568 } // handle the releasing of the edges
32569
32570
32571 for (var edgeId in containedEdges) {
32572 if (Object.prototype.hasOwnProperty.call(containedEdges, edgeId)) {
32573 this._restoreEdge(containedEdges[edgeId]);
32574 }
32575 } // remove clusterNode
32576
32577
32578 delete this.body.nodes[clusterNodeId];
32579
32580 if (refreshData === true) {
32581 this.body.emitter.emit("_dataChanged");
32582 }
32583 }
32584 /**
32585 *
32586 * @param {Cluster.id} clusterId
32587 * @returns {Array.<Node.id>}
32588 */
32589
32590 }, {
32591 key: "getNodesInCluster",
32592 value: function getNodesInCluster(clusterId) {
32593 var nodesArray = [];
32594
32595 if (this.isCluster(clusterId) === true) {
32596 var containedNodes = this.body.nodes[clusterId].containedNodes;
32597
32598 for (var nodeId in containedNodes) {
32599 if (Object.prototype.hasOwnProperty.call(containedNodes, nodeId)) {
32600 nodesArray.push(this.body.nodes[nodeId].id);
32601 }
32602 }
32603 }
32604
32605 return nodesArray;
32606 }
32607 /**
32608 * Get the stack clusterId's that a certain node resides in. cluster A -> cluster B -> cluster C -> node
32609 *
32610 * If a node can't be found in the chain, return an empty array.
32611 *
32612 * @param {string|number} nodeId
32613 * @returns {Array}
32614 */
32615
32616 }, {
32617 key: "findNode",
32618 value: function findNode(nodeId) {
32619 var stack = [];
32620 var max = 100;
32621 var counter = 0;
32622 var node;
32623
32624 while (this.clusteredNodes[nodeId] !== undefined && counter < max) {
32625 node = this.body.nodes[nodeId];
32626 if (node === undefined) return [];
32627 stack.push(node.id);
32628 nodeId = this.clusteredNodes[nodeId].clusterId;
32629 counter++;
32630 }
32631
32632 node = this.body.nodes[nodeId];
32633 if (node === undefined) return [];
32634 stack.push(node.id);
32635
32636 reverse(stack).call(stack);
32637
32638 return stack;
32639 }
32640 /**
32641 * Using a clustered nodeId, update with the new options
32642 *
32643 * @param {Node.id} clusteredNodeId
32644 * @param {object} newOptions
32645 */
32646
32647 }, {
32648 key: "updateClusteredNode",
32649 value: function updateClusteredNode(clusteredNodeId, newOptions) {
32650 if (clusteredNodeId === undefined) {
32651 throw new Error("No clusteredNodeId supplied to updateClusteredNode.");
32652 }
32653
32654 if (newOptions === undefined) {
32655 throw new Error("No newOptions supplied to updateClusteredNode.");
32656 }
32657
32658 if (this.body.nodes[clusteredNodeId] === undefined) {
32659 throw new Error("The clusteredNodeId supplied to updateClusteredNode does not exist.");
32660 }
32661
32662 this.body.nodes[clusteredNodeId].setOptions(newOptions);
32663 this.body.emitter.emit("_dataChanged");
32664 }
32665 /**
32666 * Using a base edgeId, update all related clustered edges with the new options
32667 *
32668 * @param {vis.Edge.id} startEdgeId
32669 * @param {object} newOptions
32670 */
32671
32672 }, {
32673 key: "updateEdge",
32674 value: function updateEdge(startEdgeId, newOptions) {
32675 if (startEdgeId === undefined) {
32676 throw new Error("No startEdgeId supplied to updateEdge.");
32677 }
32678
32679 if (newOptions === undefined) {
32680 throw new Error("No newOptions supplied to updateEdge.");
32681 }
32682
32683 if (this.body.edges[startEdgeId] === undefined) {
32684 throw new Error("The startEdgeId supplied to updateEdge does not exist.");
32685 }
32686
32687 var allEdgeIds = this.getClusteredEdges(startEdgeId);
32688
32689 for (var i = 0; i < allEdgeIds.length; i++) {
32690 var edge = this.body.edges[allEdgeIds[i]];
32691 edge.setOptions(newOptions);
32692 }
32693
32694 this.body.emitter.emit("_dataChanged");
32695 }
32696 /**
32697 * 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)
32698 *
32699 * @param {vis.Edge.id} edgeId
32700 * @returns {Array.<vis.Edge.id>}
32701 */
32702
32703 }, {
32704 key: "getClusteredEdges",
32705 value: function getClusteredEdges(edgeId) {
32706 var stack = [];
32707 var max = 100;
32708 var counter = 0;
32709
32710 while (edgeId !== undefined && this.body.edges[edgeId] !== undefined && counter < max) {
32711 stack.push(this.body.edges[edgeId].id);
32712 edgeId = this.body.edges[edgeId].edgeReplacedById;
32713 counter++;
32714 }
32715
32716 reverse(stack).call(stack);
32717
32718 return stack;
32719 }
32720 /**
32721 * Get the base edge id of clusterEdgeId. cluster edge (clusteredEdgeId) -> cluster edge B -> cluster edge C -> base edge
32722 *
32723 * @param {vis.Edge.id} clusteredEdgeId
32724 * @returns {vis.Edge.id} baseEdgeId
32725 *
32726 * TODO: deprecate in 5.0.0. Method getBaseEdges() is the correct one to use.
32727 */
32728
32729 }, {
32730 key: "getBaseEdge",
32731 value: function getBaseEdge(clusteredEdgeId) {
32732 // Just kludge this by returning the first base edge id found
32733 return this.getBaseEdges(clusteredEdgeId)[0];
32734 }
32735 /**
32736 * Get all regular edges for this clustered edge id.
32737 *
32738 * @param {vis.Edge.id} clusteredEdgeId
32739 * @returns {Array.<vis.Edge.id>} all baseEdgeId's under this clustered edge
32740 */
32741
32742 }, {
32743 key: "getBaseEdges",
32744 value: function getBaseEdges(clusteredEdgeId) {
32745 var IdsToHandle = [clusteredEdgeId];
32746 var doneIds = [];
32747 var foundIds = [];
32748 var max = 100;
32749 var counter = 0;
32750
32751 while (IdsToHandle.length > 0 && counter < max) {
32752 var nextId = IdsToHandle.pop();
32753 if (nextId === undefined) continue; // Paranoia here and onwards
32754
32755 var nextEdge = this.body.edges[nextId];
32756 if (nextEdge === undefined) continue;
32757 counter++;
32758 var replacingIds = nextEdge.clusteringEdgeReplacingIds;
32759
32760 if (replacingIds === undefined) {
32761 // nextId is a base id
32762 foundIds.push(nextId);
32763 } else {
32764 // Another cluster edge, unravel this one as well
32765 for (var i = 0; i < replacingIds.length; ++i) {
32766 var replacingId = replacingIds[i]; // Don't add if already handled
32767 // TODO: never triggers; find a test-case which does
32768
32769 if (indexOf(IdsToHandle).call(IdsToHandle, replacingIds) !== -1 || indexOf(doneIds).call(doneIds, replacingIds) !== -1) {
32770 continue;
32771 }
32772
32773 IdsToHandle.push(replacingId);
32774 }
32775 }
32776
32777 doneIds.push(nextId);
32778 }
32779
32780 return foundIds;
32781 }
32782 /**
32783 * Get the Id the node is connected to
32784 *
32785 * @param {vis.Edge} edge
32786 * @param {Node.id} nodeId
32787 * @returns {*}
32788 * @private
32789 */
32790
32791 }, {
32792 key: "_getConnectedId",
32793 value: function _getConnectedId(edge, nodeId) {
32794 if (edge.toId != nodeId) {
32795 return edge.toId;
32796 } else if (edge.fromId != nodeId) {
32797 return edge.fromId;
32798 } else {
32799 return edge.fromId;
32800 }
32801 }
32802 /**
32803 * We determine how many connections denote an important hub.
32804 * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%)
32805 *
32806 * @returns {number}
32807 * @private
32808 */
32809
32810 }, {
32811 key: "_getHubSize",
32812 value: function _getHubSize() {
32813 var average = 0;
32814 var averageSquared = 0;
32815 var hubCounter = 0;
32816 var largestHub = 0;
32817
32818 for (var i = 0; i < this.body.nodeIndices.length; i++) {
32819 var node = this.body.nodes[this.body.nodeIndices[i]];
32820
32821 if (node.edges.length > largestHub) {
32822 largestHub = node.edges.length;
32823 }
32824
32825 average += node.edges.length;
32826 averageSquared += Math.pow(node.edges.length, 2);
32827 hubCounter += 1;
32828 }
32829
32830 average = average / hubCounter;
32831 averageSquared = averageSquared / hubCounter;
32832 var variance = averageSquared - Math.pow(average, 2);
32833 var standardDeviation = Math.sqrt(variance);
32834 var hubThreshold = Math.floor(average + 2 * standardDeviation); // always have at least one to cluster
32835
32836 if (hubThreshold > largestHub) {
32837 hubThreshold = largestHub;
32838 }
32839
32840 return hubThreshold;
32841 }
32842 /**
32843 * Create an edge for the cluster representation.
32844 *
32845 * @param {Node.id} fromId
32846 * @param {Node.id} toId
32847 * @param {vis.Edge} baseEdge
32848 * @param {object} clusterEdgeProperties
32849 * @param {object} extraOptions
32850 * @returns {Edge} newly created clustered edge
32851 * @private
32852 */
32853
32854 }, {
32855 key: "_createClusteredEdge",
32856 value: function _createClusteredEdge(fromId, toId, baseEdge, clusterEdgeProperties, extraOptions) {
32857 // copy the options of the edge we will replace
32858 var clonedOptions = NetworkUtil.cloneOptions(baseEdge, "edge"); // make sure the properties of clusterEdges are superimposed on it
32859
32860 deepExtend(clonedOptions, clusterEdgeProperties); // set up the edge
32861
32862 clonedOptions.from = fromId;
32863 clonedOptions.to = toId;
32864 clonedOptions.id = "clusterEdge:" + v4(); // apply the edge specific options to it if specified
32865
32866 if (extraOptions !== undefined) {
32867 deepExtend(clonedOptions, extraOptions);
32868 }
32869
32870 var newEdge = this.body.functions.createEdge(clonedOptions);
32871 newEdge.clusteringEdgeReplacingIds = [baseEdge.id];
32872 newEdge.connect(); // Register the new edge
32873
32874 this.body.edges[newEdge.id] = newEdge;
32875 return newEdge;
32876 }
32877 /**
32878 * Add the passed child nodes and edges to the given cluster node.
32879 *
32880 * @param {object | Node} childNodes hash of nodes or single node to add in cluster
32881 * @param {object | Edge} childEdges hash of edges or single edge to take into account when clustering
32882 * @param {Node} clusterNode cluster node to add nodes and edges to
32883 * @param {object} [clusterEdgeProperties]
32884 * @private
32885 */
32886
32887 }, {
32888 key: "_clusterEdges",
32889 value: function _clusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties) {
32890 if (childEdges instanceof Edge) {
32891 var edge = childEdges;
32892 var obj = {};
32893 obj[edge.id] = edge;
32894 childEdges = obj;
32895 }
32896
32897 if (childNodes instanceof Node) {
32898 var node = childNodes;
32899 var _obj = {};
32900 _obj[node.id] = node;
32901 childNodes = _obj;
32902 }
32903
32904 if (clusterNode === undefined || clusterNode === null) {
32905 throw new Error("_clusterEdges: parameter clusterNode required");
32906 }
32907
32908 if (clusterEdgeProperties === undefined) {
32909 // Take the required properties from the cluster node
32910 clusterEdgeProperties = clusterNode.clusterEdgeProperties;
32911 } // create the new edges that will connect to the cluster.
32912 // All self-referencing edges will be added to childEdges here.
32913
32914
32915 this._createClusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties); // disable the childEdges
32916
32917
32918 for (var edgeId in childEdges) {
32919 if (Object.prototype.hasOwnProperty.call(childEdges, edgeId)) {
32920 if (this.body.edges[edgeId] !== undefined) {
32921 var _edge2 = this.body.edges[edgeId]; // cache the options before changing
32922
32923 this._backupEdgeOptions(_edge2); // disable physics and hide the edge
32924
32925
32926 _edge2.setOptions({
32927 physics: false
32928 });
32929 }
32930 }
32931 } // disable the childNodes
32932
32933
32934 for (var nodeId in childNodes) {
32935 if (Object.prototype.hasOwnProperty.call(childNodes, nodeId)) {
32936 this.clusteredNodes[nodeId] = {
32937 clusterId: clusterNode.id,
32938 node: this.body.nodes[nodeId]
32939 };
32940 this.body.nodes[nodeId].setOptions({
32941 physics: false
32942 });
32943 }
32944 }
32945 }
32946 /**
32947 * Determine in which cluster given nodeId resides.
32948 *
32949 * If not in cluster, return undefined.
32950 *
32951 * NOTE: If you know a cleaner way to do this, please enlighten me (wimrijnders).
32952 *
32953 * @param {Node.id} nodeId
32954 * @returns {Node|undefined} Node instance for cluster, if present
32955 * @private
32956 */
32957
32958 }, {
32959 key: "_getClusterNodeForNode",
32960 value: function _getClusterNodeForNode(nodeId) {
32961 if (nodeId === undefined) return undefined;
32962 var clusteredNode = this.clusteredNodes[nodeId]; // NOTE: If no cluster info found, it should actually be an error
32963
32964 if (clusteredNode === undefined) return undefined;
32965 var clusterId = clusteredNode.clusterId;
32966 if (clusterId === undefined) return undefined;
32967 return this.body.nodes[clusterId];
32968 }
32969 /**
32970 * Internal helper function for conditionally removing items in array
32971 *
32972 * Done like this because Array.filter() is not fully supported by all IE's.
32973 *
32974 * @param {Array} arr
32975 * @param {Function} callback
32976 * @returns {Array}
32977 * @private
32978 */
32979
32980 }, {
32981 key: "_filter",
32982 value: function _filter(arr, callback) {
32983 var ret = [];
32984 forEach$1(arr, function (item) {
32985 if (callback(item)) {
32986 ret.push(item);
32987 }
32988 });
32989 return ret;
32990 }
32991 /**
32992 * Scan all edges for changes in clustering and adjust this if necessary.
32993 *
32994 * Call this (internally) after there has been a change in node or edge data.
32995 *
32996 * Pre: States of this.body.nodes and this.body.edges consistent
32997 * Pre: this.clusteredNodes and this.clusteredEdge consistent with containedNodes and containedEdges
32998 * of cluster nodes.
32999 */
33000
33001 }, {
33002 key: "_updateState",
33003 value: function _updateState() {
33004 var _this4 = this;
33005
33006 var nodeId;
33007 var deletedNodeIds = [];
33008 var deletedEdgeIds = {};
33009 /**
33010 * Utility function to iterate over clustering nodes only
33011 *
33012 * @param {Function} callback function to call for each cluster node
33013 */
33014
33015 var eachClusterNode = function eachClusterNode(callback) {
33016 forEach$1(_this4.body.nodes, function (node) {
33017 if (node.isCluster === true) {
33018 callback(node);
33019 }
33020 });
33021 }; //
33022 // Remove deleted regular nodes from clustering
33023 //
33024 // Determine the deleted nodes
33025
33026
33027 for (nodeId in this.clusteredNodes) {
33028 if (!Object.prototype.hasOwnProperty.call(this.clusteredNodes, nodeId)) continue;
33029 var node = this.body.nodes[nodeId];
33030
33031 if (node === undefined) {
33032 deletedNodeIds.push(nodeId);
33033 }
33034 } // Remove nodes from cluster nodes
33035
33036
33037 eachClusterNode(function (clusterNode) {
33038 for (var n = 0; n < deletedNodeIds.length; n++) {
33039 delete clusterNode.containedNodes[deletedNodeIds[n]];
33040 }
33041 }); // Remove nodes from cluster list
33042
33043 for (var n = 0; n < deletedNodeIds.length; n++) {
33044 delete this.clusteredNodes[deletedNodeIds[n]];
33045 } //
33046 // Remove deleted edges from clustering
33047 //
33048 // Add the deleted clustered edges to the list
33049
33050
33051 forEach$1(this.clusteredEdges, function (edgeId) {
33052 var edge = _this4.body.edges[edgeId];
33053
33054 if (edge === undefined || !edge.endPointsValid()) {
33055 deletedEdgeIds[edgeId] = edgeId;
33056 }
33057 }); // Cluster nodes can also contain edges which are not clustered,
33058 // i.e. nodes 1-2 within cluster with an edge in between.
33059 // So the cluster nodes also need to be scanned for invalid edges
33060
33061 eachClusterNode(function (clusterNode) {
33062 forEach$1(clusterNode.containedEdges, function (edge, edgeId) {
33063 if (!edge.endPointsValid() && !deletedEdgeIds[edgeId]) {
33064 deletedEdgeIds[edgeId] = edgeId;
33065 }
33066 });
33067 }); // Also scan for cluster edges which need to be removed in the active list.
33068 // Regular edges have been removed beforehand, so this only picks up the cluster edges.
33069
33070 forEach$1(this.body.edges, function (edge, edgeId) {
33071 // Explicitly scan the contained edges for validity
33072 var isValid = true;
33073 var replacedIds = edge.clusteringEdgeReplacingIds;
33074
33075 if (replacedIds !== undefined) {
33076 var numValid = 0;
33077 forEach$1(replacedIds, function (containedEdgeId) {
33078 var containedEdge = _this4.body.edges[containedEdgeId];
33079
33080 if (containedEdge !== undefined && containedEdge.endPointsValid()) {
33081 numValid += 1;
33082 }
33083 });
33084 isValid = numValid > 0;
33085 }
33086
33087 if (!edge.endPointsValid() || !isValid) {
33088 deletedEdgeIds[edgeId] = edgeId;
33089 }
33090 }); // Remove edges from cluster nodes
33091
33092 eachClusterNode(function (clusterNode) {
33093 forEach$1(deletedEdgeIds, function (deletedEdgeId) {
33094 delete clusterNode.containedEdges[deletedEdgeId];
33095 forEach$1(clusterNode.edges, function (edge, m) {
33096 if (edge.id === deletedEdgeId) {
33097 clusterNode.edges[m] = null; // Don't want to directly delete here, because in the loop
33098
33099 return;
33100 }
33101
33102 edge.clusteringEdgeReplacingIds = _this4._filter(edge.clusteringEdgeReplacingIds, function (id) {
33103 return !deletedEdgeIds[id];
33104 });
33105 }); // Clean up the nulls
33106
33107 clusterNode.edges = _this4._filter(clusterNode.edges, function (item) {
33108 return item !== null;
33109 });
33110 });
33111 }); // Remove from cluster list
33112
33113 forEach$1(deletedEdgeIds, function (edgeId) {
33114 delete _this4.clusteredEdges[edgeId];
33115 }); // Remove cluster edges from active list (this.body.edges).
33116 // deletedEdgeIds still contains id of regular edges, but these should all
33117 // be gone when you reach here.
33118
33119 forEach$1(deletedEdgeIds, function (edgeId) {
33120 delete _this4.body.edges[edgeId];
33121 }); //
33122 // Check changed cluster state of edges
33123 //
33124 // Iterating over keys here, because edges may be removed in the loop
33125
33126 var ids = keys$4(this.body.edges);
33127
33128 forEach$1(ids, function (edgeId) {
33129 var edge = _this4.body.edges[edgeId];
33130
33131 var shouldBeClustered = _this4._isClusteredNode(edge.fromId) || _this4._isClusteredNode(edge.toId);
33132
33133 if (shouldBeClustered === _this4._isClusteredEdge(edge.id)) {
33134 return; // all is well
33135 }
33136
33137 if (shouldBeClustered) {
33138 // add edge to clustering
33139 var clusterFrom = _this4._getClusterNodeForNode(edge.fromId);
33140
33141 if (clusterFrom !== undefined) {
33142 _this4._clusterEdges(_this4.body.nodes[edge.fromId], edge, clusterFrom);
33143 }
33144
33145 var clusterTo = _this4._getClusterNodeForNode(edge.toId);
33146
33147 if (clusterTo !== undefined) {
33148 _this4._clusterEdges(_this4.body.nodes[edge.toId], edge, clusterTo);
33149 } // TODO: check that it works for both edges clustered
33150 // (This might be paranoia)
33151
33152 } else {
33153 delete _this4._clusterEdges[edgeId];
33154
33155 _this4._restoreEdge(edge); // This should not be happening, the state should
33156 // be properly updated at this point.
33157 //
33158 // If it *is* reached during normal operation, then we have to implement
33159 // undo clustering for this edge here.
33160 // throw new Error('remove edge from clustering not implemented!')
33161
33162 }
33163 }); // Clusters may be nested to any level. Keep on opening until nothing to open
33164
33165 var changed = false;
33166 var continueLoop = true;
33167
33168 var _loop2 = function _loop2() {
33169 var clustersToOpen = []; // Determine the id's of clusters that need opening
33170
33171 eachClusterNode(function (clusterNode) {
33172 var numNodes = keys$4(clusterNode.containedNodes).length;
33173
33174 var allowSingle = clusterNode.options.allowSingleNodeCluster === true;
33175
33176 if (allowSingle && numNodes < 1 || !allowSingle && numNodes < 2) {
33177 clustersToOpen.push(clusterNode.id);
33178 }
33179 }); // Open them
33180
33181 for (var _n = 0; _n < clustersToOpen.length; ++_n) {
33182 _this4.openCluster(clustersToOpen[_n], {}, false
33183 /* Don't refresh, we're in an refresh/update already */
33184 );
33185 }
33186
33187 continueLoop = clustersToOpen.length > 0;
33188 changed = changed || continueLoop;
33189 };
33190
33191 while (continueLoop) {
33192 _loop2();
33193 }
33194
33195 if (changed) {
33196 this._updateState(); // Redo this method (recursion possible! should be safe)
33197
33198 }
33199 }
33200 /**
33201 * Determine if node with given id is part of a cluster.
33202 *
33203 * @param {Node.id} nodeId
33204 * @returns {boolean} true if part of a cluster.
33205 */
33206
33207 }, {
33208 key: "_isClusteredNode",
33209 value: function _isClusteredNode(nodeId) {
33210 return this.clusteredNodes[nodeId] !== undefined;
33211 }
33212 /**
33213 * Determine if edge with given id is not visible due to clustering.
33214 *
33215 * An edge is considered clustered if:
33216 * - it is directly replaced by a clustering edge
33217 * - any of its connecting nodes is in a cluster
33218 *
33219 * @param {vis.Edge.id} edgeId
33220 * @returns {boolean} true if part of a cluster.
33221 */
33222
33223 }, {
33224 key: "_isClusteredEdge",
33225 value: function _isClusteredEdge(edgeId) {
33226 return this.clusteredEdges[edgeId] !== undefined;
33227 }
33228 }]);
33229
33230 return ClusterEngine;
33231 }();
33232
33233 function _createForOfIteratorHelper$5(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$2(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; } } }; }
33234
33235 function _unsupportedIterableToArray$5(o, minLen) { var _context4; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$5(o, minLen); var n = slice(_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$3(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$5(o, minLen); }
33236
33237 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; }
33238 /**
33239 * Initializes window.requestAnimationFrame() to a usable form.
33240 *
33241 * Specifically, set up this method for the case of running on node.js with jsdom enabled.
33242 *
33243 * NOTES:
33244 *
33245 * On node.js, when calling this directly outside of this class, `window` is not defined.
33246 * This happens even if jsdom is used.
33247 * For node.js + jsdom, `window` is available at the moment the constructor is called.
33248 * For this reason, the called is placed within the constructor.
33249 * Even then, `window.requestAnimationFrame()` is not defined, so it still needs to be added.
33250 * During unit testing, it happens that the window object is reset during execution, causing
33251 * a runtime error due to missing `requestAnimationFrame()`. This needs to be compensated for,
33252 * see `_requestNextFrame()`.
33253 * Since this is a global object, it may affect other modules besides `Network`. With normal
33254 * usage, this does not cause any problems. During unit testing, errors may occur. These have
33255 * been compensated for, see comment block in _requestNextFrame().
33256 *
33257 * @private
33258 */
33259
33260 function _initRequestAnimationFrame() {
33261 var func;
33262
33263 if (window !== undefined) {
33264 func = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
33265 }
33266
33267 if (func === undefined) {
33268 // window or method not present, setting mock requestAnimationFrame
33269 window.requestAnimationFrame = function (callback) {
33270 //console.log("Called mock requestAnimationFrame");
33271 callback();
33272 };
33273 } else {
33274 window.requestAnimationFrame = func;
33275 }
33276 }
33277 /**
33278 * The canvas renderer
33279 */
33280
33281
33282 var CanvasRenderer = /*#__PURE__*/function () {
33283 /**
33284 * @param {object} body
33285 * @param {Canvas} canvas
33286 */
33287 function CanvasRenderer(body, canvas) {
33288 _classCallCheck(this, CanvasRenderer);
33289
33290 _initRequestAnimationFrame();
33291
33292 this.body = body;
33293 this.canvas = canvas;
33294 this.redrawRequested = false;
33295 this.renderTimer = undefined;
33296 this.requiresTimeout = true;
33297 this.renderingActive = false;
33298 this.renderRequests = 0;
33299 this.allowRedraw = true;
33300 this.dragging = false;
33301 this.zooming = false;
33302 this.options = {};
33303 this.defaultOptions = {
33304 hideEdgesOnDrag: false,
33305 hideEdgesOnZoom: false,
33306 hideNodesOnDrag: false
33307 };
33308
33309 assign$2(this.options, this.defaultOptions);
33310
33311 this._determineBrowserMethod();
33312
33313 this.bindEventListeners();
33314 }
33315 /**
33316 * Binds event listeners
33317 */
33318
33319
33320 _createClass(CanvasRenderer, [{
33321 key: "bindEventListeners",
33322 value: function bindEventListeners() {
33323 var _this = this,
33324 _context2;
33325
33326 this.body.emitter.on("dragStart", function () {
33327 _this.dragging = true;
33328 });
33329 this.body.emitter.on("dragEnd", function () {
33330 _this.dragging = false;
33331 });
33332 this.body.emitter.on("zoom", function () {
33333 _this.zooming = true;
33334 window.clearTimeout(_this.zoomTimeoutId);
33335 _this.zoomTimeoutId = setTimeout$1(function () {
33336 var _context;
33337
33338 _this.zooming = false;
33339
33340 bind$6(_context = _this._requestRedraw).call(_context, _this)();
33341 }, 250);
33342 });
33343 this.body.emitter.on("_resizeNodes", function () {
33344 _this._resizeNodes();
33345 });
33346 this.body.emitter.on("_redraw", function () {
33347 if (_this.renderingActive === false) {
33348 _this._redraw();
33349 }
33350 });
33351 this.body.emitter.on("_blockRedraw", function () {
33352 _this.allowRedraw = false;
33353 });
33354 this.body.emitter.on("_allowRedraw", function () {
33355 _this.allowRedraw = true;
33356 _this.redrawRequested = false;
33357 });
33358 this.body.emitter.on("_requestRedraw", bind$6(_context2 = this._requestRedraw).call(_context2, this));
33359 this.body.emitter.on("_startRendering", function () {
33360 _this.renderRequests += 1;
33361 _this.renderingActive = true;
33362
33363 _this._startRendering();
33364 });
33365 this.body.emitter.on("_stopRendering", function () {
33366 _this.renderRequests -= 1;
33367 _this.renderingActive = _this.renderRequests > 0;
33368 _this.renderTimer = undefined;
33369 });
33370 this.body.emitter.on("destroy", function () {
33371 _this.renderRequests = 0;
33372 _this.allowRedraw = false;
33373 _this.renderingActive = false;
33374
33375 if (_this.requiresTimeout === true) {
33376 clearTimeout(_this.renderTimer);
33377 } else {
33378 window.cancelAnimationFrame(_this.renderTimer);
33379 }
33380
33381 _this.body.emitter.off();
33382 });
33383 }
33384 /**
33385 *
33386 * @param {object} options
33387 */
33388
33389 }, {
33390 key: "setOptions",
33391 value: function setOptions(options) {
33392 if (options !== undefined) {
33393 var fields = ["hideEdgesOnDrag", "hideEdgesOnZoom", "hideNodesOnDrag"];
33394 selectiveDeepExtend(fields, this.options, options);
33395 }
33396 }
33397 /**
33398 * Prepare the drawing of the next frame.
33399 *
33400 * Calls the callback when the next frame can or will be drawn.
33401 *
33402 * @param {Function} callback
33403 * @param {number} delay - timeout case only, wait this number of milliseconds
33404 * @returns {Function | undefined}
33405 * @private
33406 */
33407
33408 }, {
33409 key: "_requestNextFrame",
33410 value: function _requestNextFrame(callback, delay) {
33411 // During unit testing, it happens that the mock window object is reset while
33412 // the next frame is still pending. Then, either 'window' is not present, or
33413 // 'requestAnimationFrame()' is not present because it is not defined on the
33414 // mock window object.
33415 //
33416 // As a consequence, unrelated unit tests may appear to fail, even if the problem
33417 // described happens in the current unit test.
33418 //
33419 // This is not something that will happen in normal operation, but we still need
33420 // to take it into account.
33421 //
33422 if (typeof window === "undefined") return; // Doing `if (window === undefined)` does not work here!
33423
33424 var timer;
33425 var myWindow = window; // Grab a reference to reduce the possibility that 'window' is reset
33426 // while running this method.
33427
33428 if (this.requiresTimeout === true) {
33429 // wait given number of milliseconds and perform the animation step function
33430 timer = setTimeout$1(callback, delay);
33431 } else {
33432 if (myWindow.requestAnimationFrame) {
33433 timer = myWindow.requestAnimationFrame(callback);
33434 }
33435 }
33436
33437 return timer;
33438 }
33439 /**
33440 *
33441 * @private
33442 */
33443
33444 }, {
33445 key: "_startRendering",
33446 value: function _startRendering() {
33447 if (this.renderingActive === true) {
33448 if (this.renderTimer === undefined) {
33449 var _context3;
33450
33451 this.renderTimer = this._requestNextFrame(bind$6(_context3 = this._renderStep).call(_context3, this), this.simulationInterval);
33452 }
33453 }
33454 }
33455 /**
33456 *
33457 * @private
33458 */
33459
33460 }, {
33461 key: "_renderStep",
33462 value: function _renderStep() {
33463 if (this.renderingActive === true) {
33464 // reset the renderTimer so a new scheduled animation step can be set
33465 this.renderTimer = undefined;
33466
33467 if (this.requiresTimeout === true) {
33468 // this schedules a new simulation step
33469 this._startRendering();
33470 }
33471
33472 this._redraw();
33473
33474 if (this.requiresTimeout === false) {
33475 // this schedules a new simulation step
33476 this._startRendering();
33477 }
33478 }
33479 }
33480 /**
33481 * Redraw the network with the current data
33482 * chart will be resized too.
33483 */
33484
33485 }, {
33486 key: "redraw",
33487 value: function redraw() {
33488 this.body.emitter.emit("setSize");
33489
33490 this._redraw();
33491 }
33492 /**
33493 * Redraw the network with the current data
33494 *
33495 * @private
33496 */
33497
33498 }, {
33499 key: "_requestRedraw",
33500 value: function _requestRedraw() {
33501 var _this2 = this;
33502
33503 if (this.redrawRequested !== true && this.renderingActive === false && this.allowRedraw === true) {
33504 this.redrawRequested = true;
33505
33506 this._requestNextFrame(function () {
33507 _this2._redraw(false);
33508 }, 0);
33509 }
33510 }
33511 /**
33512 * Redraw the network with the current data
33513 *
33514 * @param {boolean} [hidden=false] | Used to get the first estimate of the node sizes.
33515 * Only the nodes are drawn after which they are quickly drawn over.
33516 * @private
33517 */
33518
33519 }, {
33520 key: "_redraw",
33521 value: function _redraw() {
33522 var hidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
33523
33524 if (this.allowRedraw === true) {
33525 this.body.emitter.emit("initRedraw");
33526 this.redrawRequested = false;
33527 var drawLater = {
33528 drawExternalLabels: null
33529 }; // when the container div was hidden, this fixes it back up!
33530
33531 if (this.canvas.frame.canvas.width === 0 || this.canvas.frame.canvas.height === 0) {
33532 this.canvas.setSize();
33533 }
33534
33535 this.canvas.setTransform();
33536 var ctx = this.canvas.getContext(); // clear the canvas
33537
33538 var w = this.canvas.frame.canvas.clientWidth;
33539 var h = this.canvas.frame.canvas.clientHeight;
33540 ctx.clearRect(0, 0, w, h); // if the div is hidden, we stop the redraw here for performance.
33541
33542 if (this.canvas.frame.clientWidth === 0) {
33543 return;
33544 } // set scaling and translation
33545
33546
33547 ctx.save();
33548 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
33549 ctx.scale(this.body.view.scale, this.body.view.scale);
33550 ctx.beginPath();
33551 this.body.emitter.emit("beforeDrawing", ctx);
33552 ctx.closePath();
33553
33554 if (hidden === false) {
33555 if ((this.dragging === false || this.dragging === true && this.options.hideEdgesOnDrag === false) && (this.zooming === false || this.zooming === true && this.options.hideEdgesOnZoom === false)) {
33556 this._drawEdges(ctx);
33557 }
33558 }
33559
33560 if (this.dragging === false || this.dragging === true && this.options.hideNodesOnDrag === false) {
33561 var _this$_drawNodes = this._drawNodes(ctx, hidden),
33562 drawExternalLabels = _this$_drawNodes.drawExternalLabels;
33563
33564 drawLater.drawExternalLabels = drawExternalLabels;
33565 } // draw the arrows last so they will be at the top
33566
33567
33568 if (hidden === false) {
33569 if ((this.dragging === false || this.dragging === true && this.options.hideEdgesOnDrag === false) && (this.zooming === false || this.zooming === true && this.options.hideEdgesOnZoom === false)) {
33570 this._drawArrows(ctx);
33571 }
33572 }
33573
33574 if (drawLater.drawExternalLabels != null) {
33575 drawLater.drawExternalLabels();
33576 }
33577
33578 if (hidden === false) {
33579 this._drawSelectionBox(ctx);
33580 }
33581
33582 ctx.beginPath();
33583 this.body.emitter.emit("afterDrawing", ctx);
33584 ctx.closePath(); // restore original scaling and translation
33585
33586 ctx.restore();
33587
33588 if (hidden === true) {
33589 ctx.clearRect(0, 0, w, h);
33590 }
33591 }
33592 }
33593 /**
33594 * Redraw all nodes
33595 *
33596 * @param {CanvasRenderingContext2D} ctx
33597 * @param {boolean} [alwaysShow]
33598 * @private
33599 */
33600
33601 }, {
33602 key: "_resizeNodes",
33603 value: function _resizeNodes() {
33604 this.canvas.setTransform();
33605 var ctx = this.canvas.getContext();
33606 ctx.save();
33607 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
33608 ctx.scale(this.body.view.scale, this.body.view.scale);
33609 var nodes = this.body.nodes;
33610 var node; // resize all nodes
33611
33612 for (var nodeId in nodes) {
33613 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
33614 node = nodes[nodeId];
33615 node.resize(ctx);
33616 node.updateBoundingBox(ctx, node.selected);
33617 }
33618 } // restore original scaling and translation
33619
33620
33621 ctx.restore();
33622 }
33623 /**
33624 * Redraw all nodes
33625 *
33626 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
33627 * @param {boolean} [alwaysShow]
33628 * @private
33629 * @returns {object} Callbacks to draw later on higher layers.
33630 */
33631
33632 }, {
33633 key: "_drawNodes",
33634 value: function _drawNodes(ctx) {
33635 var alwaysShow = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
33636 var nodes = this.body.nodes;
33637 var nodeIndices = this.body.nodeIndices;
33638 var node;
33639 var selected = [];
33640 var hovered = [];
33641 var margin = 20;
33642 var topLeft = this.canvas.DOMtoCanvas({
33643 x: -margin,
33644 y: -margin
33645 });
33646 var bottomRight = this.canvas.DOMtoCanvas({
33647 x: this.canvas.frame.canvas.clientWidth + margin,
33648 y: this.canvas.frame.canvas.clientHeight + margin
33649 });
33650 var viewableArea = {
33651 top: topLeft.y,
33652 left: topLeft.x,
33653 bottom: bottomRight.y,
33654 right: bottomRight.x
33655 };
33656 var _drawExternalLabels = []; // draw unselected nodes;
33657
33658 for (var _i = 0; _i < nodeIndices.length; _i++) {
33659 node = nodes[nodeIndices[_i]]; // set selected and hovered nodes aside
33660
33661 if (node.hover) {
33662 hovered.push(nodeIndices[_i]);
33663 } else if (node.isSelected()) {
33664 selected.push(nodeIndices[_i]);
33665 } else {
33666 if (alwaysShow === true) {
33667 var drawLater = node.draw(ctx);
33668
33669 if (drawLater.drawExternalLabel != null) {
33670 _drawExternalLabels.push(drawLater.drawExternalLabel);
33671 }
33672 } else if (node.isBoundingBoxOverlappingWith(viewableArea) === true) {
33673 var _drawLater = node.draw(ctx);
33674
33675 if (_drawLater.drawExternalLabel != null) {
33676 _drawExternalLabels.push(_drawLater.drawExternalLabel);
33677 }
33678 } else {
33679 node.updateBoundingBox(ctx, node.selected);
33680 }
33681 }
33682 }
33683
33684 var i;
33685 var selectedLength = selected.length;
33686 var hoveredLength = hovered.length; // draw the selected nodes on top
33687
33688 for (i = 0; i < selectedLength; i++) {
33689 node = nodes[selected[i]];
33690
33691 var _drawLater2 = node.draw(ctx);
33692
33693 if (_drawLater2.drawExternalLabel != null) {
33694 _drawExternalLabels.push(_drawLater2.drawExternalLabel);
33695 }
33696 } // draw hovered nodes above everything else: fixes https://github.com/visjs/vis-network/issues/226
33697
33698
33699 for (i = 0; i < hoveredLength; i++) {
33700 node = nodes[hovered[i]];
33701
33702 var _drawLater3 = node.draw(ctx);
33703
33704 if (_drawLater3.drawExternalLabel != null) {
33705 _drawExternalLabels.push(_drawLater3.drawExternalLabel);
33706 }
33707 }
33708
33709 return {
33710 drawExternalLabels: function drawExternalLabels() {
33711 var _iterator = _createForOfIteratorHelper$5(_drawExternalLabels),
33712 _step;
33713
33714 try {
33715 for (_iterator.s(); !(_step = _iterator.n()).done;) {
33716 var draw = _step.value;
33717 draw();
33718 }
33719 } catch (err) {
33720 _iterator.e(err);
33721 } finally {
33722 _iterator.f();
33723 }
33724 }
33725 };
33726 }
33727 /**
33728 * Redraw all edges
33729 *
33730 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
33731 * @private
33732 */
33733
33734 }, {
33735 key: "_drawEdges",
33736 value: function _drawEdges(ctx) {
33737 var edges = this.body.edges;
33738 var edgeIndices = this.body.edgeIndices;
33739
33740 for (var i = 0; i < edgeIndices.length; i++) {
33741 var edge = edges[edgeIndices[i]];
33742
33743 if (edge.connected === true) {
33744 edge.draw(ctx);
33745 }
33746 }
33747 }
33748 /**
33749 * Redraw all arrows
33750 *
33751 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
33752 * @private
33753 */
33754
33755 }, {
33756 key: "_drawArrows",
33757 value: function _drawArrows(ctx) {
33758 var edges = this.body.edges;
33759 var edgeIndices = this.body.edgeIndices;
33760
33761 for (var i = 0; i < edgeIndices.length; i++) {
33762 var edge = edges[edgeIndices[i]];
33763
33764 if (edge.connected === true) {
33765 edge.drawArrows(ctx);
33766 }
33767 }
33768 }
33769 /**
33770 * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because
33771 * some implementations (safari and IE9) did not support requestAnimationFrame
33772 *
33773 * @private
33774 */
33775
33776 }, {
33777 key: "_determineBrowserMethod",
33778 value: function _determineBrowserMethod() {
33779 if (typeof window !== "undefined") {
33780 var browserType = navigator.userAgent.toLowerCase();
33781 this.requiresTimeout = false;
33782
33783 if (indexOf(browserType).call(browserType, "msie 9.0") != -1) {
33784 // IE 9
33785 this.requiresTimeout = true;
33786 } else if (indexOf(browserType).call(browserType, "safari") != -1) {
33787 // safari
33788 if (indexOf(browserType).call(browserType, "chrome") <= -1) {
33789 this.requiresTimeout = true;
33790 }
33791 }
33792 } else {
33793 this.requiresTimeout = true;
33794 }
33795 }
33796 /**
33797 * Redraw selection box
33798 *
33799 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
33800 * @private
33801 */
33802
33803 }, {
33804 key: "_drawSelectionBox",
33805 value: function _drawSelectionBox(ctx) {
33806 if (this.body.selectionBox.show) {
33807 ctx.beginPath();
33808 var width = this.body.selectionBox.position.end.x - this.body.selectionBox.position.start.x;
33809 var height = this.body.selectionBox.position.end.y - this.body.selectionBox.position.start.y;
33810 ctx.rect(this.body.selectionBox.position.start.x, this.body.selectionBox.position.start.y, width, height);
33811 ctx.fillStyle = "rgba(151, 194, 252, 0.2)";
33812 ctx.fillRect(this.body.selectionBox.position.start.x, this.body.selectionBox.position.start.y, width, height);
33813 ctx.strokeStyle = "rgba(151, 194, 252, 1)";
33814 ctx.stroke();
33815 } else {
33816 ctx.closePath();
33817 }
33818 }
33819 }]);
33820
33821 return CanvasRenderer;
33822 }();
33823
33824 var path$1 = path$y;
33825 var setInterval$1 = path$1.setInterval;
33826
33827 var setInterval = setInterval$1;
33828
33829 /**
33830 * Register a touch event, taking place before a gesture
33831 *
33832 * @param {Hammer} hammer A hammer instance
33833 * @param {Function} callback Callback, called as callback(event)
33834 */
33835 function onTouch(hammer, callback) {
33836 callback.inputHandler = function (event) {
33837 if (event.isFirst) {
33838 callback(event);
33839 }
33840 };
33841
33842 hammer.on("hammer.input", callback.inputHandler);
33843 }
33844 /**
33845 * Register a release event, taking place after a gesture
33846 *
33847 * @param {Hammer} hammer A hammer instance
33848 * @param {Function} callback Callback, called as callback(event)
33849 * @returns {*}
33850 */
33851
33852 function onRelease(hammer, callback) {
33853 callback.inputHandler = function (event) {
33854 if (event.isFinal) {
33855 callback(event);
33856 }
33857 };
33858
33859 return hammer.on("hammer.input", callback.inputHandler);
33860 }
33861
33862 /**
33863 * Create the main frame for the Network.
33864 * This function is executed once when a Network object is created. The frame
33865 * contains a canvas, and this canvas contains all objects like the axis and
33866 * nodes.
33867 */
33868
33869 var Canvas = /*#__PURE__*/function () {
33870 /**
33871 * @param {object} body
33872 */
33873 function Canvas(body) {
33874 _classCallCheck(this, Canvas);
33875
33876 this.body = body;
33877 this.pixelRatio = 1;
33878 this.cameraState = {};
33879 this.initialized = false;
33880 this.canvasViewCenter = {};
33881 this._cleanupCallbacks = [];
33882 this.options = {};
33883 this.defaultOptions = {
33884 autoResize: true,
33885 height: "100%",
33886 width: "100%"
33887 };
33888
33889 assign$2(this.options, this.defaultOptions);
33890
33891 this.bindEventListeners();
33892 }
33893 /**
33894 * Binds event listeners
33895 */
33896
33897
33898 _createClass(Canvas, [{
33899 key: "bindEventListeners",
33900 value: function bindEventListeners() {
33901 var _this = this,
33902 _context;
33903
33904 // bind the events
33905 this.body.emitter.once("resize", function (obj) {
33906 if (obj.width !== 0) {
33907 _this.body.view.translation.x = obj.width * 0.5;
33908 }
33909
33910 if (obj.height !== 0) {
33911 _this.body.view.translation.y = obj.height * 0.5;
33912 }
33913 });
33914 this.body.emitter.on("setSize", bind$6(_context = this.setSize).call(_context, this));
33915 this.body.emitter.on("destroy", function () {
33916 _this.hammerFrame.destroy();
33917
33918 _this.hammer.destroy();
33919
33920 _this._cleanUp();
33921 });
33922 }
33923 /**
33924 * @param {object} options
33925 */
33926
33927 }, {
33928 key: "setOptions",
33929 value: function setOptions(options) {
33930 var _this2 = this;
33931
33932 if (options !== undefined) {
33933 var fields = ["width", "height", "autoResize"];
33934 selectiveDeepExtend(fields, this.options, options);
33935 } // Automatically adapt to changing size of the container element.
33936
33937
33938 this._cleanUp();
33939
33940 if (this.options.autoResize === true) {
33941 var _context2;
33942
33943 if (window.ResizeObserver) {
33944 // decent browsers, immediate reactions
33945 var observer = new ResizeObserver(function () {
33946 var changed = _this2.setSize();
33947
33948 if (changed === true) {
33949 _this2.body.emitter.emit("_requestRedraw");
33950 }
33951 });
33952 var frame = this.frame;
33953 observer.observe(frame);
33954
33955 this._cleanupCallbacks.push(function () {
33956 observer.unobserve(frame);
33957 });
33958 } else {
33959 // IE11, continous polling
33960 var resizeTimer = setInterval(function () {
33961 var changed = _this2.setSize();
33962
33963 if (changed === true) {
33964 _this2.body.emitter.emit("_requestRedraw");
33965 }
33966 }, 1000);
33967
33968 this._cleanupCallbacks.push(function () {
33969 clearInterval(resizeTimer);
33970 });
33971 } // Automatically adapt to changing size of the browser.
33972
33973
33974 var resizeFunction = bind$6(_context2 = this._onResize).call(_context2, this);
33975
33976 addEventListener(window, "resize", resizeFunction);
33977
33978 this._cleanupCallbacks.push(function () {
33979 removeEventListener(window, "resize", resizeFunction);
33980 });
33981 }
33982 }
33983 /**
33984 * @private
33985 */
33986
33987 }, {
33988 key: "_cleanUp",
33989 value: function _cleanUp() {
33990 var _context3, _context4, _context5;
33991
33992 forEach$2(_context3 = reverse(_context4 = splice$1(_context5 = this._cleanupCallbacks).call(_context5, 0)).call(_context4)).call(_context3, function (callback) {
33993 try {
33994 callback();
33995 } catch (error) {
33996 console.error(error);
33997 }
33998 });
33999 }
34000 /**
34001 * @private
34002 */
34003
34004 }, {
34005 key: "_onResize",
34006 value: function _onResize() {
34007 this.setSize();
34008 this.body.emitter.emit("_redraw");
34009 }
34010 /**
34011 * Get and store the cameraState
34012 *
34013 * @param {number} [pixelRatio=this.pixelRatio]
34014 * @private
34015 */
34016
34017 }, {
34018 key: "_getCameraState",
34019 value: function _getCameraState() {
34020 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.pixelRatio;
34021
34022 if (this.initialized === true) {
34023 this.cameraState.previousWidth = this.frame.canvas.width / pixelRatio;
34024 this.cameraState.previousHeight = this.frame.canvas.height / pixelRatio;
34025 this.cameraState.scale = this.body.view.scale;
34026 this.cameraState.position = this.DOMtoCanvas({
34027 x: 0.5 * this.frame.canvas.width / pixelRatio,
34028 y: 0.5 * this.frame.canvas.height / pixelRatio
34029 });
34030 }
34031 }
34032 /**
34033 * Set the cameraState
34034 *
34035 * @private
34036 */
34037
34038 }, {
34039 key: "_setCameraState",
34040 value: function _setCameraState() {
34041 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) {
34042 var widthRatio = this.frame.canvas.width / this.pixelRatio / this.cameraState.previousWidth;
34043 var heightRatio = this.frame.canvas.height / this.pixelRatio / this.cameraState.previousHeight;
34044 var newScale = this.cameraState.scale;
34045
34046 if (widthRatio != 1 && heightRatio != 1) {
34047 newScale = this.cameraState.scale * 0.5 * (widthRatio + heightRatio);
34048 } else if (widthRatio != 1) {
34049 newScale = this.cameraState.scale * widthRatio;
34050 } else if (heightRatio != 1) {
34051 newScale = this.cameraState.scale * heightRatio;
34052 }
34053
34054 this.body.view.scale = newScale; // this comes from the view module.
34055
34056 var currentViewCenter = this.DOMtoCanvas({
34057 x: 0.5 * this.frame.canvas.clientWidth,
34058 y: 0.5 * this.frame.canvas.clientHeight
34059 });
34060 var distanceFromCenter = {
34061 // offset from view, distance view has to change by these x and y to center the node
34062 x: currentViewCenter.x - this.cameraState.position.x,
34063 y: currentViewCenter.y - this.cameraState.position.y
34064 };
34065 this.body.view.translation.x += distanceFromCenter.x * this.body.view.scale;
34066 this.body.view.translation.y += distanceFromCenter.y * this.body.view.scale;
34067 }
34068 }
34069 /**
34070 *
34071 * @param {number|string} value
34072 * @returns {string}
34073 * @private
34074 */
34075
34076 }, {
34077 key: "_prepareValue",
34078 value: function _prepareValue(value) {
34079 if (typeof value === "number") {
34080 return value + "px";
34081 } else if (typeof value === "string") {
34082 if (indexOf(value).call(value, "%") !== -1 || indexOf(value).call(value, "px") !== -1) {
34083 return value;
34084 } else if (indexOf(value).call(value, "%") === -1) {
34085 return value + "px";
34086 }
34087 }
34088
34089 throw new Error("Could not use the value supplied for width or height:" + value);
34090 }
34091 /**
34092 * Create the HTML
34093 */
34094
34095 }, {
34096 key: "_create",
34097 value: function _create() {
34098 // remove all elements from the container element.
34099 while (this.body.container.hasChildNodes()) {
34100 this.body.container.removeChild(this.body.container.firstChild);
34101 }
34102
34103 this.frame = document.createElement("div");
34104 this.frame.className = "vis-network";
34105 this.frame.style.position = "relative";
34106 this.frame.style.overflow = "hidden";
34107 this.frame.tabIndex = 0; // tab index is required for keycharm to bind keystrokes to the div instead of the window
34108 //////////////////////////////////////////////////////////////////
34109
34110 this.frame.canvas = document.createElement("canvas");
34111 this.frame.canvas.style.position = "relative";
34112 this.frame.appendChild(this.frame.canvas);
34113
34114 if (!this.frame.canvas.getContext) {
34115 var noCanvas = document.createElement("DIV");
34116 noCanvas.style.color = "red";
34117 noCanvas.style.fontWeight = "bold";
34118 noCanvas.style.padding = "10px";
34119 noCanvas.innerText = "Error: your browser does not support HTML canvas";
34120 this.frame.canvas.appendChild(noCanvas);
34121 } else {
34122 this._setPixelRatio();
34123
34124 this.setTransform();
34125 } // add the frame to the container element
34126
34127
34128 this.body.container.appendChild(this.frame);
34129 this.body.view.scale = 1;
34130 this.body.view.translation = {
34131 x: 0.5 * this.frame.canvas.clientWidth,
34132 y: 0.5 * this.frame.canvas.clientHeight
34133 };
34134
34135 this._bindHammer();
34136 }
34137 /**
34138 * This function binds hammer, it can be repeated over and over due to the uniqueness check.
34139 *
34140 * @private
34141 */
34142
34143 }, {
34144 key: "_bindHammer",
34145 value: function _bindHammer() {
34146 var _this3 = this;
34147
34148 if (this.hammer !== undefined) {
34149 this.hammer.destroy();
34150 }
34151
34152 this.drag = {};
34153 this.pinch = {}; // init hammer
34154
34155 this.hammer = new Hammer(this.frame.canvas);
34156 this.hammer.get("pinch").set({
34157 enable: true
34158 }); // enable to get better response, todo: test on mobile.
34159
34160 this.hammer.get("pan").set({
34161 threshold: 5,
34162 direction: Hammer.DIRECTION_ALL
34163 });
34164 onTouch(this.hammer, function (event) {
34165 _this3.body.eventListeners.onTouch(event);
34166 });
34167 this.hammer.on("tap", function (event) {
34168 _this3.body.eventListeners.onTap(event);
34169 });
34170 this.hammer.on("doubletap", function (event) {
34171 _this3.body.eventListeners.onDoubleTap(event);
34172 });
34173 this.hammer.on("press", function (event) {
34174 _this3.body.eventListeners.onHold(event);
34175 });
34176 this.hammer.on("panstart", function (event) {
34177 _this3.body.eventListeners.onDragStart(event);
34178 });
34179 this.hammer.on("panmove", function (event) {
34180 _this3.body.eventListeners.onDrag(event);
34181 });
34182 this.hammer.on("panend", function (event) {
34183 _this3.body.eventListeners.onDragEnd(event);
34184 });
34185 this.hammer.on("pinch", function (event) {
34186 _this3.body.eventListeners.onPinch(event);
34187 }); // TODO: neatly cleanup these handlers when re-creating the Canvas, IF these are done with hammer, event.stopPropagation will not work?
34188
34189 this.frame.canvas.addEventListener("wheel", function (event) {
34190 _this3.body.eventListeners.onMouseWheel(event);
34191 });
34192 this.frame.canvas.addEventListener("mousemove", function (event) {
34193 _this3.body.eventListeners.onMouseMove(event);
34194 });
34195 this.frame.canvas.addEventListener("contextmenu", function (event) {
34196 _this3.body.eventListeners.onContext(event);
34197 });
34198 this.hammerFrame = new Hammer(this.frame);
34199 onRelease(this.hammerFrame, function (event) {
34200 _this3.body.eventListeners.onRelease(event);
34201 });
34202 }
34203 /**
34204 * Set a new size for the network
34205 *
34206 * @param {string} width Width in pixels or percentage (for example '800px'
34207 * or '50%')
34208 * @param {string} height Height in pixels or percentage (for example '400px'
34209 * or '30%')
34210 * @returns {boolean}
34211 */
34212
34213 }, {
34214 key: "setSize",
34215 value: function setSize() {
34216 var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.width;
34217 var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.height;
34218 width = this._prepareValue(width);
34219 height = this._prepareValue(height);
34220 var emitEvent = false;
34221 var oldWidth = this.frame.canvas.width;
34222 var oldHeight = this.frame.canvas.height; // update the pixel ratio
34223 //
34224 // NOTE: Comment in following is rather inconsistent; this is the ONLY place in the code
34225 // where it is assumed that the pixel ratio could change at runtime.
34226 // The only way I can think of this happening is a rotating screen or tablet; but then
34227 // there should be a mechanism for reloading the data (TODO: check if this is present).
34228 //
34229 // If the assumption is true (i.e. pixel ratio can change at runtime), then *all* usage
34230 // of pixel ratio must be overhauled for this.
34231 //
34232 // For the time being, I will humor the assumption here, and in the rest of the code assume it is
34233 // constant.
34234
34235 var previousRatio = this.pixelRatio; // we cache this because the camera state storage needs the old value
34236
34237 this._setPixelRatio();
34238
34239 if (width != this.options.width || height != this.options.height || this.frame.style.width != width || this.frame.style.height != height) {
34240 this._getCameraState(previousRatio);
34241
34242 this.frame.style.width = width;
34243 this.frame.style.height = height;
34244 this.frame.canvas.style.width = "100%";
34245 this.frame.canvas.style.height = "100%";
34246 this.frame.canvas.width = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
34247 this.frame.canvas.height = Math.round(this.frame.canvas.clientHeight * this.pixelRatio);
34248 this.options.width = width;
34249 this.options.height = height;
34250 this.canvasViewCenter = {
34251 x: 0.5 * this.frame.clientWidth,
34252 y: 0.5 * this.frame.clientHeight
34253 };
34254 emitEvent = true;
34255 } else {
34256 // this would adapt the width of the canvas to the width from 100% if and only if
34257 // there is a change.
34258 var newWidth = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
34259 var newHeight = Math.round(this.frame.canvas.clientHeight * this.pixelRatio); // store the camera if there is a change in size.
34260
34261 if (this.frame.canvas.width !== newWidth || this.frame.canvas.height !== newHeight) {
34262 this._getCameraState(previousRatio);
34263 }
34264
34265 if (this.frame.canvas.width !== newWidth) {
34266 this.frame.canvas.width = newWidth;
34267 emitEvent = true;
34268 }
34269
34270 if (this.frame.canvas.height !== newHeight) {
34271 this.frame.canvas.height = newHeight;
34272 emitEvent = true;
34273 }
34274 }
34275
34276 if (emitEvent === true) {
34277 this.body.emitter.emit("resize", {
34278 width: Math.round(this.frame.canvas.width / this.pixelRatio),
34279 height: Math.round(this.frame.canvas.height / this.pixelRatio),
34280 oldWidth: Math.round(oldWidth / this.pixelRatio),
34281 oldHeight: Math.round(oldHeight / this.pixelRatio)
34282 }); // restore the camera on change.
34283
34284 this._setCameraState();
34285 } // set initialized so the get and set camera will work from now on.
34286
34287
34288 this.initialized = true;
34289 return emitEvent;
34290 }
34291 /**
34292 *
34293 * @returns {CanvasRenderingContext2D}
34294 */
34295
34296 }, {
34297 key: "getContext",
34298 value: function getContext() {
34299 return this.frame.canvas.getContext("2d");
34300 }
34301 /**
34302 * Determine the pixel ratio for various browsers.
34303 *
34304 * @returns {number}
34305 * @private
34306 */
34307
34308 }, {
34309 key: "_determinePixelRatio",
34310 value: function _determinePixelRatio() {
34311 var ctx = this.getContext();
34312
34313 if (ctx === undefined) {
34314 throw new Error("Could not get canvax context");
34315 }
34316
34317 var numerator = 1;
34318
34319 if (typeof window !== "undefined") {
34320 // (window !== undefined) doesn't work here!
34321 // Protection during unit tests, where 'window' can be missing
34322 numerator = window.devicePixelRatio || 1;
34323 }
34324
34325 var denominator = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
34326 return numerator / denominator;
34327 }
34328 /**
34329 * Lazy determination of pixel ratio.
34330 *
34331 * @private
34332 */
34333
34334 }, {
34335 key: "_setPixelRatio",
34336 value: function _setPixelRatio() {
34337 this.pixelRatio = this._determinePixelRatio();
34338 }
34339 /**
34340 * Set the transform in the contained context, based on its pixelRatio
34341 */
34342
34343 }, {
34344 key: "setTransform",
34345 value: function setTransform() {
34346 var ctx = this.getContext();
34347
34348 if (ctx === undefined) {
34349 throw new Error("Could not get canvax context");
34350 }
34351
34352 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
34353 }
34354 /**
34355 * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
34356 * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
34357 *
34358 * @param {number} x
34359 * @returns {number}
34360 * @private
34361 */
34362
34363 }, {
34364 key: "_XconvertDOMtoCanvas",
34365 value: function _XconvertDOMtoCanvas(x) {
34366 return (x - this.body.view.translation.x) / this.body.view.scale;
34367 }
34368 /**
34369 * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
34370 * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
34371 *
34372 * @param {number} x
34373 * @returns {number}
34374 * @private
34375 */
34376
34377 }, {
34378 key: "_XconvertCanvasToDOM",
34379 value: function _XconvertCanvasToDOM(x) {
34380 return x * this.body.view.scale + this.body.view.translation.x;
34381 }
34382 /**
34383 * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
34384 * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
34385 *
34386 * @param {number} y
34387 * @returns {number}
34388 * @private
34389 */
34390
34391 }, {
34392 key: "_YconvertDOMtoCanvas",
34393 value: function _YconvertDOMtoCanvas(y) {
34394 return (y - this.body.view.translation.y) / this.body.view.scale;
34395 }
34396 /**
34397 * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
34398 * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
34399 *
34400 * @param {number} y
34401 * @returns {number}
34402 * @private
34403 */
34404
34405 }, {
34406 key: "_YconvertCanvasToDOM",
34407 value: function _YconvertCanvasToDOM(y) {
34408 return y * this.body.view.scale + this.body.view.translation.y;
34409 }
34410 /**
34411 * @param {point} pos
34412 * @returns {point}
34413 */
34414
34415 }, {
34416 key: "canvasToDOM",
34417 value: function canvasToDOM(pos) {
34418 return {
34419 x: this._XconvertCanvasToDOM(pos.x),
34420 y: this._YconvertCanvasToDOM(pos.y)
34421 };
34422 }
34423 /**
34424 *
34425 * @param {point} pos
34426 * @returns {point}
34427 */
34428
34429 }, {
34430 key: "DOMtoCanvas",
34431 value: function DOMtoCanvas(pos) {
34432 return {
34433 x: this._XconvertDOMtoCanvas(pos.x),
34434 y: this._YconvertDOMtoCanvas(pos.y)
34435 };
34436 }
34437 }]);
34438
34439 return Canvas;
34440 }();
34441
34442 /**
34443 * Validate the fit options, replace missing optional values by defaults etc.
34444 *
34445 * @param rawOptions - The raw options.
34446 * @param allNodeIds - All node ids that will be used if nodes are omitted in
34447 * the raw options.
34448 * @returns Options with everything filled in and validated.
34449 */
34450 function normalizeFitOptions(rawOptions, allNodeIds) {
34451 var options = assign$2({
34452 nodes: allNodeIds,
34453 minZoomLevel: Number.MIN_VALUE,
34454 maxZoomLevel: 1
34455 }, rawOptions !== null && rawOptions !== void 0 ? rawOptions : {});
34456
34457 if (!isArray$2(options.nodes)) {
34458 throw new TypeError("Nodes has to be an array of ids.");
34459 }
34460
34461 if (options.nodes.length === 0) {
34462 options.nodes = allNodeIds;
34463 }
34464
34465 if (!(typeof options.minZoomLevel === "number" && options.minZoomLevel > 0)) {
34466 throw new TypeError("Min zoom level has to be a number higher than zero.");
34467 }
34468
34469 if (!(typeof options.maxZoomLevel === "number" && options.minZoomLevel <= options.maxZoomLevel)) {
34470 throw new TypeError("Max zoom level has to be a number higher than min zoom level.");
34471 }
34472
34473 return options;
34474 }
34475
34476 /**
34477 * The view
34478 */
34479
34480 var View = /*#__PURE__*/function () {
34481 /**
34482 * @param {object} body
34483 * @param {Canvas} canvas
34484 */
34485 function View(body, canvas) {
34486 var _context,
34487 _this = this,
34488 _context2;
34489
34490 _classCallCheck(this, View);
34491
34492 this.body = body;
34493 this.canvas = canvas;
34494 this.animationSpeed = 1 / this.renderRefreshRate;
34495 this.animationEasingFunction = "easeInOutQuint";
34496 this.easingTime = 0;
34497 this.sourceScale = 0;
34498 this.targetScale = 0;
34499 this.sourceTranslation = 0;
34500 this.targetTranslation = 0;
34501 this.lockedOnNodeId = undefined;
34502 this.lockedOnNodeOffset = undefined;
34503 this.touchTime = 0;
34504 this.viewFunction = undefined;
34505 this.body.emitter.on("fit", bind$6(_context = this.fit).call(_context, this));
34506 this.body.emitter.on("animationFinished", function () {
34507 _this.body.emitter.emit("_stopRendering");
34508 });
34509 this.body.emitter.on("unlockNode", bind$6(_context2 = this.releaseNode).call(_context2, this));
34510 }
34511 /**
34512 *
34513 * @param {object} [options={}]
34514 */
34515
34516
34517 _createClass(View, [{
34518 key: "setOptions",
34519 value: function setOptions() {
34520 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
34521 this.options = options;
34522 }
34523 /**
34524 * This function zooms out to fit all data on screen based on amount of nodes
34525 *
34526 * @param {object} [options={{nodes=Array}}]
34527 * @param options
34528 * @param {boolean} [initialZoom=false] | zoom based on fitted formula or range, true = fitted, default = false;
34529 */
34530
34531 }, {
34532 key: "fit",
34533 value: function fit(options) {
34534 var initialZoom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
34535 options = normalizeFitOptions(options, this.body.nodeIndices);
34536 var canvasWidth = this.canvas.frame.canvas.clientWidth;
34537 var canvasHeight = this.canvas.frame.canvas.clientHeight;
34538 var range;
34539 var zoomLevel;
34540
34541 if (canvasWidth === 0 || canvasHeight === 0) {
34542 // There's no point in trying to fit into zero sized canvas. This could
34543 // potentially even result in invalid values being computed. For example
34544 // for network without nodes and zero sized canvas the zoom level would
34545 // end up being computed as 0/0 which results in NaN. In any other case
34546 // this would be 0/something which is again pointless to compute.
34547 zoomLevel = 1;
34548 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
34549 } else if (initialZoom === true) {
34550 // check if more than half of the nodes have a predefined position. If so, we use the range, not the approximation.
34551 var positionDefined = 0;
34552
34553 for (var nodeId in this.body.nodes) {
34554 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
34555 var node = this.body.nodes[nodeId];
34556
34557 if (node.predefinedPosition === true) {
34558 positionDefined += 1;
34559 }
34560 }
34561 }
34562
34563 if (positionDefined > 0.5 * this.body.nodeIndices.length) {
34564 this.fit(options, false);
34565 return;
34566 }
34567
34568 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
34569 var numberOfNodes = this.body.nodeIndices.length;
34570 zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
34571 // correct for larger canvasses.
34572
34573 var factor = Math.min(canvasWidth / 600, canvasHeight / 600);
34574 zoomLevel *= factor;
34575 } else {
34576 this.body.emitter.emit("_resizeNodes");
34577 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
34578 var xDistance = Math.abs(range.maxX - range.minX) * 1.1;
34579 var yDistance = Math.abs(range.maxY - range.minY) * 1.1;
34580 var xZoomLevel = canvasWidth / xDistance;
34581 var yZoomLevel = canvasHeight / yDistance;
34582 zoomLevel = xZoomLevel <= yZoomLevel ? xZoomLevel : yZoomLevel;
34583 }
34584
34585 if (zoomLevel > options.maxZoomLevel) {
34586 zoomLevel = options.maxZoomLevel;
34587 } else if (zoomLevel < options.minZoomLevel) {
34588 zoomLevel = options.minZoomLevel;
34589 }
34590
34591 var center = NetworkUtil.findCenter(range);
34592 var animationOptions = {
34593 position: center,
34594 scale: zoomLevel,
34595 animation: options.animation
34596 };
34597 this.moveTo(animationOptions);
34598 } // animation
34599
34600 /**
34601 * Center a node in view.
34602 *
34603 * @param {number} nodeId
34604 * @param {number} [options]
34605 */
34606
34607 }, {
34608 key: "focus",
34609 value: function focus(nodeId) {
34610 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
34611
34612 if (this.body.nodes[nodeId] !== undefined) {
34613 var nodePosition = {
34614 x: this.body.nodes[nodeId].x,
34615 y: this.body.nodes[nodeId].y
34616 };
34617 options.position = nodePosition;
34618 options.lockedOnNode = nodeId;
34619 this.moveTo(options);
34620 } else {
34621 console.error("Node: " + nodeId + " cannot be found.");
34622 }
34623 }
34624 /**
34625 *
34626 * @param {object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
34627 * | options.scale = number // scale to move to
34628 * | options.position = {x:number, y:number} // position to move to
34629 * | options.animation = {duration:number, easingFunction:String} || Boolean // position to move to
34630 */
34631
34632 }, {
34633 key: "moveTo",
34634 value: function moveTo(options) {
34635 if (options === undefined) {
34636 options = {};
34637 return;
34638 }
34639
34640 if (options.offset != null) {
34641 if (options.offset.x != null) {
34642 // Coerce and verify that x is valid.
34643 options.offset.x = +options.offset.x;
34644
34645 if (!_isFinite(options.offset.x)) {
34646 throw new TypeError('The option "offset.x" has to be a finite number.');
34647 }
34648 } else {
34649 options.offset.x = 0;
34650 }
34651
34652 if (options.offset.y != null) {
34653 // Coerce and verify that y is valid.
34654 options.offset.y = +options.offset.y;
34655
34656 if (!_isFinite(options.offset.y)) {
34657 throw new TypeError('The option "offset.y" has to be a finite number.');
34658 }
34659 } else {
34660 options.offset.x = 0;
34661 }
34662 } else {
34663 options.offset = {
34664 x: 0,
34665 y: 0
34666 };
34667 }
34668
34669 if (options.position != null) {
34670 if (options.position.x != null) {
34671 // Coerce and verify that x is valid.
34672 options.position.x = +options.position.x;
34673
34674 if (!_isFinite(options.position.x)) {
34675 throw new TypeError('The option "position.x" has to be a finite number.');
34676 }
34677 } else {
34678 options.position.x = 0;
34679 }
34680
34681 if (options.position.y != null) {
34682 // Coerce and verify that y is valid.
34683 options.position.y = +options.position.y;
34684
34685 if (!_isFinite(options.position.y)) {
34686 throw new TypeError('The option "position.y" has to be a finite number.');
34687 }
34688 } else {
34689 options.position.x = 0;
34690 }
34691 } else {
34692 options.position = this.getViewPosition();
34693 }
34694
34695 if (options.scale != null) {
34696 // Coerce and verify that the scale is valid.
34697 options.scale = +options.scale;
34698
34699 if (!(options.scale > 0)) {
34700 throw new TypeError('The option "scale" has to be a number greater than zero.');
34701 }
34702 } else {
34703 options.scale = this.body.view.scale;
34704 }
34705
34706 if (options.animation === undefined) {
34707 options.animation = {
34708 duration: 0
34709 };
34710 }
34711
34712 if (options.animation === false) {
34713 options.animation = {
34714 duration: 0
34715 };
34716 }
34717
34718 if (options.animation === true) {
34719 options.animation = {};
34720 }
34721
34722 if (options.animation.duration === undefined) {
34723 options.animation.duration = 1000;
34724 } // default duration
34725
34726
34727 if (options.animation.easingFunction === undefined) {
34728 options.animation.easingFunction = "easeInOutQuad";
34729 } // default easing function
34730
34731
34732 this.animateView(options);
34733 }
34734 /**
34735 *
34736 * @param {object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
34737 * | options.time = number // animation time in milliseconds
34738 * | options.scale = number // scale to animate to
34739 * | options.position = {x:number, y:number} // position to animate to
34740 * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad,
34741 * // easeInCubic, easeOutCubic, easeInOutCubic,
34742 * // easeInQuart, easeOutQuart, easeInOutQuart,
34743 * // easeInQuint, easeOutQuint, easeInOutQuint
34744 */
34745
34746 }, {
34747 key: "animateView",
34748 value: function animateView(options) {
34749 if (options === undefined) {
34750 return;
34751 }
34752
34753 this.animationEasingFunction = options.animation.easingFunction; // release if something focussed on the node
34754
34755 this.releaseNode();
34756
34757 if (options.locked === true) {
34758 this.lockedOnNodeId = options.lockedOnNode;
34759 this.lockedOnNodeOffset = options.offset;
34760 } // forcefully complete the old animation if it was still running
34761
34762
34763 if (this.easingTime != 0) {
34764 this._transitionRedraw(true); // by setting easingtime to 1, we finish the animation.
34765
34766 }
34767
34768 this.sourceScale = this.body.view.scale;
34769 this.sourceTranslation = this.body.view.translation;
34770 this.targetScale = options.scale; // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw
34771 // but at least then we'll have the target transition
34772
34773 this.body.view.scale = this.targetScale;
34774 var viewCenter = this.canvas.DOMtoCanvas({
34775 x: 0.5 * this.canvas.frame.canvas.clientWidth,
34776 y: 0.5 * this.canvas.frame.canvas.clientHeight
34777 });
34778 var distanceFromCenter = {
34779 // offset from view, distance view has to change by these x and y to center the node
34780 x: viewCenter.x - options.position.x,
34781 y: viewCenter.y - options.position.y
34782 };
34783 this.targetTranslation = {
34784 x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x,
34785 y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y
34786 }; // if the time is set to 0, don't do an animation
34787
34788 if (options.animation.duration === 0) {
34789 if (this.lockedOnNodeId != undefined) {
34790 var _context3;
34791
34792 this.viewFunction = bind$6(_context3 = this._lockedRedraw).call(_context3, this);
34793 this.body.emitter.on("initRedraw", this.viewFunction);
34794 } else {
34795 this.body.view.scale = this.targetScale;
34796 this.body.view.translation = this.targetTranslation;
34797 this.body.emitter.emit("_requestRedraw");
34798 }
34799 } else {
34800 var _context4;
34801
34802 this.animationSpeed = 1 / (60 * options.animation.duration * 0.001) || 1 / 60; // 60 for 60 seconds, 0.001 for milli's
34803
34804 this.animationEasingFunction = options.animation.easingFunction;
34805 this.viewFunction = bind$6(_context4 = this._transitionRedraw).call(_context4, this);
34806 this.body.emitter.on("initRedraw", this.viewFunction);
34807 this.body.emitter.emit("_startRendering");
34808 }
34809 }
34810 /**
34811 * used to animate smoothly by hijacking the redraw function.
34812 *
34813 * @private
34814 */
34815
34816 }, {
34817 key: "_lockedRedraw",
34818 value: function _lockedRedraw() {
34819 var nodePosition = {
34820 x: this.body.nodes[this.lockedOnNodeId].x,
34821 y: this.body.nodes[this.lockedOnNodeId].y
34822 };
34823 var viewCenter = this.canvas.DOMtoCanvas({
34824 x: 0.5 * this.canvas.frame.canvas.clientWidth,
34825 y: 0.5 * this.canvas.frame.canvas.clientHeight
34826 });
34827 var distanceFromCenter = {
34828 // offset from view, distance view has to change by these x and y to center the node
34829 x: viewCenter.x - nodePosition.x,
34830 y: viewCenter.y - nodePosition.y
34831 };
34832 var sourceTranslation = this.body.view.translation;
34833 var targetTranslation = {
34834 x: sourceTranslation.x + distanceFromCenter.x * this.body.view.scale + this.lockedOnNodeOffset.x,
34835 y: sourceTranslation.y + distanceFromCenter.y * this.body.view.scale + this.lockedOnNodeOffset.y
34836 };
34837 this.body.view.translation = targetTranslation;
34838 }
34839 /**
34840 * Resets state of a locked on Node
34841 */
34842
34843 }, {
34844 key: "releaseNode",
34845 value: function releaseNode() {
34846 if (this.lockedOnNodeId !== undefined && this.viewFunction !== undefined) {
34847 this.body.emitter.off("initRedraw", this.viewFunction);
34848 this.lockedOnNodeId = undefined;
34849 this.lockedOnNodeOffset = undefined;
34850 }
34851 }
34852 /**
34853 * @param {boolean} [finished=false]
34854 * @private
34855 */
34856
34857 }, {
34858 key: "_transitionRedraw",
34859 value: function _transitionRedraw() {
34860 var finished = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
34861 this.easingTime += this.animationSpeed;
34862 this.easingTime = finished === true ? 1.0 : this.easingTime;
34863 var progress = easingFunctions[this.animationEasingFunction](this.easingTime);
34864 this.body.view.scale = this.sourceScale + (this.targetScale - this.sourceScale) * progress;
34865 this.body.view.translation = {
34866 x: this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress,
34867 y: this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress
34868 }; // cleanup
34869
34870 if (this.easingTime >= 1.0) {
34871 this.body.emitter.off("initRedraw", this.viewFunction);
34872 this.easingTime = 0;
34873
34874 if (this.lockedOnNodeId != undefined) {
34875 var _context5;
34876
34877 this.viewFunction = bind$6(_context5 = this._lockedRedraw).call(_context5, this);
34878 this.body.emitter.on("initRedraw", this.viewFunction);
34879 }
34880
34881 this.body.emitter.emit("animationFinished");
34882 }
34883 }
34884 /**
34885 *
34886 * @returns {number}
34887 */
34888
34889 }, {
34890 key: "getScale",
34891 value: function getScale() {
34892 return this.body.view.scale;
34893 }
34894 /**
34895 *
34896 * @returns {{x: number, y: number}}
34897 */
34898
34899 }, {
34900 key: "getViewPosition",
34901 value: function getViewPosition() {
34902 return this.canvas.DOMtoCanvas({
34903 x: 0.5 * this.canvas.frame.canvas.clientWidth,
34904 y: 0.5 * this.canvas.frame.canvas.clientHeight
34905 });
34906 }
34907 }]);
34908
34909 return View;
34910 }();
34911
34912 /**
34913 * Created by Alex on 11/6/2014.
34914 */
34915 function keycharm(options) {
34916 var preventDefault = options && options.preventDefault || false;
34917 var container = options && options.container || window;
34918 var _exportFunctions = {};
34919 var _bound = {
34920 keydown: {},
34921 keyup: {}
34922 };
34923 var _keys = {};
34924 var i; // a - z
34925
34926 for (i = 97; i <= 122; i++) {
34927 _keys[String.fromCharCode(i)] = {
34928 code: 65 + (i - 97),
34929 shift: false
34930 };
34931 } // A - Z
34932
34933
34934 for (i = 65; i <= 90; i++) {
34935 _keys[String.fromCharCode(i)] = {
34936 code: i,
34937 shift: true
34938 };
34939 } // 0 - 9
34940
34941
34942 for (i = 0; i <= 9; i++) {
34943 _keys['' + i] = {
34944 code: 48 + i,
34945 shift: false
34946 };
34947 } // F1 - F12
34948
34949
34950 for (i = 1; i <= 12; i++) {
34951 _keys['F' + i] = {
34952 code: 111 + i,
34953 shift: false
34954 };
34955 } // num0 - num9
34956
34957
34958 for (i = 0; i <= 9; i++) {
34959 _keys['num' + i] = {
34960 code: 96 + i,
34961 shift: false
34962 };
34963 } // numpad misc
34964
34965
34966 _keys['num*'] = {
34967 code: 106,
34968 shift: false
34969 };
34970 _keys['num+'] = {
34971 code: 107,
34972 shift: false
34973 };
34974 _keys['num-'] = {
34975 code: 109,
34976 shift: false
34977 };
34978 _keys['num/'] = {
34979 code: 111,
34980 shift: false
34981 };
34982 _keys['num.'] = {
34983 code: 110,
34984 shift: false
34985 }; // arrows
34986
34987 _keys['left'] = {
34988 code: 37,
34989 shift: false
34990 };
34991 _keys['up'] = {
34992 code: 38,
34993 shift: false
34994 };
34995 _keys['right'] = {
34996 code: 39,
34997 shift: false
34998 };
34999 _keys['down'] = {
35000 code: 40,
35001 shift: false
35002 }; // extra keys
35003
35004 _keys['space'] = {
35005 code: 32,
35006 shift: false
35007 };
35008 _keys['enter'] = {
35009 code: 13,
35010 shift: false
35011 };
35012 _keys['shift'] = {
35013 code: 16,
35014 shift: undefined
35015 };
35016 _keys['esc'] = {
35017 code: 27,
35018 shift: false
35019 };
35020 _keys['backspace'] = {
35021 code: 8,
35022 shift: false
35023 };
35024 _keys['tab'] = {
35025 code: 9,
35026 shift: false
35027 };
35028 _keys['ctrl'] = {
35029 code: 17,
35030 shift: false
35031 };
35032 _keys['alt'] = {
35033 code: 18,
35034 shift: false
35035 };
35036 _keys['delete'] = {
35037 code: 46,
35038 shift: false
35039 };
35040 _keys['pageup'] = {
35041 code: 33,
35042 shift: false
35043 };
35044 _keys['pagedown'] = {
35045 code: 34,
35046 shift: false
35047 }; // symbols
35048
35049 _keys['='] = {
35050 code: 187,
35051 shift: false
35052 };
35053 _keys['-'] = {
35054 code: 189,
35055 shift: false
35056 };
35057 _keys[']'] = {
35058 code: 221,
35059 shift: false
35060 };
35061 _keys['['] = {
35062 code: 219,
35063 shift: false
35064 };
35065
35066 var down = function (event) {
35067 handleEvent(event, 'keydown');
35068 };
35069
35070 var up = function (event) {
35071 handleEvent(event, 'keyup');
35072 }; // handle the actualy bound key with the event
35073
35074
35075 var handleEvent = function (event, type) {
35076 if (_bound[type][event.keyCode] !== undefined) {
35077 var bound = _bound[type][event.keyCode];
35078
35079 for (var i = 0; i < bound.length; i++) {
35080 if (bound[i].shift === undefined) {
35081 bound[i].fn(event);
35082 } else if (bound[i].shift == true && event.shiftKey == true) {
35083 bound[i].fn(event);
35084 } else if (bound[i].shift == false && event.shiftKey == false) {
35085 bound[i].fn(event);
35086 }
35087 }
35088
35089 if (preventDefault == true) {
35090 event.preventDefault();
35091 }
35092 }
35093 }; // bind a key to a callback
35094
35095
35096 _exportFunctions.bind = function (key, callback, type) {
35097 if (type === undefined) {
35098 type = 'keydown';
35099 }
35100
35101 if (_keys[key] === undefined) {
35102 throw new Error("unsupported key: " + key);
35103 }
35104
35105 if (_bound[type][_keys[key].code] === undefined) {
35106 _bound[type][_keys[key].code] = [];
35107 }
35108
35109 _bound[type][_keys[key].code].push({
35110 fn: callback,
35111 shift: _keys[key].shift
35112 });
35113 }; // bind all keys to a call back (demo purposes)
35114
35115
35116 _exportFunctions.bindAll = function (callback, type) {
35117 if (type === undefined) {
35118 type = 'keydown';
35119 }
35120
35121 for (var key in _keys) {
35122 if (_keys.hasOwnProperty(key)) {
35123 _exportFunctions.bind(key, callback, type);
35124 }
35125 }
35126 }; // get the key label from an event
35127
35128
35129 _exportFunctions.getKey = function (event) {
35130 for (var key in _keys) {
35131 if (_keys.hasOwnProperty(key)) {
35132 if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) {
35133 return key;
35134 } else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) {
35135 return key;
35136 } else if (event.keyCode == _keys[key].code && key == 'shift') {
35137 return key;
35138 }
35139 }
35140 }
35141
35142 return "unknown key, currently not supported";
35143 }; // unbind either a specific callback from a key or all of them (by leaving callback undefined)
35144
35145
35146 _exportFunctions.unbind = function (key, callback, type) {
35147 if (type === undefined) {
35148 type = 'keydown';
35149 }
35150
35151 if (_keys[key] === undefined) {
35152 throw new Error("unsupported key: " + key);
35153 }
35154
35155 if (callback !== undefined) {
35156 var newBindings = [];
35157 var bound = _bound[type][_keys[key].code];
35158
35159 if (bound !== undefined) {
35160 for (var i = 0; i < bound.length; i++) {
35161 if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) {
35162 newBindings.push(_bound[type][_keys[key].code][i]);
35163 }
35164 }
35165 }
35166
35167 _bound[type][_keys[key].code] = newBindings;
35168 } else {
35169 _bound[type][_keys[key].code] = [];
35170 }
35171 }; // reset all bound variables.
35172
35173
35174 _exportFunctions.reset = function () {
35175 _bound = {
35176 keydown: {},
35177 keyup: {}
35178 };
35179 }; // unbind all listeners and reset all variables.
35180
35181
35182 _exportFunctions.destroy = function () {
35183 _bound = {
35184 keydown: {},
35185 keyup: {}
35186 };
35187 container.removeEventListener('keydown', down, true);
35188 container.removeEventListener('keyup', up, true);
35189 }; // create listeners.
35190
35191
35192 container.addEventListener('keydown', down, true);
35193 container.addEventListener('keyup', up, true); // return the public functions.
35194
35195 return _exportFunctions;
35196 }
35197
35198 var keycharm$1 = /*#__PURE__*/Object.freeze({
35199 __proto__: null,
35200 'default': keycharm
35201 });
35202
35203 /**
35204 * Navigation Handler
35205 */
35206
35207 var NavigationHandler = /*#__PURE__*/function () {
35208 /**
35209 * @param {object} body
35210 * @param {Canvas} canvas
35211 */
35212 function NavigationHandler(body, canvas) {
35213 var _this = this;
35214
35215 _classCallCheck(this, NavigationHandler);
35216
35217 this.body = body;
35218 this.canvas = canvas;
35219 this.iconsCreated = false;
35220 this.navigationHammers = [];
35221 this.boundFunctions = {};
35222 this.touchTime = 0;
35223 this.activated = false;
35224 this.body.emitter.on("activate", function () {
35225 _this.activated = true;
35226
35227 _this.configureKeyboardBindings();
35228 });
35229 this.body.emitter.on("deactivate", function () {
35230 _this.activated = false;
35231
35232 _this.configureKeyboardBindings();
35233 });
35234 this.body.emitter.on("destroy", function () {
35235 if (_this.keycharm !== undefined) {
35236 _this.keycharm.destroy();
35237 }
35238 });
35239 this.options = {};
35240 }
35241 /**
35242 *
35243 * @param {object} options
35244 */
35245
35246
35247 _createClass(NavigationHandler, [{
35248 key: "setOptions",
35249 value: function setOptions(options) {
35250 if (options !== undefined) {
35251 this.options = options;
35252 this.create();
35253 }
35254 }
35255 /**
35256 * Creates or refreshes navigation and sets key bindings
35257 */
35258
35259 }, {
35260 key: "create",
35261 value: function create() {
35262 if (this.options.navigationButtons === true) {
35263 if (this.iconsCreated === false) {
35264 this.loadNavigationElements();
35265 }
35266 } else if (this.iconsCreated === true) {
35267 this.cleanNavigation();
35268 }
35269
35270 this.configureKeyboardBindings();
35271 }
35272 /**
35273 * Cleans up previous navigation items
35274 */
35275
35276 }, {
35277 key: "cleanNavigation",
35278 value: function cleanNavigation() {
35279 // clean hammer bindings
35280 if (this.navigationHammers.length != 0) {
35281 for (var i = 0; i < this.navigationHammers.length; i++) {
35282 this.navigationHammers[i].destroy();
35283 }
35284
35285 this.navigationHammers = [];
35286 } // clean up previous navigation items
35287
35288
35289 if (this.navigationDOM && this.navigationDOM["wrapper"] && this.navigationDOM["wrapper"].parentNode) {
35290 this.navigationDOM["wrapper"].parentNode.removeChild(this.navigationDOM["wrapper"]);
35291 }
35292
35293 this.iconsCreated = false;
35294 }
35295 /**
35296 * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation
35297 * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent
35298 * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false.
35299 * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas.
35300 *
35301 * @private
35302 */
35303
35304 }, {
35305 key: "loadNavigationElements",
35306 value: function loadNavigationElements() {
35307 var _this2 = this;
35308
35309 this.cleanNavigation();
35310 this.navigationDOM = {};
35311 var navigationDivs = ["up", "down", "left", "right", "zoomIn", "zoomOut", "zoomExtends"];
35312 var navigationDivActions = ["_moveUp", "_moveDown", "_moveLeft", "_moveRight", "_zoomIn", "_zoomOut", "_fit"];
35313 this.navigationDOM["wrapper"] = document.createElement("div");
35314 this.navigationDOM["wrapper"].className = "vis-navigation";
35315 this.canvas.frame.appendChild(this.navigationDOM["wrapper"]);
35316
35317 for (var i = 0; i < navigationDivs.length; i++) {
35318 this.navigationDOM[navigationDivs[i]] = document.createElement("div");
35319 this.navigationDOM[navigationDivs[i]].className = "vis-button vis-" + navigationDivs[i];
35320 this.navigationDOM["wrapper"].appendChild(this.navigationDOM[navigationDivs[i]]);
35321 var hammer = new Hammer(this.navigationDOM[navigationDivs[i]]);
35322
35323 if (navigationDivActions[i] === "_fit") {
35324 var _context;
35325
35326 onTouch(hammer, bind$6(_context = this._fit).call(_context, this));
35327 } else {
35328 var _context2;
35329
35330 onTouch(hammer, bind$6(_context2 = this.bindToRedraw).call(_context2, this, navigationDivActions[i]));
35331 }
35332
35333 this.navigationHammers.push(hammer);
35334 } // use a hammer for the release so we do not require the one used in the rest of the network
35335 // the one the rest uses can be overloaded by the manipulation system.
35336
35337
35338 var hammerFrame = new Hammer(this.canvas.frame);
35339 onRelease(hammerFrame, function () {
35340 _this2._stopMovement();
35341 });
35342 this.navigationHammers.push(hammerFrame);
35343 this.iconsCreated = true;
35344 }
35345 /**
35346 *
35347 * @param {string} action
35348 */
35349
35350 }, {
35351 key: "bindToRedraw",
35352 value: function bindToRedraw(action) {
35353 if (this.boundFunctions[action] === undefined) {
35354 var _context3;
35355
35356 this.boundFunctions[action] = bind$6(_context3 = this[action]).call(_context3, this);
35357 this.body.emitter.on("initRedraw", this.boundFunctions[action]);
35358 this.body.emitter.emit("_startRendering");
35359 }
35360 }
35361 /**
35362 *
35363 * @param {string} action
35364 */
35365
35366 }, {
35367 key: "unbindFromRedraw",
35368 value: function unbindFromRedraw(action) {
35369 if (this.boundFunctions[action] !== undefined) {
35370 this.body.emitter.off("initRedraw", this.boundFunctions[action]);
35371 this.body.emitter.emit("_stopRendering");
35372 delete this.boundFunctions[action];
35373 }
35374 }
35375 /**
35376 * this stops all movement induced by the navigation buttons
35377 *
35378 * @private
35379 */
35380
35381 }, {
35382 key: "_fit",
35383 value: function _fit() {
35384 if (new Date().valueOf() - this.touchTime > 700) {
35385 // TODO: fix ugly hack to avoid hammer's double fireing of event (because we use release?)
35386 this.body.emitter.emit("fit", {
35387 duration: 700
35388 });
35389 this.touchTime = new Date().valueOf();
35390 }
35391 }
35392 /**
35393 * this stops all movement induced by the navigation buttons
35394 *
35395 * @private
35396 */
35397
35398 }, {
35399 key: "_stopMovement",
35400 value: function _stopMovement() {
35401 for (var boundAction in this.boundFunctions) {
35402 if (Object.prototype.hasOwnProperty.call(this.boundFunctions, boundAction)) {
35403 this.body.emitter.off("initRedraw", this.boundFunctions[boundAction]);
35404 this.body.emitter.emit("_stopRendering");
35405 }
35406 }
35407
35408 this.boundFunctions = {};
35409 }
35410 /**
35411 *
35412 * @private
35413 */
35414
35415 }, {
35416 key: "_moveUp",
35417 value: function _moveUp() {
35418 this.body.view.translation.y += this.options.keyboard.speed.y;
35419 }
35420 /**
35421 *
35422 * @private
35423 */
35424
35425 }, {
35426 key: "_moveDown",
35427 value: function _moveDown() {
35428 this.body.view.translation.y -= this.options.keyboard.speed.y;
35429 }
35430 /**
35431 *
35432 * @private
35433 */
35434
35435 }, {
35436 key: "_moveLeft",
35437 value: function _moveLeft() {
35438 this.body.view.translation.x += this.options.keyboard.speed.x;
35439 }
35440 /**
35441 *
35442 * @private
35443 */
35444
35445 }, {
35446 key: "_moveRight",
35447 value: function _moveRight() {
35448 this.body.view.translation.x -= this.options.keyboard.speed.x;
35449 }
35450 /**
35451 *
35452 * @private
35453 */
35454
35455 }, {
35456 key: "_zoomIn",
35457 value: function _zoomIn() {
35458 var scaleOld = this.body.view.scale;
35459 var scale = this.body.view.scale * (1 + this.options.keyboard.speed.zoom);
35460 var translation = this.body.view.translation;
35461 var scaleFrac = scale / scaleOld;
35462 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
35463 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
35464 this.body.view.scale = scale;
35465 this.body.view.translation = {
35466 x: tx,
35467 y: ty
35468 };
35469 this.body.emitter.emit("zoom", {
35470 direction: "+",
35471 scale: this.body.view.scale,
35472 pointer: null
35473 });
35474 }
35475 /**
35476 *
35477 * @private
35478 */
35479
35480 }, {
35481 key: "_zoomOut",
35482 value: function _zoomOut() {
35483 var scaleOld = this.body.view.scale;
35484 var scale = this.body.view.scale / (1 + this.options.keyboard.speed.zoom);
35485 var translation = this.body.view.translation;
35486 var scaleFrac = scale / scaleOld;
35487 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
35488 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
35489 this.body.view.scale = scale;
35490 this.body.view.translation = {
35491 x: tx,
35492 y: ty
35493 };
35494 this.body.emitter.emit("zoom", {
35495 direction: "-",
35496 scale: this.body.view.scale,
35497 pointer: null
35498 });
35499 }
35500 /**
35501 * bind all keys using keycharm.
35502 */
35503
35504 }, {
35505 key: "configureKeyboardBindings",
35506 value: function configureKeyboardBindings() {
35507 var _this3 = this;
35508
35509 if (this.keycharm !== undefined) {
35510 this.keycharm.destroy();
35511 }
35512
35513 if (this.options.keyboard.enabled === true) {
35514 if (this.options.keyboard.bindToWindow === true) {
35515 this.keycharm = keycharm({
35516 container: window,
35517 preventDefault: true
35518 });
35519 } else {
35520 this.keycharm = keycharm({
35521 container: this.canvas.frame,
35522 preventDefault: true
35523 });
35524 }
35525
35526 this.keycharm.reset();
35527
35528 if (this.activated === true) {
35529 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;
35530
35531 bind$6(_context4 = this.keycharm).call(_context4, "up", function () {
35532 _this3.bindToRedraw("_moveUp");
35533 }, "keydown");
35534
35535 bind$6(_context5 = this.keycharm).call(_context5, "down", function () {
35536 _this3.bindToRedraw("_moveDown");
35537 }, "keydown");
35538
35539 bind$6(_context6 = this.keycharm).call(_context6, "left", function () {
35540 _this3.bindToRedraw("_moveLeft");
35541 }, "keydown");
35542
35543 bind$6(_context7 = this.keycharm).call(_context7, "right", function () {
35544 _this3.bindToRedraw("_moveRight");
35545 }, "keydown");
35546
35547 bind$6(_context8 = this.keycharm).call(_context8, "=", function () {
35548 _this3.bindToRedraw("_zoomIn");
35549 }, "keydown");
35550
35551 bind$6(_context9 = this.keycharm).call(_context9, "num+", function () {
35552 _this3.bindToRedraw("_zoomIn");
35553 }, "keydown");
35554
35555 bind$6(_context10 = this.keycharm).call(_context10, "num-", function () {
35556 _this3.bindToRedraw("_zoomOut");
35557 }, "keydown");
35558
35559 bind$6(_context11 = this.keycharm).call(_context11, "-", function () {
35560 _this3.bindToRedraw("_zoomOut");
35561 }, "keydown");
35562
35563 bind$6(_context12 = this.keycharm).call(_context12, "[", function () {
35564 _this3.bindToRedraw("_zoomOut");
35565 }, "keydown");
35566
35567 bind$6(_context13 = this.keycharm).call(_context13, "]", function () {
35568 _this3.bindToRedraw("_zoomIn");
35569 }, "keydown");
35570
35571 bind$6(_context14 = this.keycharm).call(_context14, "pageup", function () {
35572 _this3.bindToRedraw("_zoomIn");
35573 }, "keydown");
35574
35575 bind$6(_context15 = this.keycharm).call(_context15, "pagedown", function () {
35576 _this3.bindToRedraw("_zoomOut");
35577 }, "keydown");
35578
35579 bind$6(_context16 = this.keycharm).call(_context16, "up", function () {
35580 _this3.unbindFromRedraw("_moveUp");
35581 }, "keyup");
35582
35583 bind$6(_context17 = this.keycharm).call(_context17, "down", function () {
35584 _this3.unbindFromRedraw("_moveDown");
35585 }, "keyup");
35586
35587 bind$6(_context18 = this.keycharm).call(_context18, "left", function () {
35588 _this3.unbindFromRedraw("_moveLeft");
35589 }, "keyup");
35590
35591 bind$6(_context19 = this.keycharm).call(_context19, "right", function () {
35592 _this3.unbindFromRedraw("_moveRight");
35593 }, "keyup");
35594
35595 bind$6(_context20 = this.keycharm).call(_context20, "=", function () {
35596 _this3.unbindFromRedraw("_zoomIn");
35597 }, "keyup");
35598
35599 bind$6(_context21 = this.keycharm).call(_context21, "num+", function () {
35600 _this3.unbindFromRedraw("_zoomIn");
35601 }, "keyup");
35602
35603 bind$6(_context22 = this.keycharm).call(_context22, "num-", function () {
35604 _this3.unbindFromRedraw("_zoomOut");
35605 }, "keyup");
35606
35607 bind$6(_context23 = this.keycharm).call(_context23, "-", function () {
35608 _this3.unbindFromRedraw("_zoomOut");
35609 }, "keyup");
35610
35611 bind$6(_context24 = this.keycharm).call(_context24, "[", function () {
35612 _this3.unbindFromRedraw("_zoomOut");
35613 }, "keyup");
35614
35615 bind$6(_context25 = this.keycharm).call(_context25, "]", function () {
35616 _this3.unbindFromRedraw("_zoomIn");
35617 }, "keyup");
35618
35619 bind$6(_context26 = this.keycharm).call(_context26, "pageup", function () {
35620 _this3.unbindFromRedraw("_zoomIn");
35621 }, "keyup");
35622
35623 bind$6(_context27 = this.keycharm).call(_context27, "pagedown", function () {
35624 _this3.unbindFromRedraw("_zoomOut");
35625 }, "keyup");
35626 }
35627 }
35628 }
35629 }]);
35630
35631 return NavigationHandler;
35632 }();
35633
35634 function _createForOfIteratorHelper$4(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$2(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; } } }; }
35635
35636 function _unsupportedIterableToArray$4(o, minLen) { var _context15; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$4(o, minLen); var n = slice(_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$3(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$4(o, minLen); }
35637
35638 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; }
35639 /**
35640 * Handler for interactions
35641 */
35642
35643 var InteractionHandler = /*#__PURE__*/function () {
35644 /**
35645 * @param {object} body
35646 * @param {Canvas} canvas
35647 * @param {SelectionHandler} selectionHandler
35648 */
35649 function InteractionHandler(body, canvas, selectionHandler) {
35650 var _context, _context2, _context3, _context4, _context5, _context6, _context7, _context8, _context9, _context10, _context11, _context12, _context13;
35651
35652 _classCallCheck(this, InteractionHandler);
35653
35654 this.body = body;
35655 this.canvas = canvas;
35656 this.selectionHandler = selectionHandler;
35657 this.navigationHandler = new NavigationHandler(body, canvas); // bind the events from hammer to functions in this object
35658
35659 this.body.eventListeners.onTap = bind$6(_context = this.onTap).call(_context, this);
35660 this.body.eventListeners.onTouch = bind$6(_context2 = this.onTouch).call(_context2, this);
35661 this.body.eventListeners.onDoubleTap = bind$6(_context3 = this.onDoubleTap).call(_context3, this);
35662 this.body.eventListeners.onHold = bind$6(_context4 = this.onHold).call(_context4, this);
35663 this.body.eventListeners.onDragStart = bind$6(_context5 = this.onDragStart).call(_context5, this);
35664 this.body.eventListeners.onDrag = bind$6(_context6 = this.onDrag).call(_context6, this);
35665 this.body.eventListeners.onDragEnd = bind$6(_context7 = this.onDragEnd).call(_context7, this);
35666 this.body.eventListeners.onMouseWheel = bind$6(_context8 = this.onMouseWheel).call(_context8, this);
35667 this.body.eventListeners.onPinch = bind$6(_context9 = this.onPinch).call(_context9, this);
35668 this.body.eventListeners.onMouseMove = bind$6(_context10 = this.onMouseMove).call(_context10, this);
35669 this.body.eventListeners.onRelease = bind$6(_context11 = this.onRelease).call(_context11, this);
35670 this.body.eventListeners.onContext = bind$6(_context12 = this.onContext).call(_context12, this);
35671 this.touchTime = 0;
35672 this.drag = {};
35673 this.pinch = {};
35674 this.popup = undefined;
35675 this.popupObj = undefined;
35676 this.popupTimer = undefined;
35677 this.body.functions.getPointer = bind$6(_context13 = this.getPointer).call(_context13, this);
35678 this.options = {};
35679 this.defaultOptions = {
35680 dragNodes: true,
35681 dragView: true,
35682 hover: false,
35683 keyboard: {
35684 enabled: false,
35685 speed: {
35686 x: 10,
35687 y: 10,
35688 zoom: 0.02
35689 },
35690 bindToWindow: true,
35691 autoFocus: true
35692 },
35693 navigationButtons: false,
35694 tooltipDelay: 300,
35695 zoomView: true,
35696 zoomSpeed: 1
35697 };
35698
35699 assign$2(this.options, this.defaultOptions);
35700
35701 this.bindEventListeners();
35702 }
35703 /**
35704 * Binds event listeners
35705 */
35706
35707
35708 _createClass(InteractionHandler, [{
35709 key: "bindEventListeners",
35710 value: function bindEventListeners() {
35711 var _this = this;
35712
35713 this.body.emitter.on("destroy", function () {
35714 clearTimeout(_this.popupTimer);
35715 delete _this.body.functions.getPointer;
35716 });
35717 }
35718 /**
35719 *
35720 * @param {object} options
35721 */
35722
35723 }, {
35724 key: "setOptions",
35725 value: function setOptions(options) {
35726 if (options !== undefined) {
35727 // extend all but the values in fields
35728 var fields = ["hideEdgesOnDrag", "hideEdgesOnZoom", "hideNodesOnDrag", "keyboard", "multiselect", "selectable", "selectConnectedEdges"];
35729 selectiveNotDeepExtend(fields, this.options, options); // merge the keyboard options in.
35730
35731 mergeOptions(this.options, options, "keyboard");
35732
35733 if (options.tooltip) {
35734 assign$2(this.options.tooltip, options.tooltip);
35735
35736 if (options.tooltip.color) {
35737 this.options.tooltip.color = parseColor(options.tooltip.color);
35738 }
35739 }
35740 }
35741
35742 this.navigationHandler.setOptions(this.options);
35743 }
35744 /**
35745 * Get the pointer location from a touch location
35746 *
35747 * @param {{x: number, y: number}} touch
35748 * @returns {{x: number, y: number}} pointer
35749 * @private
35750 */
35751
35752 }, {
35753 key: "getPointer",
35754 value: function getPointer(touch) {
35755 return {
35756 x: touch.x - getAbsoluteLeft(this.canvas.frame.canvas),
35757 y: touch.y - getAbsoluteTop(this.canvas.frame.canvas)
35758 };
35759 }
35760 /**
35761 * On start of a touch gesture, store the pointer
35762 *
35763 * @param {Event} event The event
35764 * @private
35765 */
35766
35767 }, {
35768 key: "onTouch",
35769 value: function onTouch(event) {
35770 if (new Date().valueOf() - this.touchTime > 50) {
35771 this.drag.pointer = this.getPointer(event.center);
35772 this.drag.pinched = false;
35773 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)
35774
35775 this.touchTime = new Date().valueOf();
35776 }
35777 }
35778 /**
35779 * handle tap/click event: select/unselect a node
35780 *
35781 * @param {Event} event
35782 * @private
35783 */
35784
35785 }, {
35786 key: "onTap",
35787 value: function onTap(event) {
35788 var pointer = this.getPointer(event.center);
35789 var multiselect = this.selectionHandler.options.multiselect && (event.changedPointers[0].ctrlKey || event.changedPointers[0].metaKey);
35790 this.checkSelectionChanges(pointer, multiselect);
35791 this.selectionHandler.commitAndEmit(pointer, event);
35792 this.selectionHandler.generateClickEvent("click", event, pointer);
35793 }
35794 /**
35795 * handle doubletap event
35796 *
35797 * @param {Event} event
35798 * @private
35799 */
35800
35801 }, {
35802 key: "onDoubleTap",
35803 value: function onDoubleTap(event) {
35804 var pointer = this.getPointer(event.center);
35805 this.selectionHandler.generateClickEvent("doubleClick", event, pointer);
35806 }
35807 /**
35808 * handle long tap event: multi select nodes
35809 *
35810 * @param {Event} event
35811 * @private
35812 */
35813
35814 }, {
35815 key: "onHold",
35816 value: function onHold(event) {
35817 var pointer = this.getPointer(event.center);
35818 var multiselect = this.selectionHandler.options.multiselect;
35819 this.checkSelectionChanges(pointer, multiselect);
35820 this.selectionHandler.commitAndEmit(pointer, event);
35821 this.selectionHandler.generateClickEvent("click", event, pointer);
35822 this.selectionHandler.generateClickEvent("hold", event, pointer);
35823 }
35824 /**
35825 * handle the release of the screen
35826 *
35827 * @param {Event} event
35828 * @private
35829 */
35830
35831 }, {
35832 key: "onRelease",
35833 value: function onRelease(event) {
35834 if (new Date().valueOf() - this.touchTime > 10) {
35835 var pointer = this.getPointer(event.center);
35836 this.selectionHandler.generateClickEvent("release", event, pointer); // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
35837
35838 this.touchTime = new Date().valueOf();
35839 }
35840 }
35841 /**
35842 *
35843 * @param {Event} event
35844 */
35845
35846 }, {
35847 key: "onContext",
35848 value: function onContext(event) {
35849 var pointer = this.getPointer({
35850 x: event.clientX,
35851 y: event.clientY
35852 });
35853 this.selectionHandler.generateClickEvent("oncontext", event, pointer);
35854 }
35855 /**
35856 * Select and deselect nodes depending current selection change.
35857 *
35858 * @param {{x: number, y: number}} pointer
35859 * @param {boolean} [add=false]
35860 */
35861
35862 }, {
35863 key: "checkSelectionChanges",
35864 value: function checkSelectionChanges(pointer) {
35865 var add = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
35866
35867 if (add === true) {
35868 this.selectionHandler.selectAdditionalOnPoint(pointer);
35869 } else {
35870 this.selectionHandler.selectOnPoint(pointer);
35871 }
35872 }
35873 /**
35874 * Remove all node and edge id's from the first set that are present in the second one.
35875 *
35876 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} firstSet
35877 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} secondSet
35878 * @returns {{nodes: Array.<Node>, edges: Array.<vis.Edge>}}
35879 * @private
35880 */
35881
35882 }, {
35883 key: "_determineDifference",
35884 value: function _determineDifference(firstSet, secondSet) {
35885 var arrayDiff = function arrayDiff(firstArr, secondArr) {
35886 var result = [];
35887
35888 for (var i = 0; i < firstArr.length; i++) {
35889 var value = firstArr[i];
35890
35891 if (indexOf(secondArr).call(secondArr, value) === -1) {
35892 result.push(value);
35893 }
35894 }
35895
35896 return result;
35897 };
35898
35899 return {
35900 nodes: arrayDiff(firstSet.nodes, secondSet.nodes),
35901 edges: arrayDiff(firstSet.edges, secondSet.edges)
35902 };
35903 }
35904 /**
35905 * This function is called by onDragStart.
35906 * It is separated out because we can then overload it for the datamanipulation system.
35907 *
35908 * @param {Event} event
35909 * @private
35910 */
35911
35912 }, {
35913 key: "onDragStart",
35914 value: function onDragStart(event) {
35915 // if already dragging, do not start
35916 // this can happen on touch screens with multiple fingers
35917 if (this.drag.dragging) {
35918 return;
35919 } //in case the touch event was triggered on an external div, do the initial touch now.
35920
35921
35922 if (this.drag.pointer === undefined) {
35923 this.onTouch(event);
35924 } // note: drag.pointer is set in onTouch to get the initial touch location
35925
35926
35927 var node = this.selectionHandler.getNodeAt(this.drag.pointer);
35928 this.drag.dragging = true;
35929 this.drag.selection = [];
35930 this.drag.translation = assign$2({}, this.body.view.translation); // copy the object
35931
35932 this.drag.nodeId = undefined;
35933
35934 if (event.srcEvent.shiftKey) {
35935 this.body.selectionBox.show = true;
35936 var pointer = this.getPointer(event.center);
35937 this.body.selectionBox.position.start = {
35938 x: this.canvas._XconvertDOMtoCanvas(pointer.x),
35939 y: this.canvas._YconvertDOMtoCanvas(pointer.y)
35940 };
35941 this.body.selectionBox.position.end = {
35942 x: this.canvas._XconvertDOMtoCanvas(pointer.x),
35943 y: this.canvas._YconvertDOMtoCanvas(pointer.y)
35944 };
35945 }
35946
35947 if (node !== undefined && this.options.dragNodes === true) {
35948 this.drag.nodeId = node.id; // select the clicked node if not yet selected
35949
35950 if (node.isSelected() === false) {
35951 this.selectionHandler.setSelection({
35952 nodes: [node.id]
35953 });
35954 } // after select to contain the node
35955
35956
35957 this.selectionHandler.generateClickEvent("dragStart", event, this.drag.pointer); // create an array with the selected nodes and their original location and status
35958
35959 var _iterator = _createForOfIteratorHelper$4(this.selectionHandler.getSelectedNodes()),
35960 _step;
35961
35962 try {
35963 for (_iterator.s(); !(_step = _iterator.n()).done;) {
35964 var _node = _step.value;
35965 var s = {
35966 id: _node.id,
35967 node: _node,
35968 // store original x, y, xFixed and yFixed, make the node temporarily Fixed
35969 x: _node.x,
35970 y: _node.y,
35971 xFixed: _node.options.fixed.x,
35972 yFixed: _node.options.fixed.y
35973 };
35974 _node.options.fixed.x = true;
35975 _node.options.fixed.y = true;
35976 this.drag.selection.push(s);
35977 }
35978 } catch (err) {
35979 _iterator.e(err);
35980 } finally {
35981 _iterator.f();
35982 }
35983 } else {
35984 // fallback if no node is selected and thus the view is dragged.
35985 this.selectionHandler.generateClickEvent("dragStart", event, this.drag.pointer, undefined, true);
35986 }
35987 }
35988 /**
35989 * handle drag event
35990 *
35991 * @param {Event} event
35992 * @private
35993 */
35994
35995 }, {
35996 key: "onDrag",
35997 value: function onDrag(event) {
35998 var _this2 = this;
35999
36000 if (this.drag.pinched === true) {
36001 return;
36002 } // remove the focus on node if it is focussed on by the focusOnNode
36003
36004
36005 this.body.emitter.emit("unlockNode");
36006 var pointer = this.getPointer(event.center);
36007 var selection = this.drag.selection;
36008
36009 if (selection && selection.length && this.options.dragNodes === true) {
36010 this.selectionHandler.generateClickEvent("dragging", event, pointer); // calculate delta's and new location
36011
36012 var deltaX = pointer.x - this.drag.pointer.x;
36013 var deltaY = pointer.y - this.drag.pointer.y; // update position of all selected nodes
36014
36015 forEach$2(selection).call(selection, function (selection) {
36016 var node = selection.node; // only move the node if it was not fixed initially
36017
36018 if (selection.xFixed === false) {
36019 node.x = _this2.canvas._XconvertDOMtoCanvas(_this2.canvas._XconvertCanvasToDOM(selection.x) + deltaX);
36020 } // only move the node if it was not fixed initially
36021
36022
36023 if (selection.yFixed === false) {
36024 node.y = _this2.canvas._YconvertDOMtoCanvas(_this2.canvas._YconvertCanvasToDOM(selection.y) + deltaY);
36025 }
36026 }); // start the simulation of the physics
36027
36028
36029 this.body.emitter.emit("startSimulation");
36030 } else {
36031 // create selection box
36032 if (event.srcEvent.shiftKey) {
36033 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.
36034
36035 if (this.drag.pointer === undefined) {
36036 this.onDragStart(event);
36037 return;
36038 }
36039
36040 this.body.selectionBox.position.end = {
36041 x: this.canvas._XconvertDOMtoCanvas(pointer.x),
36042 y: this.canvas._YconvertDOMtoCanvas(pointer.y)
36043 };
36044 this.body.emitter.emit("_requestRedraw");
36045 } // move the network
36046
36047
36048 if (this.options.dragView === true && !event.srcEvent.shiftKey) {
36049 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.
36050
36051 if (this.drag.pointer === undefined) {
36052 this.onDragStart(event);
36053 return;
36054 }
36055
36056 var diffX = pointer.x - this.drag.pointer.x;
36057 var diffY = pointer.y - this.drag.pointer.y;
36058 this.body.view.translation = {
36059 x: this.drag.translation.x + diffX,
36060 y: this.drag.translation.y + diffY
36061 };
36062 this.body.emitter.emit("_requestRedraw");
36063 }
36064 }
36065 }
36066 /**
36067 * handle drag start event
36068 *
36069 * @param {Event} event
36070 * @private
36071 */
36072
36073 }, {
36074 key: "onDragEnd",
36075 value: function onDragEnd(event) {
36076 var _this3 = this;
36077
36078 this.drag.dragging = false;
36079
36080 if (this.body.selectionBox.show) {
36081 var _context14;
36082
36083 this.body.selectionBox.show = false;
36084 var selectionBoxPosition = this.body.selectionBox.position;
36085 var selectionBoxPositionMinMax = {
36086 minX: Math.min(selectionBoxPosition.start.x, selectionBoxPosition.end.x),
36087 minY: Math.min(selectionBoxPosition.start.y, selectionBoxPosition.end.y),
36088 maxX: Math.max(selectionBoxPosition.start.x, selectionBoxPosition.end.x),
36089 maxY: Math.max(selectionBoxPosition.start.y, selectionBoxPosition.end.y)
36090 };
36091
36092 var toBeSelectedNodes = filter(_context14 = this.body.nodeIndices).call(_context14, function (nodeId) {
36093 var node = _this3.body.nodes[nodeId];
36094 return node.x >= selectionBoxPositionMinMax.minX && node.x <= selectionBoxPositionMinMax.maxX && node.y >= selectionBoxPositionMinMax.minY && node.y <= selectionBoxPositionMinMax.maxY;
36095 });
36096
36097 forEach$2(toBeSelectedNodes).call(toBeSelectedNodes, function (nodeId) {
36098 return _this3.selectionHandler.selectObject(_this3.body.nodes[nodeId]);
36099 });
36100
36101 var pointer = this.getPointer(event.center);
36102 this.selectionHandler.commitAndEmit(pointer, event);
36103 this.selectionHandler.generateClickEvent("dragEnd", event, this.getPointer(event.center), undefined, true);
36104 this.body.emitter.emit("_requestRedraw");
36105 } else {
36106 var selection = this.drag.selection;
36107
36108 if (selection && selection.length) {
36109 forEach$2(selection).call(selection, function (s) {
36110 // restore original xFixed and yFixed
36111 s.node.options.fixed.x = s.xFixed;
36112 s.node.options.fixed.y = s.yFixed;
36113 });
36114
36115 this.selectionHandler.generateClickEvent("dragEnd", event, this.getPointer(event.center));
36116 this.body.emitter.emit("startSimulation");
36117 } else {
36118 this.selectionHandler.generateClickEvent("dragEnd", event, this.getPointer(event.center), undefined, true);
36119 this.body.emitter.emit("_requestRedraw");
36120 }
36121 }
36122 }
36123 /**
36124 * Handle pinch event
36125 *
36126 * @param {Event} event The event
36127 * @private
36128 */
36129
36130 }, {
36131 key: "onPinch",
36132 value: function onPinch(event) {
36133 var pointer = this.getPointer(event.center);
36134 this.drag.pinched = true;
36135
36136 if (this.pinch["scale"] === undefined) {
36137 this.pinch.scale = 1;
36138 } // TODO: enabled moving while pinching?
36139
36140
36141 var scale = this.pinch.scale * event.scale;
36142 this.zoom(scale, pointer);
36143 }
36144 /**
36145 * Zoom the network in or out
36146 *
36147 * @param {number} scale a number around 1, and between 0.01 and 10
36148 * @param {{x: number, y: number}} pointer Position on screen
36149 * @private
36150 */
36151
36152 }, {
36153 key: "zoom",
36154 value: function zoom(scale, pointer) {
36155 if (this.options.zoomView === true) {
36156 var scaleOld = this.body.view.scale;
36157
36158 if (scale < 0.00001) {
36159 scale = 0.00001;
36160 }
36161
36162 if (scale > 10) {
36163 scale = 10;
36164 }
36165
36166 var preScaleDragPointer = undefined;
36167
36168 if (this.drag !== undefined) {
36169 if (this.drag.dragging === true) {
36170 preScaleDragPointer = this.canvas.DOMtoCanvas(this.drag.pointer);
36171 }
36172 } // + this.canvas.frame.canvas.clientHeight / 2
36173
36174
36175 var translation = this.body.view.translation;
36176 var scaleFrac = scale / scaleOld;
36177 var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
36178 var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
36179 this.body.view.scale = scale;
36180 this.body.view.translation = {
36181 x: tx,
36182 y: ty
36183 };
36184
36185 if (preScaleDragPointer != undefined) {
36186 var postScaleDragPointer = this.canvas.canvasToDOM(preScaleDragPointer);
36187 this.drag.pointer.x = postScaleDragPointer.x;
36188 this.drag.pointer.y = postScaleDragPointer.y;
36189 }
36190
36191 this.body.emitter.emit("_requestRedraw");
36192
36193 if (scaleOld < scale) {
36194 this.body.emitter.emit("zoom", {
36195 direction: "+",
36196 scale: this.body.view.scale,
36197 pointer: pointer
36198 });
36199 } else {
36200 this.body.emitter.emit("zoom", {
36201 direction: "-",
36202 scale: this.body.view.scale,
36203 pointer: pointer
36204 });
36205 }
36206 }
36207 }
36208 /**
36209 * Event handler for mouse wheel event, used to zoom the timeline
36210 * See http://adomas.org/javascript-mouse-wheel/
36211 * https://github.com/EightMedia/hammer.js/issues/256
36212 *
36213 * @param {MouseEvent} event
36214 * @private
36215 */
36216
36217 }, {
36218 key: "onMouseWheel",
36219 value: function onMouseWheel(event) {
36220 if (this.options.zoomView === true) {
36221 // If delta is nonzero, handle it.
36222 // Basically, delta is now positive if wheel was scrolled up,
36223 // and negative, if wheel was scrolled down.
36224 if (event.deltaY !== 0) {
36225 // calculate the new scale
36226 var scale = this.body.view.scale;
36227 scale *= 1 + (event.deltaY < 0 ? 1 : -1) * (this.options.zoomSpeed * 0.1); // calculate the pointer location
36228
36229 var pointer = this.getPointer({
36230 x: event.clientX,
36231 y: event.clientY
36232 }); // apply the new scale
36233
36234 this.zoom(scale, pointer);
36235 } // Prevent default actions caused by mouse wheel.
36236
36237
36238 event.preventDefault();
36239 }
36240 }
36241 /**
36242 * Mouse move handler for checking whether the title moves over a node with a title.
36243 *
36244 * @param {Event} event
36245 * @private
36246 */
36247
36248 }, {
36249 key: "onMouseMove",
36250 value: function onMouseMove(event) {
36251 var _this4 = this;
36252
36253 var pointer = this.getPointer({
36254 x: event.clientX,
36255 y: event.clientY
36256 });
36257 var popupVisible = false; // check if the previously selected node is still selected
36258
36259 if (this.popup !== undefined) {
36260 if (this.popup.hidden === false) {
36261 this._checkHidePopup(pointer);
36262 } // if the popup was not hidden above
36263
36264
36265 if (this.popup.hidden === false) {
36266 popupVisible = true;
36267 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
36268 this.popup.show();
36269 }
36270 } // if we bind the keyboard to the div, we have to highlight it to use it. This highlights it on mouse over.
36271
36272
36273 if (this.options.keyboard.autoFocus && this.options.keyboard.bindToWindow === false && this.options.keyboard.enabled === true) {
36274 this.canvas.frame.focus();
36275 } // start a timeout that will check if the mouse is positioned above an element
36276
36277
36278 if (popupVisible === false) {
36279 if (this.popupTimer !== undefined) {
36280 clearInterval(this.popupTimer); // stop any running calculationTimer
36281
36282 this.popupTimer = undefined;
36283 }
36284
36285 if (!this.drag.dragging) {
36286 this.popupTimer = setTimeout$1(function () {
36287 return _this4._checkShowPopup(pointer);
36288 }, this.options.tooltipDelay);
36289 }
36290 } // adding hover highlights
36291
36292
36293 if (this.options.hover === true) {
36294 this.selectionHandler.hoverObject(event, pointer);
36295 }
36296 }
36297 /**
36298 * Check if there is an element on the given position in the network
36299 * (a node or edge). If so, and if this element has a title,
36300 * show a popup window with its title.
36301 *
36302 * @param {{x:number, y:number}} pointer
36303 * @private
36304 */
36305
36306 }, {
36307 key: "_checkShowPopup",
36308 value: function _checkShowPopup(pointer) {
36309 var x = this.canvas._XconvertDOMtoCanvas(pointer.x);
36310
36311 var y = this.canvas._YconvertDOMtoCanvas(pointer.y);
36312
36313 var pointerObj = {
36314 left: x,
36315 top: y,
36316 right: x,
36317 bottom: y
36318 };
36319 var previousPopupObjId = this.popupObj === undefined ? undefined : this.popupObj.id;
36320 var nodeUnderCursor = false;
36321 var popupType = "node"; // check if a node is under the cursor.
36322
36323 if (this.popupObj === undefined) {
36324 // search the nodes for overlap, select the top one in case of multiple nodes
36325 var nodeIndices = this.body.nodeIndices;
36326 var nodes = this.body.nodes;
36327 var node;
36328 var overlappingNodes = [];
36329
36330 for (var i = 0; i < nodeIndices.length; i++) {
36331 node = nodes[nodeIndices[i]];
36332
36333 if (node.isOverlappingWith(pointerObj) === true) {
36334 nodeUnderCursor = true;
36335
36336 if (node.getTitle() !== undefined) {
36337 overlappingNodes.push(nodeIndices[i]);
36338 }
36339 }
36340 }
36341
36342 if (overlappingNodes.length > 0) {
36343 // if there are overlapping nodes, select the last one, this is the one which is drawn on top of the others
36344 this.popupObj = nodes[overlappingNodes[overlappingNodes.length - 1]]; // if you hover over a node, the title of the edge is not supposed to be shown.
36345
36346 nodeUnderCursor = true;
36347 }
36348 }
36349
36350 if (this.popupObj === undefined && nodeUnderCursor === false) {
36351 // search the edges for overlap
36352 var edgeIndices = this.body.edgeIndices;
36353 var edges = this.body.edges;
36354 var edge;
36355 var overlappingEdges = [];
36356
36357 for (var _i = 0; _i < edgeIndices.length; _i++) {
36358 edge = edges[edgeIndices[_i]];
36359
36360 if (edge.isOverlappingWith(pointerObj) === true) {
36361 if (edge.connected === true && edge.getTitle() !== undefined) {
36362 overlappingEdges.push(edgeIndices[_i]);
36363 }
36364 }
36365 }
36366
36367 if (overlappingEdges.length > 0) {
36368 this.popupObj = edges[overlappingEdges[overlappingEdges.length - 1]];
36369 popupType = "edge";
36370 }
36371 }
36372
36373 if (this.popupObj !== undefined) {
36374 // show popup message window
36375 if (this.popupObj.id !== previousPopupObjId) {
36376 if (this.popup === undefined) {
36377 this.popup = new Popup(this.canvas.frame);
36378 }
36379
36380 this.popup.popupTargetType = popupType;
36381 this.popup.popupTargetId = this.popupObj.id; // adjust a small offset such that the mouse cursor is located in the
36382 // bottom left location of the popup, and you can easily move over the
36383 // popup area
36384
36385 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
36386 this.popup.setText(this.popupObj.getTitle());
36387 this.popup.show();
36388 this.body.emitter.emit("showPopup", this.popupObj.id);
36389 }
36390 } else {
36391 if (this.popup !== undefined) {
36392 this.popup.hide();
36393 this.body.emitter.emit("hidePopup");
36394 }
36395 }
36396 }
36397 /**
36398 * Check if the popup must be hidden, which is the case when the mouse is no
36399 * longer hovering on the object
36400 *
36401 * @param {{x:number, y:number}} pointer
36402 * @private
36403 */
36404
36405 }, {
36406 key: "_checkHidePopup",
36407 value: function _checkHidePopup(pointer) {
36408 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
36409
36410 var stillOnObj = false;
36411
36412 if (this.popup.popupTargetType === "node") {
36413 if (this.body.nodes[this.popup.popupTargetId] !== undefined) {
36414 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.
36415 // we initially only check stillOnObj because this is much faster.
36416
36417 if (stillOnObj === true) {
36418 var overNode = this.selectionHandler.getNodeAt(pointer);
36419 stillOnObj = overNode === undefined ? false : overNode.id === this.popup.popupTargetId;
36420 }
36421 }
36422 } else {
36423 if (this.selectionHandler.getNodeAt(pointer) === undefined) {
36424 if (this.body.edges[this.popup.popupTargetId] !== undefined) {
36425 stillOnObj = this.body.edges[this.popup.popupTargetId].isOverlappingWith(pointerObj);
36426 }
36427 }
36428 }
36429
36430 if (stillOnObj === false) {
36431 this.popupObj = undefined;
36432 this.popup.hide();
36433 this.body.emitter.emit("hidePopup");
36434 }
36435 }
36436 }]);
36437
36438 return InteractionHandler;
36439 }();
36440
36441 var uncurryThis$1 = functionUncurryThis;
36442 var redefineAll$1 = redefineAll$3;
36443 var getWeakData = internalMetadata.exports.getWeakData;
36444 var anObject = anObject$d;
36445 var isObject$1 = isObject$j;
36446 var anInstance = anInstance$3;
36447 var iterate = iterate$3;
36448 var ArrayIterationModule = arrayIteration;
36449 var hasOwn = hasOwnProperty_1;
36450 var InternalStateModule = internalState;
36451 var setInternalState = InternalStateModule.set;
36452 var internalStateGetterFor = InternalStateModule.getterFor;
36453 var find = ArrayIterationModule.find;
36454 var findIndex = ArrayIterationModule.findIndex;
36455 var splice = uncurryThis$1([].splice);
36456 var id = 0; // fallback for uncaught frozen keys
36457
36458 var uncaughtFrozenStore = function (store) {
36459 return store.frozen || (store.frozen = new UncaughtFrozenStore());
36460 };
36461
36462 var UncaughtFrozenStore = function () {
36463 this.entries = [];
36464 };
36465
36466 var findUncaughtFrozen = function (store, key) {
36467 return find(store.entries, function (it) {
36468 return it[0] === key;
36469 });
36470 };
36471
36472 UncaughtFrozenStore.prototype = {
36473 get: function (key) {
36474 var entry = findUncaughtFrozen(this, key);
36475 if (entry) return entry[1];
36476 },
36477 has: function (key) {
36478 return !!findUncaughtFrozen(this, key);
36479 },
36480 set: function (key, value) {
36481 var entry = findUncaughtFrozen(this, key);
36482 if (entry) entry[1] = value;else this.entries.push([key, value]);
36483 },
36484 'delete': function (key) {
36485 var index = findIndex(this.entries, function (it) {
36486 return it[0] === key;
36487 });
36488 if (~index) splice(this.entries, index, 1);
36489 return !!~index;
36490 }
36491 };
36492 var collectionWeak$1 = {
36493 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
36494 var Constructor = wrapper(function (that, iterable) {
36495 anInstance(that, Prototype);
36496 setInternalState(that, {
36497 type: CONSTRUCTOR_NAME,
36498 id: id++,
36499 frozen: undefined
36500 });
36501 if (iterable != undefined) iterate(iterable, that[ADDER], {
36502 that: that,
36503 AS_ENTRIES: IS_MAP
36504 });
36505 });
36506 var Prototype = Constructor.prototype;
36507 var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
36508
36509 var define = function (that, key, value) {
36510 var state = getInternalState(that);
36511 var data = getWeakData(anObject(key), true);
36512 if (data === true) uncaughtFrozenStore(state).set(key, value);else data[state.id] = value;
36513 return that;
36514 };
36515
36516 redefineAll$1(Prototype, {
36517 // `{ WeakMap, WeakSet }.prototype.delete(key)` methods
36518 // https://tc39.es/ecma262/#sec-weakmap.prototype.delete
36519 // https://tc39.es/ecma262/#sec-weakset.prototype.delete
36520 'delete': function (key) {
36521 var state = getInternalState(this);
36522 if (!isObject$1(key)) return false;
36523 var data = getWeakData(key);
36524 if (data === true) return uncaughtFrozenStore(state)['delete'](key);
36525 return data && hasOwn(data, state.id) && delete data[state.id];
36526 },
36527 // `{ WeakMap, WeakSet }.prototype.has(key)` methods
36528 // https://tc39.es/ecma262/#sec-weakmap.prototype.has
36529 // https://tc39.es/ecma262/#sec-weakset.prototype.has
36530 has: function has(key) {
36531 var state = getInternalState(this);
36532 if (!isObject$1(key)) return false;
36533 var data = getWeakData(key);
36534 if (data === true) return uncaughtFrozenStore(state).has(key);
36535 return data && hasOwn(data, state.id);
36536 }
36537 });
36538 redefineAll$1(Prototype, IS_MAP ? {
36539 // `WeakMap.prototype.get(key)` method
36540 // https://tc39.es/ecma262/#sec-weakmap.prototype.get
36541 get: function get(key) {
36542 var state = getInternalState(this);
36543
36544 if (isObject$1(key)) {
36545 var data = getWeakData(key);
36546 if (data === true) return uncaughtFrozenStore(state).get(key);
36547 return data ? data[state.id] : undefined;
36548 }
36549 },
36550 // `WeakMap.prototype.set(key, value)` method
36551 // https://tc39.es/ecma262/#sec-weakmap.prototype.set
36552 set: function set(key, value) {
36553 return define(this, key, value);
36554 }
36555 } : {
36556 // `WeakSet.prototype.add(value)` method
36557 // https://tc39.es/ecma262/#sec-weakset.prototype.add
36558 add: function add(value) {
36559 return define(this, value, true);
36560 }
36561 });
36562 return Constructor;
36563 }
36564 };
36565
36566 var global$1 = global$P;
36567 var uncurryThis = functionUncurryThis;
36568 var redefineAll = redefineAll$3;
36569 var InternalMetadataModule = internalMetadata.exports;
36570 var collection = collection$3;
36571 var collectionWeak = collectionWeak$1;
36572 var isObject = isObject$j;
36573 var isExtensible = objectIsExtensible;
36574 var enforceInternalState = internalState.enforce;
36575 var NATIVE_WEAK_MAP = nativeWeakMap;
36576 var IS_IE11 = !global$1.ActiveXObject && 'ActiveXObject' in global$1;
36577 var InternalWeakMap;
36578
36579 var wrapper = function (init) {
36580 return function WeakMap() {
36581 return init(this, arguments.length ? arguments[0] : undefined);
36582 };
36583 }; // `WeakMap` constructor
36584 // https://tc39.es/ecma262/#sec-weakmap-constructor
36585
36586
36587 var $WeakMap = collection('WeakMap', wrapper, collectionWeak); // IE11 WeakMap frozen keys fix
36588 // We can't use feature detection because it crash some old IE builds
36589 // https://github.com/zloirock/core-js/issues/485
36590
36591 if (NATIVE_WEAK_MAP && IS_IE11) {
36592 InternalWeakMap = collectionWeak.getConstructor(wrapper, 'WeakMap', true);
36593 InternalMetadataModule.enable();
36594 var WeakMapPrototype = $WeakMap.prototype;
36595 var nativeDelete = uncurryThis(WeakMapPrototype['delete']);
36596 var nativeHas = uncurryThis(WeakMapPrototype.has);
36597 var nativeGet = uncurryThis(WeakMapPrototype.get);
36598 var nativeSet = uncurryThis(WeakMapPrototype.set);
36599 redefineAll(WeakMapPrototype, {
36600 'delete': function (key) {
36601 if (isObject(key) && !isExtensible(key)) {
36602 var state = enforceInternalState(this);
36603 if (!state.frozen) state.frozen = new InternalWeakMap();
36604 return nativeDelete(this, key) || state.frozen['delete'](key);
36605 }
36606
36607 return nativeDelete(this, key);
36608 },
36609 has: function has(key) {
36610 if (isObject(key) && !isExtensible(key)) {
36611 var state = enforceInternalState(this);
36612 if (!state.frozen) state.frozen = new InternalWeakMap();
36613 return nativeHas(this, key) || state.frozen.has(key);
36614 }
36615
36616 return nativeHas(this, key);
36617 },
36618 get: function get(key) {
36619 if (isObject(key) && !isExtensible(key)) {
36620 var state = enforceInternalState(this);
36621 if (!state.frozen) state.frozen = new InternalWeakMap();
36622 return nativeHas(this, key) ? nativeGet(this, key) : state.frozen.get(key);
36623 }
36624
36625 return nativeGet(this, key);
36626 },
36627 set: function set(key, value) {
36628 if (isObject(key) && !isExtensible(key)) {
36629 var state = enforceInternalState(this);
36630 if (!state.frozen) state.frozen = new InternalWeakMap();
36631 nativeHas(this, key) ? nativeSet(this, key, value) : state.frozen.set(key, value);
36632 } else nativeSet(this, key, value);
36633
36634 return this;
36635 }
36636 });
36637 }
36638
36639 var path = path$y;
36640 var weakMap$2 = path.WeakMap;
36641
36642 var parent$1 = weakMap$2;
36643 var weakMap$1 = parent$1;
36644
36645 var weakMap = weakMap$1;
36646
36647 /*! *****************************************************************************
36648 Copyright (c) Microsoft Corporation.
36649
36650 Permission to use, copy, modify, and/or distribute this software for any
36651 purpose with or without fee is hereby granted.
36652
36653 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
36654 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36655 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
36656 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
36657 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
36658 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
36659 PERFORMANCE OF THIS SOFTWARE.
36660 ***************************************************************************** */
36661 function __classPrivateFieldGet(receiver, state, kind, f) {
36662 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
36663 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");
36664 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
36665 }
36666 function __classPrivateFieldSet(receiver, state, value, kind, f) {
36667 if (kind === "m") throw new TypeError("Private method is not writable");
36668 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
36669 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");
36670 return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
36671 }
36672
36673 function _createForOfIteratorHelper$3(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$2(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; } } }; }
36674
36675 function _unsupportedIterableToArray$3(o, minLen) { var _context2; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$3(o, minLen); var n = slice(_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$3(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$3(o, minLen); }
36676
36677 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; }
36678
36679 var _SingleTypeSelectionAccumulator_previousSelection, _SingleTypeSelectionAccumulator_selection, _SelectionAccumulator_nodes, _SelectionAccumulator_edges, _SelectionAccumulator_commitHandler;
36680 /**
36681 * @param prev
36682 * @param next
36683 */
36684
36685 function diffSets(prev, next) {
36686 var diff = new set();
36687
36688 var _iterator = _createForOfIteratorHelper$3(next),
36689 _step;
36690
36691 try {
36692 for (_iterator.s(); !(_step = _iterator.n()).done;) {
36693 var item = _step.value;
36694
36695 if (!prev.has(item)) {
36696 diff.add(item);
36697 }
36698 }
36699 } catch (err) {
36700 _iterator.e(err);
36701 } finally {
36702 _iterator.f();
36703 }
36704
36705 return diff;
36706 }
36707
36708 var SingleTypeSelectionAccumulator = /*#__PURE__*/function () {
36709 function SingleTypeSelectionAccumulator() {
36710 _classCallCheck(this, SingleTypeSelectionAccumulator);
36711
36712 _SingleTypeSelectionAccumulator_previousSelection.set(this, new set());
36713
36714 _SingleTypeSelectionAccumulator_selection.set(this, new set());
36715 }
36716
36717 _createClass(SingleTypeSelectionAccumulator, [{
36718 key: "size",
36719 get: function get() {
36720 return __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").size;
36721 }
36722 }, {
36723 key: "add",
36724 value: function add() {
36725 for (var _len = arguments.length, items = new Array(_len), _key = 0; _key < _len; _key++) {
36726 items[_key] = arguments[_key];
36727 }
36728
36729 for (var _i = 0, _items = items; _i < _items.length; _i++) {
36730 var item = _items[_i];
36731
36732 __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").add(item);
36733 }
36734 }
36735 }, {
36736 key: "delete",
36737 value: function _delete() {
36738 for (var _len2 = arguments.length, items = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
36739 items[_key2] = arguments[_key2];
36740 }
36741
36742 for (var _i2 = 0, _items2 = items; _i2 < _items2.length; _i2++) {
36743 var item = _items2[_i2];
36744
36745 __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").delete(item);
36746 }
36747 }
36748 }, {
36749 key: "clear",
36750 value: function clear() {
36751 __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f").clear();
36752 }
36753 }, {
36754 key: "getSelection",
36755 value: function getSelection() {
36756 return _toConsumableArray(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"));
36757 }
36758 }, {
36759 key: "getChanges",
36760 value: function getChanges() {
36761 return {
36762 added: _toConsumableArray(diffSets(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f"), __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"))),
36763 deleted: _toConsumableArray(diffSets(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"), __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f"))),
36764 previous: _toConsumableArray(new set(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f"))),
36765 current: _toConsumableArray(new set(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f")))
36766 };
36767 }
36768 }, {
36769 key: "commit",
36770 value: function commit() {
36771 var changes = this.getChanges();
36772
36773 __classPrivateFieldSet(this, _SingleTypeSelectionAccumulator_previousSelection, __classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_selection, "f"), "f");
36774
36775 __classPrivateFieldSet(this, _SingleTypeSelectionAccumulator_selection, new set(__classPrivateFieldGet(this, _SingleTypeSelectionAccumulator_previousSelection, "f")), "f");
36776
36777 var _iterator2 = _createForOfIteratorHelper$3(changes.added),
36778 _step2;
36779
36780 try {
36781 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
36782 var item = _step2.value;
36783 item.select();
36784 }
36785 } catch (err) {
36786 _iterator2.e(err);
36787 } finally {
36788 _iterator2.f();
36789 }
36790
36791 var _iterator3 = _createForOfIteratorHelper$3(changes.deleted),
36792 _step3;
36793
36794 try {
36795 for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
36796 var _item = _step3.value;
36797
36798 _item.unselect();
36799 }
36800 } catch (err) {
36801 _iterator3.e(err);
36802 } finally {
36803 _iterator3.f();
36804 }
36805
36806 return changes;
36807 }
36808 }]);
36809
36810 return SingleTypeSelectionAccumulator;
36811 }();
36812
36813 _SingleTypeSelectionAccumulator_previousSelection = new weakMap(), _SingleTypeSelectionAccumulator_selection = new weakMap();
36814 var SelectionAccumulator = /*#__PURE__*/function () {
36815 function SelectionAccumulator() {
36816 var commitHandler = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
36817
36818 _classCallCheck(this, SelectionAccumulator);
36819
36820 _SelectionAccumulator_nodes.set(this, new SingleTypeSelectionAccumulator());
36821
36822 _SelectionAccumulator_edges.set(this, new SingleTypeSelectionAccumulator());
36823
36824 _SelectionAccumulator_commitHandler.set(this, void 0);
36825
36826 __classPrivateFieldSet(this, _SelectionAccumulator_commitHandler, commitHandler, "f");
36827 }
36828
36829 _createClass(SelectionAccumulator, [{
36830 key: "sizeNodes",
36831 get: function get() {
36832 return __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").size;
36833 }
36834 }, {
36835 key: "sizeEdges",
36836 get: function get() {
36837 return __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").size;
36838 }
36839 }, {
36840 key: "getNodes",
36841 value: function getNodes() {
36842 return __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").getSelection();
36843 }
36844 }, {
36845 key: "getEdges",
36846 value: function getEdges() {
36847 return __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").getSelection();
36848 }
36849 }, {
36850 key: "addNodes",
36851 value: function addNodes() {
36852 var _classPrivateFieldGe;
36853
36854 (_classPrivateFieldGe = __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f")).add.apply(_classPrivateFieldGe, arguments);
36855 }
36856 }, {
36857 key: "addEdges",
36858 value: function addEdges() {
36859 var _classPrivateFieldGe2;
36860
36861 (_classPrivateFieldGe2 = __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f")).add.apply(_classPrivateFieldGe2, arguments);
36862 }
36863 }, {
36864 key: "deleteNodes",
36865 value: function deleteNodes(node) {
36866 __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").delete(node);
36867 }
36868 }, {
36869 key: "deleteEdges",
36870 value: function deleteEdges(edge) {
36871 __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").delete(edge);
36872 }
36873 }, {
36874 key: "clear",
36875 value: function clear() {
36876 __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").clear();
36877
36878 __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").clear();
36879 }
36880 }, {
36881 key: "commit",
36882 value: function commit() {
36883 var _classPrivateFieldGe3, _context;
36884
36885 var summary = {
36886 nodes: __classPrivateFieldGet(this, _SelectionAccumulator_nodes, "f").commit(),
36887 edges: __classPrivateFieldGet(this, _SelectionAccumulator_edges, "f").commit()
36888 };
36889
36890 for (var _len3 = arguments.length, rest = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
36891 rest[_key3] = arguments[_key3];
36892 }
36893
36894 (_classPrivateFieldGe3 = __classPrivateFieldGet(this, _SelectionAccumulator_commitHandler, "f")).call.apply(_classPrivateFieldGe3, concat(_context = [this, summary]).call(_context, rest));
36895
36896 return summary;
36897 }
36898 }]);
36899
36900 return SelectionAccumulator;
36901 }();
36902 _SelectionAccumulator_nodes = new weakMap(), _SelectionAccumulator_edges = new weakMap(), _SelectionAccumulator_commitHandler = new weakMap();
36903
36904 function _createForOfIteratorHelper$2(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$2(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; } } }; }
36905
36906 function _unsupportedIterableToArray$2(o, minLen) { var _context3; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$2(o, minLen); var n = slice(_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$3(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$2(o, minLen); }
36907
36908 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; }
36909 /**
36910 * The handler for selections
36911 */
36912
36913 var SelectionHandler = /*#__PURE__*/function () {
36914 /**
36915 * @param {object} body
36916 * @param {Canvas} canvas
36917 */
36918 function SelectionHandler(body, canvas) {
36919 var _this = this;
36920
36921 _classCallCheck(this, SelectionHandler);
36922
36923 this.body = body;
36924 this.canvas = canvas; // TODO: Consider firing an event on any change to the selection, not
36925 // only those caused by clicks and taps. It would be easy to implement
36926 // now and (at least to me) it seems like something that could be
36927 // quite useful.
36928
36929 this._selectionAccumulator = new SelectionAccumulator();
36930 this.hoverObj = {
36931 nodes: {},
36932 edges: {}
36933 };
36934 this.options = {};
36935 this.defaultOptions = {
36936 multiselect: false,
36937 selectable: true,
36938 selectConnectedEdges: true,
36939 hoverConnectedEdges: true
36940 };
36941
36942 assign$2(this.options, this.defaultOptions);
36943
36944 this.body.emitter.on("_dataChanged", function () {
36945 _this.updateSelection();
36946 });
36947 }
36948 /**
36949 *
36950 * @param {object} [options]
36951 */
36952
36953
36954 _createClass(SelectionHandler, [{
36955 key: "setOptions",
36956 value: function setOptions(options) {
36957 if (options !== undefined) {
36958 var fields = ["multiselect", "hoverConnectedEdges", "selectable", "selectConnectedEdges"];
36959 selectiveDeepExtend(fields, this.options, options);
36960 }
36961 }
36962 /**
36963 * handles the selection part of the tap;
36964 *
36965 * @param {{x: number, y: number}} pointer
36966 * @returns {boolean}
36967 */
36968
36969 }, {
36970 key: "selectOnPoint",
36971 value: function selectOnPoint(pointer) {
36972 var selected = false;
36973
36974 if (this.options.selectable === true) {
36975 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer); // unselect after getting the objects in order to restore width and height.
36976
36977 this.unselectAll();
36978
36979 if (obj !== undefined) {
36980 selected = this.selectObject(obj);
36981 }
36982
36983 this.body.emitter.emit("_requestRedraw");
36984 }
36985
36986 return selected;
36987 }
36988 /**
36989 *
36990 * @param {{x: number, y: number}} pointer
36991 * @returns {boolean}
36992 */
36993
36994 }, {
36995 key: "selectAdditionalOnPoint",
36996 value: function selectAdditionalOnPoint(pointer) {
36997 var selectionChanged = false;
36998
36999 if (this.options.selectable === true) {
37000 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
37001
37002 if (obj !== undefined) {
37003 selectionChanged = true;
37004
37005 if (obj.isSelected() === true) {
37006 this.deselectObject(obj);
37007 } else {
37008 this.selectObject(obj);
37009 }
37010
37011 this.body.emitter.emit("_requestRedraw");
37012 }
37013 }
37014
37015 return selectionChanged;
37016 }
37017 /**
37018 * Create an object containing the standard fields for an event.
37019 *
37020 * @param {Event} event
37021 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
37022 * @returns {{}}
37023 * @private
37024 */
37025
37026 }, {
37027 key: "_initBaseEvent",
37028 value: function _initBaseEvent(event, pointer) {
37029 var properties = {};
37030 properties["pointer"] = {
37031 DOM: {
37032 x: pointer.x,
37033 y: pointer.y
37034 },
37035 canvas: this.canvas.DOMtoCanvas(pointer)
37036 };
37037 properties["event"] = event;
37038 return properties;
37039 }
37040 /**
37041 * Generate an event which the user can catch.
37042 *
37043 * This adds some extra data to the event with respect to cursor position and
37044 * selected nodes and edges.
37045 *
37046 * @param {string} eventType Name of event to send
37047 * @param {Event} event
37048 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
37049 * @param {object | undefined} oldSelection If present, selection state before event occured
37050 * @param {boolean|undefined} [emptySelection=false] Indicate if selection data should be passed
37051 */
37052
37053 }, {
37054 key: "generateClickEvent",
37055 value: function generateClickEvent(eventType, event, pointer, oldSelection) {
37056 var emptySelection = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
37057
37058 var properties = this._initBaseEvent(event, pointer);
37059
37060 if (emptySelection === true) {
37061 properties.nodes = [];
37062 properties.edges = [];
37063 } else {
37064 var tmp = this.getSelection();
37065 properties.nodes = tmp.nodes;
37066 properties.edges = tmp.edges;
37067 }
37068
37069 if (oldSelection !== undefined) {
37070 properties["previousSelection"] = oldSelection;
37071 }
37072
37073 if (eventType == "click") {
37074 // For the time being, restrict this functionality to
37075 // just the click event.
37076 properties.items = this.getClickedItems(pointer);
37077 }
37078
37079 if (event.controlEdge !== undefined) {
37080 properties.controlEdge = event.controlEdge;
37081 }
37082
37083 this.body.emitter.emit(eventType, properties);
37084 }
37085 /**
37086 *
37087 * @param {object} obj
37088 * @param {boolean} [highlightEdges=this.options.selectConnectedEdges]
37089 * @returns {boolean}
37090 */
37091
37092 }, {
37093 key: "selectObject",
37094 value: function selectObject(obj) {
37095 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.selectConnectedEdges;
37096
37097 if (obj !== undefined) {
37098 if (obj instanceof Node) {
37099 if (highlightEdges === true) {
37100 var _this$_selectionAccum;
37101
37102 (_this$_selectionAccum = this._selectionAccumulator).addEdges.apply(_this$_selectionAccum, _toConsumableArray(obj.edges));
37103 }
37104
37105 this._selectionAccumulator.addNodes(obj);
37106 } else {
37107 this._selectionAccumulator.addEdges(obj);
37108 }
37109
37110 return true;
37111 }
37112
37113 return false;
37114 }
37115 /**
37116 *
37117 * @param {object} obj
37118 */
37119
37120 }, {
37121 key: "deselectObject",
37122 value: function deselectObject(obj) {
37123 if (obj.isSelected() === true) {
37124 obj.selected = false;
37125
37126 this._removeFromSelection(obj);
37127 }
37128 }
37129 /**
37130 * retrieve all nodes overlapping with given object
37131 *
37132 * @param {object} object An object with parameters left, top, right, bottom
37133 * @returns {number[]} An array with id's of the overlapping nodes
37134 * @private
37135 */
37136
37137 }, {
37138 key: "_getAllNodesOverlappingWith",
37139 value: function _getAllNodesOverlappingWith(object) {
37140 var overlappingNodes = [];
37141 var nodes = this.body.nodes;
37142
37143 for (var i = 0; i < this.body.nodeIndices.length; i++) {
37144 var nodeId = this.body.nodeIndices[i];
37145
37146 if (nodes[nodeId].isOverlappingWith(object)) {
37147 overlappingNodes.push(nodeId);
37148 }
37149 }
37150
37151 return overlappingNodes;
37152 }
37153 /**
37154 * Return a position object in canvasspace from a single point in screenspace
37155 *
37156 * @param {{x: number, y: number}} pointer
37157 * @returns {{left: number, top: number, right: number, bottom: number}}
37158 * @private
37159 */
37160
37161 }, {
37162 key: "_pointerToPositionObject",
37163 value: function _pointerToPositionObject(pointer) {
37164 var canvasPos = this.canvas.DOMtoCanvas(pointer);
37165 return {
37166 left: canvasPos.x - 1,
37167 top: canvasPos.y + 1,
37168 right: canvasPos.x + 1,
37169 bottom: canvasPos.y - 1
37170 };
37171 }
37172 /**
37173 * Get the top node at the passed point (like a click)
37174 *
37175 * @param {{x: number, y: number}} pointer
37176 * @param {boolean} [returnNode=true]
37177 * @returns {Node | undefined} node
37178 */
37179
37180 }, {
37181 key: "getNodeAt",
37182 value: function getNodeAt(pointer) {
37183 var returnNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
37184
37185 // we first check if this is an navigation controls element
37186 var positionObject = this._pointerToPositionObject(pointer);
37187
37188 var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); // if there are overlapping nodes, select the last one, this is the
37189 // one which is drawn on top of the others
37190
37191
37192 if (overlappingNodes.length > 0) {
37193 if (returnNode === true) {
37194 return this.body.nodes[overlappingNodes[overlappingNodes.length - 1]];
37195 } else {
37196 return overlappingNodes[overlappingNodes.length - 1];
37197 }
37198 } else {
37199 return undefined;
37200 }
37201 }
37202 /**
37203 * retrieve all edges overlapping with given object, selector is around center
37204 *
37205 * @param {object} object An object with parameters left, top, right, bottom
37206 * @param {number[]} overlappingEdges An array with id's of the overlapping nodes
37207 * @private
37208 */
37209
37210 }, {
37211 key: "_getEdgesOverlappingWith",
37212 value: function _getEdgesOverlappingWith(object, overlappingEdges) {
37213 var edges = this.body.edges;
37214
37215 for (var i = 0; i < this.body.edgeIndices.length; i++) {
37216 var edgeId = this.body.edgeIndices[i];
37217
37218 if (edges[edgeId].isOverlappingWith(object)) {
37219 overlappingEdges.push(edgeId);
37220 }
37221 }
37222 }
37223 /**
37224 * retrieve all nodes overlapping with given object
37225 *
37226 * @param {object} object An object with parameters left, top, right, bottom
37227 * @returns {number[]} An array with id's of the overlapping nodes
37228 * @private
37229 */
37230
37231 }, {
37232 key: "_getAllEdgesOverlappingWith",
37233 value: function _getAllEdgesOverlappingWith(object) {
37234 var overlappingEdges = [];
37235
37236 this._getEdgesOverlappingWith(object, overlappingEdges);
37237
37238 return overlappingEdges;
37239 }
37240 /**
37241 * Get the edges nearest to the passed point (like a click)
37242 *
37243 * @param {{x: number, y: number}} pointer
37244 * @param {boolean} [returnEdge=true]
37245 * @returns {Edge | undefined} node
37246 */
37247
37248 }, {
37249 key: "getEdgeAt",
37250 value: function getEdgeAt(pointer) {
37251 var returnEdge = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
37252 // Iterate over edges, pick closest within 10
37253 var canvasPos = this.canvas.DOMtoCanvas(pointer);
37254 var mindist = 10;
37255 var overlappingEdge = null;
37256 var edges = this.body.edges;
37257
37258 for (var i = 0; i < this.body.edgeIndices.length; i++) {
37259 var edgeId = this.body.edgeIndices[i];
37260 var edge = edges[edgeId];
37261
37262 if (edge.connected) {
37263 var xFrom = edge.from.x;
37264 var yFrom = edge.from.y;
37265 var xTo = edge.to.x;
37266 var yTo = edge.to.y;
37267 var dist = edge.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, canvasPos.x, canvasPos.y);
37268
37269 if (dist < mindist) {
37270 overlappingEdge = edgeId;
37271 mindist = dist;
37272 }
37273 }
37274 }
37275
37276 if (overlappingEdge !== null) {
37277 if (returnEdge === true) {
37278 return this.body.edges[overlappingEdge];
37279 } else {
37280 return overlappingEdge;
37281 }
37282 } else {
37283 return undefined;
37284 }
37285 }
37286 /**
37287 * Add object to the selection array.
37288 *
37289 * @param {object} obj
37290 * @private
37291 */
37292
37293 }, {
37294 key: "_addToHover",
37295 value: function _addToHover(obj) {
37296 if (obj instanceof Node) {
37297 this.hoverObj.nodes[obj.id] = obj;
37298 } else {
37299 this.hoverObj.edges[obj.id] = obj;
37300 }
37301 }
37302 /**
37303 * Remove a single option from selection.
37304 *
37305 * @param {object} obj
37306 * @private
37307 */
37308
37309 }, {
37310 key: "_removeFromSelection",
37311 value: function _removeFromSelection(obj) {
37312 if (obj instanceof Node) {
37313 var _this$_selectionAccum2;
37314
37315 this._selectionAccumulator.deleteNodes(obj);
37316
37317 (_this$_selectionAccum2 = this._selectionAccumulator).deleteEdges.apply(_this$_selectionAccum2, _toConsumableArray(obj.edges));
37318 } else {
37319 this._selectionAccumulator.deleteEdges(obj);
37320 }
37321 }
37322 /**
37323 * Unselect all nodes and edges.
37324 */
37325
37326 }, {
37327 key: "unselectAll",
37328 value: function unselectAll() {
37329 this._selectionAccumulator.clear();
37330 }
37331 /**
37332 * return the number of selected nodes
37333 *
37334 * @returns {number}
37335 */
37336
37337 }, {
37338 key: "getSelectedNodeCount",
37339 value: function getSelectedNodeCount() {
37340 return this._selectionAccumulator.sizeNodes;
37341 }
37342 /**
37343 * return the number of selected edges
37344 *
37345 * @returns {number}
37346 */
37347
37348 }, {
37349 key: "getSelectedEdgeCount",
37350 value: function getSelectedEdgeCount() {
37351 return this._selectionAccumulator.sizeEdges;
37352 }
37353 /**
37354 * select the edges connected to the node that is being selected
37355 *
37356 * @param {Node} node
37357 * @private
37358 */
37359
37360 }, {
37361 key: "_hoverConnectedEdges",
37362 value: function _hoverConnectedEdges(node) {
37363 for (var i = 0; i < node.edges.length; i++) {
37364 var edge = node.edges[i];
37365 edge.hover = true;
37366
37367 this._addToHover(edge);
37368 }
37369 }
37370 /**
37371 * Remove the highlight from a node or edge, in response to mouse movement
37372 *
37373 * @param {Event} event
37374 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
37375 * @param {Node|vis.Edge} object
37376 * @private
37377 */
37378
37379 }, {
37380 key: "emitBlurEvent",
37381 value: function emitBlurEvent(event, pointer, object) {
37382 var properties = this._initBaseEvent(event, pointer);
37383
37384 if (object.hover === true) {
37385 object.hover = false;
37386
37387 if (object instanceof Node) {
37388 properties.node = object.id;
37389 this.body.emitter.emit("blurNode", properties);
37390 } else {
37391 properties.edge = object.id;
37392 this.body.emitter.emit("blurEdge", properties);
37393 }
37394 }
37395 }
37396 /**
37397 * Create the highlight for a node or edge, in response to mouse movement
37398 *
37399 * @param {Event} event
37400 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
37401 * @param {Node|vis.Edge} object
37402 * @returns {boolean} hoverChanged
37403 * @private
37404 */
37405
37406 }, {
37407 key: "emitHoverEvent",
37408 value: function emitHoverEvent(event, pointer, object) {
37409 var properties = this._initBaseEvent(event, pointer);
37410
37411 var hoverChanged = false;
37412
37413 if (object.hover === false) {
37414 object.hover = true;
37415
37416 this._addToHover(object);
37417
37418 hoverChanged = true;
37419
37420 if (object instanceof Node) {
37421 properties.node = object.id;
37422 this.body.emitter.emit("hoverNode", properties);
37423 } else {
37424 properties.edge = object.id;
37425 this.body.emitter.emit("hoverEdge", properties);
37426 }
37427 }
37428
37429 return hoverChanged;
37430 }
37431 /**
37432 * Perform actions in response to a mouse movement.
37433 *
37434 * @param {Event} event
37435 * @param {{x: number, y: number}} pointer | object with the x and y screen coordinates of the mouse
37436 */
37437
37438 }, {
37439 key: "hoverObject",
37440 value: function hoverObject(event, pointer) {
37441 var object = this.getNodeAt(pointer);
37442
37443 if (object === undefined) {
37444 object = this.getEdgeAt(pointer);
37445 }
37446
37447 var hoverChanged = false; // remove all node hover highlights
37448
37449 for (var nodeId in this.hoverObj.nodes) {
37450 if (Object.prototype.hasOwnProperty.call(this.hoverObj.nodes, nodeId)) {
37451 if (object === undefined || object instanceof Node && object.id != nodeId || object instanceof Edge) {
37452 this.emitBlurEvent(event, pointer, this.hoverObj.nodes[nodeId]);
37453 delete this.hoverObj.nodes[nodeId];
37454 hoverChanged = true;
37455 }
37456 }
37457 } // removing all edge hover highlights
37458
37459
37460 for (var edgeId in this.hoverObj.edges) {
37461 if (Object.prototype.hasOwnProperty.call(this.hoverObj.edges, edgeId)) {
37462 // if the hover has been changed here it means that the node has been hovered over or off
37463 // we then do not use the emitBlurEvent method here.
37464 if (hoverChanged === true) {
37465 this.hoverObj.edges[edgeId].hover = false;
37466 delete this.hoverObj.edges[edgeId];
37467 } // if the blur remains the same and the object is undefined (mouse off) or another
37468 // edge has been hovered, or another node has been hovered we blur the edge.
37469 else if (object === undefined || object instanceof Edge && object.id != edgeId || object instanceof Node && !object.hover) {
37470 this.emitBlurEvent(event, pointer, this.hoverObj.edges[edgeId]);
37471 delete this.hoverObj.edges[edgeId];
37472 hoverChanged = true;
37473 }
37474 }
37475 }
37476
37477 if (object !== undefined) {
37478 var hoveredEdgesCount = keys$4(this.hoverObj.edges).length;
37479
37480 var hoveredNodesCount = keys$4(this.hoverObj.nodes).length;
37481
37482 var newOnlyHoveredEdge = object instanceof Edge && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
37483 var newOnlyHoveredNode = object instanceof Node && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
37484
37485 if (hoverChanged || newOnlyHoveredEdge || newOnlyHoveredNode) {
37486 hoverChanged = this.emitHoverEvent(event, pointer, object);
37487 }
37488
37489 if (object instanceof Node && this.options.hoverConnectedEdges === true) {
37490 this._hoverConnectedEdges(object);
37491 }
37492 }
37493
37494 if (hoverChanged === true) {
37495 this.body.emitter.emit("_requestRedraw");
37496 }
37497 }
37498 /**
37499 * Commit the selection changes but don't emit any events.
37500 */
37501
37502 }, {
37503 key: "commitWithoutEmitting",
37504 value: function commitWithoutEmitting() {
37505 this._selectionAccumulator.commit();
37506 }
37507 /**
37508 * Select and deselect nodes depending current selection change.
37509 *
37510 * For changing nodes, select/deselect events are fired.
37511 *
37512 * NOTE: For a given edge, if one connecting node is deselected and with the
37513 * same click the other node is selected, no events for the edge will fire. It
37514 * was selected and it will remain selected.
37515 *
37516 * @param {{x: number, y: number}} pointer - The x and y coordinates of the
37517 * click, tap, dragend… that triggered this.
37518 * @param {UIEvent} event - The event that triggered this.
37519 */
37520
37521 }, {
37522 key: "commitAndEmit",
37523 value: function commitAndEmit(pointer, event) {
37524 var selected = false;
37525
37526 var selectionChanges = this._selectionAccumulator.commit();
37527
37528 var previousSelection = {
37529 nodes: selectionChanges.nodes.previous,
37530 edges: selectionChanges.edges.previous
37531 };
37532
37533 if (selectionChanges.edges.deleted.length > 0) {
37534 this.generateClickEvent("deselectEdge", event, pointer, previousSelection);
37535 selected = true;
37536 }
37537
37538 if (selectionChanges.nodes.deleted.length > 0) {
37539 this.generateClickEvent("deselectNode", event, pointer, previousSelection);
37540 selected = true;
37541 }
37542
37543 if (selectionChanges.nodes.added.length > 0) {
37544 this.generateClickEvent("selectNode", event, pointer);
37545 selected = true;
37546 }
37547
37548 if (selectionChanges.edges.added.length > 0) {
37549 this.generateClickEvent("selectEdge", event, pointer);
37550 selected = true;
37551 } // fire the select event if anything has been selected or deselected
37552
37553
37554 if (selected === true) {
37555 // select or unselect
37556 this.generateClickEvent("select", event, pointer);
37557 }
37558 }
37559 /**
37560 * Retrieve the currently selected node and edge ids.
37561 *
37562 * @returns {{nodes: Array.<string>, edges: Array.<string>}} Arrays with the
37563 * ids of the selected nodes and edges.
37564 */
37565
37566 }, {
37567 key: "getSelection",
37568 value: function getSelection() {
37569 return {
37570 nodes: this.getSelectedNodeIds(),
37571 edges: this.getSelectedEdgeIds()
37572 };
37573 }
37574 /**
37575 * Retrieve the currently selected nodes.
37576 *
37577 * @returns {Array} An array with selected nodes.
37578 */
37579
37580 }, {
37581 key: "getSelectedNodes",
37582 value: function getSelectedNodes() {
37583 return this._selectionAccumulator.getNodes();
37584 }
37585 /**
37586 * Retrieve the currently selected edges.
37587 *
37588 * @returns {Array} An array with selected edges.
37589 */
37590
37591 }, {
37592 key: "getSelectedEdges",
37593 value: function getSelectedEdges() {
37594 return this._selectionAccumulator.getEdges();
37595 }
37596 /**
37597 * Retrieve the currently selected node ids.
37598 *
37599 * @returns {Array} An array with the ids of the selected nodes.
37600 */
37601
37602 }, {
37603 key: "getSelectedNodeIds",
37604 value: function getSelectedNodeIds() {
37605 var _context;
37606
37607 return map$3(_context = this._selectionAccumulator.getNodes()).call(_context, function (node) {
37608 return node.id;
37609 });
37610 }
37611 /**
37612 * Retrieve the currently selected edge ids.
37613 *
37614 * @returns {Array} An array with the ids of the selected edges.
37615 */
37616
37617 }, {
37618 key: "getSelectedEdgeIds",
37619 value: function getSelectedEdgeIds() {
37620 var _context2;
37621
37622 return map$3(_context2 = this._selectionAccumulator.getEdges()).call(_context2, function (edge) {
37623 return edge.id;
37624 });
37625 }
37626 /**
37627 * Updates the current selection
37628 *
37629 * @param {{nodes: Array.<string>, edges: Array.<string>}} selection
37630 * @param {object} options Options
37631 */
37632
37633 }, {
37634 key: "setSelection",
37635 value: function setSelection(selection) {
37636 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
37637
37638 if (!selection || !selection.nodes && !selection.edges) {
37639 throw new TypeError("Selection must be an object with nodes and/or edges properties");
37640 } // first unselect any selected node, if option is true or undefined
37641
37642
37643 if (options.unselectAll || options.unselectAll === undefined) {
37644 this.unselectAll();
37645 }
37646
37647 if (selection.nodes) {
37648 var _iterator = _createForOfIteratorHelper$2(selection.nodes),
37649 _step;
37650
37651 try {
37652 for (_iterator.s(); !(_step = _iterator.n()).done;) {
37653 var id = _step.value;
37654 var node = this.body.nodes[id];
37655
37656 if (!node) {
37657 throw new RangeError('Node with id "' + id + '" not found');
37658 } // don't select edges with it
37659
37660
37661 this.selectObject(node, options.highlightEdges);
37662 }
37663 } catch (err) {
37664 _iterator.e(err);
37665 } finally {
37666 _iterator.f();
37667 }
37668 }
37669
37670 if (selection.edges) {
37671 var _iterator2 = _createForOfIteratorHelper$2(selection.edges),
37672 _step2;
37673
37674 try {
37675 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
37676 var _id = _step2.value;
37677 var edge = this.body.edges[_id];
37678
37679 if (!edge) {
37680 throw new RangeError('Edge with id "' + _id + '" not found');
37681 }
37682
37683 this.selectObject(edge);
37684 }
37685 } catch (err) {
37686 _iterator2.e(err);
37687 } finally {
37688 _iterator2.f();
37689 }
37690 }
37691
37692 this.body.emitter.emit("_requestRedraw");
37693
37694 this._selectionAccumulator.commit();
37695 }
37696 /**
37697 * select zero or more nodes with the option to highlight edges
37698 *
37699 * @param {number[] | string[]} selection An array with the ids of the
37700 * selected nodes.
37701 * @param {boolean} [highlightEdges]
37702 */
37703
37704 }, {
37705 key: "selectNodes",
37706 value: function selectNodes(selection) {
37707 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
37708 if (!selection || selection.length === undefined) throw "Selection must be an array with ids";
37709 this.setSelection({
37710 nodes: selection
37711 }, {
37712 highlightEdges: highlightEdges
37713 });
37714 }
37715 /**
37716 * select zero or more edges
37717 *
37718 * @param {number[] | string[]} selection An array with the ids of the
37719 * selected nodes.
37720 */
37721
37722 }, {
37723 key: "selectEdges",
37724 value: function selectEdges(selection) {
37725 if (!selection || selection.length === undefined) throw "Selection must be an array with ids";
37726 this.setSelection({
37727 edges: selection
37728 });
37729 }
37730 /**
37731 * Validate the selection: remove ids of nodes which no longer exist
37732 *
37733 * @private
37734 */
37735
37736 }, {
37737 key: "updateSelection",
37738 value: function updateSelection() {
37739 for (var node in this._selectionAccumulator.getNodes()) {
37740 if (!Object.prototype.hasOwnProperty.call(this.body.nodes, node.id)) {
37741 this._selectionAccumulator.deleteNodes(node);
37742 }
37743 }
37744
37745 for (var edge in this._selectionAccumulator.getEdges()) {
37746 if (!Object.prototype.hasOwnProperty.call(this.body.edges, edge.id)) {
37747 this._selectionAccumulator.deleteEdges(edge);
37748 }
37749 }
37750 }
37751 /**
37752 * Determine all the visual elements clicked which are on the given point.
37753 *
37754 * All elements are returned; this includes nodes, edges and their labels.
37755 * The order returned is from highest to lowest, i.e. element 0 of the return
37756 * value is the topmost item clicked on.
37757 *
37758 * The return value consists of an array of the following possible elements:
37759 *
37760 * - `{nodeId:number}` - node with given id clicked on
37761 * - `{nodeId:number, labelId:0}` - label of node with given id clicked on
37762 * - `{edgeId:number}` - edge with given id clicked on
37763 * - `{edge:number, labelId:0}` - label of edge with given id clicked on
37764 *
37765 * ## NOTES
37766 *
37767 * - Currently, there is only one label associated with a node or an edge,
37768 * but this is expected to change somewhere in the future.
37769 * - Since there is no z-indexing yet, it is not really possible to set the nodes and
37770 * edges in the correct order. For the time being, nodes come first.
37771 *
37772 * @param {point} pointer mouse position in screen coordinates
37773 * @returns {Array.<nodeClickItem|nodeLabelClickItem|edgeClickItem|edgeLabelClickItem>}
37774 * @private
37775 */
37776
37777 }, {
37778 key: "getClickedItems",
37779 value: function getClickedItems(pointer) {
37780 var point = this.canvas.DOMtoCanvas(pointer);
37781 var items = []; // Note reverse order; we want the topmost clicked items to be first in the array
37782 // Also note that selected nodes are disregarded here; these normally display on top
37783
37784 var nodeIndices = this.body.nodeIndices;
37785 var nodes = this.body.nodes;
37786
37787 for (var i = nodeIndices.length - 1; i >= 0; i--) {
37788 var node = nodes[nodeIndices[i]];
37789 var ret = node.getItemsOnPoint(point);
37790 items.push.apply(items, ret); // Append the return value to the running list.
37791 }
37792
37793 var edgeIndices = this.body.edgeIndices;
37794 var edges = this.body.edges;
37795
37796 for (var _i = edgeIndices.length - 1; _i >= 0; _i--) {
37797 var edge = edges[edgeIndices[_i]];
37798
37799 var _ret = edge.getItemsOnPoint(point);
37800
37801 items.push.apply(items, _ret); // Append the return value to the running list.
37802 }
37803
37804 return items;
37805 }
37806 }]);
37807
37808 return SelectionHandler;
37809 }();
37810
37811 var timsort$1 = {};
37812
37813 /****
37814 * The MIT License
37815 *
37816 * Copyright (c) 2015 Marco Ziccardi
37817 *
37818 * Permission is hereby granted, free of charge, to any person obtaining a copy
37819 * of this software and associated documentation files (the "Software"), to deal
37820 * in the Software without restriction, including without limitation the rights
37821 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37822 * copies of the Software, and to permit persons to whom the Software is
37823 * furnished to do so, subject to the following conditions:
37824 *
37825 * The above copyright notice and this permission notice shall be included in
37826 * all copies or substantial portions of the Software.
37827 *
37828 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37829 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37830 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37831 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37832 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37833 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37834 * THE SOFTWARE.
37835 *
37836 ****/
37837
37838 (function (exports) {
37839 (function (global, factory) {
37840 {
37841 factory(exports);
37842 }
37843 })(commonjsGlobal, function (exports) {
37844
37845 exports.__esModule = true;
37846 exports.sort = sort;
37847
37848 function _classCallCheck(instance, Constructor) {
37849 if (!(instance instanceof Constructor)) {
37850 throw new TypeError('Cannot call a class as a function');
37851 }
37852 }
37853
37854 var DEFAULT_MIN_MERGE = 32;
37855 var DEFAULT_MIN_GALLOPING = 7;
37856 var DEFAULT_TMP_STORAGE_LENGTH = 256;
37857 var POWERS_OF_TEN = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9];
37858
37859 function log10(x) {
37860 if (x < 1e5) {
37861 if (x < 1e2) {
37862 return x < 1e1 ? 0 : 1;
37863 }
37864
37865 if (x < 1e4) {
37866 return x < 1e3 ? 2 : 3;
37867 }
37868
37869 return 4;
37870 }
37871
37872 if (x < 1e7) {
37873 return x < 1e6 ? 5 : 6;
37874 }
37875
37876 if (x < 1e9) {
37877 return x < 1e8 ? 7 : 8;
37878 }
37879
37880 return 9;
37881 }
37882
37883 function alphabeticalCompare(a, b) {
37884 if (a === b) {
37885 return 0;
37886 }
37887
37888 if (~~a === a && ~~b === b) {
37889 if (a === 0 || b === 0) {
37890 return a < b ? -1 : 1;
37891 }
37892
37893 if (a < 0 || b < 0) {
37894 if (b >= 0) {
37895 return -1;
37896 }
37897
37898 if (a >= 0) {
37899 return 1;
37900 }
37901
37902 a = -a;
37903 b = -b;
37904 }
37905
37906 var al = log10(a);
37907 var bl = log10(b);
37908 var t = 0;
37909
37910 if (al < bl) {
37911 a *= POWERS_OF_TEN[bl - al - 1];
37912 b /= 10;
37913 t = -1;
37914 } else if (al > bl) {
37915 b *= POWERS_OF_TEN[al - bl - 1];
37916 a /= 10;
37917 t = 1;
37918 }
37919
37920 if (a === b) {
37921 return t;
37922 }
37923
37924 return a < b ? -1 : 1;
37925 }
37926
37927 var aStr = String(a);
37928 var bStr = String(b);
37929
37930 if (aStr === bStr) {
37931 return 0;
37932 }
37933
37934 return aStr < bStr ? -1 : 1;
37935 }
37936
37937 function minRunLength(n) {
37938 var r = 0;
37939
37940 while (n >= DEFAULT_MIN_MERGE) {
37941 r |= n & 1;
37942 n >>= 1;
37943 }
37944
37945 return n + r;
37946 }
37947
37948 function makeAscendingRun(array, lo, hi, compare) {
37949 var runHi = lo + 1;
37950
37951 if (runHi === hi) {
37952 return 1;
37953 }
37954
37955 if (compare(array[runHi++], array[lo]) < 0) {
37956 while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
37957 runHi++;
37958 }
37959
37960 reverseRun(array, lo, runHi);
37961 } else {
37962 while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
37963 runHi++;
37964 }
37965 }
37966
37967 return runHi - lo;
37968 }
37969
37970 function reverseRun(array, lo, hi) {
37971 hi--;
37972
37973 while (lo < hi) {
37974 var t = array[lo];
37975 array[lo++] = array[hi];
37976 array[hi--] = t;
37977 }
37978 }
37979
37980 function binaryInsertionSort(array, lo, hi, start, compare) {
37981 if (start === lo) {
37982 start++;
37983 }
37984
37985 for (; start < hi; start++) {
37986 var pivot = array[start];
37987 var left = lo;
37988 var right = start;
37989
37990 while (left < right) {
37991 var mid = left + right >>> 1;
37992
37993 if (compare(pivot, array[mid]) < 0) {
37994 right = mid;
37995 } else {
37996 left = mid + 1;
37997 }
37998 }
37999
38000 var n = start - left;
38001
38002 switch (n) {
38003 case 3:
38004 array[left + 3] = array[left + 2];
38005
38006 case 2:
38007 array[left + 2] = array[left + 1];
38008
38009 case 1:
38010 array[left + 1] = array[left];
38011 break;
38012
38013 default:
38014 while (n > 0) {
38015 array[left + n] = array[left + n - 1];
38016 n--;
38017 }
38018
38019 }
38020
38021 array[left] = pivot;
38022 }
38023 }
38024
38025 function gallopLeft(value, array, start, length, hint, compare) {
38026 var lastOffset = 0;
38027 var maxOffset = 0;
38028 var offset = 1;
38029
38030 if (compare(value, array[start + hint]) > 0) {
38031 maxOffset = length - hint;
38032
38033 while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
38034 lastOffset = offset;
38035 offset = (offset << 1) + 1;
38036
38037 if (offset <= 0) {
38038 offset = maxOffset;
38039 }
38040 }
38041
38042 if (offset > maxOffset) {
38043 offset = maxOffset;
38044 }
38045
38046 lastOffset += hint;
38047 offset += hint;
38048 } else {
38049 maxOffset = hint + 1;
38050
38051 while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
38052 lastOffset = offset;
38053 offset = (offset << 1) + 1;
38054
38055 if (offset <= 0) {
38056 offset = maxOffset;
38057 }
38058 }
38059
38060 if (offset > maxOffset) {
38061 offset = maxOffset;
38062 }
38063
38064 var tmp = lastOffset;
38065 lastOffset = hint - offset;
38066 offset = hint - tmp;
38067 }
38068
38069 lastOffset++;
38070
38071 while (lastOffset < offset) {
38072 var m = lastOffset + (offset - lastOffset >>> 1);
38073
38074 if (compare(value, array[start + m]) > 0) {
38075 lastOffset = m + 1;
38076 } else {
38077 offset = m;
38078 }
38079 }
38080
38081 return offset;
38082 }
38083
38084 function gallopRight(value, array, start, length, hint, compare) {
38085 var lastOffset = 0;
38086 var maxOffset = 0;
38087 var offset = 1;
38088
38089 if (compare(value, array[start + hint]) < 0) {
38090 maxOffset = hint + 1;
38091
38092 while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
38093 lastOffset = offset;
38094 offset = (offset << 1) + 1;
38095
38096 if (offset <= 0) {
38097 offset = maxOffset;
38098 }
38099 }
38100
38101 if (offset > maxOffset) {
38102 offset = maxOffset;
38103 }
38104
38105 var tmp = lastOffset;
38106 lastOffset = hint - offset;
38107 offset = hint - tmp;
38108 } else {
38109 maxOffset = length - hint;
38110
38111 while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
38112 lastOffset = offset;
38113 offset = (offset << 1) + 1;
38114
38115 if (offset <= 0) {
38116 offset = maxOffset;
38117 }
38118 }
38119
38120 if (offset > maxOffset) {
38121 offset = maxOffset;
38122 }
38123
38124 lastOffset += hint;
38125 offset += hint;
38126 }
38127
38128 lastOffset++;
38129
38130 while (lastOffset < offset) {
38131 var m = lastOffset + (offset - lastOffset >>> 1);
38132
38133 if (compare(value, array[start + m]) < 0) {
38134 offset = m;
38135 } else {
38136 lastOffset = m + 1;
38137 }
38138 }
38139
38140 return offset;
38141 }
38142
38143 var TimSort = function () {
38144 function TimSort(array, compare) {
38145 _classCallCheck(this, TimSort);
38146
38147 this.array = null;
38148 this.compare = null;
38149 this.minGallop = DEFAULT_MIN_GALLOPING;
38150 this.length = 0;
38151 this.tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
38152 this.stackLength = 0;
38153 this.runStart = null;
38154 this.runLength = null;
38155 this.stackSize = 0;
38156 this.array = array;
38157 this.compare = compare;
38158 this.length = array.length;
38159
38160 if (this.length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
38161 this.tmpStorageLength = this.length >>> 1;
38162 }
38163
38164 this.tmp = new Array(this.tmpStorageLength);
38165 this.stackLength = this.length < 120 ? 5 : this.length < 1542 ? 10 : this.length < 119151 ? 19 : 40;
38166 this.runStart = new Array(this.stackLength);
38167 this.runLength = new Array(this.stackLength);
38168 }
38169
38170 TimSort.prototype.pushRun = function pushRun(runStart, runLength) {
38171 this.runStart[this.stackSize] = runStart;
38172 this.runLength[this.stackSize] = runLength;
38173 this.stackSize += 1;
38174 };
38175
38176 TimSort.prototype.mergeRuns = function mergeRuns() {
38177 while (this.stackSize > 1) {
38178 var n = this.stackSize - 2;
38179
38180 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]) {
38181 if (this.runLength[n - 1] < this.runLength[n + 1]) {
38182 n--;
38183 }
38184 } else if (this.runLength[n] > this.runLength[n + 1]) {
38185 break;
38186 }
38187
38188 this.mergeAt(n);
38189 }
38190 };
38191
38192 TimSort.prototype.forceMergeRuns = function forceMergeRuns() {
38193 while (this.stackSize > 1) {
38194 var n = this.stackSize - 2;
38195
38196 if (n > 0 && this.runLength[n - 1] < this.runLength[n + 1]) {
38197 n--;
38198 }
38199
38200 this.mergeAt(n);
38201 }
38202 };
38203
38204 TimSort.prototype.mergeAt = function mergeAt(i) {
38205 var compare = this.compare;
38206 var array = this.array;
38207 var start1 = this.runStart[i];
38208 var length1 = this.runLength[i];
38209 var start2 = this.runStart[i + 1];
38210 var length2 = this.runLength[i + 1];
38211 this.runLength[i] = length1 + length2;
38212
38213 if (i === this.stackSize - 3) {
38214 this.runStart[i + 1] = this.runStart[i + 2];
38215 this.runLength[i + 1] = this.runLength[i + 2];
38216 }
38217
38218 this.stackSize--;
38219 var k = gallopRight(array[start2], array, start1, length1, 0, compare);
38220 start1 += k;
38221 length1 -= k;
38222
38223 if (length1 === 0) {
38224 return;
38225 }
38226
38227 length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
38228
38229 if (length2 === 0) {
38230 return;
38231 }
38232
38233 if (length1 <= length2) {
38234 this.mergeLow(start1, length1, start2, length2);
38235 } else {
38236 this.mergeHigh(start1, length1, start2, length2);
38237 }
38238 };
38239
38240 TimSort.prototype.mergeLow = function mergeLow(start1, length1, start2, length2) {
38241 var compare = this.compare;
38242 var array = this.array;
38243 var tmp = this.tmp;
38244 var i = 0;
38245
38246 for (i = 0; i < length1; i++) {
38247 tmp[i] = array[start1 + i];
38248 }
38249
38250 var cursor1 = 0;
38251 var cursor2 = start2;
38252 var dest = start1;
38253 array[dest++] = array[cursor2++];
38254
38255 if (--length2 === 0) {
38256 for (i = 0; i < length1; i++) {
38257 array[dest + i] = tmp[cursor1 + i];
38258 }
38259
38260 return;
38261 }
38262
38263 if (length1 === 1) {
38264 for (i = 0; i < length2; i++) {
38265 array[dest + i] = array[cursor2 + i];
38266 }
38267
38268 array[dest + length2] = tmp[cursor1];
38269 return;
38270 }
38271
38272 var minGallop = this.minGallop;
38273
38274 while (true) {
38275 var count1 = 0;
38276 var count2 = 0;
38277 var exit = false;
38278
38279 do {
38280 if (compare(array[cursor2], tmp[cursor1]) < 0) {
38281 array[dest++] = array[cursor2++];
38282 count2++;
38283 count1 = 0;
38284
38285 if (--length2 === 0) {
38286 exit = true;
38287 break;
38288 }
38289 } else {
38290 array[dest++] = tmp[cursor1++];
38291 count1++;
38292 count2 = 0;
38293
38294 if (--length1 === 1) {
38295 exit = true;
38296 break;
38297 }
38298 }
38299 } while ((count1 | count2) < minGallop);
38300
38301 if (exit) {
38302 break;
38303 }
38304
38305 do {
38306 count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
38307
38308 if (count1 !== 0) {
38309 for (i = 0; i < count1; i++) {
38310 array[dest + i] = tmp[cursor1 + i];
38311 }
38312
38313 dest += count1;
38314 cursor1 += count1;
38315 length1 -= count1;
38316
38317 if (length1 <= 1) {
38318 exit = true;
38319 break;
38320 }
38321 }
38322
38323 array[dest++] = array[cursor2++];
38324
38325 if (--length2 === 0) {
38326 exit = true;
38327 break;
38328 }
38329
38330 count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
38331
38332 if (count2 !== 0) {
38333 for (i = 0; i < count2; i++) {
38334 array[dest + i] = array[cursor2 + i];
38335 }
38336
38337 dest += count2;
38338 cursor2 += count2;
38339 length2 -= count2;
38340
38341 if (length2 === 0) {
38342 exit = true;
38343 break;
38344 }
38345 }
38346
38347 array[dest++] = tmp[cursor1++];
38348
38349 if (--length1 === 1) {
38350 exit = true;
38351 break;
38352 }
38353
38354 minGallop--;
38355 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
38356
38357 if (exit) {
38358 break;
38359 }
38360
38361 if (minGallop < 0) {
38362 minGallop = 0;
38363 }
38364
38365 minGallop += 2;
38366 }
38367
38368 this.minGallop = minGallop;
38369
38370 if (minGallop < 1) {
38371 this.minGallop = 1;
38372 }
38373
38374 if (length1 === 1) {
38375 for (i = 0; i < length2; i++) {
38376 array[dest + i] = array[cursor2 + i];
38377 }
38378
38379 array[dest + length2] = tmp[cursor1];
38380 } else if (length1 === 0) {
38381 throw new Error('mergeLow preconditions were not respected');
38382 } else {
38383 for (i = 0; i < length1; i++) {
38384 array[dest + i] = tmp[cursor1 + i];
38385 }
38386 }
38387 };
38388
38389 TimSort.prototype.mergeHigh = function mergeHigh(start1, length1, start2, length2) {
38390 var compare = this.compare;
38391 var array = this.array;
38392 var tmp = this.tmp;
38393 var i = 0;
38394
38395 for (i = 0; i < length2; i++) {
38396 tmp[i] = array[start2 + i];
38397 }
38398
38399 var cursor1 = start1 + length1 - 1;
38400 var cursor2 = length2 - 1;
38401 var dest = start2 + length2 - 1;
38402 var customCursor = 0;
38403 var customDest = 0;
38404 array[dest--] = array[cursor1--];
38405
38406 if (--length1 === 0) {
38407 customCursor = dest - (length2 - 1);
38408
38409 for (i = 0; i < length2; i++) {
38410 array[customCursor + i] = tmp[i];
38411 }
38412
38413 return;
38414 }
38415
38416 if (length2 === 1) {
38417 dest -= length1;
38418 cursor1 -= length1;
38419 customDest = dest + 1;
38420 customCursor = cursor1 + 1;
38421
38422 for (i = length1 - 1; i >= 0; i--) {
38423 array[customDest + i] = array[customCursor + i];
38424 }
38425
38426 array[dest] = tmp[cursor2];
38427 return;
38428 }
38429
38430 var minGallop = this.minGallop;
38431
38432 while (true) {
38433 var count1 = 0;
38434 var count2 = 0;
38435 var exit = false;
38436
38437 do {
38438 if (compare(tmp[cursor2], array[cursor1]) < 0) {
38439 array[dest--] = array[cursor1--];
38440 count1++;
38441 count2 = 0;
38442
38443 if (--length1 === 0) {
38444 exit = true;
38445 break;
38446 }
38447 } else {
38448 array[dest--] = tmp[cursor2--];
38449 count2++;
38450 count1 = 0;
38451
38452 if (--length2 === 1) {
38453 exit = true;
38454 break;
38455 }
38456 }
38457 } while ((count1 | count2) < minGallop);
38458
38459 if (exit) {
38460 break;
38461 }
38462
38463 do {
38464 count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
38465
38466 if (count1 !== 0) {
38467 dest -= count1;
38468 cursor1 -= count1;
38469 length1 -= count1;
38470 customDest = dest + 1;
38471 customCursor = cursor1 + 1;
38472
38473 for (i = count1 - 1; i >= 0; i--) {
38474 array[customDest + i] = array[customCursor + i];
38475 }
38476
38477 if (length1 === 0) {
38478 exit = true;
38479 break;
38480 }
38481 }
38482
38483 array[dest--] = tmp[cursor2--];
38484
38485 if (--length2 === 1) {
38486 exit = true;
38487 break;
38488 }
38489
38490 count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
38491
38492 if (count2 !== 0) {
38493 dest -= count2;
38494 cursor2 -= count2;
38495 length2 -= count2;
38496 customDest = dest + 1;
38497 customCursor = cursor2 + 1;
38498
38499 for (i = 0; i < count2; i++) {
38500 array[customDest + i] = tmp[customCursor + i];
38501 }
38502
38503 if (length2 <= 1) {
38504 exit = true;
38505 break;
38506 }
38507 }
38508
38509 array[dest--] = array[cursor1--];
38510
38511 if (--length1 === 0) {
38512 exit = true;
38513 break;
38514 }
38515
38516 minGallop--;
38517 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
38518
38519 if (exit) {
38520 break;
38521 }
38522
38523 if (minGallop < 0) {
38524 minGallop = 0;
38525 }
38526
38527 minGallop += 2;
38528 }
38529
38530 this.minGallop = minGallop;
38531
38532 if (minGallop < 1) {
38533 this.minGallop = 1;
38534 }
38535
38536 if (length2 === 1) {
38537 dest -= length1;
38538 cursor1 -= length1;
38539 customDest = dest + 1;
38540 customCursor = cursor1 + 1;
38541
38542 for (i = length1 - 1; i >= 0; i--) {
38543 array[customDest + i] = array[customCursor + i];
38544 }
38545
38546 array[dest] = tmp[cursor2];
38547 } else if (length2 === 0) {
38548 throw new Error('mergeHigh preconditions were not respected');
38549 } else {
38550 customCursor = dest - (length2 - 1);
38551
38552 for (i = 0; i < length2; i++) {
38553 array[customCursor + i] = tmp[i];
38554 }
38555 }
38556 };
38557
38558 return TimSort;
38559 }();
38560
38561 function sort(array, compare, lo, hi) {
38562 if (!Array.isArray(array)) {
38563 throw new TypeError('Can only sort arrays');
38564 }
38565
38566 if (!compare) {
38567 compare = alphabeticalCompare;
38568 } else if (typeof compare !== 'function') {
38569 hi = lo;
38570 lo = compare;
38571 compare = alphabeticalCompare;
38572 }
38573
38574 if (!lo) {
38575 lo = 0;
38576 }
38577
38578 if (!hi) {
38579 hi = array.length;
38580 }
38581
38582 var remaining = hi - lo;
38583
38584 if (remaining < 2) {
38585 return;
38586 }
38587
38588 var runLength = 0;
38589
38590 if (remaining < DEFAULT_MIN_MERGE) {
38591 runLength = makeAscendingRun(array, lo, hi, compare);
38592 binaryInsertionSort(array, lo, hi, lo + runLength, compare);
38593 return;
38594 }
38595
38596 var ts = new TimSort(array, compare);
38597 var minRun = minRunLength(remaining);
38598
38599 do {
38600 runLength = makeAscendingRun(array, lo, hi, compare);
38601
38602 if (runLength < minRun) {
38603 var force = remaining;
38604
38605 if (force > minRun) {
38606 force = minRun;
38607 }
38608
38609 binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
38610 runLength = force;
38611 }
38612
38613 ts.pushRun(lo, runLength);
38614 ts.mergeRuns();
38615 remaining -= runLength;
38616 lo += runLength;
38617 } while (remaining !== 0);
38618
38619 ts.forceMergeRuns();
38620 }
38621 });
38622 })(timsort$1);
38623
38624 var timsort = timsort$1;
38625
38626 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); }; }
38627
38628 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; } }
38629 /**
38630 * Interface definition for direction strategy classes.
38631 *
38632 * This class describes the interface for the Strategy
38633 * pattern classes used to differentiate horizontal and vertical
38634 * direction of hierarchical results.
38635 *
38636 * For a given direction, one coordinate will be 'fixed', meaning that it is
38637 * determined by level.
38638 * The other coordinate is 'unfixed', meaning that the nodes on a given level
38639 * can still move along that coordinate. So:
38640 *
38641 * - `vertical` layout: `x` unfixed, `y` fixed per level
38642 * - `horizontal` layout: `x` fixed per level, `y` unfixed
38643 *
38644 * The local methods are stubs and should be regarded as abstract.
38645 * Derived classes **must** implement all the methods themselves.
38646 *
38647 * @private
38648 */
38649
38650 var DirectionInterface = /*#__PURE__*/function () {
38651 function DirectionInterface() {
38652 _classCallCheck(this, DirectionInterface);
38653 }
38654
38655 _createClass(DirectionInterface, [{
38656 key: "abstract",
38657 value:
38658 /**
38659 * @ignore
38660 */
38661 function abstract() {
38662 throw new Error("Can't instantiate abstract class!");
38663 }
38664 /**
38665 * This is a dummy call which is used to suppress the jsdoc errors of type:
38666 *
38667 * "'param' is assigned a value but never used"
38668 *
38669 * @ignore
38670 */
38671
38672 }, {
38673 key: "fake_use",
38674 value: function fake_use() {// Do nothing special
38675 }
38676 /**
38677 * Type to use to translate dynamic curves to, in the case of hierarchical layout.
38678 * Dynamic curves do not work for these.
38679 *
38680 * The value should be perpendicular to the actual direction of the layout.
38681 *
38682 * @returns {string} Direction, either 'vertical' or 'horizontal'
38683 */
38684
38685 }, {
38686 key: "curveType",
38687 value: function curveType() {
38688 return this.abstract();
38689 }
38690 /**
38691 * Return the value of the coordinate that is not fixed for this direction.
38692 *
38693 * @param {Node} node The node to read
38694 * @returns {number} Value of the unfixed coordinate
38695 */
38696
38697 }, {
38698 key: "getPosition",
38699 value: function getPosition(node) {
38700 this.fake_use(node);
38701 return this.abstract();
38702 }
38703 /**
38704 * Set the value of the coordinate that is not fixed for this direction.
38705 *
38706 * @param {Node} node The node to adjust
38707 * @param {number} position
38708 * @param {number} [level] if specified, the hierarchy level that this node should be fixed to
38709 */
38710
38711 }, {
38712 key: "setPosition",
38713 value: function setPosition(node, position) {
38714 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
38715 this.fake_use(node, position, level);
38716 this.abstract();
38717 }
38718 /**
38719 * Get the width of a tree.
38720 *
38721 * A `tree` here is a subset of nodes within the network which are not connected to other nodes,
38722 * only among themselves. In essence, it is a sub-network.
38723 *
38724 * @param {number} index The index number of a tree
38725 * @returns {number} the width of a tree in the view coordinates
38726 */
38727
38728 }, {
38729 key: "getTreeSize",
38730 value: function getTreeSize(index) {
38731 this.fake_use(index);
38732 return this.abstract();
38733 }
38734 /**
38735 * Sort array of nodes on the unfixed coordinates.
38736 *
38737 * Note:** chrome has non-stable sorting implementation, which
38738 * has a tendency to change the order of the array items,
38739 * even if the custom sort function returns 0.
38740 *
38741 * For this reason, an external sort implementation is used,
38742 * which has the added benefit of being faster than the standard
38743 * platforms implementation. This has been verified on `node.js`,
38744 * `firefox` and `chrome` (all linux).
38745 *
38746 * @param {Array.<Node>} nodeArray array of nodes to sort
38747 */
38748
38749 }, {
38750 key: "sort",
38751 value: function sort(nodeArray) {
38752 this.fake_use(nodeArray);
38753 this.abstract();
38754 }
38755 /**
38756 * Assign the fixed coordinate of the node to the given level
38757 *
38758 * @param {Node} node The node to adjust
38759 * @param {number} level The level to fix to
38760 */
38761
38762 }, {
38763 key: "fix",
38764 value: function fix(node, level) {
38765 this.fake_use(node, level);
38766 this.abstract();
38767 }
38768 /**
38769 * Add an offset to the unfixed coordinate of the given node.
38770 *
38771 * @param {NodeId} nodeId Id of the node to adjust
38772 * @param {number} diff Offset to add to the unfixed coordinate
38773 */
38774
38775 }, {
38776 key: "shift",
38777 value: function shift(nodeId, diff) {
38778 this.fake_use(nodeId, diff);
38779 this.abstract();
38780 }
38781 }]);
38782
38783 return DirectionInterface;
38784 }();
38785 /**
38786 * Vertical Strategy
38787 *
38788 * Coordinate `y` is fixed on levels, coordinate `x` is unfixed.
38789 *
38790 * @augments DirectionInterface
38791 * @private
38792 */
38793
38794
38795 var VerticalStrategy = /*#__PURE__*/function (_DirectionInterface) {
38796 _inherits(VerticalStrategy, _DirectionInterface);
38797
38798 var _super = _createSuper(VerticalStrategy);
38799
38800 /**
38801 * Constructor
38802 *
38803 * @param {object} layout reference to the parent LayoutEngine instance.
38804 */
38805 function VerticalStrategy(layout) {
38806 var _this;
38807
38808 _classCallCheck(this, VerticalStrategy);
38809
38810 _this = _super.call(this);
38811 _this.layout = layout;
38812 return _this;
38813 }
38814 /** @inheritDoc */
38815
38816
38817 _createClass(VerticalStrategy, [{
38818 key: "curveType",
38819 value: function curveType() {
38820 return "horizontal";
38821 }
38822 /** @inheritDoc */
38823
38824 }, {
38825 key: "getPosition",
38826 value: function getPosition(node) {
38827 return node.x;
38828 }
38829 /** @inheritDoc */
38830
38831 }, {
38832 key: "setPosition",
38833 value: function setPosition(node, position) {
38834 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
38835
38836 if (level !== undefined) {
38837 this.layout.hierarchical.addToOrdering(node, level);
38838 }
38839
38840 node.x = position;
38841 }
38842 /** @inheritDoc */
38843
38844 }, {
38845 key: "getTreeSize",
38846 value: function getTreeSize(index) {
38847 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
38848 return {
38849 min: res.min_x,
38850 max: res.max_x
38851 };
38852 }
38853 /** @inheritDoc */
38854
38855 }, {
38856 key: "sort",
38857 value: function sort(nodeArray) {
38858 timsort.sort(nodeArray, function (a, b) {
38859 return a.x - b.x;
38860 });
38861 }
38862 /** @inheritDoc */
38863
38864 }, {
38865 key: "fix",
38866 value: function fix(node, level) {
38867 node.y = this.layout.options.hierarchical.levelSeparation * level;
38868 node.options.fixed.y = true;
38869 }
38870 /** @inheritDoc */
38871
38872 }, {
38873 key: "shift",
38874 value: function shift(nodeId, diff) {
38875 this.layout.body.nodes[nodeId].x += diff;
38876 }
38877 }]);
38878
38879 return VerticalStrategy;
38880 }(DirectionInterface);
38881 /**
38882 * Horizontal Strategy
38883 *
38884 * Coordinate `x` is fixed on levels, coordinate `y` is unfixed.
38885 *
38886 * @augments DirectionInterface
38887 * @private
38888 */
38889
38890
38891 var HorizontalStrategy = /*#__PURE__*/function (_DirectionInterface2) {
38892 _inherits(HorizontalStrategy, _DirectionInterface2);
38893
38894 var _super2 = _createSuper(HorizontalStrategy);
38895
38896 /**
38897 * Constructor
38898 *
38899 * @param {object} layout reference to the parent LayoutEngine instance.
38900 */
38901 function HorizontalStrategy(layout) {
38902 var _this2;
38903
38904 _classCallCheck(this, HorizontalStrategy);
38905
38906 _this2 = _super2.call(this);
38907 _this2.layout = layout;
38908 return _this2;
38909 }
38910 /** @inheritDoc */
38911
38912
38913 _createClass(HorizontalStrategy, [{
38914 key: "curveType",
38915 value: function curveType() {
38916 return "vertical";
38917 }
38918 /** @inheritDoc */
38919
38920 }, {
38921 key: "getPosition",
38922 value: function getPosition(node) {
38923 return node.y;
38924 }
38925 /** @inheritDoc */
38926
38927 }, {
38928 key: "setPosition",
38929 value: function setPosition(node, position) {
38930 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
38931
38932 if (level !== undefined) {
38933 this.layout.hierarchical.addToOrdering(node, level);
38934 }
38935
38936 node.y = position;
38937 }
38938 /** @inheritDoc */
38939
38940 }, {
38941 key: "getTreeSize",
38942 value: function getTreeSize(index) {
38943 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
38944 return {
38945 min: res.min_y,
38946 max: res.max_y
38947 };
38948 }
38949 /** @inheritDoc */
38950
38951 }, {
38952 key: "sort",
38953 value: function sort(nodeArray) {
38954 timsort.sort(nodeArray, function (a, b) {
38955 return a.y - b.y;
38956 });
38957 }
38958 /** @inheritDoc */
38959
38960 }, {
38961 key: "fix",
38962 value: function fix(node, level) {
38963 node.x = this.layout.options.hierarchical.levelSeparation * level;
38964 node.options.fixed.x = true;
38965 }
38966 /** @inheritDoc */
38967
38968 }, {
38969 key: "shift",
38970 value: function shift(nodeId, diff) {
38971 this.layout.body.nodes[nodeId].y += diff;
38972 }
38973 }]);
38974
38975 return HorizontalStrategy;
38976 }(DirectionInterface);
38977
38978 var $ = _export;
38979 var $every = arrayIteration.every;
38980 var arrayMethodIsStrict = arrayMethodIsStrict$6;
38981 var STRICT_METHOD = arrayMethodIsStrict('every'); // `Array.prototype.every` method
38982 // https://tc39.es/ecma262/#sec-array.prototype.every
38983
38984 $({
38985 target: 'Array',
38986 proto: true,
38987 forced: !STRICT_METHOD
38988 }, {
38989 every: function every(callbackfn
38990 /* , thisArg */
38991 ) {
38992 return $every(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
38993 }
38994 });
38995
38996 var entryVirtual = entryVirtual$l;
38997 var every$3 = entryVirtual('Array').every;
38998
38999 var isPrototypeOf = objectIsPrototypeOf;
39000 var method = every$3;
39001 var ArrayPrototype = Array.prototype;
39002
39003 var every$2 = function (it) {
39004 var own = it.every;
39005 return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.every ? method : own;
39006 };
39007
39008 var parent = every$2;
39009 var every$1 = parent;
39010
39011 var every = every$1;
39012
39013 function _createForOfIteratorHelper$1(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$2(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; } } }; }
39014
39015 function _unsupportedIterableToArray$1(o, minLen) { var _context9; if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); var n = slice(_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$3(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); }
39016
39017 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; }
39018
39019 /**
39020 * Try to assign levels to nodes according to their positions in the cyclic “hierarchy”.
39021 *
39022 * @param nodes - Visible nodes of the graph.
39023 * @param levels - If present levels will be added to it, if not a new object will be created.
39024 * @returns Populated node levels.
39025 */
39026 function fillLevelsByDirectionCyclic(nodes, levels) {
39027 var edges = new set();
39028
39029 forEach$2(nodes).call(nodes, function (node) {
39030 var _context;
39031
39032 forEach$2(_context = node.edges).call(_context, function (edge) {
39033 if (edge.connected) {
39034 edges.add(edge);
39035 }
39036 });
39037 });
39038
39039 forEach$2(edges).call(edges, function (edge) {
39040 var fromId = edge.from.id;
39041 var toId = edge.to.id;
39042
39043 if (levels[fromId] == null) {
39044 levels[fromId] = 0;
39045 }
39046
39047 if (levels[toId] == null || levels[fromId] >= levels[toId]) {
39048 levels[toId] = levels[fromId] + 1;
39049 }
39050 });
39051
39052 return levels;
39053 }
39054 /**
39055 * 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.
39056 *
39057 * @param nodes - Visible nodes of the graph.
39058 * @returns Populated node levels.
39059 */
39060
39061
39062 function fillLevelsByDirectionLeaves(nodes) {
39063 return fillLevelsByDirection( // Pick only leaves (nodes without children).
39064 function (node) {
39065 var _context2, _context3;
39066
39067 return every(_context2 = filter(_context3 = node.edges // Take only visible nodes into account.
39068 ).call(_context3, function (edge) {
39069 return nodes.has(edge.toId);
39070 }) // Check that all edges lead to this node (leaf).
39071 ).call(_context2, function (edge) {
39072 return edge.to === node;
39073 });
39074 }, // Use the lowest level.
39075 function (newLevel, oldLevel) {
39076 return oldLevel > newLevel;
39077 }, // Go against the direction of the edges.
39078 "from", nodes);
39079 }
39080 /**
39081 * 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.
39082 *
39083 * @param nodes - Visible nodes of the graph.
39084 * @returns Populated node levels.
39085 */
39086
39087 function fillLevelsByDirectionRoots(nodes) {
39088 return fillLevelsByDirection( // Pick only roots (nodes without parents).
39089 function (node) {
39090 var _context4, _context5;
39091
39092 return every(_context4 = filter(_context5 = node.edges // Take only visible nodes into account.
39093 ).call(_context5, function (edge) {
39094 return nodes.has(edge.toId);
39095 }) // Check that all edges lead from this node (root).
39096 ).call(_context4, function (edge) {
39097 return edge.from === node;
39098 });
39099 }, // Use the highest level.
39100 function (newLevel, oldLevel) {
39101 return oldLevel < newLevel;
39102 }, // Go in the direction of the edges.
39103 "to", nodes);
39104 }
39105 /**
39106 * Assign levels to nodes according to their positions in the hierarchy.
39107 *
39108 * @param isEntryNode - Checks and return true if the graph should be traversed from this node.
39109 * @param shouldLevelBeReplaced - Checks and returns true if the level of given node should be updated to the new value.
39110 * @param direction - Wheter the graph should be traversed in the direction of the edges `"to"` or in the other way `"from"`.
39111 * @param nodes - Visible nodes of the graph.
39112 * @returns Populated node levels.
39113 */
39114
39115 function fillLevelsByDirection(isEntryNode, shouldLevelBeReplaced, direction, nodes) {
39116 var _context6;
39117
39118 var levels = create$5(null); // If acyclic, the graph can be walked through with (most likely way) fewer
39119 // steps than the number bellow. The exact value isn't too important as long
39120 // as it's quick to compute (doesn't impact acyclic graphs too much), is
39121 // higher than the number of steps actually needed (doesn't cut off before
39122 // acyclic graph is walked through) and prevents infinite loops (cuts off for
39123 // cyclic graphs).
39124
39125
39126 var limit = reduce(_context6 = _toConsumableArray(values(nodes).call(nodes))).call(_context6, function (acc, node) {
39127 return acc + 1 + node.edges.length;
39128 }, 0);
39129
39130 var edgeIdProp = direction + "Id";
39131 var newLevelDiff = direction === "to" ? 1 : -1;
39132
39133 var _iterator = _createForOfIteratorHelper$1(nodes),
39134 _step;
39135
39136 try {
39137 var _loop = function _loop() {
39138 var _step$value = _slicedToArray(_step.value, 2),
39139 entryNodeId = _step$value[0],
39140 entryNode = _step$value[1];
39141
39142 if ( // Skip if the node is not visible.
39143 !nodes.has(entryNodeId) || // Skip if the node is not an entry node.
39144 !isEntryNode(entryNode)) {
39145 return "continue";
39146 } // Line up all the entry nodes on level 0.
39147
39148
39149 levels[entryNodeId] = 0;
39150 var stack = [entryNode];
39151 var done = 0;
39152 var node = void 0;
39153
39154 var _loop2 = function _loop2() {
39155 var _context7, _context8;
39156
39157 if (!nodes.has(entryNodeId)) {
39158 // Skip if the node is not visible.
39159 return "continue";
39160 }
39161
39162 var newLevel = levels[node.id] + newLevelDiff;
39163
39164 forEach$2(_context7 = filter(_context8 = node.edges).call(_context8, function (edge) {
39165 return (// Ignore disconnected edges.
39166 edge.connected && // Ignore circular edges.
39167 edge.to !== edge.from && // Ignore edges leading to the node that's currently being processed.
39168 edge[direction] !== node && // Ignore edges connecting to an invisible node.
39169 nodes.has(edge.toId) && // Ignore edges connecting from an invisible node.
39170 nodes.has(edge.fromId)
39171 );
39172 })).call(_context7, function (edge) {
39173 var targetNodeId = edge[edgeIdProp];
39174 var oldLevel = levels[targetNodeId];
39175
39176 if (oldLevel == null || shouldLevelBeReplaced(newLevel, oldLevel)) {
39177 levels[targetNodeId] = newLevel;
39178 stack.push(edge[direction]);
39179 }
39180 });
39181
39182 if (done > limit) {
39183 // This would run forever on a cyclic graph.
39184 return {
39185 v: {
39186 v: fillLevelsByDirectionCyclic(nodes, levels)
39187 }
39188 };
39189 } else {
39190 ++done;
39191 }
39192 };
39193
39194 while (node = stack.pop()) {
39195 var _ret2 = _loop2();
39196
39197 if (_ret2 === "continue") continue;
39198 if (_typeof(_ret2) === "object") return _ret2.v;
39199 }
39200 };
39201
39202 for (_iterator.s(); !(_step = _iterator.n()).done;) {
39203 var _ret = _loop();
39204
39205 if (_ret === "continue") continue;
39206 if (_typeof(_ret) === "object") return _ret.v;
39207 }
39208 } catch (err) {
39209 _iterator.e(err);
39210 } finally {
39211 _iterator.f();
39212 }
39213
39214 return levels;
39215 }
39216
39217 /**
39218 * There's a mix-up with terms in the code. Following are the formal definitions:
39219 *
39220 * tree - a strict hierarchical network, i.e. every node has at most one parent
39221 * forest - a collection of trees. These distinct trees are thus not connected.
39222 *
39223 * So:
39224 * - in a network that is not a tree, there exist nodes with multiple parents.
39225 * - a network consisting of unconnected sub-networks, of which at least one
39226 * is not a tree, is not a forest.
39227 *
39228 * In the code, the definitions are:
39229 *
39230 * tree - any disconnected sub-network, strict hierarchical or not.
39231 * forest - a bunch of these sub-networks
39232 *
39233 * The difference between tree and not-tree is important in the code, notably within
39234 * to the block-shifting algorithm. The algorithm assumes formal trees and fails
39235 * for not-trees, often in a spectacular manner (search for 'exploding network' in the issues).
39236 *
39237 * In order to distinguish the definitions in the following code, the adjective 'formal' is
39238 * used. If 'formal' is absent, you must assume the non-formal definition.
39239 *
39240 * ----------------------------------------------------------------------------------
39241 * NOTES
39242 * =====
39243 *
39244 * A hierarchical layout is a different thing from a hierarchical network.
39245 * The layout is a way to arrange the nodes in the view; this can be done
39246 * on non-hierarchical networks as well. The converse is also possible.
39247 */
39248 /**
39249 * Container for derived data on current network, relating to hierarchy.
39250 *
39251 * @private
39252 */
39253
39254 var HierarchicalStatus = /*#__PURE__*/function () {
39255 /**
39256 * @ignore
39257 */
39258 function HierarchicalStatus() {
39259 _classCallCheck(this, HierarchicalStatus);
39260
39261 this.childrenReference = {}; // child id's per node id
39262
39263 this.parentReference = {}; // parent id's per node id
39264
39265 this.trees = {}; // tree id per node id; i.e. to which tree does given node id belong
39266
39267 this.distributionOrdering = {}; // The nodes per level, in the display order
39268
39269 this.levels = {}; // hierarchy level per node id
39270
39271 this.distributionIndex = {}; // The position of the node in the level sorting order, per node id.
39272
39273 this.isTree = false; // True if current network is a formal tree
39274
39275 this.treeIndex = -1; // Highest tree id in current network.
39276 }
39277 /**
39278 * Add the relation between given nodes to the current state.
39279 *
39280 * @param {Node.id} parentNodeId
39281 * @param {Node.id} childNodeId
39282 */
39283
39284
39285 _createClass(HierarchicalStatus, [{
39286 key: "addRelation",
39287 value: function addRelation(parentNodeId, childNodeId) {
39288 if (this.childrenReference[parentNodeId] === undefined) {
39289 this.childrenReference[parentNodeId] = [];
39290 }
39291
39292 this.childrenReference[parentNodeId].push(childNodeId);
39293
39294 if (this.parentReference[childNodeId] === undefined) {
39295 this.parentReference[childNodeId] = [];
39296 }
39297
39298 this.parentReference[childNodeId].push(parentNodeId);
39299 }
39300 /**
39301 * Check if the current state is for a formal tree or formal forest.
39302 *
39303 * This is the case if every node has at most one parent.
39304 *
39305 * Pre: parentReference init'ed properly for current network
39306 */
39307
39308 }, {
39309 key: "checkIfTree",
39310 value: function checkIfTree() {
39311 for (var i in this.parentReference) {
39312 if (this.parentReference[i].length > 1) {
39313 this.isTree = false;
39314 return;
39315 }
39316 }
39317
39318 this.isTree = true;
39319 }
39320 /**
39321 * Return the number of separate trees in the current network.
39322 *
39323 * @returns {number}
39324 */
39325
39326 }, {
39327 key: "numTrees",
39328 value: function numTrees() {
39329 return this.treeIndex + 1; // This assumes the indexes are assigned consecitively
39330 }
39331 /**
39332 * Assign a tree id to a node
39333 *
39334 * @param {Node} node
39335 * @param {string|number} treeId
39336 */
39337
39338 }, {
39339 key: "setTreeIndex",
39340 value: function setTreeIndex(node, treeId) {
39341 if (treeId === undefined) return; // Don't bother
39342
39343 if (this.trees[node.id] === undefined) {
39344 this.trees[node.id] = treeId;
39345 this.treeIndex = Math.max(treeId, this.treeIndex);
39346 }
39347 }
39348 /**
39349 * Ensure level for given id is defined.
39350 *
39351 * Sets level to zero for given node id if not already present
39352 *
39353 * @param {Node.id} nodeId
39354 */
39355
39356 }, {
39357 key: "ensureLevel",
39358 value: function ensureLevel(nodeId) {
39359 if (this.levels[nodeId] === undefined) {
39360 this.levels[nodeId] = 0;
39361 }
39362 }
39363 /**
39364 * get the maximum level of a branch.
39365 *
39366 * TODO: Never entered; find a test case to test this!
39367 *
39368 * @param {Node.id} nodeId
39369 * @returns {number}
39370 */
39371
39372 }, {
39373 key: "getMaxLevel",
39374 value: function getMaxLevel(nodeId) {
39375 var _this = this;
39376
39377 var accumulator = {};
39378
39379 var _getMaxLevel = function _getMaxLevel(nodeId) {
39380 if (accumulator[nodeId] !== undefined) {
39381 return accumulator[nodeId];
39382 }
39383
39384 var level = _this.levels[nodeId];
39385
39386 if (_this.childrenReference[nodeId]) {
39387 var children = _this.childrenReference[nodeId];
39388
39389 if (children.length > 0) {
39390 for (var i = 0; i < children.length; i++) {
39391 level = Math.max(level, _getMaxLevel(children[i]));
39392 }
39393 }
39394 }
39395
39396 accumulator[nodeId] = level;
39397 return level;
39398 };
39399
39400 return _getMaxLevel(nodeId);
39401 }
39402 /**
39403 *
39404 * @param {Node} nodeA
39405 * @param {Node} nodeB
39406 */
39407
39408 }, {
39409 key: "levelDownstream",
39410 value: function levelDownstream(nodeA, nodeB) {
39411 if (this.levels[nodeB.id] === undefined) {
39412 // set initial level
39413 if (this.levels[nodeA.id] === undefined) {
39414 this.levels[nodeA.id] = 0;
39415 } // set level
39416
39417
39418 this.levels[nodeB.id] = this.levels[nodeA.id] + 1;
39419 }
39420 }
39421 /**
39422 * Small util method to set the minimum levels of the nodes to zero.
39423 *
39424 * @param {Array.<Node>} nodes
39425 */
39426
39427 }, {
39428 key: "setMinLevelToZero",
39429 value: function setMinLevelToZero(nodes) {
39430 var minLevel = 1e9; // get the minimum level
39431
39432 for (var nodeId in nodes) {
39433 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
39434 if (this.levels[nodeId] !== undefined) {
39435 minLevel = Math.min(this.levels[nodeId], minLevel);
39436 }
39437 }
39438 } // subtract the minimum from the set so we have a range starting from 0
39439
39440
39441 for (var _nodeId in nodes) {
39442 if (Object.prototype.hasOwnProperty.call(nodes, _nodeId)) {
39443 if (this.levels[_nodeId] !== undefined) {
39444 this.levels[_nodeId] -= minLevel;
39445 }
39446 }
39447 }
39448 }
39449 /**
39450 * Get the min and max xy-coordinates of a given tree
39451 *
39452 * @param {Array.<Node>} nodes
39453 * @param {number} index
39454 * @returns {{min_x: number, max_x: number, min_y: number, max_y: number}}
39455 */
39456
39457 }, {
39458 key: "getTreeSize",
39459 value: function getTreeSize(nodes, index) {
39460 var min_x = 1e9;
39461 var max_x = -1e9;
39462 var min_y = 1e9;
39463 var max_y = -1e9;
39464
39465 for (var nodeId in this.trees) {
39466 if (Object.prototype.hasOwnProperty.call(this.trees, nodeId)) {
39467 if (this.trees[nodeId] === index) {
39468 var node = nodes[nodeId];
39469 min_x = Math.min(node.x, min_x);
39470 max_x = Math.max(node.x, max_x);
39471 min_y = Math.min(node.y, min_y);
39472 max_y = Math.max(node.y, max_y);
39473 }
39474 }
39475 }
39476
39477 return {
39478 min_x: min_x,
39479 max_x: max_x,
39480 min_y: min_y,
39481 max_y: max_y
39482 };
39483 }
39484 /**
39485 * Check if two nodes have the same parent(s)
39486 *
39487 * @param {Node} node1
39488 * @param {Node} node2
39489 * @returns {boolean} true if the two nodes have a same ancestor node, false otherwise
39490 */
39491
39492 }, {
39493 key: "hasSameParent",
39494 value: function hasSameParent(node1, node2) {
39495 var parents1 = this.parentReference[node1.id];
39496 var parents2 = this.parentReference[node2.id];
39497
39498 if (parents1 === undefined || parents2 === undefined) {
39499 return false;
39500 }
39501
39502 for (var i = 0; i < parents1.length; i++) {
39503 for (var j = 0; j < parents2.length; j++) {
39504 if (parents1[i] == parents2[j]) {
39505 return true;
39506 }
39507 }
39508 }
39509
39510 return false;
39511 }
39512 /**
39513 * Check if two nodes are in the same tree.
39514 *
39515 * @param {Node} node1
39516 * @param {Node} node2
39517 * @returns {boolean} true if this is so, false otherwise
39518 */
39519
39520 }, {
39521 key: "inSameSubNetwork",
39522 value: function inSameSubNetwork(node1, node2) {
39523 return this.trees[node1.id] === this.trees[node2.id];
39524 }
39525 /**
39526 * Get a list of the distinct levels in the current network
39527 *
39528 * @returns {Array}
39529 */
39530
39531 }, {
39532 key: "getLevels",
39533 value: function getLevels() {
39534 return keys$4(this.distributionOrdering);
39535 }
39536 /**
39537 * Add a node to the ordering per level
39538 *
39539 * @param {Node} node
39540 * @param {number} level
39541 */
39542
39543 }, {
39544 key: "addToOrdering",
39545 value: function addToOrdering(node, level) {
39546 if (this.distributionOrdering[level] === undefined) {
39547 this.distributionOrdering[level] = [];
39548 }
39549
39550 var isPresent = false;
39551 var curLevel = this.distributionOrdering[level];
39552
39553 for (var n in curLevel) {
39554 //if (curLevel[n].id === node.id) {
39555 if (curLevel[n] === node) {
39556 isPresent = true;
39557 break;
39558 }
39559 }
39560
39561 if (!isPresent) {
39562 this.distributionOrdering[level].push(node);
39563 this.distributionIndex[node.id] = this.distributionOrdering[level].length - 1;
39564 }
39565 }
39566 }]);
39567
39568 return HierarchicalStatus;
39569 }();
39570 /**
39571 * The Layout Engine
39572 */
39573
39574
39575 var LayoutEngine = /*#__PURE__*/function () {
39576 /**
39577 * @param {object} body
39578 */
39579 function LayoutEngine(body) {
39580 _classCallCheck(this, LayoutEngine);
39581
39582 this.body = body; // Make sure there always is some RNG because the setOptions method won't
39583 // set it unless there's a seed for it.
39584
39585 this._resetRNG(Math.random() + ":" + now$1());
39586
39587 this.setPhysics = false;
39588 this.options = {};
39589 this.optionsBackup = {
39590 physics: {}
39591 };
39592 this.defaultOptions = {
39593 randomSeed: undefined,
39594 improvedLayout: true,
39595 clusterThreshold: 150,
39596 hierarchical: {
39597 enabled: false,
39598 levelSeparation: 150,
39599 nodeSpacing: 100,
39600 treeSpacing: 200,
39601 blockShifting: true,
39602 edgeMinimization: true,
39603 parentCentralization: true,
39604 direction: "UD",
39605 // UD, DU, LR, RL
39606 sortMethod: "hubsize" // hubsize, directed
39607
39608 }
39609 };
39610
39611 assign$2(this.options, this.defaultOptions);
39612
39613 this.bindEventListeners();
39614 }
39615 /**
39616 * Binds event listeners
39617 */
39618
39619
39620 _createClass(LayoutEngine, [{
39621 key: "bindEventListeners",
39622 value: function bindEventListeners() {
39623 var _this2 = this;
39624
39625 this.body.emitter.on("_dataChanged", function () {
39626 _this2.setupHierarchicalLayout();
39627 });
39628 this.body.emitter.on("_dataLoaded", function () {
39629 _this2.layoutNetwork();
39630 });
39631 this.body.emitter.on("_resetHierarchicalLayout", function () {
39632 _this2.setupHierarchicalLayout();
39633 });
39634 this.body.emitter.on("_adjustEdgesForHierarchicalLayout", function () {
39635 if (_this2.options.hierarchical.enabled !== true) {
39636 return;
39637 } // get the type of static smooth curve in case it is required
39638
39639
39640 var type = _this2.direction.curveType(); // force all edges into static smooth curves.
39641
39642
39643 _this2.body.emitter.emit("_forceDisableDynamicCurves", type, false);
39644 });
39645 }
39646 /**
39647 *
39648 * @param {object} options
39649 * @param {object} allOptions
39650 * @returns {object}
39651 */
39652
39653 }, {
39654 key: "setOptions",
39655 value: function setOptions(options, allOptions) {
39656 if (options !== undefined) {
39657 var hierarchical = this.options.hierarchical;
39658 var prevHierarchicalState = hierarchical.enabled;
39659 selectiveDeepExtend(["randomSeed", "improvedLayout", "clusterThreshold"], this.options, options);
39660 mergeOptions(this.options, options, "hierarchical");
39661
39662 if (options.randomSeed !== undefined) {
39663 this._resetRNG(options.randomSeed);
39664 }
39665
39666 if (hierarchical.enabled === true) {
39667 if (prevHierarchicalState === true) {
39668 // refresh the overridden options for nodes and edges.
39669 this.body.emitter.emit("refresh", true);
39670 } // make sure the level separation is the right way up
39671
39672
39673 if (hierarchical.direction === "RL" || hierarchical.direction === "DU") {
39674 if (hierarchical.levelSeparation > 0) {
39675 hierarchical.levelSeparation *= -1;
39676 }
39677 } else {
39678 if (hierarchical.levelSeparation < 0) {
39679 hierarchical.levelSeparation *= -1;
39680 }
39681 }
39682
39683 this.setDirectionStrategy();
39684 this.body.emitter.emit("_resetHierarchicalLayout"); // because the hierarchical system needs it's own physics and smooth curve settings,
39685 // we adapt the other options if needed.
39686
39687 return this.adaptAllOptionsForHierarchicalLayout(allOptions);
39688 } else {
39689 if (prevHierarchicalState === true) {
39690 // refresh the overridden options for nodes and edges.
39691 this.body.emitter.emit("refresh");
39692 return deepExtend(allOptions, this.optionsBackup);
39693 }
39694 }
39695 }
39696
39697 return allOptions;
39698 }
39699 /**
39700 * Reset the random number generator with given seed.
39701 *
39702 * @param {any} seed - The seed that will be forwarded the the RNG.
39703 */
39704
39705 }, {
39706 key: "_resetRNG",
39707 value: function _resetRNG(seed) {
39708 this.initialRandomSeed = seed;
39709 this._rng = Alea(this.initialRandomSeed);
39710 }
39711 /**
39712 *
39713 * @param {object} allOptions
39714 * @returns {object}
39715 */
39716
39717 }, {
39718 key: "adaptAllOptionsForHierarchicalLayout",
39719 value: function adaptAllOptionsForHierarchicalLayout(allOptions) {
39720 if (this.options.hierarchical.enabled === true) {
39721 var backupPhysics = this.optionsBackup.physics; // set the physics
39722
39723 if (allOptions.physics === undefined || allOptions.physics === true) {
39724 allOptions.physics = {
39725 enabled: backupPhysics.enabled === undefined ? true : backupPhysics.enabled,
39726 solver: "hierarchicalRepulsion"
39727 };
39728 backupPhysics.enabled = backupPhysics.enabled === undefined ? true : backupPhysics.enabled;
39729 backupPhysics.solver = backupPhysics.solver || "barnesHut";
39730 } else if (_typeof(allOptions.physics) === "object") {
39731 backupPhysics.enabled = allOptions.physics.enabled === undefined ? true : allOptions.physics.enabled;
39732 backupPhysics.solver = allOptions.physics.solver || "barnesHut";
39733 allOptions.physics.solver = "hierarchicalRepulsion";
39734 } else if (allOptions.physics !== false) {
39735 backupPhysics.solver = "barnesHut";
39736 allOptions.physics = {
39737 solver: "hierarchicalRepulsion"
39738 };
39739 } // get the type of static smooth curve in case it is required
39740
39741
39742 var type = this.direction.curveType(); // disable smooth curves if nothing is defined. If smooth curves have been turned on,
39743 // turn them into static smooth curves.
39744
39745 if (allOptions.edges === undefined) {
39746 this.optionsBackup.edges = {
39747 smooth: {
39748 enabled: true,
39749 type: "dynamic"
39750 }
39751 };
39752 allOptions.edges = {
39753 smooth: false
39754 };
39755 } else if (allOptions.edges.smooth === undefined) {
39756 this.optionsBackup.edges = {
39757 smooth: {
39758 enabled: true,
39759 type: "dynamic"
39760 }
39761 };
39762 allOptions.edges.smooth = false;
39763 } else {
39764 if (typeof allOptions.edges.smooth === "boolean") {
39765 this.optionsBackup.edges = {
39766 smooth: allOptions.edges.smooth
39767 };
39768 allOptions.edges.smooth = {
39769 enabled: allOptions.edges.smooth,
39770 type: type
39771 };
39772 } else {
39773 var smooth = allOptions.edges.smooth; // allow custom types except for dynamic
39774
39775 if (smooth.type !== undefined && smooth.type !== "dynamic") {
39776 type = smooth.type;
39777 } // TODO: this is options merging; see if the standard routines can be used here.
39778
39779
39780 this.optionsBackup.edges = {
39781 smooth: {
39782 enabled: smooth.enabled === undefined ? true : smooth.enabled,
39783 type: smooth.type === undefined ? "dynamic" : smooth.type,
39784 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
39785 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
39786 }
39787 }; // NOTE: Copying an object to self; this is basically setting defaults for undefined variables
39788
39789 allOptions.edges.smooth = {
39790 enabled: smooth.enabled === undefined ? true : smooth.enabled,
39791 type: type,
39792 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
39793 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
39794 };
39795 }
39796 } // Force all edges into static smooth curves.
39797 // Only applies to edges that do not use the global options for smooth.
39798
39799
39800 this.body.emitter.emit("_forceDisableDynamicCurves", type);
39801 }
39802
39803 return allOptions;
39804 }
39805 /**
39806 *
39807 * @param {Array.<Node>} nodesArray
39808 */
39809
39810 }, {
39811 key: "positionInitially",
39812 value: function positionInitially(nodesArray) {
39813 if (this.options.hierarchical.enabled !== true) {
39814 this._resetRNG(this.initialRandomSeed);
39815
39816 var radius = nodesArray.length + 50;
39817
39818 for (var i = 0; i < nodesArray.length; i++) {
39819 var node = nodesArray[i];
39820
39821 var angle = 2 * Math.PI * this._rng();
39822
39823 if (node.x === undefined) {
39824 node.x = radius * Math.cos(angle);
39825 }
39826
39827 if (node.y === undefined) {
39828 node.y = radius * Math.sin(angle);
39829 }
39830 }
39831 }
39832 }
39833 /**
39834 * Use Kamada Kawai to position nodes. This is quite a heavy algorithm so if there are a lot of nodes we
39835 * cluster them first to reduce the amount.
39836 */
39837
39838 }, {
39839 key: "layoutNetwork",
39840 value: function layoutNetwork() {
39841 if (this.options.hierarchical.enabled !== true && this.options.improvedLayout === true) {
39842 var indices = this.body.nodeIndices; // first check if we should Kamada Kawai to layout. The threshold is if less than half of the visible
39843 // nodes have predefined positions we use this.
39844
39845 var positionDefined = 0;
39846
39847 for (var i = 0; i < indices.length; i++) {
39848 var node = this.body.nodes[indices[i]];
39849
39850 if (node.predefinedPosition === true) {
39851 positionDefined += 1;
39852 }
39853 } // if less than half of the nodes have a predefined position we continue
39854
39855
39856 if (positionDefined < 0.5 * indices.length) {
39857 var MAX_LEVELS = 10;
39858 var level = 0;
39859 var clusterThreshold = this.options.clusterThreshold; //
39860 // Define the options for the hidden cluster nodes
39861 // These options don't propagate outside the clustering phase.
39862 //
39863 // Some options are explicitly disabled, because they may be set in group or default node options.
39864 // The clusters are never displayed, so most explicit settings here serve as performance optimizations.
39865 //
39866 // The explicit setting of 'shape' is to avoid `shape: 'image'`; images are not passed to the hidden
39867 // cluster nodes, leading to an exception on creation.
39868 //
39869 // All settings here are performance related, except when noted otherwise.
39870 //
39871
39872 var clusterOptions = {
39873 clusterNodeProperties: {
39874 shape: "ellipse",
39875 // Bugfix: avoid type 'image', no images supplied
39876 label: "",
39877 // avoid label handling
39878 group: "",
39879 // avoid group handling
39880 font: {
39881 multi: false
39882 } // avoid font propagation
39883
39884 },
39885 clusterEdgeProperties: {
39886 label: "",
39887 // avoid label handling
39888 font: {
39889 multi: false
39890 },
39891 // avoid font propagation
39892 smooth: {
39893 enabled: false // avoid drawing penalty for complex edges
39894
39895 }
39896 }
39897 }; // if there are a lot of nodes, we cluster before we run the algorithm.
39898 // NOTE: this part fails to find clusters for large scale-free networks, which should
39899 // be easily clusterable.
39900 // TODO: examine why this is so
39901
39902 if (indices.length > clusterThreshold) {
39903 var startLength = indices.length;
39904
39905 while (indices.length > clusterThreshold && level <= MAX_LEVELS) {
39906 //console.time("clustering")
39907 level += 1;
39908 var before = indices.length; // if there are many nodes we do a hubsize cluster
39909
39910 if (level % 3 === 0) {
39911 this.body.modules.clustering.clusterBridges(clusterOptions);
39912 } else {
39913 this.body.modules.clustering.clusterOutliers(clusterOptions);
39914 }
39915
39916 var after = indices.length;
39917
39918 if (before == after && level % 3 !== 0) {
39919 this._declusterAll();
39920
39921 this.body.emitter.emit("_layoutFailed");
39922 console.info("This network could not be positioned by this version of the improved layout algorithm." + " Please disable improvedLayout for better performance.");
39923 return;
39924 } //console.timeEnd("clustering")
39925 //console.log(before,level,after);
39926
39927 } // increase the size of the edges
39928
39929
39930 this.body.modules.kamadaKawai.setOptions({
39931 springLength: Math.max(150, 2 * startLength)
39932 });
39933 }
39934
39935 if (level > MAX_LEVELS) {
39936 console.info("The clustering didn't succeed within the amount of interations allowed," + " progressing with partial result.");
39937 } // position the system for these nodes and edges
39938
39939
39940 this.body.modules.kamadaKawai.solve(indices, this.body.edgeIndices, true); // shift to center point
39941
39942 this._shiftToCenter(); // perturb the nodes a little bit to force the physics to kick in
39943
39944
39945 var offset = 70;
39946
39947 for (var _i = 0; _i < indices.length; _i++) {
39948 // Only perturb the nodes that aren't fixed
39949 var _node = this.body.nodes[indices[_i]];
39950
39951 if (_node.predefinedPosition === false) {
39952 _node.x += (0.5 - this._rng()) * offset;
39953 _node.y += (0.5 - this._rng()) * offset;
39954 }
39955 } // uncluster all clusters
39956
39957
39958 this._declusterAll(); // reposition all bezier nodes.
39959
39960
39961 this.body.emitter.emit("_repositionBezierNodes");
39962 }
39963 }
39964 }
39965 /**
39966 * Move all the nodes towards to the center so gravitational pull wil not move the nodes away from view
39967 *
39968 * @private
39969 */
39970
39971 }, {
39972 key: "_shiftToCenter",
39973 value: function _shiftToCenter() {
39974 var range = NetworkUtil.getRangeCore(this.body.nodes, this.body.nodeIndices);
39975 var center = NetworkUtil.findCenter(range);
39976
39977 for (var i = 0; i < this.body.nodeIndices.length; i++) {
39978 var node = this.body.nodes[this.body.nodeIndices[i]];
39979 node.x -= center.x;
39980 node.y -= center.y;
39981 }
39982 }
39983 /**
39984 * Expands all clusters
39985 *
39986 * @private
39987 */
39988
39989 }, {
39990 key: "_declusterAll",
39991 value: function _declusterAll() {
39992 var clustersPresent = true;
39993
39994 while (clustersPresent === true) {
39995 clustersPresent = false;
39996
39997 for (var i = 0; i < this.body.nodeIndices.length; i++) {
39998 if (this.body.nodes[this.body.nodeIndices[i]].isCluster === true) {
39999 clustersPresent = true;
40000 this.body.modules.clustering.openCluster(this.body.nodeIndices[i], {}, false);
40001 }
40002 }
40003
40004 if (clustersPresent === true) {
40005 this.body.emitter.emit("_dataChanged");
40006 }
40007 }
40008 }
40009 /**
40010 *
40011 * @returns {number|*}
40012 */
40013
40014 }, {
40015 key: "getSeed",
40016 value: function getSeed() {
40017 return this.initialRandomSeed;
40018 }
40019 /**
40020 * This is the main function to layout the nodes in a hierarchical way.
40021 * It checks if the node details are supplied correctly
40022 *
40023 * @private
40024 */
40025
40026 }, {
40027 key: "setupHierarchicalLayout",
40028 value: function setupHierarchicalLayout() {
40029 if (this.options.hierarchical.enabled === true && this.body.nodeIndices.length > 0) {
40030 // get the size of the largest hubs and check if the user has defined a level for a node.
40031 var node, nodeId;
40032 var definedLevel = false;
40033 var undefinedLevel = false;
40034 this.lastNodeOnLevel = {};
40035 this.hierarchical = new HierarchicalStatus();
40036
40037 for (nodeId in this.body.nodes) {
40038 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
40039 node = this.body.nodes[nodeId];
40040
40041 if (node.options.level !== undefined) {
40042 definedLevel = true;
40043 this.hierarchical.levels[nodeId] = node.options.level;
40044 } else {
40045 undefinedLevel = true;
40046 }
40047 }
40048 } // if the user defined some levels but not all, alert and run without hierarchical layout
40049
40050
40051 if (undefinedLevel === true && definedLevel === true) {
40052 throw new Error("To use the hierarchical layout, nodes require either no predefined levels" + " or levels have to be defined for all nodes.");
40053 } else {
40054 // define levels if undefined by the users. Based on hubsize.
40055 if (undefinedLevel === true) {
40056 var sortMethod = this.options.hierarchical.sortMethod;
40057
40058 if (sortMethod === "hubsize") {
40059 this._determineLevelsByHubsize();
40060 } else if (sortMethod === "directed") {
40061 this._determineLevelsDirected();
40062 } else if (sortMethod === "custom") {
40063 this._determineLevelsCustomCallback();
40064 }
40065 } // fallback for cases where there are nodes but no edges
40066
40067
40068 for (var _nodeId2 in this.body.nodes) {
40069 if (Object.prototype.hasOwnProperty.call(this.body.nodes, _nodeId2)) {
40070 this.hierarchical.ensureLevel(_nodeId2);
40071 }
40072 } // check the distribution of the nodes per level.
40073
40074
40075 var distribution = this._getDistribution(); // get the parent children relations.
40076
40077
40078 this._generateMap(); // place the nodes on the canvas.
40079
40080
40081 this._placeNodesByHierarchy(distribution); // condense the whitespace.
40082
40083
40084 this._condenseHierarchy(); // shift to center so gravity does not have to do much
40085
40086
40087 this._shiftToCenter();
40088 }
40089 }
40090 }
40091 /**
40092 * @private
40093 */
40094
40095 }, {
40096 key: "_condenseHierarchy",
40097 value: function _condenseHierarchy() {
40098 var _this3 = this;
40099
40100 // Global var in this scope to define when the movement has stopped.
40101 var stillShifting = false;
40102 var branches = {}; // first we have some methods to help shifting trees around.
40103 // the main method to shift the trees
40104
40105 var shiftTrees = function shiftTrees() {
40106 var treeSizes = getTreeSizes();
40107 var shiftBy = 0;
40108
40109 for (var i = 0; i < treeSizes.length - 1; i++) {
40110 var diff = treeSizes[i].max - treeSizes[i + 1].min;
40111 shiftBy += diff + _this3.options.hierarchical.treeSpacing;
40112 shiftTree(i + 1, shiftBy);
40113 }
40114 }; // shift a single tree by an offset
40115
40116
40117 var shiftTree = function shiftTree(index, offset) {
40118 var trees = _this3.hierarchical.trees;
40119
40120 for (var nodeId in trees) {
40121 if (Object.prototype.hasOwnProperty.call(trees, nodeId)) {
40122 if (trees[nodeId] === index) {
40123 _this3.direction.shift(nodeId, offset);
40124 }
40125 }
40126 }
40127 }; // get the width of all trees
40128
40129
40130 var getTreeSizes = function getTreeSizes() {
40131 var treeWidths = [];
40132
40133 for (var i = 0; i < _this3.hierarchical.numTrees(); i++) {
40134 treeWidths.push(_this3.direction.getTreeSize(i));
40135 }
40136
40137 return treeWidths;
40138 }; // get a map of all nodes in this branch
40139
40140
40141 var getBranchNodes = function getBranchNodes(source, map) {
40142 if (map[source.id]) {
40143 return;
40144 }
40145
40146 map[source.id] = true;
40147
40148 if (_this3.hierarchical.childrenReference[source.id]) {
40149 var children = _this3.hierarchical.childrenReference[source.id];
40150
40151 if (children.length > 0) {
40152 for (var i = 0; i < children.length; i++) {
40153 getBranchNodes(_this3.body.nodes[children[i]], map);
40154 }
40155 }
40156 }
40157 }; // get a min max width as well as the maximum movement space it has on either sides
40158 // we use min max terminology because width and height can interchange depending on the direction of the layout
40159
40160
40161 var getBranchBoundary = function getBranchBoundary(branchMap) {
40162 var maxLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1e9;
40163 var minSpace = 1e9;
40164 var maxSpace = 1e9;
40165 var min = 1e9;
40166 var max = -1e9;
40167
40168 for (var branchNode in branchMap) {
40169 if (Object.prototype.hasOwnProperty.call(branchMap, branchNode)) {
40170 var node = _this3.body.nodes[branchNode];
40171 var level = _this3.hierarchical.levels[node.id];
40172
40173 var position = _this3.direction.getPosition(node); // get the space around the node.
40174
40175
40176 var _this3$_getSpaceAroun = _this3._getSpaceAroundNode(node, branchMap),
40177 _this3$_getSpaceAroun2 = _slicedToArray(_this3$_getSpaceAroun, 2),
40178 minSpaceNode = _this3$_getSpaceAroun2[0],
40179 maxSpaceNode = _this3$_getSpaceAroun2[1];
40180
40181 minSpace = Math.min(minSpaceNode, minSpace);
40182 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.
40183
40184 if (level <= maxLevel) {
40185 min = Math.min(position, min);
40186 max = Math.max(position, max);
40187 }
40188 }
40189 }
40190
40191 return [min, max, minSpace, maxSpace];
40192 }; // check what the maximum level is these nodes have in common.
40193
40194
40195 var getCollisionLevel = function getCollisionLevel(node1, node2) {
40196 var maxLevel1 = _this3.hierarchical.getMaxLevel(node1.id);
40197
40198 var maxLevel2 = _this3.hierarchical.getMaxLevel(node2.id);
40199
40200 return Math.min(maxLevel1, maxLevel2);
40201 };
40202 /**
40203 * Condense elements. These can be nodes or branches depending on the callback.
40204 *
40205 * @param {Function} callback
40206 * @param {Array.<number>} levels
40207 * @param {*} centerParents
40208 */
40209
40210
40211 var shiftElementsCloser = function shiftElementsCloser(callback, levels, centerParents) {
40212 var hier = _this3.hierarchical;
40213
40214 for (var i = 0; i < levels.length; i++) {
40215 var level = levels[i];
40216 var levelNodes = hier.distributionOrdering[level];
40217
40218 if (levelNodes.length > 1) {
40219 for (var j = 0; j < levelNodes.length - 1; j++) {
40220 var node1 = levelNodes[j];
40221 var node2 = levelNodes[j + 1]; // NOTE: logic maintained as it was; if nodes have same ancestor,
40222 // then of course they are in the same sub-network.
40223
40224 if (hier.hasSameParent(node1, node2) && hier.inSameSubNetwork(node1, node2)) {
40225 callback(node1, node2, centerParents);
40226 }
40227 }
40228 }
40229 }
40230 }; // callback for shifting branches
40231
40232
40233 var branchShiftCallback = function branchShiftCallback(node1, node2) {
40234 var centerParent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
40235
40236 //window.CALLBACKS.push(() => {
40237 var pos1 = _this3.direction.getPosition(node1);
40238
40239 var pos2 = _this3.direction.getPosition(node2);
40240
40241 var diffAbs = Math.abs(pos2 - pos1);
40242 var nodeSpacing = _this3.options.hierarchical.nodeSpacing; //console.log("NOW CHECKING:", node1.id, node2.id, diffAbs);
40243
40244 if (diffAbs > nodeSpacing) {
40245 var branchNodes1 = {};
40246 var branchNodes2 = {};
40247 getBranchNodes(node1, branchNodes1);
40248 getBranchNodes(node2, branchNodes2); // check the largest distance between the branches
40249
40250 var maxLevel = getCollisionLevel(node1, node2);
40251 var branchNodeBoundary1 = getBranchBoundary(branchNodes1, maxLevel);
40252 var branchNodeBoundary2 = getBranchBoundary(branchNodes2, maxLevel);
40253 var max1 = branchNodeBoundary1[1];
40254 var min2 = branchNodeBoundary2[0];
40255 var minSpace2 = branchNodeBoundary2[2]; //console.log(node1.id, getBranchBoundary(branchNodes1, maxLevel), node2.id,
40256 // getBranchBoundary(branchNodes2, maxLevel), maxLevel);
40257
40258 var diffBranch = Math.abs(max1 - min2);
40259
40260 if (diffBranch > nodeSpacing) {
40261 var offset = max1 - min2 + nodeSpacing;
40262
40263 if (offset < -minSpace2 + nodeSpacing) {
40264 offset = -minSpace2 + nodeSpacing; //console.log("RESETTING OFFSET", max1 - min2 + this.options.hierarchical.nodeSpacing, -minSpace2, offset);
40265 }
40266
40267 if (offset < 0) {
40268 //console.log("SHIFTING", node2.id, offset);
40269 _this3._shiftBlock(node2.id, offset);
40270
40271 stillShifting = true;
40272 if (centerParent === true) _this3._centerParent(node2);
40273 }
40274 }
40275 } //this.body.emitter.emit("_redraw");})
40276
40277 };
40278
40279 var minimizeEdgeLength = function minimizeEdgeLength(iterations, node) {
40280 //window.CALLBACKS.push(() => {
40281 // console.log("ts",node.id);
40282 var nodeId = node.id;
40283 var allEdges = node.edges;
40284 var nodeLevel = _this3.hierarchical.levels[node.id]; // gather constants
40285
40286 var C2 = _this3.options.hierarchical.levelSeparation * _this3.options.hierarchical.levelSeparation;
40287 var referenceNodes = {};
40288 var aboveEdges = [];
40289
40290 for (var i = 0; i < allEdges.length; i++) {
40291 var edge = allEdges[i];
40292
40293 if (edge.toId != edge.fromId) {
40294 var otherNode = edge.toId == nodeId ? edge.from : edge.to;
40295 referenceNodes[allEdges[i].id] = otherNode;
40296
40297 if (_this3.hierarchical.levels[otherNode.id] < nodeLevel) {
40298 aboveEdges.push(edge);
40299 }
40300 }
40301 } // differentiated sum of lengths based on only moving one node over one axis
40302
40303
40304 var getFx = function getFx(point, edges) {
40305 var sum = 0;
40306
40307 for (var _i2 = 0; _i2 < edges.length; _i2++) {
40308 if (referenceNodes[edges[_i2].id] !== undefined) {
40309 var a = _this3.direction.getPosition(referenceNodes[edges[_i2].id]) - point;
40310 sum += a / Math.sqrt(a * a + C2);
40311 }
40312 }
40313
40314 return sum;
40315 }; // doubly differentiated sum of lengths based on only moving one node over one axis
40316
40317
40318 var getDFx = function getDFx(point, edges) {
40319 var sum = 0;
40320
40321 for (var _i3 = 0; _i3 < edges.length; _i3++) {
40322 if (referenceNodes[edges[_i3].id] !== undefined) {
40323 var a = _this3.direction.getPosition(referenceNodes[edges[_i3].id]) - point;
40324 sum -= C2 * Math.pow(a * a + C2, -1.5);
40325 }
40326 }
40327
40328 return sum;
40329 };
40330
40331 var getGuess = function getGuess(iterations, edges) {
40332 var guess = _this3.direction.getPosition(node); // Newton's method for optimization
40333
40334
40335 var guessMap = {};
40336
40337 for (var _i4 = 0; _i4 < iterations; _i4++) {
40338 var fx = getFx(guess, edges);
40339 var dfx = getDFx(guess, edges); // we limit the movement to avoid instability.
40340
40341 var limit = 40;
40342 var ratio = Math.max(-limit, Math.min(limit, Math.round(fx / dfx)));
40343 guess = guess - ratio; // reduce duplicates
40344
40345 if (guessMap[guess] !== undefined) {
40346 break;
40347 }
40348
40349 guessMap[guess] = _i4;
40350 }
40351
40352 return guess;
40353 };
40354
40355 var moveBranch = function moveBranch(guess) {
40356 // position node if there is space
40357 var nodePosition = _this3.direction.getPosition(node); // check movable area of the branch
40358
40359
40360 if (branches[node.id] === undefined) {
40361 var branchNodes = {};
40362 getBranchNodes(node, branchNodes);
40363 branches[node.id] = branchNodes;
40364 }
40365
40366 var branchBoundary = getBranchBoundary(branches[node.id]);
40367 var minSpaceBranch = branchBoundary[2];
40368 var maxSpaceBranch = branchBoundary[3];
40369 var diff = guess - nodePosition; // check if we are allowed to move the node:
40370
40371 var branchOffset = 0;
40372
40373 if (diff > 0) {
40374 branchOffset = Math.min(diff, maxSpaceBranch - _this3.options.hierarchical.nodeSpacing);
40375 } else if (diff < 0) {
40376 branchOffset = -Math.min(-diff, minSpaceBranch - _this3.options.hierarchical.nodeSpacing);
40377 }
40378
40379 if (branchOffset != 0) {
40380 //console.log("moving branch:",branchOffset, maxSpaceBranch, minSpaceBranch)
40381 _this3._shiftBlock(node.id, branchOffset); //this.body.emitter.emit("_redraw");
40382
40383
40384 stillShifting = true;
40385 }
40386 };
40387
40388 var moveNode = function moveNode(guess) {
40389 var nodePosition = _this3.direction.getPosition(node); // position node if there is space
40390
40391
40392 var _this3$_getSpaceAroun3 = _this3._getSpaceAroundNode(node),
40393 _this3$_getSpaceAroun4 = _slicedToArray(_this3$_getSpaceAroun3, 2),
40394 minSpace = _this3$_getSpaceAroun4[0],
40395 maxSpace = _this3$_getSpaceAroun4[1];
40396
40397 var diff = guess - nodePosition; // check if we are allowed to move the node:
40398
40399 var newPosition = nodePosition;
40400
40401 if (diff > 0) {
40402 newPosition = Math.min(nodePosition + (maxSpace - _this3.options.hierarchical.nodeSpacing), guess);
40403 } else if (diff < 0) {
40404 newPosition = Math.max(nodePosition - (minSpace - _this3.options.hierarchical.nodeSpacing), guess);
40405 }
40406
40407 if (newPosition !== nodePosition) {
40408 //console.log("moving Node:",diff, minSpace, maxSpace);
40409 _this3.direction.setPosition(node, newPosition); //this.body.emitter.emit("_redraw");
40410
40411
40412 stillShifting = true;
40413 }
40414 };
40415
40416 var guess = getGuess(iterations, aboveEdges);
40417 moveBranch(guess);
40418 guess = getGuess(iterations, allEdges);
40419 moveNode(guess); //})
40420 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
40421
40422
40423 var minimizeEdgeLengthBottomUp = function minimizeEdgeLengthBottomUp(iterations) {
40424 var levels = _this3.hierarchical.getLevels();
40425
40426 levels = reverse(levels).call(levels);
40427
40428 for (var i = 0; i < iterations; i++) {
40429 stillShifting = false;
40430
40431 for (var j = 0; j < levels.length; j++) {
40432 var level = levels[j];
40433 var levelNodes = _this3.hierarchical.distributionOrdering[level];
40434
40435 for (var k = 0; k < levelNodes.length; k++) {
40436 minimizeEdgeLength(1000, levelNodes[k]);
40437 }
40438 }
40439
40440 if (stillShifting !== true) {
40441 //console.log("FINISHED minimizeEdgeLengthBottomUp IN " + i);
40442 break;
40443 }
40444 }
40445 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
40446
40447
40448 var shiftBranchesCloserBottomUp = function shiftBranchesCloserBottomUp(iterations) {
40449 var levels = _this3.hierarchical.getLevels();
40450
40451 levels = reverse(levels).call(levels);
40452
40453 for (var i = 0; i < iterations; i++) {
40454 stillShifting = false;
40455 shiftElementsCloser(branchShiftCallback, levels, true);
40456
40457 if (stillShifting !== true) {
40458 //console.log("FINISHED shiftBranchesCloserBottomUp IN " + (i+1));
40459 break;
40460 }
40461 }
40462 }; // center all parents
40463
40464
40465 var centerAllParents = function centerAllParents() {
40466 for (var nodeId in _this3.body.nodes) {
40467 if (Object.prototype.hasOwnProperty.call(_this3.body.nodes, nodeId)) _this3._centerParent(_this3.body.nodes[nodeId]);
40468 }
40469 }; // center all parents
40470
40471
40472 var centerAllParentsBottomUp = function centerAllParentsBottomUp() {
40473 var levels = _this3.hierarchical.getLevels();
40474
40475 levels = reverse(levels).call(levels);
40476
40477 for (var i = 0; i < levels.length; i++) {
40478 var level = levels[i];
40479 var levelNodes = _this3.hierarchical.distributionOrdering[level];
40480
40481 for (var j = 0; j < levelNodes.length; j++) {
40482 _this3._centerParent(levelNodes[j]);
40483 }
40484 }
40485 }; // the actual work is done here.
40486
40487
40488 if (this.options.hierarchical.blockShifting === true) {
40489 shiftBranchesCloserBottomUp(5);
40490 centerAllParents();
40491 } // minimize edge length
40492
40493
40494 if (this.options.hierarchical.edgeMinimization === true) {
40495 minimizeEdgeLengthBottomUp(20);
40496 }
40497
40498 if (this.options.hierarchical.parentCentralization === true) {
40499 centerAllParentsBottomUp();
40500 }
40501
40502 shiftTrees();
40503 }
40504 /**
40505 * This gives the space around the node. IF a map is supplied, it will only check against nodes NOT in the map.
40506 * This is used to only get the distances to nodes outside of a branch.
40507 *
40508 * @param {Node} node
40509 * @param {{Node.id: vis.Node}} map
40510 * @returns {number[]}
40511 * @private
40512 */
40513
40514 }, {
40515 key: "_getSpaceAroundNode",
40516 value: function _getSpaceAroundNode(node, map) {
40517 var useMap = true;
40518
40519 if (map === undefined) {
40520 useMap = false;
40521 }
40522
40523 var level = this.hierarchical.levels[node.id];
40524
40525 if (level !== undefined) {
40526 var index = this.hierarchical.distributionIndex[node.id];
40527 var position = this.direction.getPosition(node);
40528 var ordering = this.hierarchical.distributionOrdering[level];
40529 var minSpace = 1e9;
40530 var maxSpace = 1e9;
40531
40532 if (index !== 0) {
40533 var prevNode = ordering[index - 1];
40534
40535 if (useMap === true && map[prevNode.id] === undefined || useMap === false) {
40536 var prevPos = this.direction.getPosition(prevNode);
40537 minSpace = position - prevPos;
40538 }
40539 }
40540
40541 if (index != ordering.length - 1) {
40542 var nextNode = ordering[index + 1];
40543
40544 if (useMap === true && map[nextNode.id] === undefined || useMap === false) {
40545 var nextPos = this.direction.getPosition(nextNode);
40546 maxSpace = Math.min(maxSpace, nextPos - position);
40547 }
40548 }
40549
40550 return [minSpace, maxSpace];
40551 } else {
40552 return [0, 0];
40553 }
40554 }
40555 /**
40556 * We use this method to center a parent node and check if it does not cross other nodes when it does.
40557 *
40558 * @param {Node} node
40559 * @private
40560 */
40561
40562 }, {
40563 key: "_centerParent",
40564 value: function _centerParent(node) {
40565 if (this.hierarchical.parentReference[node.id]) {
40566 var parents = this.hierarchical.parentReference[node.id];
40567
40568 for (var i = 0; i < parents.length; i++) {
40569 var parentId = parents[i];
40570 var parentNode = this.body.nodes[parentId];
40571 var children = this.hierarchical.childrenReference[parentId];
40572
40573 if (children !== undefined) {
40574 // get the range of the children
40575 var newPosition = this._getCenterPosition(children);
40576
40577 var position = this.direction.getPosition(parentNode);
40578
40579 var _this$_getSpaceAround = this._getSpaceAroundNode(parentNode),
40580 _this$_getSpaceAround2 = _slicedToArray(_this$_getSpaceAround, 2),
40581 minSpace = _this$_getSpaceAround2[0],
40582 maxSpace = _this$_getSpaceAround2[1];
40583
40584 var diff = position - newPosition;
40585
40586 if (diff < 0 && Math.abs(diff) < maxSpace - this.options.hierarchical.nodeSpacing || diff > 0 && Math.abs(diff) < minSpace - this.options.hierarchical.nodeSpacing) {
40587 this.direction.setPosition(parentNode, newPosition);
40588 }
40589 }
40590 }
40591 }
40592 }
40593 /**
40594 * This function places the nodes on the canvas based on the hierarchial distribution.
40595 *
40596 * @param {object} distribution | obtained by the function this._getDistribution()
40597 * @private
40598 */
40599
40600 }, {
40601 key: "_placeNodesByHierarchy",
40602 value: function _placeNodesByHierarchy(distribution) {
40603 this.positionedNodes = {}; // start placing all the level 0 nodes first. Then recursively position their branches.
40604
40605 for (var level in distribution) {
40606 if (Object.prototype.hasOwnProperty.call(distribution, level)) {
40607 var _context;
40608
40609 // sort nodes in level by position:
40610 var nodeArray = keys$4(distribution[level]);
40611
40612 nodeArray = this._indexArrayToNodes(nodeArray);
40613
40614 sort(_context = this.direction).call(_context, nodeArray);
40615
40616 var handledNodeCount = 0;
40617
40618 for (var i = 0; i < nodeArray.length; i++) {
40619 var node = nodeArray[i];
40620
40621 if (this.positionedNodes[node.id] === undefined) {
40622 var spacing = this.options.hierarchical.nodeSpacing;
40623 var pos = spacing * handledNodeCount; // We get the X or Y values we need and store them in pos and previousPos.
40624 // The get and set make sure we get X or Y
40625
40626 if (handledNodeCount > 0) {
40627 pos = this.direction.getPosition(nodeArray[i - 1]) + spacing;
40628 }
40629
40630 this.direction.setPosition(node, pos, level);
40631
40632 this._validatePositionAndContinue(node, level, pos);
40633
40634 handledNodeCount++;
40635 }
40636 }
40637 }
40638 }
40639 }
40640 /**
40641 * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes
40642 * on a X position that ensures there will be no overlap.
40643 *
40644 * @param {Node.id} parentId
40645 * @param {number} parentLevel
40646 * @private
40647 */
40648
40649 }, {
40650 key: "_placeBranchNodes",
40651 value: function _placeBranchNodes(parentId, parentLevel) {
40652 var _context2;
40653
40654 var childRef = this.hierarchical.childrenReference[parentId]; // if this is not a parent, cancel the placing. This can happen with multiple parents to one child.
40655
40656 if (childRef === undefined) {
40657 return;
40658 } // get a list of childNodes
40659
40660
40661 var childNodes = [];
40662
40663 for (var i = 0; i < childRef.length; i++) {
40664 childNodes.push(this.body.nodes[childRef[i]]);
40665 } // use the positions to order the nodes.
40666
40667
40668 sort(_context2 = this.direction).call(_context2, childNodes); // position the childNodes
40669
40670
40671 for (var _i5 = 0; _i5 < childNodes.length; _i5++) {
40672 var childNode = childNodes[_i5];
40673 var childNodeLevel = this.hierarchical.levels[childNode.id]; // check if the child node is below the parent node and if it has already been positioned.
40674
40675 if (childNodeLevel > parentLevel && this.positionedNodes[childNode.id] === undefined) {
40676 // get the amount of space required for this node. If parent the width is based on the amount of children.
40677 var spacing = this.options.hierarchical.nodeSpacing;
40678 var pos = void 0; // we get the X or Y values we need and store them in pos and previousPos.
40679 // The get and set make sure we get X or Y
40680
40681 if (_i5 === 0) {
40682 pos = this.direction.getPosition(this.body.nodes[parentId]);
40683 } else {
40684 pos = this.direction.getPosition(childNodes[_i5 - 1]) + spacing;
40685 }
40686
40687 this.direction.setPosition(childNode, pos, childNodeLevel);
40688
40689 this._validatePositionAndContinue(childNode, childNodeLevel, pos);
40690 } else {
40691 return;
40692 }
40693 } // center the parent nodes.
40694
40695
40696 var center = this._getCenterPosition(childNodes);
40697
40698 this.direction.setPosition(this.body.nodes[parentId], center, parentLevel);
40699 }
40700 /**
40701 * This method checks for overlap and if required shifts the branch. It also keeps records of positioned nodes.
40702 * Finally it will call _placeBranchNodes to place the branch nodes.
40703 *
40704 * @param {Node} node
40705 * @param {number} level
40706 * @param {number} pos
40707 * @private
40708 */
40709
40710 }, {
40711 key: "_validatePositionAndContinue",
40712 value: function _validatePositionAndContinue(node, level, pos) {
40713 // This method only works for formal trees and formal forests
40714 // Early exit if this is not the case
40715 if (!this.hierarchical.isTree) return; // if overlap has been detected, we shift the branch
40716
40717 if (this.lastNodeOnLevel[level] !== undefined) {
40718 var previousPos = this.direction.getPosition(this.body.nodes[this.lastNodeOnLevel[level]]);
40719
40720 if (pos - previousPos < this.options.hierarchical.nodeSpacing) {
40721 var diff = previousPos + this.options.hierarchical.nodeSpacing - pos;
40722
40723 var sharedParent = this._findCommonParent(this.lastNodeOnLevel[level], node.id);
40724
40725 this._shiftBlock(sharedParent.withChild, diff);
40726 }
40727 }
40728
40729 this.lastNodeOnLevel[level] = node.id; // store change in position.
40730
40731 this.positionedNodes[node.id] = true;
40732
40733 this._placeBranchNodes(node.id, level);
40734 }
40735 /**
40736 * Receives an array with node indices and returns an array with the actual node references.
40737 * Used for sorting based on node properties.
40738 *
40739 * @param {Array.<Node.id>} idArray
40740 * @returns {Array.<Node>}
40741 */
40742
40743 }, {
40744 key: "_indexArrayToNodes",
40745 value: function _indexArrayToNodes(idArray) {
40746 var array = [];
40747
40748 for (var i = 0; i < idArray.length; i++) {
40749 array.push(this.body.nodes[idArray[i]]);
40750 }
40751
40752 return array;
40753 }
40754 /**
40755 * This function get the distribution of levels based on hubsize
40756 *
40757 * @returns {object}
40758 * @private
40759 */
40760
40761 }, {
40762 key: "_getDistribution",
40763 value: function _getDistribution() {
40764 var distribution = {};
40765 var nodeId, node; // we fix Y because the hierarchy is vertical,
40766 // we fix X so we do not give a node an x position for a second time.
40767 // the fix of X is removed after the x value has been set.
40768
40769 for (nodeId in this.body.nodes) {
40770 if (Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) {
40771 node = this.body.nodes[nodeId];
40772 var level = this.hierarchical.levels[nodeId] === undefined ? 0 : this.hierarchical.levels[nodeId];
40773 this.direction.fix(node, level);
40774
40775 if (distribution[level] === undefined) {
40776 distribution[level] = {};
40777 }
40778
40779 distribution[level][nodeId] = node;
40780 }
40781 }
40782
40783 return distribution;
40784 }
40785 /**
40786 * Return the active (i.e. visible) edges for this node
40787 *
40788 * @param {Node} node
40789 * @returns {Array.<vis.Edge>} Array of edge instances
40790 * @private
40791 */
40792
40793 }, {
40794 key: "_getActiveEdges",
40795 value: function _getActiveEdges(node) {
40796 var _this4 = this;
40797
40798 var result = [];
40799 forEach$1(node.edges, function (edge) {
40800 var _context3;
40801
40802 if (indexOf(_context3 = _this4.body.edgeIndices).call(_context3, edge.id) !== -1) {
40803 result.push(edge);
40804 }
40805 });
40806 return result;
40807 }
40808 /**
40809 * Get the hubsizes for all active nodes.
40810 *
40811 * @returns {number}
40812 * @private
40813 */
40814
40815 }, {
40816 key: "_getHubSizes",
40817 value: function _getHubSizes() {
40818 var _this5 = this;
40819
40820 var hubSizes = {};
40821 var nodeIds = this.body.nodeIndices;
40822 forEach$1(nodeIds, function (nodeId) {
40823 var node = _this5.body.nodes[nodeId];
40824
40825 var hubSize = _this5._getActiveEdges(node).length;
40826
40827 hubSizes[hubSize] = true;
40828 }); // Make an array of the size sorted descending
40829
40830 var result = [];
40831 forEach$1(hubSizes, function (size) {
40832 result.push(Number(size));
40833 });
40834
40835 sort(timsort).call(timsort, result, function (a, b) {
40836 return b - a;
40837 });
40838
40839 return result;
40840 }
40841 /**
40842 * this function allocates nodes in levels based on the recursive branching from the largest hubs.
40843 *
40844 * @private
40845 */
40846
40847 }, {
40848 key: "_determineLevelsByHubsize",
40849 value: function _determineLevelsByHubsize() {
40850 var _this6 = this;
40851
40852 var levelDownstream = function levelDownstream(nodeA, nodeB) {
40853 _this6.hierarchical.levelDownstream(nodeA, nodeB);
40854 };
40855
40856 var hubSizes = this._getHubSizes();
40857
40858 var _loop = function _loop(i) {
40859 var hubSize = hubSizes[i];
40860 if (hubSize === 0) return "break";
40861 forEach$1(_this6.body.nodeIndices, function (nodeId) {
40862 var node = _this6.body.nodes[nodeId];
40863
40864 if (hubSize === _this6._getActiveEdges(node).length) {
40865 _this6._crawlNetwork(levelDownstream, nodeId);
40866 }
40867 });
40868 };
40869
40870 for (var i = 0; i < hubSizes.length; ++i) {
40871 var _ret = _loop(i);
40872
40873 if (_ret === "break") break;
40874 }
40875 }
40876 /**
40877 * TODO: release feature
40878 * TODO: Determine if this feature is needed at all
40879 *
40880 * @private
40881 */
40882
40883 }, {
40884 key: "_determineLevelsCustomCallback",
40885 value: function _determineLevelsCustomCallback() {
40886 var _this7 = this;
40887
40888 var minLevel = 100000; // TODO: this should come from options.
40889 // eslint-disable-next-line no-unused-vars -- This should eventually be implemented with these parameters used.
40890
40891 var customCallback = function customCallback(nodeA, nodeB, edge) {}; // TODO: perhaps move to HierarchicalStatus.
40892 // But I currently don't see the point, this method is not used.
40893
40894
40895 var levelByDirection = function levelByDirection(nodeA, nodeB, edge) {
40896 var levelA = _this7.hierarchical.levels[nodeA.id]; // set initial level
40897
40898 if (levelA === undefined) {
40899 levelA = _this7.hierarchical.levels[nodeA.id] = minLevel;
40900 }
40901
40902 var diff = customCallback(NetworkUtil.cloneOptions(nodeA, "node"), NetworkUtil.cloneOptions(nodeB, "node"), NetworkUtil.cloneOptions(edge, "edge"));
40903 _this7.hierarchical.levels[nodeB.id] = levelA + diff;
40904 };
40905
40906 this._crawlNetwork(levelByDirection);
40907
40908 this.hierarchical.setMinLevelToZero(this.body.nodes);
40909 }
40910 /**
40911 * Allocate nodes in levels based on the direction of the edges.
40912 *
40913 * @private
40914 */
40915
40916 }, {
40917 key: "_determineLevelsDirected",
40918 value: function _determineLevelsDirected() {
40919 var _context4,
40920 _this8 = this;
40921
40922 var nodes = reduce(_context4 = this.body.nodeIndices).call(_context4, function (acc, id) {
40923 acc.set(id, _this8.body.nodes[id]);
40924 return acc;
40925 }, new map());
40926
40927 if (this.options.hierarchical.shakeTowards === "roots") {
40928 this.hierarchical.levels = fillLevelsByDirectionRoots(nodes);
40929 } else {
40930 this.hierarchical.levels = fillLevelsByDirectionLeaves(nodes);
40931 }
40932
40933 this.hierarchical.setMinLevelToZero(this.body.nodes);
40934 }
40935 /**
40936 * Update the bookkeeping of parent and child.
40937 *
40938 * @private
40939 */
40940
40941 }, {
40942 key: "_generateMap",
40943 value: function _generateMap() {
40944 var _this9 = this;
40945
40946 var fillInRelations = function fillInRelations(parentNode, childNode) {
40947 if (_this9.hierarchical.levels[childNode.id] > _this9.hierarchical.levels[parentNode.id]) {
40948 _this9.hierarchical.addRelation(parentNode.id, childNode.id);
40949 }
40950 };
40951
40952 this._crawlNetwork(fillInRelations);
40953
40954 this.hierarchical.checkIfTree();
40955 }
40956 /**
40957 * Crawl over the entire network and use a callback on each node couple that is connected to each other.
40958 *
40959 * @param {Function} [callback=function(){}] | will receive nodeA, nodeB and the connecting edge. A and B are distinct.
40960 * @param {Node.id} startingNodeId
40961 * @private
40962 */
40963
40964 }, {
40965 key: "_crawlNetwork",
40966 value: function _crawlNetwork() {
40967 var _this10 = this;
40968
40969 var callback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
40970 var startingNodeId = arguments.length > 1 ? arguments[1] : undefined;
40971 var progress = {};
40972
40973 var crawler = function crawler(node, tree) {
40974 if (progress[node.id] === undefined) {
40975 _this10.hierarchical.setTreeIndex(node, tree);
40976
40977 progress[node.id] = true;
40978 var childNode;
40979
40980 var edges = _this10._getActiveEdges(node);
40981
40982 for (var i = 0; i < edges.length; i++) {
40983 var edge = edges[i];
40984
40985 if (edge.connected === true) {
40986 if (edge.toId == node.id) {
40987 // Not '===' because id's can be string and numeric
40988 childNode = edge.from;
40989 } else {
40990 childNode = edge.to;
40991 }
40992
40993 if (node.id != childNode.id) {
40994 // Not '!==' because id's can be string and numeric
40995 callback(node, childNode, edge);
40996 crawler(childNode, tree);
40997 }
40998 }
40999 }
41000 }
41001 };
41002
41003 if (startingNodeId === undefined) {
41004 // Crawl over all nodes
41005 var treeIndex = 0; // Serves to pass a unique id for the current distinct tree
41006
41007 for (var i = 0; i < this.body.nodeIndices.length; i++) {
41008 var nodeId = this.body.nodeIndices[i];
41009
41010 if (progress[nodeId] === undefined) {
41011 var node = this.body.nodes[nodeId];
41012 crawler(node, treeIndex);
41013 treeIndex += 1;
41014 }
41015 }
41016 } else {
41017 // Crawl from the given starting node
41018 var _node2 = this.body.nodes[startingNodeId];
41019
41020 if (_node2 === undefined) {
41021 console.error("Node not found:", startingNodeId);
41022 return;
41023 }
41024
41025 crawler(_node2);
41026 }
41027 }
41028 /**
41029 * Shift a branch a certain distance
41030 *
41031 * @param {Node.id} parentId
41032 * @param {number} diff
41033 * @private
41034 */
41035
41036 }, {
41037 key: "_shiftBlock",
41038 value: function _shiftBlock(parentId, diff) {
41039 var _this11 = this;
41040
41041 var progress = {};
41042
41043 var shifter = function shifter(parentId) {
41044 if (progress[parentId]) {
41045 return;
41046 }
41047
41048 progress[parentId] = true;
41049
41050 _this11.direction.shift(parentId, diff);
41051
41052 var childRef = _this11.hierarchical.childrenReference[parentId];
41053
41054 if (childRef !== undefined) {
41055 for (var i = 0; i < childRef.length; i++) {
41056 shifter(childRef[i]);
41057 }
41058 }
41059 };
41060
41061 shifter(parentId);
41062 }
41063 /**
41064 * Find a common parent between branches.
41065 *
41066 * @param {Node.id} childA
41067 * @param {Node.id} childB
41068 * @returns {{foundParent, withChild}}
41069 * @private
41070 */
41071
41072 }, {
41073 key: "_findCommonParent",
41074 value: function _findCommonParent(childA, childB) {
41075 var _this12 = this;
41076
41077 var parents = {};
41078
41079 var iterateParents = function iterateParents(parents, child) {
41080 var parentRef = _this12.hierarchical.parentReference[child];
41081
41082 if (parentRef !== undefined) {
41083 for (var i = 0; i < parentRef.length; i++) {
41084 var parent = parentRef[i];
41085 parents[parent] = true;
41086 iterateParents(parents, parent);
41087 }
41088 }
41089 };
41090
41091 var findParent = function findParent(parents, child) {
41092 var parentRef = _this12.hierarchical.parentReference[child];
41093
41094 if (parentRef !== undefined) {
41095 for (var i = 0; i < parentRef.length; i++) {
41096 var parent = parentRef[i];
41097
41098 if (parents[parent] !== undefined) {
41099 return {
41100 foundParent: parent,
41101 withChild: child
41102 };
41103 }
41104
41105 var branch = findParent(parents, parent);
41106
41107 if (branch.foundParent !== null) {
41108 return branch;
41109 }
41110 }
41111 }
41112
41113 return {
41114 foundParent: null,
41115 withChild: child
41116 };
41117 };
41118
41119 iterateParents(parents, childA);
41120 return findParent(parents, childB);
41121 }
41122 /**
41123 * Set the strategy pattern for handling the coordinates given the current direction.
41124 *
41125 * The individual instances contain all the operations and data specific to a layout direction.
41126 *
41127 * @param {Node} node
41128 * @param {{x: number, y: number}} position
41129 * @param {number} level
41130 * @param {boolean} [doNotUpdate=false]
41131 * @private
41132 */
41133
41134 }, {
41135 key: "setDirectionStrategy",
41136 value: function setDirectionStrategy() {
41137 var isVertical = this.options.hierarchical.direction === "UD" || this.options.hierarchical.direction === "DU";
41138
41139 if (isVertical) {
41140 this.direction = new VerticalStrategy(this);
41141 } else {
41142 this.direction = new HorizontalStrategy(this);
41143 }
41144 }
41145 /**
41146 * Determine the center position of a branch from the passed list of child nodes
41147 *
41148 * This takes into account the positions of all the child nodes.
41149 *
41150 * @param {Array.<Node|vis.Node.id>} childNodes Array of either child nodes or node id's
41151 * @returns {number}
41152 * @private
41153 */
41154
41155 }, {
41156 key: "_getCenterPosition",
41157 value: function _getCenterPosition(childNodes) {
41158 var minPos = 1e9;
41159 var maxPos = -1e9;
41160
41161 for (var i = 0; i < childNodes.length; i++) {
41162 var childNode = void 0;
41163
41164 if (childNodes[i].id !== undefined) {
41165 childNode = childNodes[i];
41166 } else {
41167 var childNodeId = childNodes[i];
41168 childNode = this.body.nodes[childNodeId];
41169 }
41170
41171 var position = this.direction.getPosition(childNode);
41172 minPos = Math.min(minPos, position);
41173 maxPos = Math.max(maxPos, position);
41174 }
41175
41176 return 0.5 * (minPos + maxPos);
41177 }
41178 }]);
41179
41180 return LayoutEngine;
41181 }();
41182
41183 function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof symbol !== "undefined" && getIteratorMethod$1(o) || o["@@iterator"]; if (!it) { if (isArray$2(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; } } }; }
41184
41185 function _unsupportedIterableToArray(o, minLen) { var _context32; if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = slice(_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$3(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
41186
41187 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; }
41188 /**
41189 * Clears the toolbar div element of children
41190 *
41191 * @private
41192 */
41193
41194 var ManipulationSystem = /*#__PURE__*/function () {
41195 /**
41196 * @param {object} body
41197 * @param {Canvas} canvas
41198 * @param {SelectionHandler} selectionHandler
41199 * @param {InteractionHandler} interactionHandler
41200 */
41201 function ManipulationSystem(body, canvas, selectionHandler, interactionHandler) {
41202 var _this = this,
41203 _context,
41204 _context2;
41205
41206 _classCallCheck(this, ManipulationSystem);
41207
41208 this.body = body;
41209 this.canvas = canvas;
41210 this.selectionHandler = selectionHandler;
41211 this.interactionHandler = interactionHandler;
41212 this.editMode = false;
41213 this.manipulationDiv = undefined;
41214 this.editModeDiv = undefined;
41215 this.closeDiv = undefined;
41216 this._domEventListenerCleanupQueue = [];
41217 this.temporaryUIFunctions = {};
41218 this.temporaryEventFunctions = [];
41219 this.touchTime = 0;
41220 this.temporaryIds = {
41221 nodes: [],
41222 edges: []
41223 };
41224 this.guiEnabled = false;
41225 this.inMode = false;
41226 this.selectedControlNode = undefined;
41227 this.options = {};
41228 this.defaultOptions = {
41229 enabled: false,
41230 initiallyActive: false,
41231 addNode: true,
41232 addEdge: true,
41233 editNode: undefined,
41234 editEdge: true,
41235 deleteNode: true,
41236 deleteEdge: true,
41237 controlNodeStyle: {
41238 shape: "dot",
41239 size: 6,
41240 color: {
41241 background: "#ff0000",
41242 border: "#3c3c3c",
41243 highlight: {
41244 background: "#07f968",
41245 border: "#3c3c3c"
41246 }
41247 },
41248 borderWidth: 2,
41249 borderWidthSelected: 2
41250 }
41251 };
41252
41253 assign$2(this.options, this.defaultOptions);
41254
41255 this.body.emitter.on("destroy", function () {
41256 _this._clean();
41257 });
41258 this.body.emitter.on("_dataChanged", bind$6(_context = this._restore).call(_context, this));
41259 this.body.emitter.on("_resetData", bind$6(_context2 = this._restore).call(_context2, this));
41260 }
41261 /**
41262 * If something changes in the data during editing, switch back to the initial datamanipulation state and close all edit modes.
41263 *
41264 * @private
41265 */
41266
41267
41268 _createClass(ManipulationSystem, [{
41269 key: "_restore",
41270 value: function _restore() {
41271 if (this.inMode !== false) {
41272 if (this.options.initiallyActive === true) {
41273 this.enableEditMode();
41274 } else {
41275 this.disableEditMode();
41276 }
41277 }
41278 }
41279 /**
41280 * Set the Options
41281 *
41282 * @param {object} options
41283 * @param {object} allOptions
41284 * @param {object} globalOptions
41285 */
41286
41287 }, {
41288 key: "setOptions",
41289 value: function setOptions(options, allOptions, globalOptions) {
41290 if (allOptions !== undefined) {
41291 if (allOptions.locale !== undefined) {
41292 this.options.locale = allOptions.locale;
41293 } else {
41294 this.options.locale = globalOptions.locale;
41295 }
41296
41297 if (allOptions.locales !== undefined) {
41298 this.options.locales = allOptions.locales;
41299 } else {
41300 this.options.locales = globalOptions.locales;
41301 }
41302 }
41303
41304 if (options !== undefined) {
41305 if (typeof options === "boolean") {
41306 this.options.enabled = options;
41307 } else {
41308 this.options.enabled = true;
41309 deepExtend(this.options, options);
41310 }
41311
41312 if (this.options.initiallyActive === true) {
41313 this.editMode = true;
41314 }
41315
41316 this._setup();
41317 }
41318 }
41319 /**
41320 * Enable or disable edit-mode. Draws the DOM required and cleans up after itself.
41321 *
41322 * @private
41323 */
41324
41325 }, {
41326 key: "toggleEditMode",
41327 value: function toggleEditMode() {
41328 if (this.editMode === true) {
41329 this.disableEditMode();
41330 } else {
41331 this.enableEditMode();
41332 }
41333 }
41334 /**
41335 * Enables Edit Mode
41336 */
41337
41338 }, {
41339 key: "enableEditMode",
41340 value: function enableEditMode() {
41341 this.editMode = true;
41342
41343 this._clean();
41344
41345 if (this.guiEnabled === true) {
41346 this.manipulationDiv.style.display = "block";
41347 this.closeDiv.style.display = "block";
41348 this.editModeDiv.style.display = "none";
41349 this.showManipulatorToolbar();
41350 }
41351 }
41352 /**
41353 * Disables Edit Mode
41354 */
41355
41356 }, {
41357 key: "disableEditMode",
41358 value: function disableEditMode() {
41359 this.editMode = false;
41360
41361 this._clean();
41362
41363 if (this.guiEnabled === true) {
41364 this.manipulationDiv.style.display = "none";
41365 this.closeDiv.style.display = "none";
41366 this.editModeDiv.style.display = "block";
41367
41368 this._createEditButton();
41369 }
41370 }
41371 /**
41372 * Creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar.
41373 *
41374 * @private
41375 */
41376
41377 }, {
41378 key: "showManipulatorToolbar",
41379 value: function showManipulatorToolbar() {
41380 // restore the state of any bound functions or events, remove control nodes, restore physics
41381 this._clean(); // reset global variables
41382
41383
41384 this.manipulationDOM = {}; // if the gui is enabled, draw all elements.
41385
41386 if (this.guiEnabled === true) {
41387 var _context3, _context4;
41388
41389 // a _restore will hide these menus
41390 this.editMode = true;
41391 this.manipulationDiv.style.display = "block";
41392 this.closeDiv.style.display = "block";
41393 var selectedNodeCount = this.selectionHandler.getSelectedNodeCount();
41394 var selectedEdgeCount = this.selectionHandler.getSelectedEdgeCount();
41395 var selectedTotalCount = selectedNodeCount + selectedEdgeCount;
41396 var locale = this.options.locales[this.options.locale];
41397 var needSeperator = false;
41398
41399 if (this.options.addNode !== false) {
41400 this._createAddNodeButton(locale);
41401
41402 needSeperator = true;
41403 }
41404
41405 if (this.options.addEdge !== false) {
41406 if (needSeperator === true) {
41407 this._createSeperator(1);
41408 } else {
41409 needSeperator = true;
41410 }
41411
41412 this._createAddEdgeButton(locale);
41413 }
41414
41415 if (selectedNodeCount === 1 && typeof this.options.editNode === "function") {
41416 if (needSeperator === true) {
41417 this._createSeperator(2);
41418 } else {
41419 needSeperator = true;
41420 }
41421
41422 this._createEditNodeButton(locale);
41423 } else if (selectedEdgeCount === 1 && selectedNodeCount === 0 && this.options.editEdge !== false) {
41424 if (needSeperator === true) {
41425 this._createSeperator(3);
41426 } else {
41427 needSeperator = true;
41428 }
41429
41430 this._createEditEdgeButton(locale);
41431 } // remove buttons
41432
41433
41434 if (selectedTotalCount !== 0) {
41435 if (selectedNodeCount > 0 && this.options.deleteNode !== false) {
41436 if (needSeperator === true) {
41437 this._createSeperator(4);
41438 }
41439
41440 this._createDeleteButton(locale);
41441 } else if (selectedNodeCount === 0 && this.options.deleteEdge !== false) {
41442 if (needSeperator === true) {
41443 this._createSeperator(4);
41444 }
41445
41446 this._createDeleteButton(locale);
41447 }
41448 } // bind the close button
41449
41450
41451 this._bindElementEvents(this.closeDiv, bind$6(_context3 = this.toggleEditMode).call(_context3, this)); // refresh this bar based on what has been selected
41452
41453
41454 this._temporaryBindEvent("select", bind$6(_context4 = this.showManipulatorToolbar).call(_context4, this));
41455 } // redraw to show any possible changes
41456
41457
41458 this.body.emitter.emit("_redraw");
41459 }
41460 /**
41461 * Create the toolbar for adding Nodes
41462 */
41463
41464 }, {
41465 key: "addNodeMode",
41466 value: function addNodeMode() {
41467 var _context6;
41468
41469 // when using the gui, enable edit mode if it wasnt already.
41470 if (this.editMode !== true) {
41471 this.enableEditMode();
41472 } // restore the state of any bound functions or events, remove control nodes, restore physics
41473
41474
41475 this._clean();
41476
41477 this.inMode = "addNode";
41478
41479 if (this.guiEnabled === true) {
41480 var _context5;
41481
41482 var locale = this.options.locales[this.options.locale];
41483 this.manipulationDOM = {};
41484
41485 this._createBackButton(locale);
41486
41487 this._createSeperator();
41488
41489 this._createDescription(locale["addDescription"] || this.options.locales["en"]["addDescription"]); // bind the close button
41490
41491
41492 this._bindElementEvents(this.closeDiv, bind$6(_context5 = this.toggleEditMode).call(_context5, this));
41493 }
41494
41495 this._temporaryBindEvent("click", bind$6(_context6 = this._performAddNode).call(_context6, this));
41496 }
41497 /**
41498 * call the bound function to handle the editing of the node. The node has to be selected.
41499 */
41500
41501 }, {
41502 key: "editNode",
41503 value: function editNode() {
41504 var _this2 = this;
41505
41506 // when using the gui, enable edit mode if it wasnt already.
41507 if (this.editMode !== true) {
41508 this.enableEditMode();
41509 } // restore the state of any bound functions or events, remove control nodes, restore physics
41510
41511
41512 this._clean();
41513
41514 var node = this.selectionHandler.getSelectedNodes()[0];
41515
41516 if (node !== undefined) {
41517 this.inMode = "editNode";
41518
41519 if (typeof this.options.editNode === "function") {
41520 if (node.isCluster !== true) {
41521 var data = deepExtend({}, node.options, false);
41522 data.x = node.x;
41523 data.y = node.y;
41524
41525 if (this.options.editNode.length === 2) {
41526 this.options.editNode(data, function (finalizedData) {
41527 if (finalizedData !== null && finalizedData !== undefined && _this2.inMode === "editNode") {
41528 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
41529 _this2.body.data.nodes.getDataSet().update(finalizedData);
41530 }
41531
41532 _this2.showManipulatorToolbar();
41533 });
41534 } else {
41535 throw new Error("The function for edit does not support two arguments (data, callback)");
41536 }
41537 } else {
41538 alert(this.options.locales[this.options.locale]["editClusterError"] || this.options.locales["en"]["editClusterError"]);
41539 }
41540 } else {
41541 throw new Error("No function has been configured to handle the editing of nodes.");
41542 }
41543 } else {
41544 this.showManipulatorToolbar();
41545 }
41546 }
41547 /**
41548 * create the toolbar to connect nodes
41549 */
41550
41551 }, {
41552 key: "addEdgeMode",
41553 value: function addEdgeMode() {
41554 var _context8, _context9, _context10, _context11, _context12;
41555
41556 // when using the gui, enable edit mode if it wasnt already.
41557 if (this.editMode !== true) {
41558 this.enableEditMode();
41559 } // restore the state of any bound functions or events, remove control nodes, restore physics
41560
41561
41562 this._clean();
41563
41564 this.inMode = "addEdge";
41565
41566 if (this.guiEnabled === true) {
41567 var _context7;
41568
41569 var locale = this.options.locales[this.options.locale];
41570 this.manipulationDOM = {};
41571
41572 this._createBackButton(locale);
41573
41574 this._createSeperator();
41575
41576 this._createDescription(locale["edgeDescription"] || this.options.locales["en"]["edgeDescription"]); // bind the close button
41577
41578
41579 this._bindElementEvents(this.closeDiv, bind$6(_context7 = this.toggleEditMode).call(_context7, this));
41580 } // temporarily overload functions
41581
41582
41583 this._temporaryBindUI("onTouch", bind$6(_context8 = this._handleConnect).call(_context8, this));
41584
41585 this._temporaryBindUI("onDragEnd", bind$6(_context9 = this._finishConnect).call(_context9, this));
41586
41587 this._temporaryBindUI("onDrag", bind$6(_context10 = this._dragControlNode).call(_context10, this));
41588
41589 this._temporaryBindUI("onRelease", bind$6(_context11 = this._finishConnect).call(_context11, this));
41590
41591 this._temporaryBindUI("onDragStart", bind$6(_context12 = this._dragStartEdge).call(_context12, this));
41592
41593 this._temporaryBindUI("onHold", function () {});
41594 }
41595 /**
41596 * create the toolbar to edit edges
41597 */
41598
41599 }, {
41600 key: "editEdgeMode",
41601 value: function editEdgeMode() {
41602 // when using the gui, enable edit mode if it wasn't already.
41603 if (this.editMode !== true) {
41604 this.enableEditMode();
41605 } // restore the state of any bound functions or events, remove control nodes, restore physics
41606
41607
41608 this._clean();
41609
41610 this.inMode = "editEdge";
41611
41612 if (_typeof(this.options.editEdge) === "object" && typeof this.options.editEdge.editWithoutDrag === "function") {
41613 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdgeIds()[0];
41614
41615 if (this.edgeBeingEditedId !== undefined) {
41616 var edge = this.body.edges[this.edgeBeingEditedId];
41617
41618 this._performEditEdge(edge.from.id, edge.to.id);
41619
41620 return;
41621 }
41622 }
41623
41624 if (this.guiEnabled === true) {
41625 var _context13;
41626
41627 var locale = this.options.locales[this.options.locale];
41628 this.manipulationDOM = {};
41629
41630 this._createBackButton(locale);
41631
41632 this._createSeperator();
41633
41634 this._createDescription(locale["editEdgeDescription"] || this.options.locales["en"]["editEdgeDescription"]); // bind the close button
41635
41636
41637 this._bindElementEvents(this.closeDiv, bind$6(_context13 = this.toggleEditMode).call(_context13, this));
41638 }
41639
41640 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdgeIds()[0];
41641
41642 if (this.edgeBeingEditedId !== undefined) {
41643 var _context14, _context15, _context16, _context17;
41644
41645 var _edge = this.body.edges[this.edgeBeingEditedId]; // create control nodes
41646
41647 var controlNodeFrom = this._getNewTargetNode(_edge.from.x, _edge.from.y);
41648
41649 var controlNodeTo = this._getNewTargetNode(_edge.to.x, _edge.to.y);
41650
41651 this.temporaryIds.nodes.push(controlNodeFrom.id);
41652 this.temporaryIds.nodes.push(controlNodeTo.id);
41653 this.body.nodes[controlNodeFrom.id] = controlNodeFrom;
41654 this.body.nodeIndices.push(controlNodeFrom.id);
41655 this.body.nodes[controlNodeTo.id] = controlNodeTo;
41656 this.body.nodeIndices.push(controlNodeTo.id); // temporarily overload UI functions, cleaned up automatically because of _temporaryBindUI
41657
41658 this._temporaryBindUI("onTouch", bind$6(_context14 = this._controlNodeTouch).call(_context14, this)); // used to get the position
41659
41660
41661 this._temporaryBindUI("onTap", function () {}); // disabled
41662
41663
41664 this._temporaryBindUI("onHold", function () {}); // disabled
41665
41666
41667 this._temporaryBindUI("onDragStart", bind$6(_context15 = this._controlNodeDragStart).call(_context15, this)); // used to select control node
41668
41669
41670 this._temporaryBindUI("onDrag", bind$6(_context16 = this._controlNodeDrag).call(_context16, this)); // used to drag control node
41671
41672
41673 this._temporaryBindUI("onDragEnd", bind$6(_context17 = this._controlNodeDragEnd).call(_context17, this)); // used to connect or revert control nodes
41674
41675
41676 this._temporaryBindUI("onMouseMove", function () {}); // disabled
41677 // create function to position control nodes correctly on movement
41678 // automatically cleaned up because we use the temporary bind
41679
41680
41681 this._temporaryBindEvent("beforeDrawing", function (ctx) {
41682 var positions = _edge.edgeType.findBorderPositions(ctx);
41683
41684 if (controlNodeFrom.selected === false) {
41685 controlNodeFrom.x = positions.from.x;
41686 controlNodeFrom.y = positions.from.y;
41687 }
41688
41689 if (controlNodeTo.selected === false) {
41690 controlNodeTo.x = positions.to.x;
41691 controlNodeTo.y = positions.to.y;
41692 }
41693 });
41694
41695 this.body.emitter.emit("_redraw");
41696 } else {
41697 this.showManipulatorToolbar();
41698 }
41699 }
41700 /**
41701 * delete everything in the selection
41702 */
41703
41704 }, {
41705 key: "deleteSelected",
41706 value: function deleteSelected() {
41707 var _this3 = this;
41708
41709 // when using the gui, enable edit mode if it wasnt already.
41710 if (this.editMode !== true) {
41711 this.enableEditMode();
41712 } // restore the state of any bound functions or events, remove control nodes, restore physics
41713
41714
41715 this._clean();
41716
41717 this.inMode = "delete";
41718 var selectedNodes = this.selectionHandler.getSelectedNodeIds();
41719 var selectedEdges = this.selectionHandler.getSelectedEdgeIds();
41720 var deleteFunction = undefined;
41721
41722 if (selectedNodes.length > 0) {
41723 for (var i = 0; i < selectedNodes.length; i++) {
41724 if (this.body.nodes[selectedNodes[i]].isCluster === true) {
41725 alert(this.options.locales[this.options.locale]["deleteClusterError"] || this.options.locales["en"]["deleteClusterError"]);
41726 return;
41727 }
41728 }
41729
41730 if (typeof this.options.deleteNode === "function") {
41731 deleteFunction = this.options.deleteNode;
41732 }
41733 } else if (selectedEdges.length > 0) {
41734 if (typeof this.options.deleteEdge === "function") {
41735 deleteFunction = this.options.deleteEdge;
41736 }
41737 }
41738
41739 if (typeof deleteFunction === "function") {
41740 var data = {
41741 nodes: selectedNodes,
41742 edges: selectedEdges
41743 };
41744
41745 if (deleteFunction.length === 2) {
41746 deleteFunction(data, function (finalizedData) {
41747 if (finalizedData !== null && finalizedData !== undefined && _this3.inMode === "delete") {
41748 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
41749 _this3.body.data.edges.getDataSet().remove(finalizedData.edges);
41750
41751 _this3.body.data.nodes.getDataSet().remove(finalizedData.nodes);
41752
41753 _this3.body.emitter.emit("startSimulation");
41754
41755 _this3.showManipulatorToolbar();
41756 } else {
41757 _this3.body.emitter.emit("startSimulation");
41758
41759 _this3.showManipulatorToolbar();
41760 }
41761 });
41762 } else {
41763 throw new Error("The function for delete does not support two arguments (data, callback)");
41764 }
41765 } else {
41766 this.body.data.edges.getDataSet().remove(selectedEdges);
41767 this.body.data.nodes.getDataSet().remove(selectedNodes);
41768 this.body.emitter.emit("startSimulation");
41769 this.showManipulatorToolbar();
41770 }
41771 } //********************************************** PRIVATE ***************************************//
41772
41773 /**
41774 * draw or remove the DOM
41775 *
41776 * @private
41777 */
41778
41779 }, {
41780 key: "_setup",
41781 value: function _setup() {
41782 if (this.options.enabled === true) {
41783 // Enable the GUI
41784 this.guiEnabled = true;
41785
41786 this._createWrappers();
41787
41788 if (this.editMode === false) {
41789 this._createEditButton();
41790 } else {
41791 this.showManipulatorToolbar();
41792 }
41793 } else {
41794 this._removeManipulationDOM(); // disable the gui
41795
41796
41797 this.guiEnabled = false;
41798 }
41799 }
41800 /**
41801 * create the div overlays that contain the DOM
41802 *
41803 * @private
41804 */
41805
41806 }, {
41807 key: "_createWrappers",
41808 value: function _createWrappers() {
41809 // load the manipulator HTML elements. All styling done in css.
41810 if (this.manipulationDiv === undefined) {
41811 this.manipulationDiv = document.createElement("div");
41812 this.manipulationDiv.className = "vis-manipulation";
41813
41814 if (this.editMode === true) {
41815 this.manipulationDiv.style.display = "block";
41816 } else {
41817 this.manipulationDiv.style.display = "none";
41818 }
41819
41820 this.canvas.frame.appendChild(this.manipulationDiv);
41821 } // container for the edit button.
41822
41823
41824 if (this.editModeDiv === undefined) {
41825 this.editModeDiv = document.createElement("div");
41826 this.editModeDiv.className = "vis-edit-mode";
41827
41828 if (this.editMode === true) {
41829 this.editModeDiv.style.display = "none";
41830 } else {
41831 this.editModeDiv.style.display = "block";
41832 }
41833
41834 this.canvas.frame.appendChild(this.editModeDiv);
41835 } // container for the close div button
41836
41837
41838 if (this.closeDiv === undefined) {
41839 var _this$options$locales, _this$options$locales2;
41840
41841 this.closeDiv = document.createElement("button");
41842 this.closeDiv.className = "vis-close";
41843 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"]);
41844 this.closeDiv.style.display = this.manipulationDiv.style.display;
41845 this.canvas.frame.appendChild(this.closeDiv);
41846 }
41847 }
41848 /**
41849 * generate a new target node. Used for creating new edges and editing edges
41850 *
41851 * @param {number} x
41852 * @param {number} y
41853 * @returns {Node}
41854 * @private
41855 */
41856
41857 }, {
41858 key: "_getNewTargetNode",
41859 value: function _getNewTargetNode(x, y) {
41860 var controlNodeStyle = deepExtend({}, this.options.controlNodeStyle);
41861 controlNodeStyle.id = "targetNode" + v4();
41862 controlNodeStyle.hidden = false;
41863 controlNodeStyle.physics = false;
41864 controlNodeStyle.x = x;
41865 controlNodeStyle.y = y; // we have to define the bounding box in order for the nodes to be drawn immediately
41866
41867 var node = this.body.functions.createNode(controlNodeStyle);
41868 node.shape.boundingBox = {
41869 left: x,
41870 right: x,
41871 top: y,
41872 bottom: y
41873 };
41874 return node;
41875 }
41876 /**
41877 * Create the edit button
41878 */
41879
41880 }, {
41881 key: "_createEditButton",
41882 value: function _createEditButton() {
41883 var _context18;
41884
41885 // restore everything to it's original state (if applicable)
41886 this._clean(); // reset the manipulationDOM
41887
41888
41889 this.manipulationDOM = {}; // empty the editModeDiv
41890
41891 recursiveDOMDelete(this.editModeDiv); // create the contents for the editMode button
41892
41893 var locale = this.options.locales[this.options.locale];
41894
41895 var button = this._createButton("editMode", "vis-edit vis-edit-mode", locale["edit"] || this.options.locales["en"]["edit"]);
41896
41897 this.editModeDiv.appendChild(button); // bind a hammer listener to the button, calling the function toggleEditMode.
41898
41899 this._bindElementEvents(button, bind$6(_context18 = this.toggleEditMode).call(_context18, this));
41900 }
41901 /**
41902 * this function cleans up after everything this module does. Temporary elements, functions and events are removed, physics restored, hammers removed.
41903 *
41904 * @private
41905 */
41906
41907 }, {
41908 key: "_clean",
41909 value: function _clean() {
41910 // not in mode
41911 this.inMode = false; // _clean the divs
41912
41913 if (this.guiEnabled === true) {
41914 recursiveDOMDelete(this.editModeDiv);
41915 recursiveDOMDelete(this.manipulationDiv); // removes all the bindings and overloads
41916
41917 this._cleanupDOMEventListeners();
41918 } // remove temporary nodes and edges
41919
41920
41921 this._cleanupTemporaryNodesAndEdges(); // restore overloaded UI functions
41922
41923
41924 this._unbindTemporaryUIs(); // remove the temporaryEventFunctions
41925
41926
41927 this._unbindTemporaryEvents(); // restore the physics if required
41928
41929
41930 this.body.emitter.emit("restorePhysics");
41931 }
41932 /**
41933 * Each dom element has it's own hammer. They are stored in this.manipulationHammers. This cleans them up.
41934 *
41935 * @private
41936 */
41937
41938 }, {
41939 key: "_cleanupDOMEventListeners",
41940 value: function _cleanupDOMEventListeners() {
41941 var _context19;
41942
41943 // _clean DOM event listener bindings
41944 var _iterator = _createForOfIteratorHelper(splice$1(_context19 = this._domEventListenerCleanupQueue).call(_context19, 0)),
41945 _step;
41946
41947 try {
41948 for (_iterator.s(); !(_step = _iterator.n()).done;) {
41949 var callback = _step.value;
41950 callback();
41951 }
41952 } catch (err) {
41953 _iterator.e(err);
41954 } finally {
41955 _iterator.f();
41956 }
41957 }
41958 /**
41959 * Remove all DOM elements created by this module.
41960 *
41961 * @private
41962 */
41963
41964 }, {
41965 key: "_removeManipulationDOM",
41966 value: function _removeManipulationDOM() {
41967 // removes all the bindings and overloads
41968 this._clean(); // empty the manipulation divs
41969
41970
41971 recursiveDOMDelete(this.manipulationDiv);
41972 recursiveDOMDelete(this.editModeDiv);
41973 recursiveDOMDelete(this.closeDiv); // remove the manipulation divs
41974
41975 if (this.manipulationDiv) {
41976 this.canvas.frame.removeChild(this.manipulationDiv);
41977 }
41978
41979 if (this.editModeDiv) {
41980 this.canvas.frame.removeChild(this.editModeDiv);
41981 }
41982
41983 if (this.closeDiv) {
41984 this.canvas.frame.removeChild(this.closeDiv);
41985 } // set the references to undefined
41986
41987
41988 this.manipulationDiv = undefined;
41989 this.editModeDiv = undefined;
41990 this.closeDiv = undefined;
41991 }
41992 /**
41993 * create a seperator line. the index is to differentiate in the manipulation dom
41994 *
41995 * @param {number} [index=1]
41996 * @private
41997 */
41998
41999 }, {
42000 key: "_createSeperator",
42001 value: function _createSeperator() {
42002 var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
42003 this.manipulationDOM["seperatorLineDiv" + index] = document.createElement("div");
42004 this.manipulationDOM["seperatorLineDiv" + index].className = "vis-separator-line";
42005 this.manipulationDiv.appendChild(this.manipulationDOM["seperatorLineDiv" + index]);
42006 } // ---------------------- DOM functions for buttons --------------------------//
42007
42008 /**
42009 *
42010 * @param {Locale} locale
42011 * @private
42012 */
42013
42014 }, {
42015 key: "_createAddNodeButton",
42016 value: function _createAddNodeButton(locale) {
42017 var _context20;
42018
42019 var button = this._createButton("addNode", "vis-add", locale["addNode"] || this.options.locales["en"]["addNode"]);
42020
42021 this.manipulationDiv.appendChild(button);
42022
42023 this._bindElementEvents(button, bind$6(_context20 = this.addNodeMode).call(_context20, this));
42024 }
42025 /**
42026 *
42027 * @param {Locale} locale
42028 * @private
42029 */
42030
42031 }, {
42032 key: "_createAddEdgeButton",
42033 value: function _createAddEdgeButton(locale) {
42034 var _context21;
42035
42036 var button = this._createButton("addEdge", "vis-connect", locale["addEdge"] || this.options.locales["en"]["addEdge"]);
42037
42038 this.manipulationDiv.appendChild(button);
42039
42040 this._bindElementEvents(button, bind$6(_context21 = this.addEdgeMode).call(_context21, this));
42041 }
42042 /**
42043 *
42044 * @param {Locale} locale
42045 * @private
42046 */
42047
42048 }, {
42049 key: "_createEditNodeButton",
42050 value: function _createEditNodeButton(locale) {
42051 var _context22;
42052
42053 var button = this._createButton("editNode", "vis-edit", locale["editNode"] || this.options.locales["en"]["editNode"]);
42054
42055 this.manipulationDiv.appendChild(button);
42056
42057 this._bindElementEvents(button, bind$6(_context22 = this.editNode).call(_context22, this));
42058 }
42059 /**
42060 *
42061 * @param {Locale} locale
42062 * @private
42063 */
42064
42065 }, {
42066 key: "_createEditEdgeButton",
42067 value: function _createEditEdgeButton(locale) {
42068 var _context23;
42069
42070 var button = this._createButton("editEdge", "vis-edit", locale["editEdge"] || this.options.locales["en"]["editEdge"]);
42071
42072 this.manipulationDiv.appendChild(button);
42073
42074 this._bindElementEvents(button, bind$6(_context23 = this.editEdgeMode).call(_context23, this));
42075 }
42076 /**
42077 *
42078 * @param {Locale} locale
42079 * @private
42080 */
42081
42082 }, {
42083 key: "_createDeleteButton",
42084 value: function _createDeleteButton(locale) {
42085 var _context24;
42086
42087 var deleteBtnClass;
42088
42089 if (this.options.rtl) {
42090 deleteBtnClass = "vis-delete-rtl";
42091 } else {
42092 deleteBtnClass = "vis-delete";
42093 }
42094
42095 var button = this._createButton("delete", deleteBtnClass, locale["del"] || this.options.locales["en"]["del"]);
42096
42097 this.manipulationDiv.appendChild(button);
42098
42099 this._bindElementEvents(button, bind$6(_context24 = this.deleteSelected).call(_context24, this));
42100 }
42101 /**
42102 *
42103 * @param {Locale} locale
42104 * @private
42105 */
42106
42107 }, {
42108 key: "_createBackButton",
42109 value: function _createBackButton(locale) {
42110 var _context25;
42111
42112 var button = this._createButton("back", "vis-back", locale["back"] || this.options.locales["en"]["back"]);
42113
42114 this.manipulationDiv.appendChild(button);
42115
42116 this._bindElementEvents(button, bind$6(_context25 = this.showManipulatorToolbar).call(_context25, this));
42117 }
42118 /**
42119 *
42120 * @param {number|string} id
42121 * @param {string} className
42122 * @param {label} label
42123 * @param {string} labelClassName
42124 * @returns {HTMLElement}
42125 * @private
42126 */
42127
42128 }, {
42129 key: "_createButton",
42130 value: function _createButton(id, className, label) {
42131 var labelClassName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "vis-label";
42132 this.manipulationDOM[id + "Div"] = document.createElement("button");
42133 this.manipulationDOM[id + "Div"].className = "vis-button " + className;
42134 this.manipulationDOM[id + "Label"] = document.createElement("div");
42135 this.manipulationDOM[id + "Label"].className = labelClassName;
42136 this.manipulationDOM[id + "Label"].innerText = label;
42137 this.manipulationDOM[id + "Div"].appendChild(this.manipulationDOM[id + "Label"]);
42138 return this.manipulationDOM[id + "Div"];
42139 }
42140 /**
42141 *
42142 * @param {Label} label
42143 * @private
42144 */
42145
42146 }, {
42147 key: "_createDescription",
42148 value: function _createDescription(label) {
42149 this.manipulationDOM["descriptionLabel"] = document.createElement("div");
42150 this.manipulationDOM["descriptionLabel"].className = "vis-none";
42151 this.manipulationDOM["descriptionLabel"].innerText = label;
42152 this.manipulationDiv.appendChild(this.manipulationDOM["descriptionLabel"]);
42153 } // -------------------------- End of DOM functions for buttons ------------------------------//
42154
42155 /**
42156 * this binds an event until cleanup by the clean functions.
42157 *
42158 * @param {Event} event The event
42159 * @param {Function} newFunction
42160 * @private
42161 */
42162
42163 }, {
42164 key: "_temporaryBindEvent",
42165 value: function _temporaryBindEvent(event, newFunction) {
42166 this.temporaryEventFunctions.push({
42167 event: event,
42168 boundFunction: newFunction
42169 });
42170 this.body.emitter.on(event, newFunction);
42171 }
42172 /**
42173 * this overrides an UI function until cleanup by the clean function
42174 *
42175 * @param {string} UIfunctionName
42176 * @param {Function} newFunction
42177 * @private
42178 */
42179
42180 }, {
42181 key: "_temporaryBindUI",
42182 value: function _temporaryBindUI(UIfunctionName, newFunction) {
42183 if (this.body.eventListeners[UIfunctionName] !== undefined) {
42184 this.temporaryUIFunctions[UIfunctionName] = this.body.eventListeners[UIfunctionName];
42185 this.body.eventListeners[UIfunctionName] = newFunction;
42186 } else {
42187 throw new Error("This UI function does not exist. Typo? You tried: " + UIfunctionName + " possible are: " + stringify$1(keys$4(this.body.eventListeners)));
42188 }
42189 }
42190 /**
42191 * Restore the overridden UI functions to their original state.
42192 *
42193 * @private
42194 */
42195
42196 }, {
42197 key: "_unbindTemporaryUIs",
42198 value: function _unbindTemporaryUIs() {
42199 for (var functionName in this.temporaryUIFunctions) {
42200 if (Object.prototype.hasOwnProperty.call(this.temporaryUIFunctions, functionName)) {
42201 this.body.eventListeners[functionName] = this.temporaryUIFunctions[functionName];
42202 delete this.temporaryUIFunctions[functionName];
42203 }
42204 }
42205
42206 this.temporaryUIFunctions = {};
42207 }
42208 /**
42209 * Unbind the events created by _temporaryBindEvent
42210 *
42211 * @private
42212 */
42213
42214 }, {
42215 key: "_unbindTemporaryEvents",
42216 value: function _unbindTemporaryEvents() {
42217 for (var i = 0; i < this.temporaryEventFunctions.length; i++) {
42218 var eventName = this.temporaryEventFunctions[i].event;
42219 var boundFunction = this.temporaryEventFunctions[i].boundFunction;
42220 this.body.emitter.off(eventName, boundFunction);
42221 }
42222
42223 this.temporaryEventFunctions = [];
42224 }
42225 /**
42226 * Bind an hammer instance to a DOM element.
42227 *
42228 * @param {Element} domElement
42229 * @param {Function} boundFunction
42230 */
42231
42232 }, {
42233 key: "_bindElementEvents",
42234 value: function _bindElementEvents(domElement, boundFunction) {
42235 // Bind touch events.
42236 var hammer = new Hammer(domElement, {});
42237 onTouch(hammer, boundFunction);
42238
42239 this._domEventListenerCleanupQueue.push(function () {
42240 hammer.destroy();
42241 }); // Bind keyboard events.
42242
42243
42244 var keyupListener = function keyupListener(_ref) {
42245 var keyCode = _ref.keyCode,
42246 key = _ref.key;
42247
42248 if (key === "Enter" || key === " " || keyCode === 13 || keyCode === 32) {
42249 boundFunction();
42250 }
42251 };
42252
42253 domElement.addEventListener("keyup", keyupListener, false);
42254
42255 this._domEventListenerCleanupQueue.push(function () {
42256 domElement.removeEventListener("keyup", keyupListener, false);
42257 });
42258 }
42259 /**
42260 * Neatly clean up temporary edges and nodes
42261 *
42262 * @private
42263 */
42264
42265 }, {
42266 key: "_cleanupTemporaryNodesAndEdges",
42267 value: function _cleanupTemporaryNodesAndEdges() {
42268 // _clean temporary edges
42269 for (var i = 0; i < this.temporaryIds.edges.length; i++) {
42270 var _context26;
42271
42272 this.body.edges[this.temporaryIds.edges[i]].disconnect();
42273 delete this.body.edges[this.temporaryIds.edges[i]];
42274
42275 var indexTempEdge = indexOf(_context26 = this.body.edgeIndices).call(_context26, this.temporaryIds.edges[i]);
42276
42277 if (indexTempEdge !== -1) {
42278 var _context27;
42279
42280 splice$1(_context27 = this.body.edgeIndices).call(_context27, indexTempEdge, 1);
42281 }
42282 } // _clean temporary nodes
42283
42284
42285 for (var _i = 0; _i < this.temporaryIds.nodes.length; _i++) {
42286 var _context28;
42287
42288 delete this.body.nodes[this.temporaryIds.nodes[_i]];
42289
42290 var indexTempNode = indexOf(_context28 = this.body.nodeIndices).call(_context28, this.temporaryIds.nodes[_i]);
42291
42292 if (indexTempNode !== -1) {
42293 var _context29;
42294
42295 splice$1(_context29 = this.body.nodeIndices).call(_context29, indexTempNode, 1);
42296 }
42297 }
42298
42299 this.temporaryIds = {
42300 nodes: [],
42301 edges: []
42302 };
42303 } // ------------------------------------------ EDIT EDGE FUNCTIONS -----------------------------------------//
42304
42305 /**
42306 * the touch is used to get the position of the initial click
42307 *
42308 * @param {Event} event The event
42309 * @private
42310 */
42311
42312 }, {
42313 key: "_controlNodeTouch",
42314 value: function _controlNodeTouch(event) {
42315 this.selectionHandler.unselectAll();
42316 this.lastTouch = this.body.functions.getPointer(event.center);
42317 this.lastTouch.translation = assign$2({}, this.body.view.translation); // copy the object
42318 }
42319 /**
42320 * the drag start is used to mark one of the control nodes as selected.
42321 *
42322 * @private
42323 */
42324
42325 }, {
42326 key: "_controlNodeDragStart",
42327 value: function _controlNodeDragStart() {
42328 var pointer = this.lastTouch;
42329
42330 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
42331
42332 var from = this.body.nodes[this.temporaryIds.nodes[0]];
42333 var to = this.body.nodes[this.temporaryIds.nodes[1]];
42334 var edge = this.body.edges[this.edgeBeingEditedId];
42335 this.selectedControlNode = undefined;
42336 var fromSelect = from.isOverlappingWith(pointerObj);
42337 var toSelect = to.isOverlappingWith(pointerObj);
42338
42339 if (fromSelect === true) {
42340 this.selectedControlNode = from;
42341 edge.edgeType.from = from;
42342 } else if (toSelect === true) {
42343 this.selectedControlNode = to;
42344 edge.edgeType.to = to;
42345 } // we use the selection to find the node that is being dragged. We explicitly select it here.
42346
42347
42348 if (this.selectedControlNode !== undefined) {
42349 this.selectionHandler.selectObject(this.selectedControlNode);
42350 }
42351
42352 this.body.emitter.emit("_redraw");
42353 }
42354 /**
42355 * dragging the control nodes or the canvas
42356 *
42357 * @param {Event} event The event
42358 * @private
42359 */
42360
42361 }, {
42362 key: "_controlNodeDrag",
42363 value: function _controlNodeDrag(event) {
42364 this.body.emitter.emit("disablePhysics");
42365 var pointer = this.body.functions.getPointer(event.center);
42366 var pos = this.canvas.DOMtoCanvas(pointer);
42367
42368 if (this.selectedControlNode !== undefined) {
42369 this.selectedControlNode.x = pos.x;
42370 this.selectedControlNode.y = pos.y;
42371 } else {
42372 this.interactionHandler.onDrag(event);
42373 }
42374
42375 this.body.emitter.emit("_redraw");
42376 }
42377 /**
42378 * connecting or restoring the control nodes.
42379 *
42380 * @param {Event} event The event
42381 * @private
42382 */
42383
42384 }, {
42385 key: "_controlNodeDragEnd",
42386 value: function _controlNodeDragEnd(event) {
42387 var pointer = this.body.functions.getPointer(event.center);
42388
42389 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
42390
42391 var edge = this.body.edges[this.edgeBeingEditedId]; // if the node that was dragged is not a control node, return
42392
42393 if (this.selectedControlNode === undefined) {
42394 return;
42395 } // we use the selection to find the node that is being dragged. We explicitly DEselect the control node here.
42396
42397
42398 this.selectionHandler.unselectAll();
42399
42400 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
42401
42402 var node = undefined;
42403
42404 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
42405 if (overlappingNodeIds[i] !== this.selectedControlNode.id) {
42406 node = this.body.nodes[overlappingNodeIds[i]];
42407 break;
42408 }
42409 } // perform the connection
42410
42411
42412 if (node !== undefined && this.selectedControlNode !== undefined) {
42413 if (node.isCluster === true) {
42414 alert(this.options.locales[this.options.locale]["createEdgeError"] || this.options.locales["en"]["createEdgeError"]);
42415 } else {
42416 var from = this.body.nodes[this.temporaryIds.nodes[0]];
42417
42418 if (this.selectedControlNode.id === from.id) {
42419 this._performEditEdge(node.id, edge.to.id);
42420 } else {
42421 this._performEditEdge(edge.from.id, node.id);
42422 }
42423 }
42424 } else {
42425 edge.updateEdgeType();
42426 this.body.emitter.emit("restorePhysics");
42427 }
42428
42429 this.body.emitter.emit("_redraw");
42430 } // ------------------------------------ END OF EDIT EDGE FUNCTIONS -----------------------------------------//
42431 // ------------------------------------------- ADD EDGE FUNCTIONS -----------------------------------------//
42432
42433 /**
42434 * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
42435 * to walk the user through the process.
42436 *
42437 * @param {Event} event
42438 * @private
42439 */
42440
42441 }, {
42442 key: "_handleConnect",
42443 value: function _handleConnect(event) {
42444 // check to avoid double fireing of this function.
42445 if (new Date().valueOf() - this.touchTime > 100) {
42446 this.lastTouch = this.body.functions.getPointer(event.center);
42447 this.lastTouch.translation = assign$2({}, this.body.view.translation); // copy the object
42448
42449 this.interactionHandler.drag.pointer = this.lastTouch; // Drag pointer is not updated when adding edges
42450
42451 this.interactionHandler.drag.translation = this.lastTouch.translation;
42452 var pointer = this.lastTouch;
42453 var node = this.selectionHandler.getNodeAt(pointer);
42454
42455 if (node !== undefined) {
42456 if (node.isCluster === true) {
42457 alert(this.options.locales[this.options.locale]["createEdgeError"] || this.options.locales["en"]["createEdgeError"]);
42458 } else {
42459 // create a node the temporary line can look at
42460 var targetNode = this._getNewTargetNode(node.x, node.y);
42461
42462 this.body.nodes[targetNode.id] = targetNode;
42463 this.body.nodeIndices.push(targetNode.id); // create a temporary edge
42464
42465 var connectionEdge = this.body.functions.createEdge({
42466 id: "connectionEdge" + v4(),
42467 from: node.id,
42468 to: targetNode.id,
42469 physics: false,
42470 smooth: {
42471 enabled: true,
42472 type: "continuous",
42473 roundness: 0.5
42474 }
42475 });
42476 this.body.edges[connectionEdge.id] = connectionEdge;
42477 this.body.edgeIndices.push(connectionEdge.id);
42478 this.temporaryIds.nodes.push(targetNode.id);
42479 this.temporaryIds.edges.push(connectionEdge.id);
42480 }
42481 }
42482
42483 this.touchTime = new Date().valueOf();
42484 }
42485 }
42486 /**
42487 *
42488 * @param {Event} event
42489 * @private
42490 */
42491
42492 }, {
42493 key: "_dragControlNode",
42494 value: function _dragControlNode(event) {
42495 var pointer = this.body.functions.getPointer(event.center);
42496
42497 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
42498
42499
42500 var connectFromId = undefined;
42501
42502 if (this.temporaryIds.edges[0] !== undefined) {
42503 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
42504 } // get the overlapping node but NOT the temporary node;
42505
42506
42507 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
42508
42509 var node = undefined;
42510
42511 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
42512 var _context30;
42513
42514 // if the node id is NOT a temporary node, accept the node.
42515 if (indexOf(_context30 = this.temporaryIds.nodes).call(_context30, overlappingNodeIds[i]) === -1) {
42516 node = this.body.nodes[overlappingNodeIds[i]];
42517 break;
42518 }
42519 }
42520
42521 event.controlEdge = {
42522 from: connectFromId,
42523 to: node ? node.id : undefined
42524 };
42525 this.selectionHandler.generateClickEvent("controlNodeDragging", event, pointer);
42526
42527 if (this.temporaryIds.nodes[0] !== undefined) {
42528 var targetNode = this.body.nodes[this.temporaryIds.nodes[0]]; // there is only one temp node in the add edge mode.
42529
42530 targetNode.x = this.canvas._XconvertDOMtoCanvas(pointer.x);
42531 targetNode.y = this.canvas._YconvertDOMtoCanvas(pointer.y);
42532 this.body.emitter.emit("_redraw");
42533 } else {
42534 this.interactionHandler.onDrag(event);
42535 }
42536 }
42537 /**
42538 * Connect the new edge to the target if one exists, otherwise remove temp line
42539 *
42540 * @param {Event} event The event
42541 * @private
42542 */
42543
42544 }, {
42545 key: "_finishConnect",
42546 value: function _finishConnect(event) {
42547 var pointer = this.body.functions.getPointer(event.center);
42548
42549 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
42550
42551
42552 var connectFromId = undefined;
42553
42554 if (this.temporaryIds.edges[0] !== undefined) {
42555 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
42556 } // get the overlapping node but NOT the temporary node;
42557
42558
42559 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
42560
42561 var node = undefined;
42562
42563 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
42564 var _context31;
42565
42566 // if the node id is NOT a temporary node, accept the node.
42567 if (indexOf(_context31 = this.temporaryIds.nodes).call(_context31, overlappingNodeIds[i]) === -1) {
42568 node = this.body.nodes[overlappingNodeIds[i]];
42569 break;
42570 }
42571 } // clean temporary nodes and edges.
42572
42573
42574 this._cleanupTemporaryNodesAndEdges(); // perform the connection
42575
42576
42577 if (node !== undefined) {
42578 if (node.isCluster === true) {
42579 alert(this.options.locales[this.options.locale]["createEdgeError"] || this.options.locales["en"]["createEdgeError"]);
42580 } else {
42581 if (this.body.nodes[connectFromId] !== undefined && this.body.nodes[node.id] !== undefined) {
42582 this._performAddEdge(connectFromId, node.id);
42583 }
42584 }
42585 }
42586
42587 event.controlEdge = {
42588 from: connectFromId,
42589 to: node ? node.id : undefined
42590 };
42591 this.selectionHandler.generateClickEvent("controlNodeDragEnd", event, pointer); // No need to do _generateclickevent('dragEnd') here, the regular dragEnd event fires.
42592
42593 this.body.emitter.emit("_redraw");
42594 }
42595 /**
42596 *
42597 * @param {Event} event
42598 * @private
42599 */
42600
42601 }, {
42602 key: "_dragStartEdge",
42603 value: function _dragStartEdge(event) {
42604 var pointer = this.lastTouch;
42605 this.selectionHandler.generateClickEvent("dragStart", event, pointer, undefined, true);
42606 } // --------------------------------------- END OF ADD EDGE FUNCTIONS -------------------------------------//
42607 // ------------------------------ Performing all the actual data manipulation ------------------------//
42608
42609 /**
42610 * Adds a node on the specified location
42611 *
42612 * @param {object} clickData
42613 * @private
42614 */
42615
42616 }, {
42617 key: "_performAddNode",
42618 value: function _performAddNode(clickData) {
42619 var _this4 = this;
42620
42621 var defaultData = {
42622 id: v4(),
42623 x: clickData.pointer.canvas.x,
42624 y: clickData.pointer.canvas.y,
42625 label: "new"
42626 };
42627
42628 if (typeof this.options.addNode === "function") {
42629 if (this.options.addNode.length === 2) {
42630 this.options.addNode(defaultData, function (finalizedData) {
42631 if (finalizedData !== null && finalizedData !== undefined && _this4.inMode === "addNode") {
42632 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
42633 _this4.body.data.nodes.getDataSet().add(finalizedData);
42634 }
42635
42636 _this4.showManipulatorToolbar();
42637 });
42638 } else {
42639 this.showManipulatorToolbar();
42640 throw new Error("The function for add does not support two arguments (data,callback)");
42641 }
42642 } else {
42643 this.body.data.nodes.getDataSet().add(defaultData);
42644 this.showManipulatorToolbar();
42645 }
42646 }
42647 /**
42648 * connect two nodes with a new edge.
42649 *
42650 * @param {Node.id} sourceNodeId
42651 * @param {Node.id} targetNodeId
42652 * @private
42653 */
42654
42655 }, {
42656 key: "_performAddEdge",
42657 value: function _performAddEdge(sourceNodeId, targetNodeId) {
42658 var _this5 = this;
42659
42660 var defaultData = {
42661 from: sourceNodeId,
42662 to: targetNodeId
42663 };
42664
42665 if (typeof this.options.addEdge === "function") {
42666 if (this.options.addEdge.length === 2) {
42667 this.options.addEdge(defaultData, function (finalizedData) {
42668 if (finalizedData !== null && finalizedData !== undefined && _this5.inMode === "addEdge") {
42669 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
42670 _this5.body.data.edges.getDataSet().add(finalizedData);
42671
42672 _this5.selectionHandler.unselectAll();
42673
42674 _this5.showManipulatorToolbar();
42675 }
42676 });
42677 } else {
42678 throw new Error("The function for connect does not support two arguments (data,callback)");
42679 }
42680 } else {
42681 this.body.data.edges.getDataSet().add(defaultData);
42682 this.selectionHandler.unselectAll();
42683 this.showManipulatorToolbar();
42684 }
42685 }
42686 /**
42687 * connect two nodes with a new edge.
42688 *
42689 * @param {Node.id} sourceNodeId
42690 * @param {Node.id} targetNodeId
42691 * @private
42692 */
42693
42694 }, {
42695 key: "_performEditEdge",
42696 value: function _performEditEdge(sourceNodeId, targetNodeId) {
42697 var _this6 = this;
42698
42699 var defaultData = {
42700 id: this.edgeBeingEditedId,
42701 from: sourceNodeId,
42702 to: targetNodeId,
42703 label: this.body.data.edges.get(this.edgeBeingEditedId).label
42704 };
42705 var eeFunct = this.options.editEdge;
42706
42707 if (_typeof(eeFunct) === "object") {
42708 eeFunct = eeFunct.editWithoutDrag;
42709 }
42710
42711 if (typeof eeFunct === "function") {
42712 if (eeFunct.length === 2) {
42713 eeFunct(defaultData, function (finalizedData) {
42714 if (finalizedData === null || finalizedData === undefined || _this6.inMode !== "editEdge") {
42715 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
42716 _this6.body.edges[defaultData.id].updateEdgeType();
42717
42718 _this6.body.emitter.emit("_redraw");
42719
42720 _this6.showManipulatorToolbar();
42721 } else {
42722 _this6.body.data.edges.getDataSet().update(finalizedData);
42723
42724 _this6.selectionHandler.unselectAll();
42725
42726 _this6.showManipulatorToolbar();
42727 }
42728 });
42729 } else {
42730 throw new Error("The function for edit does not support two arguments (data, callback)");
42731 }
42732 } else {
42733 this.body.data.edges.getDataSet().update(defaultData);
42734 this.selectionHandler.unselectAll();
42735 this.showManipulatorToolbar();
42736 }
42737 }
42738 }]);
42739
42740 return ManipulationSystem;
42741 }();
42742
42743 /**
42744 * This object contains all possible options. It will check if the types are correct, if required if the option is one
42745 * of the allowed values.
42746 *
42747 * __any__ means that the name of the property does not matter.
42748 * __type__ is a required field for all objects and contains the allowed types of all objects
42749 */
42750 var string = "string";
42751 var bool = "boolean";
42752 var number = "number";
42753 var array = "array";
42754 var object = "object"; // should only be in a __type__ property
42755
42756 var dom = "dom";
42757 var any = "any"; // List of endpoints
42758
42759 var endPoints = ["arrow", "bar", "box", "circle", "crow", "curve", "diamond", "image", "inv_curve", "inv_triangle", "triangle", "vee"];
42760 /* eslint-disable @typescript-eslint/naming-convention -- The __*__ format is used to prevent collisions with actual option names. */
42761
42762 var nodeOptions = {
42763 borderWidth: {
42764 number: number
42765 },
42766 borderWidthSelected: {
42767 number: number,
42768 undefined: "undefined"
42769 },
42770 brokenImage: {
42771 string: string,
42772 undefined: "undefined"
42773 },
42774 chosen: {
42775 label: {
42776 boolean: bool,
42777 function: "function"
42778 },
42779 node: {
42780 boolean: bool,
42781 function: "function"
42782 },
42783 __type__: {
42784 object: object,
42785 boolean: bool
42786 }
42787 },
42788 color: {
42789 border: {
42790 string: string
42791 },
42792 background: {
42793 string: string
42794 },
42795 highlight: {
42796 border: {
42797 string: string
42798 },
42799 background: {
42800 string: string
42801 },
42802 __type__: {
42803 object: object,
42804 string: string
42805 }
42806 },
42807 hover: {
42808 border: {
42809 string: string
42810 },
42811 background: {
42812 string: string
42813 },
42814 __type__: {
42815 object: object,
42816 string: string
42817 }
42818 },
42819 __type__: {
42820 object: object,
42821 string: string
42822 }
42823 },
42824 opacity: {
42825 number: number,
42826 undefined: "undefined"
42827 },
42828 fixed: {
42829 x: {
42830 boolean: bool
42831 },
42832 y: {
42833 boolean: bool
42834 },
42835 __type__: {
42836 object: object,
42837 boolean: bool
42838 }
42839 },
42840 font: {
42841 align: {
42842 string: string
42843 },
42844 color: {
42845 string: string
42846 },
42847 size: {
42848 number: number
42849 },
42850 face: {
42851 string: string
42852 },
42853 background: {
42854 string: string
42855 },
42856 strokeWidth: {
42857 number: number
42858 },
42859 strokeColor: {
42860 string: string
42861 },
42862 vadjust: {
42863 number: number
42864 },
42865 multi: {
42866 boolean: bool,
42867 string: string
42868 },
42869 bold: {
42870 color: {
42871 string: string
42872 },
42873 size: {
42874 number: number
42875 },
42876 face: {
42877 string: string
42878 },
42879 mod: {
42880 string: string
42881 },
42882 vadjust: {
42883 number: number
42884 },
42885 __type__: {
42886 object: object,
42887 string: string
42888 }
42889 },
42890 boldital: {
42891 color: {
42892 string: string
42893 },
42894 size: {
42895 number: number
42896 },
42897 face: {
42898 string: string
42899 },
42900 mod: {
42901 string: string
42902 },
42903 vadjust: {
42904 number: number
42905 },
42906 __type__: {
42907 object: object,
42908 string: string
42909 }
42910 },
42911 ital: {
42912 color: {
42913 string: string
42914 },
42915 size: {
42916 number: number
42917 },
42918 face: {
42919 string: string
42920 },
42921 mod: {
42922 string: string
42923 },
42924 vadjust: {
42925 number: number
42926 },
42927 __type__: {
42928 object: object,
42929 string: string
42930 }
42931 },
42932 mono: {
42933 color: {
42934 string: string
42935 },
42936 size: {
42937 number: number
42938 },
42939 face: {
42940 string: string
42941 },
42942 mod: {
42943 string: string
42944 },
42945 vadjust: {
42946 number: number
42947 },
42948 __type__: {
42949 object: object,
42950 string: string
42951 }
42952 },
42953 __type__: {
42954 object: object,
42955 string: string
42956 }
42957 },
42958 group: {
42959 string: string,
42960 number: number,
42961 undefined: "undefined"
42962 },
42963 heightConstraint: {
42964 minimum: {
42965 number: number
42966 },
42967 valign: {
42968 string: string
42969 },
42970 __type__: {
42971 object: object,
42972 boolean: bool,
42973 number: number
42974 }
42975 },
42976 hidden: {
42977 boolean: bool
42978 },
42979 icon: {
42980 face: {
42981 string: string
42982 },
42983 code: {
42984 string: string
42985 },
42986 size: {
42987 number: number
42988 },
42989 color: {
42990 string: string
42991 },
42992 weight: {
42993 string: string,
42994 number: number
42995 },
42996 __type__: {
42997 object: object
42998 }
42999 },
43000 id: {
43001 string: string,
43002 number: number
43003 },
43004 image: {
43005 selected: {
43006 string: string,
43007 undefined: "undefined"
43008 },
43009 unselected: {
43010 string: string,
43011 undefined: "undefined"
43012 },
43013 __type__: {
43014 object: object,
43015 string: string
43016 }
43017 },
43018 imagePadding: {
43019 top: {
43020 number: number
43021 },
43022 right: {
43023 number: number
43024 },
43025 bottom: {
43026 number: number
43027 },
43028 left: {
43029 number: number
43030 },
43031 __type__: {
43032 object: object,
43033 number: number
43034 }
43035 },
43036 label: {
43037 string: string,
43038 undefined: "undefined"
43039 },
43040 labelHighlightBold: {
43041 boolean: bool
43042 },
43043 level: {
43044 number: number,
43045 undefined: "undefined"
43046 },
43047 margin: {
43048 top: {
43049 number: number
43050 },
43051 right: {
43052 number: number
43053 },
43054 bottom: {
43055 number: number
43056 },
43057 left: {
43058 number: number
43059 },
43060 __type__: {
43061 object: object,
43062 number: number
43063 }
43064 },
43065 mass: {
43066 number: number
43067 },
43068 physics: {
43069 boolean: bool
43070 },
43071 scaling: {
43072 min: {
43073 number: number
43074 },
43075 max: {
43076 number: number
43077 },
43078 label: {
43079 enabled: {
43080 boolean: bool
43081 },
43082 min: {
43083 number: number
43084 },
43085 max: {
43086 number: number
43087 },
43088 maxVisible: {
43089 number: number
43090 },
43091 drawThreshold: {
43092 number: number
43093 },
43094 __type__: {
43095 object: object,
43096 boolean: bool
43097 }
43098 },
43099 customScalingFunction: {
43100 function: "function"
43101 },
43102 __type__: {
43103 object: object
43104 }
43105 },
43106 shadow: {
43107 enabled: {
43108 boolean: bool
43109 },
43110 color: {
43111 string: string
43112 },
43113 size: {
43114 number: number
43115 },
43116 x: {
43117 number: number
43118 },
43119 y: {
43120 number: number
43121 },
43122 __type__: {
43123 object: object,
43124 boolean: bool
43125 }
43126 },
43127 shape: {
43128 string: ["custom", "ellipse", "circle", "database", "box", "text", "image", "circularImage", "diamond", "dot", "star", "triangle", "triangleDown", "square", "icon", "hexagon"]
43129 },
43130 ctxRenderer: {
43131 function: "function"
43132 },
43133 shapeProperties: {
43134 borderDashes: {
43135 boolean: bool,
43136 array: array
43137 },
43138 borderRadius: {
43139 number: number
43140 },
43141 interpolation: {
43142 boolean: bool
43143 },
43144 useImageSize: {
43145 boolean: bool
43146 },
43147 useBorderWithImage: {
43148 boolean: bool
43149 },
43150 coordinateOrigin: {
43151 string: ["center", "top-left"]
43152 },
43153 __type__: {
43154 object: object
43155 }
43156 },
43157 size: {
43158 number: number
43159 },
43160 title: {
43161 string: string,
43162 dom: dom,
43163 undefined: "undefined"
43164 },
43165 value: {
43166 number: number,
43167 undefined: "undefined"
43168 },
43169 widthConstraint: {
43170 minimum: {
43171 number: number
43172 },
43173 maximum: {
43174 number: number
43175 },
43176 __type__: {
43177 object: object,
43178 boolean: bool,
43179 number: number
43180 }
43181 },
43182 x: {
43183 number: number
43184 },
43185 y: {
43186 number: number
43187 },
43188 __type__: {
43189 object: object
43190 }
43191 };
43192 var allOptions = {
43193 configure: {
43194 enabled: {
43195 boolean: bool
43196 },
43197 filter: {
43198 boolean: bool,
43199 string: string,
43200 array: array,
43201 function: "function"
43202 },
43203 container: {
43204 dom: dom
43205 },
43206 showButton: {
43207 boolean: bool
43208 },
43209 __type__: {
43210 object: object,
43211 boolean: bool,
43212 string: string,
43213 array: array,
43214 function: "function"
43215 }
43216 },
43217 edges: {
43218 arrows: {
43219 to: {
43220 enabled: {
43221 boolean: bool
43222 },
43223 scaleFactor: {
43224 number: number
43225 },
43226 type: {
43227 string: endPoints
43228 },
43229 imageHeight: {
43230 number: number
43231 },
43232 imageWidth: {
43233 number: number
43234 },
43235 src: {
43236 string: string
43237 },
43238 __type__: {
43239 object: object,
43240 boolean: bool
43241 }
43242 },
43243 middle: {
43244 enabled: {
43245 boolean: bool
43246 },
43247 scaleFactor: {
43248 number: number
43249 },
43250 type: {
43251 string: endPoints
43252 },
43253 imageWidth: {
43254 number: number
43255 },
43256 imageHeight: {
43257 number: number
43258 },
43259 src: {
43260 string: string
43261 },
43262 __type__: {
43263 object: object,
43264 boolean: bool
43265 }
43266 },
43267 from: {
43268 enabled: {
43269 boolean: bool
43270 },
43271 scaleFactor: {
43272 number: number
43273 },
43274 type: {
43275 string: endPoints
43276 },
43277 imageWidth: {
43278 number: number
43279 },
43280 imageHeight: {
43281 number: number
43282 },
43283 src: {
43284 string: string
43285 },
43286 __type__: {
43287 object: object,
43288 boolean: bool
43289 }
43290 },
43291 __type__: {
43292 string: ["from", "to", "middle"],
43293 object: object
43294 }
43295 },
43296 endPointOffset: {
43297 from: {
43298 number: number
43299 },
43300 to: {
43301 number: number
43302 },
43303 __type__: {
43304 object: object,
43305 number: number
43306 }
43307 },
43308 arrowStrikethrough: {
43309 boolean: bool
43310 },
43311 background: {
43312 enabled: {
43313 boolean: bool
43314 },
43315 color: {
43316 string: string
43317 },
43318 size: {
43319 number: number
43320 },
43321 dashes: {
43322 boolean: bool,
43323 array: array
43324 },
43325 __type__: {
43326 object: object,
43327 boolean: bool
43328 }
43329 },
43330 chosen: {
43331 label: {
43332 boolean: bool,
43333 function: "function"
43334 },
43335 edge: {
43336 boolean: bool,
43337 function: "function"
43338 },
43339 __type__: {
43340 object: object,
43341 boolean: bool
43342 }
43343 },
43344 color: {
43345 color: {
43346 string: string
43347 },
43348 highlight: {
43349 string: string
43350 },
43351 hover: {
43352 string: string
43353 },
43354 inherit: {
43355 string: ["from", "to", "both"],
43356 boolean: bool
43357 },
43358 opacity: {
43359 number: number
43360 },
43361 __type__: {
43362 object: object,
43363 string: string
43364 }
43365 },
43366 dashes: {
43367 boolean: bool,
43368 array: array
43369 },
43370 font: {
43371 color: {
43372 string: string
43373 },
43374 size: {
43375 number: number
43376 },
43377 face: {
43378 string: string
43379 },
43380 background: {
43381 string: string
43382 },
43383 strokeWidth: {
43384 number: number
43385 },
43386 strokeColor: {
43387 string: string
43388 },
43389 align: {
43390 string: ["horizontal", "top", "middle", "bottom"]
43391 },
43392 vadjust: {
43393 number: number
43394 },
43395 multi: {
43396 boolean: bool,
43397 string: string
43398 },
43399 bold: {
43400 color: {
43401 string: string
43402 },
43403 size: {
43404 number: number
43405 },
43406 face: {
43407 string: string
43408 },
43409 mod: {
43410 string: string
43411 },
43412 vadjust: {
43413 number: number
43414 },
43415 __type__: {
43416 object: object,
43417 string: string
43418 }
43419 },
43420 boldital: {
43421 color: {
43422 string: string
43423 },
43424 size: {
43425 number: number
43426 },
43427 face: {
43428 string: string
43429 },
43430 mod: {
43431 string: string
43432 },
43433 vadjust: {
43434 number: number
43435 },
43436 __type__: {
43437 object: object,
43438 string: string
43439 }
43440 },
43441 ital: {
43442 color: {
43443 string: string
43444 },
43445 size: {
43446 number: number
43447 },
43448 face: {
43449 string: string
43450 },
43451 mod: {
43452 string: string
43453 },
43454 vadjust: {
43455 number: number
43456 },
43457 __type__: {
43458 object: object,
43459 string: string
43460 }
43461 },
43462 mono: {
43463 color: {
43464 string: string
43465 },
43466 size: {
43467 number: number
43468 },
43469 face: {
43470 string: string
43471 },
43472 mod: {
43473 string: string
43474 },
43475 vadjust: {
43476 number: number
43477 },
43478 __type__: {
43479 object: object,
43480 string: string
43481 }
43482 },
43483 __type__: {
43484 object: object,
43485 string: string
43486 }
43487 },
43488 hidden: {
43489 boolean: bool
43490 },
43491 hoverWidth: {
43492 function: "function",
43493 number: number
43494 },
43495 label: {
43496 string: string,
43497 undefined: "undefined"
43498 },
43499 labelHighlightBold: {
43500 boolean: bool
43501 },
43502 length: {
43503 number: number,
43504 undefined: "undefined"
43505 },
43506 physics: {
43507 boolean: bool
43508 },
43509 scaling: {
43510 min: {
43511 number: number
43512 },
43513 max: {
43514 number: number
43515 },
43516 label: {
43517 enabled: {
43518 boolean: bool
43519 },
43520 min: {
43521 number: number
43522 },
43523 max: {
43524 number: number
43525 },
43526 maxVisible: {
43527 number: number
43528 },
43529 drawThreshold: {
43530 number: number
43531 },
43532 __type__: {
43533 object: object,
43534 boolean: bool
43535 }
43536 },
43537 customScalingFunction: {
43538 function: "function"
43539 },
43540 __type__: {
43541 object: object
43542 }
43543 },
43544 selectionWidth: {
43545 function: "function",
43546 number: number
43547 },
43548 selfReferenceSize: {
43549 number: number
43550 },
43551 selfReference: {
43552 size: {
43553 number: number
43554 },
43555 angle: {
43556 number: number
43557 },
43558 renderBehindTheNode: {
43559 boolean: bool
43560 },
43561 __type__: {
43562 object: object
43563 }
43564 },
43565 shadow: {
43566 enabled: {
43567 boolean: bool
43568 },
43569 color: {
43570 string: string
43571 },
43572 size: {
43573 number: number
43574 },
43575 x: {
43576 number: number
43577 },
43578 y: {
43579 number: number
43580 },
43581 __type__: {
43582 object: object,
43583 boolean: bool
43584 }
43585 },
43586 smooth: {
43587 enabled: {
43588 boolean: bool
43589 },
43590 type: {
43591 string: ["dynamic", "continuous", "discrete", "diagonalCross", "straightCross", "horizontal", "vertical", "curvedCW", "curvedCCW", "cubicBezier"]
43592 },
43593 roundness: {
43594 number: number
43595 },
43596 forceDirection: {
43597 string: ["horizontal", "vertical", "none"],
43598 boolean: bool
43599 },
43600 __type__: {
43601 object: object,
43602 boolean: bool
43603 }
43604 },
43605 title: {
43606 string: string,
43607 undefined: "undefined"
43608 },
43609 width: {
43610 number: number
43611 },
43612 widthConstraint: {
43613 maximum: {
43614 number: number
43615 },
43616 __type__: {
43617 object: object,
43618 boolean: bool,
43619 number: number
43620 }
43621 },
43622 value: {
43623 number: number,
43624 undefined: "undefined"
43625 },
43626 __type__: {
43627 object: object
43628 }
43629 },
43630 groups: {
43631 useDefaultGroups: {
43632 boolean: bool
43633 },
43634 __any__: nodeOptions,
43635 __type__: {
43636 object: object
43637 }
43638 },
43639 interaction: {
43640 dragNodes: {
43641 boolean: bool
43642 },
43643 dragView: {
43644 boolean: bool
43645 },
43646 hideEdgesOnDrag: {
43647 boolean: bool
43648 },
43649 hideEdgesOnZoom: {
43650 boolean: bool
43651 },
43652 hideNodesOnDrag: {
43653 boolean: bool
43654 },
43655 hover: {
43656 boolean: bool
43657 },
43658 keyboard: {
43659 enabled: {
43660 boolean: bool
43661 },
43662 speed: {
43663 x: {
43664 number: number
43665 },
43666 y: {
43667 number: number
43668 },
43669 zoom: {
43670 number: number
43671 },
43672 __type__: {
43673 object: object
43674 }
43675 },
43676 bindToWindow: {
43677 boolean: bool
43678 },
43679 autoFocus: {
43680 boolean: bool
43681 },
43682 __type__: {
43683 object: object,
43684 boolean: bool
43685 }
43686 },
43687 multiselect: {
43688 boolean: bool
43689 },
43690 navigationButtons: {
43691 boolean: bool
43692 },
43693 selectable: {
43694 boolean: bool
43695 },
43696 selectConnectedEdges: {
43697 boolean: bool
43698 },
43699 hoverConnectedEdges: {
43700 boolean: bool
43701 },
43702 tooltipDelay: {
43703 number: number
43704 },
43705 zoomView: {
43706 boolean: bool
43707 },
43708 zoomSpeed: {
43709 number: number
43710 },
43711 __type__: {
43712 object: object
43713 }
43714 },
43715 layout: {
43716 randomSeed: {
43717 undefined: "undefined",
43718 number: number,
43719 string: string
43720 },
43721 improvedLayout: {
43722 boolean: bool
43723 },
43724 clusterThreshold: {
43725 number: number
43726 },
43727 hierarchical: {
43728 enabled: {
43729 boolean: bool
43730 },
43731 levelSeparation: {
43732 number: number
43733 },
43734 nodeSpacing: {
43735 number: number
43736 },
43737 treeSpacing: {
43738 number: number
43739 },
43740 blockShifting: {
43741 boolean: bool
43742 },
43743 edgeMinimization: {
43744 boolean: bool
43745 },
43746 parentCentralization: {
43747 boolean: bool
43748 },
43749 direction: {
43750 string: ["UD", "DU", "LR", "RL"]
43751 },
43752 sortMethod: {
43753 string: ["hubsize", "directed"]
43754 },
43755 shakeTowards: {
43756 string: ["leaves", "roots"]
43757 },
43758 __type__: {
43759 object: object,
43760 boolean: bool
43761 }
43762 },
43763 __type__: {
43764 object: object
43765 }
43766 },
43767 manipulation: {
43768 enabled: {
43769 boolean: bool
43770 },
43771 initiallyActive: {
43772 boolean: bool
43773 },
43774 addNode: {
43775 boolean: bool,
43776 function: "function"
43777 },
43778 addEdge: {
43779 boolean: bool,
43780 function: "function"
43781 },
43782 editNode: {
43783 function: "function"
43784 },
43785 editEdge: {
43786 editWithoutDrag: {
43787 function: "function"
43788 },
43789 __type__: {
43790 object: object,
43791 boolean: bool,
43792 function: "function"
43793 }
43794 },
43795 deleteNode: {
43796 boolean: bool,
43797 function: "function"
43798 },
43799 deleteEdge: {
43800 boolean: bool,
43801 function: "function"
43802 },
43803 controlNodeStyle: nodeOptions,
43804 __type__: {
43805 object: object,
43806 boolean: bool
43807 }
43808 },
43809 nodes: nodeOptions,
43810 physics: {
43811 enabled: {
43812 boolean: bool
43813 },
43814 barnesHut: {
43815 theta: {
43816 number: number
43817 },
43818 gravitationalConstant: {
43819 number: number
43820 },
43821 centralGravity: {
43822 number: number
43823 },
43824 springLength: {
43825 number: number
43826 },
43827 springConstant: {
43828 number: number
43829 },
43830 damping: {
43831 number: number
43832 },
43833 avoidOverlap: {
43834 number: number
43835 },
43836 __type__: {
43837 object: object
43838 }
43839 },
43840 forceAtlas2Based: {
43841 theta: {
43842 number: number
43843 },
43844 gravitationalConstant: {
43845 number: number
43846 },
43847 centralGravity: {
43848 number: number
43849 },
43850 springLength: {
43851 number: number
43852 },
43853 springConstant: {
43854 number: number
43855 },
43856 damping: {
43857 number: number
43858 },
43859 avoidOverlap: {
43860 number: number
43861 },
43862 __type__: {
43863 object: object
43864 }
43865 },
43866 repulsion: {
43867 centralGravity: {
43868 number: number
43869 },
43870 springLength: {
43871 number: number
43872 },
43873 springConstant: {
43874 number: number
43875 },
43876 nodeDistance: {
43877 number: number
43878 },
43879 damping: {
43880 number: number
43881 },
43882 __type__: {
43883 object: object
43884 }
43885 },
43886 hierarchicalRepulsion: {
43887 centralGravity: {
43888 number: number
43889 },
43890 springLength: {
43891 number: number
43892 },
43893 springConstant: {
43894 number: number
43895 },
43896 nodeDistance: {
43897 number: number
43898 },
43899 damping: {
43900 number: number
43901 },
43902 avoidOverlap: {
43903 number: number
43904 },
43905 __type__: {
43906 object: object
43907 }
43908 },
43909 maxVelocity: {
43910 number: number
43911 },
43912 minVelocity: {
43913 number: number
43914 },
43915 solver: {
43916 string: ["barnesHut", "repulsion", "hierarchicalRepulsion", "forceAtlas2Based"]
43917 },
43918 stabilization: {
43919 enabled: {
43920 boolean: bool
43921 },
43922 iterations: {
43923 number: number
43924 },
43925 updateInterval: {
43926 number: number
43927 },
43928 onlyDynamicEdges: {
43929 boolean: bool
43930 },
43931 fit: {
43932 boolean: bool
43933 },
43934 __type__: {
43935 object: object,
43936 boolean: bool
43937 }
43938 },
43939 timestep: {
43940 number: number
43941 },
43942 adaptiveTimestep: {
43943 boolean: bool
43944 },
43945 wind: {
43946 x: {
43947 number: number
43948 },
43949 y: {
43950 number: number
43951 },
43952 __type__: {
43953 object: object
43954 }
43955 },
43956 __type__: {
43957 object: object,
43958 boolean: bool
43959 }
43960 },
43961 //globals :
43962 autoResize: {
43963 boolean: bool
43964 },
43965 clickToUse: {
43966 boolean: bool
43967 },
43968 locale: {
43969 string: string
43970 },
43971 locales: {
43972 __any__: {
43973 any: any
43974 },
43975 __type__: {
43976 object: object
43977 }
43978 },
43979 height: {
43980 string: string
43981 },
43982 width: {
43983 string: string
43984 },
43985 __type__: {
43986 object: object
43987 }
43988 };
43989 /* eslint-enable @typescript-eslint/naming-convention */
43990
43991 /**
43992 * This provides ranges, initial values, steps and dropdown menu choices for the
43993 * configuration.
43994 *
43995 * @remarks
43996 * Checkbox: `boolean`
43997 * The value supllied will be used as the initial value.
43998 *
43999 * Text field: `string`
44000 * The passed text will be used as the initial value. Any text will be
44001 * accepted afterwards.
44002 *
44003 * Number range: `[number, number, number, number]`
44004 * The meanings are `[initial value, min, max, step]`.
44005 *
44006 * Dropdown: `[Exclude<string, "color">, ...(string | number | boolean)[]]`
44007 * Translations for people with poor understanding of TypeScript: the first
44008 * value always has to be a string but never `"color"`, the rest can be any
44009 * combination of strings, numbers and booleans.
44010 *
44011 * Color picker: `["color", string]`
44012 * The first value says this will be a color picker not a dropdown menu. The
44013 * next value is the initial color.
44014 */
44015
44016 var configureOptions = {
44017 nodes: {
44018 borderWidth: [1, 0, 10, 1],
44019 borderWidthSelected: [2, 0, 10, 1],
44020 color: {
44021 border: ["color", "#2B7CE9"],
44022 background: ["color", "#97C2FC"],
44023 highlight: {
44024 border: ["color", "#2B7CE9"],
44025 background: ["color", "#D2E5FF"]
44026 },
44027 hover: {
44028 border: ["color", "#2B7CE9"],
44029 background: ["color", "#D2E5FF"]
44030 }
44031 },
44032 opacity: [0, 0, 1, 0.1],
44033 fixed: {
44034 x: false,
44035 y: false
44036 },
44037 font: {
44038 color: ["color", "#343434"],
44039 size: [14, 0, 100, 1],
44040 face: ["arial", "verdana", "tahoma"],
44041 background: ["color", "none"],
44042 strokeWidth: [0, 0, 50, 1],
44043 strokeColor: ["color", "#ffffff"]
44044 },
44045 //group: 'string',
44046 hidden: false,
44047 labelHighlightBold: true,
44048 //icon: {
44049 // face: 'string', //'FontAwesome',
44050 // code: 'string', //'\uf007',
44051 // size: [50, 0, 200, 1], //50,
44052 // color: ['color','#2B7CE9'] //'#aa00ff'
44053 //},
44054 //image: 'string', // --> URL
44055 physics: true,
44056 scaling: {
44057 min: [10, 0, 200, 1],
44058 max: [30, 0, 200, 1],
44059 label: {
44060 enabled: false,
44061 min: [14, 0, 200, 1],
44062 max: [30, 0, 200, 1],
44063 maxVisible: [30, 0, 200, 1],
44064 drawThreshold: [5, 0, 20, 1]
44065 }
44066 },
44067 shadow: {
44068 enabled: false,
44069 color: "rgba(0,0,0,0.5)",
44070 size: [10, 0, 20, 1],
44071 x: [5, -30, 30, 1],
44072 y: [5, -30, 30, 1]
44073 },
44074 shape: ["ellipse", "box", "circle", "database", "diamond", "dot", "square", "star", "text", "triangle", "triangleDown", "hexagon"],
44075 shapeProperties: {
44076 borderDashes: false,
44077 borderRadius: [6, 0, 20, 1],
44078 interpolation: true,
44079 useImageSize: false
44080 },
44081 size: [25, 0, 200, 1]
44082 },
44083 edges: {
44084 arrows: {
44085 to: {
44086 enabled: false,
44087 scaleFactor: [1, 0, 3, 0.05],
44088 type: "arrow"
44089 },
44090 middle: {
44091 enabled: false,
44092 scaleFactor: [1, 0, 3, 0.05],
44093 type: "arrow"
44094 },
44095 from: {
44096 enabled: false,
44097 scaleFactor: [1, 0, 3, 0.05],
44098 type: "arrow"
44099 }
44100 },
44101 endPointOffset: {
44102 from: [0, -10, 10, 1],
44103 to: [0, -10, 10, 1]
44104 },
44105 arrowStrikethrough: true,
44106 color: {
44107 color: ["color", "#848484"],
44108 highlight: ["color", "#848484"],
44109 hover: ["color", "#848484"],
44110 inherit: ["from", "to", "both", true, false],
44111 opacity: [1, 0, 1, 0.05]
44112 },
44113 dashes: false,
44114 font: {
44115 color: ["color", "#343434"],
44116 size: [14, 0, 100, 1],
44117 face: ["arial", "verdana", "tahoma"],
44118 background: ["color", "none"],
44119 strokeWidth: [2, 0, 50, 1],
44120 strokeColor: ["color", "#ffffff"],
44121 align: ["horizontal", "top", "middle", "bottom"]
44122 },
44123 hidden: false,
44124 hoverWidth: [1.5, 0, 5, 0.1],
44125 labelHighlightBold: true,
44126 physics: true,
44127 scaling: {
44128 min: [1, 0, 100, 1],
44129 max: [15, 0, 100, 1],
44130 label: {
44131 enabled: true,
44132 min: [14, 0, 200, 1],
44133 max: [30, 0, 200, 1],
44134 maxVisible: [30, 0, 200, 1],
44135 drawThreshold: [5, 0, 20, 1]
44136 }
44137 },
44138 selectionWidth: [1.5, 0, 5, 0.1],
44139 selfReferenceSize: [20, 0, 200, 1],
44140 selfReference: {
44141 size: [20, 0, 200, 1],
44142 angle: [Math.PI / 2, -6 * Math.PI, 6 * Math.PI, Math.PI / 8],
44143 renderBehindTheNode: true
44144 },
44145 shadow: {
44146 enabled: false,
44147 color: "rgba(0,0,0,0.5)",
44148 size: [10, 0, 20, 1],
44149 x: [5, -30, 30, 1],
44150 y: [5, -30, 30, 1]
44151 },
44152 smooth: {
44153 enabled: true,
44154 type: ["dynamic", "continuous", "discrete", "diagonalCross", "straightCross", "horizontal", "vertical", "curvedCW", "curvedCCW", "cubicBezier"],
44155 forceDirection: ["horizontal", "vertical", "none"],
44156 roundness: [0.5, 0, 1, 0.05]
44157 },
44158 width: [1, 0, 30, 1]
44159 },
44160 layout: {
44161 //randomSeed: [0, 0, 500, 1],
44162 //improvedLayout: true,
44163 hierarchical: {
44164 enabled: false,
44165 levelSeparation: [150, 20, 500, 5],
44166 nodeSpacing: [100, 20, 500, 5],
44167 treeSpacing: [200, 20, 500, 5],
44168 blockShifting: true,
44169 edgeMinimization: true,
44170 parentCentralization: true,
44171 direction: ["UD", "DU", "LR", "RL"],
44172 sortMethod: ["hubsize", "directed"],
44173 shakeTowards: ["leaves", "roots"] // leaves, roots
44174
44175 }
44176 },
44177 interaction: {
44178 dragNodes: true,
44179 dragView: true,
44180 hideEdgesOnDrag: false,
44181 hideEdgesOnZoom: false,
44182 hideNodesOnDrag: false,
44183 hover: false,
44184 keyboard: {
44185 enabled: false,
44186 speed: {
44187 x: [10, 0, 40, 1],
44188 y: [10, 0, 40, 1],
44189 zoom: [0.02, 0, 0.1, 0.005]
44190 },
44191 bindToWindow: true,
44192 autoFocus: true
44193 },
44194 multiselect: false,
44195 navigationButtons: false,
44196 selectable: true,
44197 selectConnectedEdges: true,
44198 hoverConnectedEdges: true,
44199 tooltipDelay: [300, 0, 1000, 25],
44200 zoomView: true,
44201 zoomSpeed: [1, 0.1, 2, 0.1]
44202 },
44203 manipulation: {
44204 enabled: false,
44205 initiallyActive: false
44206 },
44207 physics: {
44208 enabled: true,
44209 barnesHut: {
44210 theta: [0.5, 0.1, 1, 0.05],
44211 gravitationalConstant: [-2000, -30000, 0, 50],
44212 centralGravity: [0.3, 0, 10, 0.05],
44213 springLength: [95, 0, 500, 5],
44214 springConstant: [0.04, 0, 1.2, 0.005],
44215 damping: [0.09, 0, 1, 0.01],
44216 avoidOverlap: [0, 0, 1, 0.01]
44217 },
44218 forceAtlas2Based: {
44219 theta: [0.5, 0.1, 1, 0.05],
44220 gravitationalConstant: [-50, -500, 0, 1],
44221 centralGravity: [0.01, 0, 1, 0.005],
44222 springLength: [95, 0, 500, 5],
44223 springConstant: [0.08, 0, 1.2, 0.005],
44224 damping: [0.4, 0, 1, 0.01],
44225 avoidOverlap: [0, 0, 1, 0.01]
44226 },
44227 repulsion: {
44228 centralGravity: [0.2, 0, 10, 0.05],
44229 springLength: [200, 0, 500, 5],
44230 springConstant: [0.05, 0, 1.2, 0.005],
44231 nodeDistance: [100, 0, 500, 5],
44232 damping: [0.09, 0, 1, 0.01]
44233 },
44234 hierarchicalRepulsion: {
44235 centralGravity: [0.2, 0, 10, 0.05],
44236 springLength: [100, 0, 500, 5],
44237 springConstant: [0.01, 0, 1.2, 0.005],
44238 nodeDistance: [120, 0, 500, 5],
44239 damping: [0.09, 0, 1, 0.01],
44240 avoidOverlap: [0, 0, 1, 0.01]
44241 },
44242 maxVelocity: [50, 0, 150, 1],
44243 minVelocity: [0.1, 0.01, 0.5, 0.01],
44244 solver: ["barnesHut", "forceAtlas2Based", "repulsion", "hierarchicalRepulsion"],
44245 timestep: [0.5, 0.01, 1, 0.01],
44246 wind: {
44247 x: [0, -10, 10, 0.1],
44248 y: [0, -10, 10, 0.1]
44249 } //adaptiveTimestep: true
44250
44251 }
44252 };
44253 var configuratorHideOption = function configuratorHideOption(parentPath, optionName, options) {
44254 var _context;
44255
44256 if (includes(parentPath).call(parentPath, "physics") && includes(_context = configureOptions.physics.solver).call(_context, optionName) && options.physics.solver !== optionName && optionName !== "wind") {
44257 return true;
44258 }
44259
44260 return false;
44261 };
44262
44263 var allOptions$1 = /*#__PURE__*/Object.freeze({
44264 __proto__: null,
44265 configuratorHideOption: configuratorHideOption,
44266 allOptions: allOptions,
44267 configureOptions: configureOptions
44268 });
44269
44270 /**
44271 * The Floyd–Warshall algorithm is an algorithm for finding shortest paths in
44272 * a weighted graph with positive or negative edge weights (but with no negative
44273 * cycles). - https://en.wikipedia.org/wiki/Floyd–Warshall_algorithm
44274 */
44275 var FloydWarshall = /*#__PURE__*/function () {
44276 /**
44277 * @ignore
44278 */
44279 function FloydWarshall() {
44280 _classCallCheck(this, FloydWarshall);
44281 }
44282 /**
44283 *
44284 * @param {object} body
44285 * @param {Array.<Node>} nodesArray
44286 * @param {Array.<Edge>} edgesArray
44287 * @returns {{}}
44288 */
44289
44290
44291 _createClass(FloydWarshall, [{
44292 key: "getDistances",
44293 value: function getDistances(body, nodesArray, edgesArray) {
44294 var D_matrix = {};
44295 var edges = body.edges; // prepare matrix with large numbers
44296
44297 for (var i = 0; i < nodesArray.length; i++) {
44298 var node = nodesArray[i];
44299 var cell = {};
44300 D_matrix[node] = cell;
44301
44302 for (var j = 0; j < nodesArray.length; j++) {
44303 cell[nodesArray[j]] = i == j ? 0 : 1e9;
44304 }
44305 } // put the weights for the edges in. This assumes unidirectionality.
44306
44307
44308 for (var _i = 0; _i < edgesArray.length; _i++) {
44309 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
44310
44311 if (edge.connected === true && D_matrix[edge.fromId] !== undefined && D_matrix[edge.toId] !== undefined) {
44312 D_matrix[edge.fromId][edge.toId] = 1;
44313 D_matrix[edge.toId][edge.fromId] = 1;
44314 }
44315 }
44316
44317 var nodeCount = nodesArray.length; // Adapted FloydWarshall based on unidirectionality to greatly reduce complexity.
44318
44319 for (var k = 0; k < nodeCount; k++) {
44320 var knode = nodesArray[k];
44321 var kcolm = D_matrix[knode];
44322
44323 for (var _i2 = 0; _i2 < nodeCount - 1; _i2++) {
44324 var inode = nodesArray[_i2];
44325 var icolm = D_matrix[inode];
44326
44327 for (var _j = _i2 + 1; _j < nodeCount; _j++) {
44328 var jnode = nodesArray[_j];
44329 var jcolm = D_matrix[jnode];
44330 var val = Math.min(icolm[jnode], icolm[knode] + kcolm[jnode]);
44331 icolm[jnode] = val;
44332 jcolm[inode] = val;
44333 }
44334 }
44335 }
44336
44337 return D_matrix;
44338 }
44339 }]);
44340
44341 return FloydWarshall;
44342 }();
44343
44344 /**
44345 * KamadaKawai positions the nodes initially based on
44346 *
44347 * "AN ALGORITHM FOR DRAWING GENERAL UNDIRECTED GRAPHS"
44348 * -- Tomihisa KAMADA and Satoru KAWAI in 1989
44349 *
44350 * Possible optimizations in the distance calculation can be implemented.
44351 */
44352
44353 var KamadaKawai = /*#__PURE__*/function () {
44354 /**
44355 * @param {object} body
44356 * @param {number} edgeLength
44357 * @param {number} edgeStrength
44358 */
44359 function KamadaKawai(body, edgeLength, edgeStrength) {
44360 _classCallCheck(this, KamadaKawai);
44361
44362 this.body = body;
44363 this.springLength = edgeLength;
44364 this.springConstant = edgeStrength;
44365 this.distanceSolver = new FloydWarshall();
44366 }
44367 /**
44368 * Not sure if needed but can be used to update the spring length and spring constant
44369 *
44370 * @param {object} options
44371 */
44372
44373
44374 _createClass(KamadaKawai, [{
44375 key: "setOptions",
44376 value: function setOptions(options) {
44377 if (options) {
44378 if (options.springLength) {
44379 this.springLength = options.springLength;
44380 }
44381
44382 if (options.springConstant) {
44383 this.springConstant = options.springConstant;
44384 }
44385 }
44386 }
44387 /**
44388 * Position the system
44389 *
44390 * @param {Array.<Node>} nodesArray
44391 * @param {Array.<vis.Edge>} edgesArray
44392 * @param {boolean} [ignoreClusters=false]
44393 */
44394
44395 }, {
44396 key: "solve",
44397 value: function solve(nodesArray, edgesArray) {
44398 var ignoreClusters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
44399 // get distance matrix
44400 var D_matrix = this.distanceSolver.getDistances(this.body, nodesArray, edgesArray); // distance matrix
44401 // get the L Matrix
44402
44403 this._createL_matrix(D_matrix); // get the K Matrix
44404
44405
44406 this._createK_matrix(D_matrix); // initial E Matrix
44407
44408
44409 this._createE_matrix(); // calculate positions
44410
44411
44412 var threshold = 0.01;
44413 var innerThreshold = 1;
44414 var iterations = 0;
44415 var maxIterations = Math.max(1000, Math.min(10 * this.body.nodeIndices.length, 6000));
44416 var maxInnerIterations = 5;
44417 var maxEnergy = 1e9;
44418 var highE_nodeId = 0,
44419 dE_dx = 0,
44420 dE_dy = 0,
44421 delta_m = 0,
44422 subIterations = 0;
44423
44424 while (maxEnergy > threshold && iterations < maxIterations) {
44425 iterations += 1;
44426
44427 var _this$_getHighestEner = this._getHighestEnergyNode(ignoreClusters);
44428
44429 var _this$_getHighestEner2 = _slicedToArray(_this$_getHighestEner, 4);
44430
44431 highE_nodeId = _this$_getHighestEner2[0];
44432 maxEnergy = _this$_getHighestEner2[1];
44433 dE_dx = _this$_getHighestEner2[2];
44434 dE_dy = _this$_getHighestEner2[3];
44435 delta_m = maxEnergy;
44436 subIterations = 0;
44437
44438 while (delta_m > innerThreshold && subIterations < maxInnerIterations) {
44439 subIterations += 1;
44440
44441 this._moveNode(highE_nodeId, dE_dx, dE_dy);
44442
44443 var _this$_getEnergy = this._getEnergy(highE_nodeId);
44444
44445 var _this$_getEnergy2 = _slicedToArray(_this$_getEnergy, 3);
44446
44447 delta_m = _this$_getEnergy2[0];
44448 dE_dx = _this$_getEnergy2[1];
44449 dE_dy = _this$_getEnergy2[2];
44450 }
44451 }
44452 }
44453 /**
44454 * get the node with the highest energy
44455 *
44456 * @param {boolean} ignoreClusters
44457 * @returns {number[]}
44458 * @private
44459 */
44460
44461 }, {
44462 key: "_getHighestEnergyNode",
44463 value: function _getHighestEnergyNode(ignoreClusters) {
44464 var nodesArray = this.body.nodeIndices;
44465 var nodes = this.body.nodes;
44466 var maxEnergy = 0;
44467 var maxEnergyNodeId = nodesArray[0];
44468 var dE_dx_max = 0,
44469 dE_dy_max = 0;
44470
44471 for (var nodeIdx = 0; nodeIdx < nodesArray.length; nodeIdx++) {
44472 var m = nodesArray[nodeIdx]; // by not evaluating nodes with predefined positions we should only move nodes that have no positions.
44473
44474 if (nodes[m].predefinedPosition !== true || nodes[m].isCluster === true && ignoreClusters === true || nodes[m].options.fixed.x !== true || nodes[m].options.fixed.y !== true) {
44475 var _this$_getEnergy3 = this._getEnergy(m),
44476 _this$_getEnergy4 = _slicedToArray(_this$_getEnergy3, 3),
44477 delta_m = _this$_getEnergy4[0],
44478 dE_dx = _this$_getEnergy4[1],
44479 dE_dy = _this$_getEnergy4[2];
44480
44481 if (maxEnergy < delta_m) {
44482 maxEnergy = delta_m;
44483 maxEnergyNodeId = m;
44484 dE_dx_max = dE_dx;
44485 dE_dy_max = dE_dy;
44486 }
44487 }
44488 }
44489
44490 return [maxEnergyNodeId, maxEnergy, dE_dx_max, dE_dy_max];
44491 }
44492 /**
44493 * calculate the energy of a single node
44494 *
44495 * @param {Node.id} m
44496 * @returns {number[]}
44497 * @private
44498 */
44499
44500 }, {
44501 key: "_getEnergy",
44502 value: function _getEnergy(m) {
44503 var _this$E_sums$m = _slicedToArray(this.E_sums[m], 2),
44504 dE_dx = _this$E_sums$m[0],
44505 dE_dy = _this$E_sums$m[1];
44506
44507 var delta_m = Math.sqrt(Math.pow(dE_dx, 2) + Math.pow(dE_dy, 2));
44508 return [delta_m, dE_dx, dE_dy];
44509 }
44510 /**
44511 * move the node based on it's energy
44512 * the dx and dy are calculated from the linear system proposed by Kamada and Kawai
44513 *
44514 * @param {number} m
44515 * @param {number} dE_dx
44516 * @param {number} dE_dy
44517 * @private
44518 */
44519
44520 }, {
44521 key: "_moveNode",
44522 value: function _moveNode(m, dE_dx, dE_dy) {
44523 var nodesArray = this.body.nodeIndices;
44524 var nodes = this.body.nodes;
44525 var d2E_dx2 = 0;
44526 var d2E_dxdy = 0;
44527 var d2E_dy2 = 0;
44528 var x_m = nodes[m].x;
44529 var y_m = nodes[m].y;
44530 var km = this.K_matrix[m];
44531 var lm = this.L_matrix[m];
44532
44533 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
44534 var i = nodesArray[iIdx];
44535
44536 if (i !== m) {
44537 var x_i = nodes[i].x;
44538 var y_i = nodes[i].y;
44539 var kmat = km[i];
44540 var lmat = lm[i];
44541 var denominator = 1.0 / Math.pow(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2), 1.5);
44542 d2E_dx2 += kmat * (1 - lmat * Math.pow(y_m - y_i, 2) * denominator);
44543 d2E_dxdy += kmat * (lmat * (x_m - x_i) * (y_m - y_i) * denominator);
44544 d2E_dy2 += kmat * (1 - lmat * Math.pow(x_m - x_i, 2) * denominator);
44545 }
44546 } // make the variable names easier to make the solving of the linear system easier to read
44547
44548
44549 var A = d2E_dx2,
44550 B = d2E_dxdy,
44551 C = dE_dx,
44552 D = d2E_dy2,
44553 E = dE_dy; // solve the linear system for dx and dy
44554
44555 var dy = (C / A + E / B) / (B / A - D / B);
44556 var dx = -(B * dy + C) / A; // move the node
44557
44558 nodes[m].x += dx;
44559 nodes[m].y += dy; // Recalculate E_matrix (should be incremental)
44560
44561 this._updateE_matrix(m);
44562 }
44563 /**
44564 * Create the L matrix: edge length times shortest path
44565 *
44566 * @param {object} D_matrix
44567 * @private
44568 */
44569
44570 }, {
44571 key: "_createL_matrix",
44572 value: function _createL_matrix(D_matrix) {
44573 var nodesArray = this.body.nodeIndices;
44574 var edgeLength = this.springLength;
44575 this.L_matrix = [];
44576
44577 for (var i = 0; i < nodesArray.length; i++) {
44578 this.L_matrix[nodesArray[i]] = {};
44579
44580 for (var j = 0; j < nodesArray.length; j++) {
44581 this.L_matrix[nodesArray[i]][nodesArray[j]] = edgeLength * D_matrix[nodesArray[i]][nodesArray[j]];
44582 }
44583 }
44584 }
44585 /**
44586 * Create the K matrix: spring constants times shortest path
44587 *
44588 * @param {object} D_matrix
44589 * @private
44590 */
44591
44592 }, {
44593 key: "_createK_matrix",
44594 value: function _createK_matrix(D_matrix) {
44595 var nodesArray = this.body.nodeIndices;
44596 var edgeStrength = this.springConstant;
44597 this.K_matrix = [];
44598
44599 for (var i = 0; i < nodesArray.length; i++) {
44600 this.K_matrix[nodesArray[i]] = {};
44601
44602 for (var j = 0; j < nodesArray.length; j++) {
44603 this.K_matrix[nodesArray[i]][nodesArray[j]] = edgeStrength * Math.pow(D_matrix[nodesArray[i]][nodesArray[j]], -2);
44604 }
44605 }
44606 }
44607 /**
44608 * Create matrix with all energies between nodes
44609 *
44610 * @private
44611 */
44612
44613 }, {
44614 key: "_createE_matrix",
44615 value: function _createE_matrix() {
44616 var nodesArray = this.body.nodeIndices;
44617 var nodes = this.body.nodes;
44618 this.E_matrix = {};
44619 this.E_sums = {};
44620
44621 for (var mIdx = 0; mIdx < nodesArray.length; mIdx++) {
44622 this.E_matrix[nodesArray[mIdx]] = [];
44623 }
44624
44625 for (var _mIdx = 0; _mIdx < nodesArray.length; _mIdx++) {
44626 var m = nodesArray[_mIdx];
44627 var x_m = nodes[m].x;
44628 var y_m = nodes[m].y;
44629 var dE_dx = 0;
44630 var dE_dy = 0;
44631
44632 for (var iIdx = _mIdx; iIdx < nodesArray.length; iIdx++) {
44633 var i = nodesArray[iIdx];
44634
44635 if (i !== m) {
44636 var x_i = nodes[i].x;
44637 var y_i = nodes[i].y;
44638 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
44639 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)];
44640 this.E_matrix[i][_mIdx] = this.E_matrix[m][iIdx];
44641 dE_dx += this.E_matrix[m][iIdx][0];
44642 dE_dy += this.E_matrix[m][iIdx][1];
44643 }
44644 } //Store sum
44645
44646
44647 this.E_sums[m] = [dE_dx, dE_dy];
44648 }
44649 }
44650 /**
44651 * Update method, just doing single column (rows are auto-updated) (update all sums)
44652 *
44653 * @param {number} m
44654 * @private
44655 */
44656
44657 }, {
44658 key: "_updateE_matrix",
44659 value: function _updateE_matrix(m) {
44660 var nodesArray = this.body.nodeIndices;
44661 var nodes = this.body.nodes;
44662 var colm = this.E_matrix[m];
44663 var kcolm = this.K_matrix[m];
44664 var lcolm = this.L_matrix[m];
44665 var x_m = nodes[m].x;
44666 var y_m = nodes[m].y;
44667 var dE_dx = 0;
44668 var dE_dy = 0;
44669
44670 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
44671 var i = nodesArray[iIdx];
44672
44673 if (i !== m) {
44674 //Keep old energy value for sum modification below
44675 var cell = colm[iIdx];
44676 var oldDx = cell[0];
44677 var oldDy = cell[1]; //Calc new energy:
44678
44679 var x_i = nodes[i].x;
44680 var y_i = nodes[i].y;
44681 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
44682 var dx = kcolm[i] * (x_m - x_i - lcolm[i] * (x_m - x_i) * denominator);
44683 var dy = kcolm[i] * (y_m - y_i - lcolm[i] * (y_m - y_i) * denominator);
44684 colm[iIdx] = [dx, dy];
44685 dE_dx += dx;
44686 dE_dy += dy; //add new energy to sum of each column
44687
44688 var sum = this.E_sums[i];
44689 sum[0] += dx - oldDx;
44690 sum[1] += dy - oldDy;
44691 }
44692 } //Store sum at -1 index
44693
44694
44695 this.E_sums[m] = [dE_dx, dE_dy];
44696 }
44697 }]);
44698
44699 return KamadaKawai;
44700 }();
44701
44702 /**
44703 * Create a network visualization, displaying nodes and edges.
44704 *
44705 * @param {Element} container The DOM element in which the Network will
44706 * be created. Normally a div element.
44707 * @param {object} data An object containing parameters
44708 * {Array} nodes
44709 * {Array} edges
44710 * @param {object} options Options
44711 * @class Network
44712 */
44713
44714 function Network(container, data, options) {
44715 var _context,
44716 _context2,
44717 _context3,
44718 _context4,
44719 _this = this;
44720
44721 if (!(this instanceof Network)) {
44722 throw new SyntaxError("Constructor must be called with the new operator");
44723 } // set constant values
44724
44725
44726 this.options = {};
44727 this.defaultOptions = {
44728 locale: "en",
44729 locales: locales,
44730 clickToUse: false
44731 };
44732
44733 assign$2(this.options, this.defaultOptions);
44734 /**
44735 * Containers for nodes and edges.
44736 *
44737 * 'edges' and 'nodes' contain the full definitions of all the network elements.
44738 * 'nodeIndices' and 'edgeIndices' contain the id's of the active elements.
44739 *
44740 * The distinction is important, because a defined node need not be active, i.e.
44741 * visible on the canvas. This happens in particular when clusters are defined, in
44742 * that case there will be nodes and edges not displayed.
44743 * The bottom line is that all code with actions related to visibility, *must* use
44744 * 'nodeIndices' and 'edgeIndices', not 'nodes' and 'edges' directly.
44745 */
44746
44747
44748 this.body = {
44749 container: container,
44750 // See comment above for following fields
44751 nodes: {},
44752 nodeIndices: [],
44753 edges: {},
44754 edgeIndices: [],
44755 emitter: {
44756 on: bind$6(_context = this.on).call(_context, this),
44757 off: bind$6(_context2 = this.off).call(_context2, this),
44758 emit: bind$6(_context3 = this.emit).call(_context3, this),
44759 once: bind$6(_context4 = this.once).call(_context4, this)
44760 },
44761 eventListeners: {
44762 onTap: function onTap() {},
44763 onTouch: function onTouch() {},
44764 onDoubleTap: function onDoubleTap() {},
44765 onHold: function onHold() {},
44766 onDragStart: function onDragStart() {},
44767 onDrag: function onDrag() {},
44768 onDragEnd: function onDragEnd() {},
44769 onMouseWheel: function onMouseWheel() {},
44770 onPinch: function onPinch() {},
44771 onMouseMove: function onMouseMove() {},
44772 onRelease: function onRelease() {},
44773 onContext: function onContext() {}
44774 },
44775 data: {
44776 nodes: null,
44777 // A DataSet or DataView
44778 edges: null // A DataSet or DataView
44779
44780 },
44781 functions: {
44782 createNode: function createNode() {},
44783 createEdge: function createEdge() {},
44784 getPointer: function getPointer() {}
44785 },
44786 modules: {},
44787 view: {
44788 scale: 1,
44789 translation: {
44790 x: 0,
44791 y: 0
44792 }
44793 },
44794 selectionBox: {
44795 show: false,
44796 position: {
44797 start: {
44798 x: 0,
44799 y: 0
44800 },
44801 end: {
44802 x: 0,
44803 y: 0
44804 }
44805 }
44806 }
44807 }; // bind the event listeners
44808
44809 this.bindEventListeners(); // setting up all modules
44810
44811 this.images = new Images(function () {
44812 return _this.body.emitter.emit("_requestRedraw");
44813 }); // object with images
44814
44815 this.groups = new Groups(); // object with groups
44816
44817 this.canvas = new Canvas(this.body); // DOM handler
44818
44819 this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler
44820
44821 this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key
44822
44823 this.view = new View(this.body, this.canvas); // camera handler, does animations and zooms
44824
44825 this.renderer = new CanvasRenderer(this.body, this.canvas); // renderer, starts renderloop, has events that modules can hook into
44826
44827 this.physics = new PhysicsEngine(this.body); // physics engine, does all the simulations
44828
44829 this.layoutEngine = new LayoutEngine(this.body); // layout engine for inital layout and hierarchical layout
44830
44831 this.clustering = new ClusterEngine(this.body); // clustering api
44832
44833 this.manipulation = new ManipulationSystem(this.body, this.canvas, this.selectionHandler, this.interactionHandler); // data manipulation system
44834
44835 this.nodesHandler = new NodesHandler(this.body, this.images, this.groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
44836
44837 this.edgesHandler = new EdgesHandler(this.body, this.images, this.groups); // Handle adding, deleting and updating of edges as well as global options
44838
44839 this.body.modules["kamadaKawai"] = new KamadaKawai(this.body, 150, 0.05); // Layouting algorithm.
44840
44841 this.body.modules["clustering"] = this.clustering; // create the DOM elements
44842
44843 this.canvas._create(); // apply options
44844
44845
44846 this.setOptions(options); // load data (the disable start variable will be the same as the enabled clustering)
44847
44848 this.setData(data);
44849 } // Extend Network with an Emitter mixin
44850
44851 Emitter(Network.prototype);
44852 /**
44853 * Set options
44854 *
44855 * @param {object} options
44856 */
44857
44858 Network.prototype.setOptions = function (options) {
44859 var _this2 = this;
44860
44861 if (options === null) {
44862 options = undefined; // This ensures that options handling doesn't crash in the handling
44863 }
44864
44865 if (options !== undefined) {
44866 var errorFound = Validator.validate(options, allOptions);
44867
44868 if (errorFound === true) {
44869 console.error("%cErrors have been found in the supplied options object.", VALIDATOR_PRINT_STYLE);
44870 } // copy the global fields over
44871
44872
44873 var fields = ["locale", "locales", "clickToUse"];
44874 selectiveDeepExtend(fields, this.options, options); // normalize the locale or use English
44875
44876 if (options.locale !== undefined) {
44877 options.locale = normalizeLanguageCode(options.locales || this.options.locales, options.locale);
44878 } // the hierarchical system can adapt the edges and the physics to it's own options because not all combinations work with the hierarichical system.
44879
44880
44881 options = this.layoutEngine.setOptions(options.layout, options);
44882 this.canvas.setOptions(options); // options for canvas are in globals
44883 // pass the options to the modules
44884
44885 this.groups.setOptions(options.groups);
44886 this.nodesHandler.setOptions(options.nodes);
44887 this.edgesHandler.setOptions(options.edges);
44888 this.physics.setOptions(options.physics);
44889 this.manipulation.setOptions(options.manipulation, options, this.options); // manipulation uses the locales in the globals
44890
44891 this.interactionHandler.setOptions(options.interaction);
44892 this.renderer.setOptions(options.interaction); // options for rendering are in interaction
44893
44894 this.selectionHandler.setOptions(options.interaction); // options for selection are in interaction
44895 // reload the settings of the nodes to apply changes in groups that are not referenced by pointer.
44896
44897 if (options.groups !== undefined) {
44898 this.body.emitter.emit("refreshNodes");
44899 } // these two do not have options at the moment, here for completeness
44900 //this.view.setOptions(options.view);
44901 //this.clustering.setOptions(options.clustering);
44902
44903
44904 if ("configure" in options) {
44905 if (!this.configurator) {
44906 this.configurator = new Configurator(this, this.body.container, configureOptions, this.canvas.pixelRatio, configuratorHideOption);
44907 }
44908
44909 this.configurator.setOptions(options.configure);
44910 } // if the configuration system is enabled, copy all options and put them into the config system
44911
44912
44913 if (this.configurator && this.configurator.options.enabled === true) {
44914 var networkOptions = {
44915 nodes: {},
44916 edges: {},
44917 layout: {},
44918 interaction: {},
44919 manipulation: {},
44920 physics: {},
44921 global: {}
44922 };
44923 deepExtend(networkOptions.nodes, this.nodesHandler.options);
44924 deepExtend(networkOptions.edges, this.edgesHandler.options);
44925 deepExtend(networkOptions.layout, this.layoutEngine.options); // load the selectionHandler and render default options in to the interaction group
44926
44927 deepExtend(networkOptions.interaction, this.selectionHandler.options);
44928 deepExtend(networkOptions.interaction, this.renderer.options);
44929 deepExtend(networkOptions.interaction, this.interactionHandler.options);
44930 deepExtend(networkOptions.manipulation, this.manipulation.options);
44931 deepExtend(networkOptions.physics, this.physics.options); // load globals into the global object
44932
44933 deepExtend(networkOptions.global, this.canvas.options);
44934 deepExtend(networkOptions.global, this.options);
44935 this.configurator.setModuleOptions(networkOptions);
44936 } // handle network global options
44937
44938
44939 if (options.clickToUse !== undefined) {
44940 if (options.clickToUse === true) {
44941 if (this.activator === undefined) {
44942 this.activator = new Activator(this.canvas.frame);
44943 this.activator.on("change", function () {
44944 _this2.body.emitter.emit("activate");
44945 });
44946 }
44947 } else {
44948 if (this.activator !== undefined) {
44949 this.activator.destroy();
44950 delete this.activator;
44951 }
44952
44953 this.body.emitter.emit("activate");
44954 }
44955 } else {
44956 this.body.emitter.emit("activate");
44957 }
44958
44959 this.canvas.setSize(); // start the physics simulation. Can be safely called multiple times.
44960
44961 this.body.emitter.emit("startSimulation");
44962 }
44963 };
44964 /**
44965 * Update the visible nodes and edges list with the most recent node state.
44966 *
44967 * Visible nodes are stored in this.body.nodeIndices.
44968 * Visible edges are stored in this.body.edgeIndices.
44969 * A node or edges is visible if it is not hidden or clustered.
44970 *
44971 * @private
44972 */
44973
44974
44975 Network.prototype._updateVisibleIndices = function () {
44976 var nodes = this.body.nodes;
44977 var edges = this.body.edges;
44978 this.body.nodeIndices = [];
44979 this.body.edgeIndices = [];
44980
44981 for (var nodeId in nodes) {
44982 if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
44983 if (!this.clustering._isClusteredNode(nodeId) && nodes[nodeId].options.hidden === false) {
44984 this.body.nodeIndices.push(nodes[nodeId].id);
44985 }
44986 }
44987 }
44988
44989 for (var edgeId in edges) {
44990 if (Object.prototype.hasOwnProperty.call(edges, edgeId)) {
44991 var edge = edges[edgeId]; // It can happen that this is executed *after* a node edge has been removed,
44992 // but *before* the edge itself has been removed. Taking this into account.
44993
44994 var fromNode = nodes[edge.fromId];
44995 var toNode = nodes[edge.toId];
44996 var edgeNodesPresent = fromNode !== undefined && toNode !== undefined;
44997 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
44998 toNode.options.hidden === false; // idem
44999
45000 if (isVisible) {
45001 this.body.edgeIndices.push(edge.id);
45002 }
45003 }
45004 }
45005 };
45006 /**
45007 * Bind all events
45008 */
45009
45010
45011 Network.prototype.bindEventListeners = function () {
45012 var _this3 = this;
45013
45014 // This event will trigger a rebuilding of the cache everything.
45015 // Used when nodes or edges have been added or removed.
45016 this.body.emitter.on("_dataChanged", function () {
45017 _this3.edgesHandler._updateState();
45018
45019 _this3.body.emitter.emit("_dataUpdated");
45020 }); // this is called when options of EXISTING nodes or edges have changed.
45021
45022 this.body.emitter.on("_dataUpdated", function () {
45023 // Order important in following block
45024 _this3.clustering._updateState();
45025
45026 _this3._updateVisibleIndices();
45027
45028 _this3._updateValueRange(_this3.body.nodes);
45029
45030 _this3._updateValueRange(_this3.body.edges); // start simulation (can be called safely, even if already running)
45031
45032
45033 _this3.body.emitter.emit("startSimulation");
45034
45035 _this3.body.emitter.emit("_requestRedraw");
45036 });
45037 };
45038 /**
45039 * Set nodes and edges, and optionally options as well.
45040 *
45041 * @param {object} data Object containing parameters:
45042 * {Array | DataSet | DataView} [nodes] Array with nodes
45043 * {Array | DataSet | DataView} [edges] Array with edges
45044 * {String} [dot] String containing data in DOT format
45045 * {String} [gephi] String containing data in gephi JSON format
45046 * {Options} [options] Object with options
45047 */
45048
45049
45050 Network.prototype.setData = function (data) {
45051 // reset the physics engine.
45052 this.body.emitter.emit("resetPhysics");
45053 this.body.emitter.emit("_resetData"); // unselect all to ensure no selections from old data are carried over.
45054
45055 this.selectionHandler.unselectAll();
45056
45057 if (data && data.dot && (data.nodes || data.edges)) {
45058 throw new SyntaxError('Data must contain either parameter "dot" or ' + ' parameter pair "nodes" and "edges", but not both.');
45059 } // set options
45060
45061
45062 this.setOptions(data && data.options); // set all data
45063
45064 if (data && data.dot) {
45065 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
45066
45067 var dotData = DOTToGraph(data.dot);
45068 this.setData(dotData);
45069 return;
45070 } else if (data && data.gephi) {
45071 // parse DOT file
45072 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);");
45073 var gephiData = parseGephi(data.gephi);
45074 this.setData(gephiData);
45075 return;
45076 } else {
45077 this.nodesHandler.setData(data && data.nodes, true);
45078 this.edgesHandler.setData(data && data.edges, true);
45079 } // emit change in data
45080
45081
45082 this.body.emitter.emit("_dataChanged"); // emit data loaded
45083
45084 this.body.emitter.emit("_dataLoaded"); // find a stable position or start animating to a stable position
45085
45086 this.body.emitter.emit("initPhysics");
45087 };
45088 /**
45089 * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function.
45090 * var network = new vis.Network(..);
45091 * network.destroy();
45092 * network = null;
45093 */
45094
45095
45096 Network.prototype.destroy = function () {
45097 this.body.emitter.emit("destroy"); // clear events
45098
45099 this.body.emitter.off();
45100 this.off(); // delete modules
45101
45102 delete this.groups;
45103 delete this.canvas;
45104 delete this.selectionHandler;
45105 delete this.interactionHandler;
45106 delete this.view;
45107 delete this.renderer;
45108 delete this.physics;
45109 delete this.layoutEngine;
45110 delete this.clustering;
45111 delete this.manipulation;
45112 delete this.nodesHandler;
45113 delete this.edgesHandler;
45114 delete this.configurator;
45115 delete this.images;
45116
45117 for (var nodeId in this.body.nodes) {
45118 if (!Object.prototype.hasOwnProperty.call(this.body.nodes, nodeId)) continue;
45119 delete this.body.nodes[nodeId];
45120 }
45121
45122 for (var edgeId in this.body.edges) {
45123 if (!Object.prototype.hasOwnProperty.call(this.body.edges, edgeId)) continue;
45124 delete this.body.edges[edgeId];
45125 } // remove the container and everything inside it recursively
45126
45127
45128 recursiveDOMDelete(this.body.container);
45129 };
45130 /**
45131 * Update the values of all object in the given array according to the current
45132 * value range of the objects in the array.
45133 *
45134 * @param {object} obj An object containing a set of Edges or Nodes
45135 * The objects must have a method getValue() and
45136 * setValueRange(min, max).
45137 * @private
45138 */
45139
45140
45141 Network.prototype._updateValueRange = function (obj) {
45142 var id; // determine the range of the objects
45143
45144 var valueMin = undefined;
45145 var valueMax = undefined;
45146 var valueTotal = 0;
45147
45148 for (id in obj) {
45149 if (Object.prototype.hasOwnProperty.call(obj, id)) {
45150 var value = obj[id].getValue();
45151
45152 if (value !== undefined) {
45153 valueMin = valueMin === undefined ? value : Math.min(value, valueMin);
45154 valueMax = valueMax === undefined ? value : Math.max(value, valueMax);
45155 valueTotal += value;
45156 }
45157 }
45158 } // adjust the range of all objects
45159
45160
45161 if (valueMin !== undefined && valueMax !== undefined) {
45162 for (id in obj) {
45163 if (Object.prototype.hasOwnProperty.call(obj, id)) {
45164 obj[id].setValueRange(valueMin, valueMax, valueTotal);
45165 }
45166 }
45167 }
45168 };
45169 /**
45170 * Returns true when the Network is active.
45171 *
45172 * @returns {boolean}
45173 */
45174
45175
45176 Network.prototype.isActive = function () {
45177 return !this.activator || this.activator.active;
45178 };
45179
45180 Network.prototype.setSize = function () {
45181 return this.canvas.setSize.apply(this.canvas, arguments);
45182 };
45183
45184 Network.prototype.canvasToDOM = function () {
45185 return this.canvas.canvasToDOM.apply(this.canvas, arguments);
45186 };
45187
45188 Network.prototype.DOMtoCanvas = function () {
45189 return this.canvas.DOMtoCanvas.apply(this.canvas, arguments);
45190 };
45191 /**
45192 * Nodes can be in clusters. Clusters can also be in clusters. This function returns and array of
45193 * nodeIds showing where the node is.
45194 *
45195 * If any nodeId in the chain, especially the first passed in as a parameter, is not present in
45196 * the current nodes list, an empty array is returned.
45197 *
45198 * Example:
45199 * cluster 'A' contains cluster 'B',
45200 * cluster 'B' contains cluster 'C',
45201 * cluster 'C' contains node 'fred'.
45202 * `jsnetwork.clustering.findNode('fred')` will return `['A','B','C','fred']`.
45203 *
45204 * @param {string|number} nodeId
45205 * @returns {Array}
45206 */
45207
45208
45209 Network.prototype.findNode = function () {
45210 return this.clustering.findNode.apply(this.clustering, arguments);
45211 };
45212
45213 Network.prototype.isCluster = function () {
45214 return this.clustering.isCluster.apply(this.clustering, arguments);
45215 };
45216
45217 Network.prototype.openCluster = function () {
45218 return this.clustering.openCluster.apply(this.clustering, arguments);
45219 };
45220
45221 Network.prototype.cluster = function () {
45222 return this.clustering.cluster.apply(this.clustering, arguments);
45223 };
45224
45225 Network.prototype.getNodesInCluster = function () {
45226 return this.clustering.getNodesInCluster.apply(this.clustering, arguments);
45227 };
45228
45229 Network.prototype.clusterByConnection = function () {
45230 return this.clustering.clusterByConnection.apply(this.clustering, arguments);
45231 };
45232
45233 Network.prototype.clusterByHubsize = function () {
45234 return this.clustering.clusterByHubsize.apply(this.clustering, arguments);
45235 };
45236
45237 Network.prototype.updateClusteredNode = function () {
45238 return this.clustering.updateClusteredNode.apply(this.clustering, arguments);
45239 };
45240
45241 Network.prototype.getClusteredEdges = function () {
45242 return this.clustering.getClusteredEdges.apply(this.clustering, arguments);
45243 };
45244
45245 Network.prototype.getBaseEdge = function () {
45246 return this.clustering.getBaseEdge.apply(this.clustering, arguments);
45247 };
45248
45249 Network.prototype.getBaseEdges = function () {
45250 return this.clustering.getBaseEdges.apply(this.clustering, arguments);
45251 };
45252
45253 Network.prototype.updateEdge = function () {
45254 return this.clustering.updateEdge.apply(this.clustering, arguments);
45255 };
45256 /**
45257 * This method will cluster all nodes with 1 edge with their respective connected node.
45258 * The options object is explained in full <a data-scroll="" data-options="{ &quot;easing&quot;: &quot;easeInCubic&quot; }" href="#optionsObject">below</a>.
45259 *
45260 * @param {object} [options]
45261 * @returns {undefined}
45262 */
45263
45264
45265 Network.prototype.clusterOutliers = function () {
45266 return this.clustering.clusterOutliers.apply(this.clustering, arguments);
45267 };
45268
45269 Network.prototype.getSeed = function () {
45270 return this.layoutEngine.getSeed.apply(this.layoutEngine, arguments);
45271 };
45272
45273 Network.prototype.enableEditMode = function () {
45274 return this.manipulation.enableEditMode.apply(this.manipulation, arguments);
45275 };
45276
45277 Network.prototype.disableEditMode = function () {
45278 return this.manipulation.disableEditMode.apply(this.manipulation, arguments);
45279 };
45280
45281 Network.prototype.addNodeMode = function () {
45282 return this.manipulation.addNodeMode.apply(this.manipulation, arguments);
45283 };
45284
45285 Network.prototype.editNode = function () {
45286 return this.manipulation.editNode.apply(this.manipulation, arguments);
45287 };
45288
45289 Network.prototype.editNodeMode = function () {
45290 console.warn("Deprecated: Please use editNode instead of editNodeMode.");
45291 return this.manipulation.editNode.apply(this.manipulation, arguments);
45292 };
45293
45294 Network.prototype.addEdgeMode = function () {
45295 return this.manipulation.addEdgeMode.apply(this.manipulation, arguments);
45296 };
45297
45298 Network.prototype.editEdgeMode = function () {
45299 return this.manipulation.editEdgeMode.apply(this.manipulation, arguments);
45300 };
45301
45302 Network.prototype.deleteSelected = function () {
45303 return this.manipulation.deleteSelected.apply(this.manipulation, arguments);
45304 };
45305
45306 Network.prototype.getPositions = function () {
45307 return this.nodesHandler.getPositions.apply(this.nodesHandler, arguments);
45308 };
45309
45310 Network.prototype.getPosition = function () {
45311 return this.nodesHandler.getPosition.apply(this.nodesHandler, arguments);
45312 };
45313
45314 Network.prototype.storePositions = function () {
45315 return this.nodesHandler.storePositions.apply(this.nodesHandler, arguments);
45316 };
45317
45318 Network.prototype.moveNode = function () {
45319 return this.nodesHandler.moveNode.apply(this.nodesHandler, arguments);
45320 };
45321
45322 Network.prototype.getBoundingBox = function () {
45323 return this.nodesHandler.getBoundingBox.apply(this.nodesHandler, arguments);
45324 };
45325
45326 Network.prototype.getConnectedNodes = function (objectId) {
45327 if (this.body.nodes[objectId] !== undefined) {
45328 return this.nodesHandler.getConnectedNodes.apply(this.nodesHandler, arguments);
45329 } else {
45330 return this.edgesHandler.getConnectedNodes.apply(this.edgesHandler, arguments);
45331 }
45332 };
45333
45334 Network.prototype.getConnectedEdges = function () {
45335 return this.nodesHandler.getConnectedEdges.apply(this.nodesHandler, arguments);
45336 };
45337
45338 Network.prototype.startSimulation = function () {
45339 return this.physics.startSimulation.apply(this.physics, arguments);
45340 };
45341
45342 Network.prototype.stopSimulation = function () {
45343 return this.physics.stopSimulation.apply(this.physics, arguments);
45344 };
45345
45346 Network.prototype.stabilize = function () {
45347 return this.physics.stabilize.apply(this.physics, arguments);
45348 };
45349
45350 Network.prototype.getSelection = function () {
45351 return this.selectionHandler.getSelection.apply(this.selectionHandler, arguments);
45352 };
45353
45354 Network.prototype.setSelection = function () {
45355 return this.selectionHandler.setSelection.apply(this.selectionHandler, arguments);
45356 };
45357
45358 Network.prototype.getSelectedNodes = function () {
45359 return this.selectionHandler.getSelectedNodeIds.apply(this.selectionHandler, arguments);
45360 };
45361
45362 Network.prototype.getSelectedEdges = function () {
45363 return this.selectionHandler.getSelectedEdgeIds.apply(this.selectionHandler, arguments);
45364 };
45365
45366 Network.prototype.getNodeAt = function () {
45367 var node = this.selectionHandler.getNodeAt.apply(this.selectionHandler, arguments);
45368
45369 if (node !== undefined && node.id !== undefined) {
45370 return node.id;
45371 }
45372
45373 return node;
45374 };
45375
45376 Network.prototype.getEdgeAt = function () {
45377 var edge = this.selectionHandler.getEdgeAt.apply(this.selectionHandler, arguments);
45378
45379 if (edge !== undefined && edge.id !== undefined) {
45380 return edge.id;
45381 }
45382
45383 return edge;
45384 };
45385
45386 Network.prototype.selectNodes = function () {
45387 return this.selectionHandler.selectNodes.apply(this.selectionHandler, arguments);
45388 };
45389
45390 Network.prototype.selectEdges = function () {
45391 return this.selectionHandler.selectEdges.apply(this.selectionHandler, arguments);
45392 };
45393
45394 Network.prototype.unselectAll = function () {
45395 this.selectionHandler.unselectAll.apply(this.selectionHandler, arguments);
45396 this.selectionHandler.commitWithoutEmitting.apply(this.selectionHandler);
45397 this.redraw();
45398 };
45399
45400 Network.prototype.redraw = function () {
45401 return this.renderer.redraw.apply(this.renderer, arguments);
45402 };
45403
45404 Network.prototype.getScale = function () {
45405 return this.view.getScale.apply(this.view, arguments);
45406 };
45407
45408 Network.prototype.getViewPosition = function () {
45409 return this.view.getViewPosition.apply(this.view, arguments);
45410 };
45411
45412 Network.prototype.fit = function () {
45413 return this.view.fit.apply(this.view, arguments);
45414 };
45415
45416 Network.prototype.moveTo = function () {
45417 return this.view.moveTo.apply(this.view, arguments);
45418 };
45419
45420 Network.prototype.focus = function () {
45421 return this.view.focus.apply(this.view, arguments);
45422 };
45423
45424 Network.prototype.releaseNode = function () {
45425 return this.view.releaseNode.apply(this.view, arguments);
45426 };
45427
45428 Network.prototype.getOptionsFromConfigurator = function () {
45429 var options = {};
45430
45431 if (this.configurator) {
45432 options = this.configurator.getOptions.apply(this.configurator);
45433 }
45434
45435 return options;
45436 };
45437
45438 // DOM utility methods
45439
45440 /**
45441 * this prepares the JSON container for allocating SVG elements
45442 *
45443 * @param {object} JSONcontainer
45444 * @private
45445 */
45446 function prepareElements(JSONcontainer) {
45447 // cleanup the redundant svgElements;
45448 for (var elementType in JSONcontainer) {
45449 if (Object.prototype.hasOwnProperty.call(JSONcontainer, elementType)) {
45450 JSONcontainer[elementType].redundant = JSONcontainer[elementType].used;
45451 JSONcontainer[elementType].used = [];
45452 }
45453 }
45454 }
45455 /**
45456 * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from
45457 * which to remove the redundant elements.
45458 *
45459 * @param {object} JSONcontainer
45460 * @private
45461 */
45462
45463 function cleanupElements(JSONcontainer) {
45464 // cleanup the redundant svgElements;
45465 for (var elementType in JSONcontainer) {
45466 if (Object.prototype.hasOwnProperty.call(JSONcontainer, elementType)) {
45467 if (JSONcontainer[elementType].redundant) {
45468 for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) {
45469 JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]);
45470 }
45471
45472 JSONcontainer[elementType].redundant = [];
45473 }
45474 }
45475 }
45476 }
45477 /**
45478 * Ensures that all elements are removed first up so they can be recreated cleanly
45479 *
45480 * @param {object} JSONcontainer
45481 */
45482
45483 function resetElements(JSONcontainer) {
45484 prepareElements(JSONcontainer);
45485 cleanupElements(JSONcontainer);
45486 prepareElements(JSONcontainer);
45487 }
45488 /**
45489 * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
45490 * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
45491 *
45492 * @param {string} elementType
45493 * @param {object} JSONcontainer
45494 * @param {object} svgContainer
45495 * @returns {Element}
45496 * @private
45497 */
45498
45499 function getSVGElement(elementType, JSONcontainer, svgContainer) {
45500 var element; // allocate SVG element, if it doesnt yet exist, create one.
45501
45502 if (Object.prototype.hasOwnProperty.call(JSONcontainer, elementType)) {
45503 // this element has been created before
45504 // check if there is an redundant element
45505 if (JSONcontainer[elementType].redundant.length > 0) {
45506 element = JSONcontainer[elementType].redundant[0];
45507 JSONcontainer[elementType].redundant.shift();
45508 } else {
45509 // create a new element and add it to the SVG
45510 element = document.createElementNS("http://www.w3.org/2000/svg", elementType);
45511 svgContainer.appendChild(element);
45512 }
45513 } else {
45514 // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
45515 element = document.createElementNS("http://www.w3.org/2000/svg", elementType);
45516 JSONcontainer[elementType] = {
45517 used: [],
45518 redundant: []
45519 };
45520 svgContainer.appendChild(element);
45521 }
45522
45523 JSONcontainer[elementType].used.push(element);
45524 return element;
45525 }
45526 /**
45527 * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
45528 * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
45529 *
45530 * @param {string} elementType
45531 * @param {object} JSONcontainer
45532 * @param {Element} DOMContainer
45533 * @param {Element} insertBefore
45534 * @returns {*}
45535 */
45536
45537 function getDOMElement(elementType, JSONcontainer, DOMContainer, insertBefore) {
45538 var element; // allocate DOM element, if it doesnt yet exist, create one.
45539
45540 if (Object.prototype.hasOwnProperty.call(JSONcontainer, elementType)) {
45541 // this element has been created before
45542 // check if there is an redundant element
45543 if (JSONcontainer[elementType].redundant.length > 0) {
45544 element = JSONcontainer[elementType].redundant[0];
45545 JSONcontainer[elementType].redundant.shift();
45546 } else {
45547 // create a new element and add it to the SVG
45548 element = document.createElement(elementType);
45549
45550 if (insertBefore !== undefined) {
45551 DOMContainer.insertBefore(element, insertBefore);
45552 } else {
45553 DOMContainer.appendChild(element);
45554 }
45555 }
45556 } else {
45557 // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
45558 element = document.createElement(elementType);
45559 JSONcontainer[elementType] = {
45560 used: [],
45561 redundant: []
45562 };
45563
45564 if (insertBefore !== undefined) {
45565 DOMContainer.insertBefore(element, insertBefore);
45566 } else {
45567 DOMContainer.appendChild(element);
45568 }
45569 }
45570
45571 JSONcontainer[elementType].used.push(element);
45572 return element;
45573 }
45574 /**
45575 * Draw a point object. This is a separate function because it can also be called by the legend.
45576 * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions
45577 * as well.
45578 *
45579 * @param {number} x
45580 * @param {number} y
45581 * @param {object} groupTemplate: A template containing the necessary information to draw the datapoint e.g., {style: 'circle', size: 5, className: 'className' }
45582 * @param groupTemplate
45583 * @param {object} JSONcontainer
45584 * @param {object} svgContainer
45585 * @param {object} labelObj
45586 * @returns {vis.PointItem}
45587 */
45588
45589 function drawPoint(x, y, groupTemplate, JSONcontainer, svgContainer, labelObj) {
45590 var point;
45591
45592 if (groupTemplate.style == "circle") {
45593 point = getSVGElement("circle", JSONcontainer, svgContainer);
45594 point.setAttributeNS(null, "cx", x);
45595 point.setAttributeNS(null, "cy", y);
45596 point.setAttributeNS(null, "r", 0.5 * groupTemplate.size);
45597 } else {
45598 point = getSVGElement("rect", JSONcontainer, svgContainer);
45599 point.setAttributeNS(null, "x", x - 0.5 * groupTemplate.size);
45600 point.setAttributeNS(null, "y", y - 0.5 * groupTemplate.size);
45601 point.setAttributeNS(null, "width", groupTemplate.size);
45602 point.setAttributeNS(null, "height", groupTemplate.size);
45603 }
45604
45605 if (groupTemplate.styles !== undefined) {
45606 point.setAttributeNS(null, "style", groupTemplate.styles);
45607 }
45608
45609 point.setAttributeNS(null, "class", groupTemplate.className + " vis-point"); //handle label
45610
45611 if (labelObj) {
45612 var label = getSVGElement("text", JSONcontainer, svgContainer);
45613
45614 if (labelObj.xOffset) {
45615 x = x + labelObj.xOffset;
45616 }
45617
45618 if (labelObj.yOffset) {
45619 y = y + labelObj.yOffset;
45620 }
45621
45622 if (labelObj.content) {
45623 label.textContent = labelObj.content;
45624 }
45625
45626 if (labelObj.className) {
45627 label.setAttributeNS(null, "class", labelObj.className + " vis-label");
45628 }
45629
45630 label.setAttributeNS(null, "x", x);
45631 label.setAttributeNS(null, "y", y);
45632 }
45633
45634 return point;
45635 }
45636 /**
45637 * draw a bar SVG element centered on the X coordinate
45638 *
45639 * @param {number} x
45640 * @param {number} y
45641 * @param {number} width
45642 * @param {number} height
45643 * @param {string} className
45644 * @param {object} JSONcontainer
45645 * @param {object} svgContainer
45646 * @param {string} style
45647 */
45648
45649 function drawBar(x, y, width, height, className, JSONcontainer, svgContainer, style) {
45650 if (height != 0) {
45651 if (height < 0) {
45652 height *= -1;
45653 y -= height;
45654 }
45655
45656 var rect = getSVGElement("rect", JSONcontainer, svgContainer);
45657 rect.setAttributeNS(null, "x", x - 0.5 * width);
45658 rect.setAttributeNS(null, "y", y);
45659 rect.setAttributeNS(null, "width", width);
45660 rect.setAttributeNS(null, "height", height);
45661 rect.setAttributeNS(null, "class", className);
45662
45663 if (style) {
45664 rect.setAttributeNS(null, "style", style);
45665 }
45666 }
45667 }
45668
45669 var DOMutil = /*#__PURE__*/Object.freeze({
45670 __proto__: null,
45671 prepareElements: prepareElements,
45672 cleanupElements: cleanupElements,
45673 resetElements: resetElements,
45674 getSVGElement: getSVGElement,
45675 getDOMElement: getDOMElement,
45676 drawPoint: drawPoint,
45677 drawBar: drawBar
45678 });
45679
45680 // Network.
45681 var network = {
45682 Images: Images,
45683 dotparser: dotparser,
45684 gephiParser: gephiParser,
45685 allOptions: allOptions$1,
45686 convertDot: DOTToGraph,
45687 convertGephi: parseGephi
45688 }; // utils
45689
45690 var indexLegacy = /*#__PURE__*/Object.freeze({
45691 __proto__: null,
45692 network: network,
45693 DOMutil: DOMutil,
45694 util: index$2,
45695 data: index,
45696 Hammer: Hammer,
45697 keycharm: keycharm$1,
45698 DataSet: DataSet,
45699 DataView: DataView,
45700 Queue: Queue,
45701 Network: Network
45702 });
45703
45704 exports.DOMutil = DOMutil;
45705 exports.DataSet = DataSet;
45706 exports.DataView = DataView;
45707 exports.Hammer = Hammer;
45708 exports.Network = Network;
45709 exports.Queue = Queue;
45710 exports.data = index;
45711 exports["default"] = indexLegacy;
45712 exports.keycharm = keycharm$1;
45713 exports.network = network;
45714 exports.util = index$2;
45715
45716 Object.defineProperty(exports, '__esModule', { value: true });
45717
45718}));
45719//# sourceMappingURL=vis-network.js.map