@qe-libs/qeviz 0.2.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -3
- package/dist/qeviz.es.js +2421 -3062
- package/dist/qeviz.es.js.map +1 -1
- package/dist/qeviz.umd.js +5 -4078
- package/dist/qeviz.umd.js.map +1 -1
- package/package.json +2 -2
package/dist/qeviz.umd.js
CHANGED
|
@@ -1,1887 +1,11 @@
|
|
|
1
|
-
(function(global, factory) {
|
|
2
|
-
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.QEViz = {}));
|
|
3
|
-
})(this, (function(exports2) {
|
|
4
|
-
"use strict";var __defProp = Object.defineProperty;
|
|
5
|
-
var __typeError = (msg) => {
|
|
6
|
-
throw TypeError(msg);
|
|
7
|
-
};
|
|
8
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
-
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
10
|
-
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
11
|
-
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
12
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
13
|
-
|
|
14
|
-
var _rowNumber, _rowName, _names, _parent, _classes, _name, _type, _rowNames, _parent2, _names2, _rowNames2, _classes2, _flipped, _names3, _edge, _with_arrow, _arrow;
|
|
15
|
-
const _DataFrameRow = class _DataFrameRow extends Array {
|
|
16
|
-
constructor(names, values, rowName, parent, index) {
|
|
17
|
-
super(...values);
|
|
18
|
-
__privateAdd(this, _rowNumber);
|
|
19
|
-
__privateAdd(this, _rowName);
|
|
20
|
-
__privateAdd(this, _names);
|
|
21
|
-
__privateAdd(this, _parent);
|
|
22
|
-
__privateAdd(this, _classes);
|
|
23
|
-
__privateSet(this, _names, names);
|
|
24
|
-
__privateSet(this, _rowName, rowName);
|
|
25
|
-
__privateSet(this, _parent, parent);
|
|
26
|
-
__privateSet(this, _classes, parent == null ? void 0 : parent.classes);
|
|
27
|
-
__privateSet(this, _rowNumber, index);
|
|
28
|
-
}
|
|
29
|
-
get parent() {
|
|
30
|
-
return __privateGet(this, _parent);
|
|
31
|
-
}
|
|
32
|
-
get names() {
|
|
33
|
-
return __privateGet(this, _names);
|
|
34
|
-
}
|
|
35
|
-
get rowName() {
|
|
36
|
-
return __privateGet(this, _rowName);
|
|
37
|
-
}
|
|
38
|
-
get types() {
|
|
39
|
-
if (!__privateGet(this, _parent)) throw new Error("No parent DataFrame attached to this row.");
|
|
40
|
-
return __privateGet(this, _parent).types;
|
|
41
|
-
}
|
|
42
|
-
get classes() {
|
|
43
|
-
return __privateGet(this, _classes);
|
|
44
|
-
}
|
|
45
|
-
get rowNumber() {
|
|
46
|
-
return __privateGet(this, _rowNumber);
|
|
47
|
-
}
|
|
48
|
-
col(wh) {
|
|
49
|
-
if (!__privateGet(this, _parent)) throw new Error("No parent DataFrame attached to this row.");
|
|
50
|
-
return __privateGet(this, _parent).col(wh);
|
|
51
|
-
}
|
|
52
|
-
cols(...wh) {
|
|
53
|
-
if (!__privateGet(this, _parent)) throw new Error("No parent DataFrame attached to this row.");
|
|
54
|
-
return __privateGet(this, _parent).cols(...wh);
|
|
55
|
-
}
|
|
56
|
-
filter(predicate) {
|
|
57
|
-
console.error("DataFrameRow does not currently support filtering.");
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
_rowNumber = new WeakMap();
|
|
61
|
-
_rowName = new WeakMap();
|
|
62
|
-
_names = new WeakMap();
|
|
63
|
-
_parent = new WeakMap();
|
|
64
|
-
_classes = new WeakMap();
|
|
65
|
-
__name(_DataFrameRow, "DataFrameRow");
|
|
66
|
-
let DataFrameRow = _DataFrameRow;
|
|
67
|
-
var DataFrameColumnType = /* @__PURE__ */ ((DataFrameColumnType2) => {
|
|
68
|
-
DataFrameColumnType2["Character"] = "character";
|
|
69
|
-
DataFrameColumnType2["Double"] = "double";
|
|
70
|
-
DataFrameColumnType2["Logical"] = "logical";
|
|
71
|
-
DataFrameColumnType2["Integer"] = "integer";
|
|
72
|
-
return DataFrameColumnType2;
|
|
73
|
-
})(DataFrameColumnType || {});
|
|
74
|
-
const _DataFrameColumn = class _DataFrameColumn extends Array {
|
|
75
|
-
constructor(name, column, rowNames, parent) {
|
|
76
|
-
super(column.length);
|
|
77
|
-
__privateAdd(this, _name);
|
|
78
|
-
__privateAdd(this, _type);
|
|
79
|
-
__privateAdd(this, _rowNames);
|
|
80
|
-
__privateAdd(this, _parent2);
|
|
81
|
-
for (let i = 0; i < column.length; i++) {
|
|
82
|
-
this[i] = column[i];
|
|
83
|
-
}
|
|
84
|
-
__privateSet(this, _name, name);
|
|
85
|
-
if (column.type !== void 0) {
|
|
86
|
-
__privateSet(this, _type, column.type);
|
|
87
|
-
} else {
|
|
88
|
-
if (column.every((v) => typeof v === "string" || v === null || v === void 0)) {
|
|
89
|
-
__privateSet(this, _type, "character");
|
|
90
|
-
} else if (column.every((v) => Number.isInteger(v) || v === null || v === void 0)) {
|
|
91
|
-
if (column.every((v) => v === 0 || v === 1 || v === null || v === void 0)) {
|
|
92
|
-
__privateSet(this, _type, "logical");
|
|
93
|
-
} else {
|
|
94
|
-
__privateSet(this, _type, "integer");
|
|
95
|
-
}
|
|
96
|
-
} else if (column.every((v) => typeof v === "number" || v === null || v === void 0)) {
|
|
97
|
-
__privateSet(this, _type, "double");
|
|
98
|
-
} else if (column.every((v) => typeof v === "boolean" || v === null || v === void 0)) {
|
|
99
|
-
__privateSet(this, _type, "logical");
|
|
100
|
-
} else {
|
|
101
|
-
__privateSet(this, _type, "character");
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
__privateSet(this, _parent2, parent);
|
|
105
|
-
if (rowNames && rowNames.length !== this.length) {
|
|
106
|
-
throw new Error("Row names length must match the number of rows in the DataFrameColumn.");
|
|
107
|
-
}
|
|
108
|
-
if (rowNames && rowNames.length > 0) {
|
|
109
|
-
__privateSet(this, _rowNames, rowNames);
|
|
110
|
-
} else {
|
|
111
|
-
__privateSet(this, _rowNames, void 0);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
get name() {
|
|
115
|
-
return __privateGet(this, _name);
|
|
116
|
-
}
|
|
117
|
-
get type() {
|
|
118
|
-
return __privateGet(this, _type);
|
|
119
|
-
}
|
|
120
|
-
get rowNames() {
|
|
121
|
-
return __privateGet(this, _rowNames);
|
|
122
|
-
}
|
|
123
|
-
row(wh) {
|
|
124
|
-
if (!__privateGet(this, _parent2)) throw new Error("No parent DataFrame attached to this column.");
|
|
125
|
-
return __privateGet(this, _parent2).row(wh);
|
|
126
|
-
}
|
|
127
|
-
rows(...wh) {
|
|
128
|
-
if (!__privateGet(this, _parent2)) throw new Error("No parent DataFrame attached to this column.");
|
|
129
|
-
return __privateGet(this, _parent2).rows(...wh);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
_name = new WeakMap();
|
|
133
|
-
_type = new WeakMap();
|
|
134
|
-
_rowNames = new WeakMap();
|
|
135
|
-
_parent2 = new WeakMap();
|
|
136
|
-
__name(_DataFrameColumn, "DataFrameColumn");
|
|
137
|
-
let DataFrameColumn = _DataFrameColumn;
|
|
138
|
-
const _DataFrame = class _DataFrame extends Array {
|
|
139
|
-
constructor(names, colValues, rowNames, classes) {
|
|
140
|
-
if (!names || !colValues) {
|
|
141
|
-
colValues = [];
|
|
142
|
-
names = [];
|
|
143
|
-
}
|
|
144
|
-
if (colValues.map((c) => c.length).every((l) => l === names.length)) {
|
|
145
|
-
const transposed = [];
|
|
146
|
-
for (let i = 0; i < names.length; i++) {
|
|
147
|
-
const col = [];
|
|
148
|
-
for (let j = 0; j < colValues.length; j++) {
|
|
149
|
-
col.push(colValues[j][i]);
|
|
150
|
-
}
|
|
151
|
-
transposed.push(col);
|
|
152
|
-
}
|
|
153
|
-
colValues = transposed;
|
|
154
|
-
}
|
|
155
|
-
super(colValues.length);
|
|
156
|
-
__privateAdd(this, _names2);
|
|
157
|
-
__privateAdd(this, _rowNames2);
|
|
158
|
-
__privateAdd(this, _classes2);
|
|
159
|
-
colValues.forEach((col, index) => {
|
|
160
|
-
if (col instanceof DataFrameColumn) {
|
|
161
|
-
this[index] = col;
|
|
162
|
-
} else {
|
|
163
|
-
this[index] = new DataFrameColumn(names[index], col, rowNames, this);
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
__privateSet(this, _names2, names);
|
|
167
|
-
if (rowNames && this[0] && rowNames.length !== this[0].length) {
|
|
168
|
-
throw new Error("Row names length must match the number of rows in the DataFrame.");
|
|
169
|
-
}
|
|
170
|
-
if (rowNames && rowNames.length > 0) {
|
|
171
|
-
__privateSet(this, _rowNames2, rowNames);
|
|
172
|
-
}
|
|
173
|
-
if (classes && classes.length !== this.length) {
|
|
174
|
-
throw new Error("Classes length must match the number of columns in the DataFrame.");
|
|
175
|
-
}
|
|
176
|
-
if (classes && classes.length > 0) {
|
|
177
|
-
__privateSet(this, _classes2, classes);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
get classes() {
|
|
181
|
-
return __privateGet(this, _classes2);
|
|
182
|
-
}
|
|
183
|
-
getColumnByName(name) {
|
|
184
|
-
const idx = __privateGet(this, _names2).indexOf(name);
|
|
185
|
-
return idx >= 0 ? this[idx] : void 0;
|
|
186
|
-
}
|
|
187
|
-
getRowByIndex(index) {
|
|
188
|
-
if (this && this.length === 0) {
|
|
189
|
-
console.warn("DataFrame is empty, cannot get row by index", index);
|
|
190
|
-
return new DataFrameRow(__privateGet(this, _names2), [], void 0, this, index);
|
|
191
|
-
}
|
|
192
|
-
const result_vals = [];
|
|
193
|
-
for (let col of this) {
|
|
194
|
-
let v = col[index];
|
|
195
|
-
result_vals.push(v);
|
|
196
|
-
}
|
|
197
|
-
return new DataFrameRow(__privateGet(this, _names2), result_vals, __privateGet(this, _rowNames2) ? __privateGet(this, _rowNames2)[index] : void 0, this, index);
|
|
198
|
-
}
|
|
199
|
-
getRowByName(name) {
|
|
200
|
-
if (!__privateGet(this, _rowNames2)) return void 0;
|
|
201
|
-
const index = __privateGet(this, _rowNames2).indexOf(name);
|
|
202
|
-
if (index === -1) return void 0;
|
|
203
|
-
return this.getRowByIndex(index);
|
|
204
|
-
}
|
|
205
|
-
get types() {
|
|
206
|
-
return this.map((col) => col.type);
|
|
207
|
-
}
|
|
208
|
-
type(wh) {
|
|
209
|
-
var _a;
|
|
210
|
-
if (typeof wh === "number") {
|
|
211
|
-
return (_a = this[wh]) == null ? void 0 : _a.type;
|
|
212
|
-
} else if (typeof wh === "string") {
|
|
213
|
-
const col = this.getColumnByName(wh);
|
|
214
|
-
return col ? col.type : void 0;
|
|
215
|
-
}
|
|
216
|
-
return void 0;
|
|
217
|
-
}
|
|
218
|
-
// row(wh: string | number): DataFrameRow | undefined {
|
|
219
|
-
row(wh) {
|
|
220
|
-
if (typeof wh === "number") {
|
|
221
|
-
return this.getRowByIndex(wh);
|
|
222
|
-
} else if (typeof wh === "string") {
|
|
223
|
-
return this.getRowByName(wh);
|
|
224
|
-
}
|
|
225
|
-
return void 0;
|
|
226
|
-
}
|
|
227
|
-
// rows(...wh: (string | number)[]): DataFrame {
|
|
228
|
-
rows(...wh) {
|
|
229
|
-
let selectors, selectedRows = [], selectedRowNames = [];
|
|
230
|
-
if (wh.length === 0) {
|
|
231
|
-
if (!this[0] || this.length === 0) {
|
|
232
|
-
return [];
|
|
233
|
-
}
|
|
234
|
-
const numRows = this[0].length;
|
|
235
|
-
selectedRows = Array.from({ length: numRows }, (_, i) => this.getRowByIndex(i));
|
|
236
|
-
selectedRowNames = __privateGet(this, _rowNames2);
|
|
237
|
-
} else {
|
|
238
|
-
if (wh.length === 1 && Array.isArray(wh[0])) {
|
|
239
|
-
selectors = wh[0];
|
|
240
|
-
} else {
|
|
241
|
-
selectors = wh;
|
|
242
|
-
}
|
|
243
|
-
selectedRows = selectors.map((item, i) => {
|
|
244
|
-
let r = this.row(item);
|
|
245
|
-
if (__privateGet(this, _rowNames2) && r) {
|
|
246
|
-
selectedRowNames == null ? void 0 : selectedRowNames.push(__privateGet(this, _rowNames2)[i]);
|
|
247
|
-
}
|
|
248
|
-
return r;
|
|
249
|
-
}).filter((row) => row !== void 0);
|
|
250
|
-
}
|
|
251
|
-
return selectedRows;
|
|
252
|
-
}
|
|
253
|
-
col(wh) {
|
|
254
|
-
if (typeof wh === "number") {
|
|
255
|
-
return this[wh];
|
|
256
|
-
} else if (typeof wh === "string") {
|
|
257
|
-
return this.getColumnByName(wh);
|
|
258
|
-
}
|
|
259
|
-
return void 0;
|
|
260
|
-
}
|
|
261
|
-
cols(...wh) {
|
|
262
|
-
let selectors, selectedCols, selectedNames = [];
|
|
263
|
-
if (wh.length === 0) {
|
|
264
|
-
selectedCols = this.slice();
|
|
265
|
-
selectedNames = __privateGet(this, _names2);
|
|
266
|
-
} else {
|
|
267
|
-
if (wh.length === 1 && Array.isArray(wh[0])) {
|
|
268
|
-
selectors = wh[0];
|
|
269
|
-
} else {
|
|
270
|
-
selectors = wh;
|
|
271
|
-
}
|
|
272
|
-
selectedCols = selectors.map((item) => this.col(item)).filter((col) => col !== void 0);
|
|
273
|
-
selectedNames = selectedCols.map((col) => col.name);
|
|
274
|
-
}
|
|
275
|
-
return new _DataFrame(selectedNames, selectedCols, __privateGet(this, _rowNames2));
|
|
276
|
-
}
|
|
277
|
-
subset(rows, cols) {
|
|
278
|
-
const selectedCols = cols && cols.length > 0 ? this.cols(...cols) : this.slice();
|
|
279
|
-
return new _DataFrame(
|
|
280
|
-
selectedCols.map((col) => col.name),
|
|
281
|
-
selectedCols.map((col) => col.values),
|
|
282
|
-
__privateGet(this, _rowNames2)
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
get names() {
|
|
286
|
-
return __privateGet(this, _names2);
|
|
287
|
-
}
|
|
288
|
-
get rowNames() {
|
|
289
|
-
return __privateGet(this, _rowNames2);
|
|
290
|
-
}
|
|
291
|
-
get nrow() {
|
|
292
|
-
return this[0] ? this[0].length : 0;
|
|
293
|
-
}
|
|
294
|
-
get ncol() {
|
|
295
|
-
return this.length;
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
_names2 = new WeakMap();
|
|
299
|
-
_rowNames2 = new WeakMap();
|
|
300
|
-
_classes2 = new WeakMap();
|
|
301
|
-
__name(_DataFrame, "DataFrame");
|
|
302
|
-
let DataFrame = _DataFrame;
|
|
303
|
-
const _Model = class _Model {
|
|
304
|
-
constructor(o = {}) {
|
|
305
|
-
this.unit_id_col = "id";
|
|
306
|
-
this.node_id_col = "id";
|
|
307
|
-
this.group_col = null;
|
|
308
|
-
this.directed = false;
|
|
309
|
-
this._points = o.points ?? new DataFrame();
|
|
310
|
-
this._nodes = o.nodes ?? new DataFrame();
|
|
311
|
-
this._edges = o.edges ?? new DataFrame();
|
|
312
|
-
this._dimensions = o.dimensions ?? [];
|
|
313
|
-
this._confidence = void 0;
|
|
314
|
-
this._outlier = void 0;
|
|
315
|
-
this._groups = void 0;
|
|
316
|
-
}
|
|
317
|
-
get updated() {
|
|
318
|
-
return this._updated;
|
|
319
|
-
}
|
|
320
|
-
set updated(v) {
|
|
321
|
-
this._updated = v;
|
|
322
|
-
}
|
|
323
|
-
get points() {
|
|
324
|
-
return this._points;
|
|
325
|
-
}
|
|
326
|
-
set points(v) {
|
|
327
|
-
this._points = v;
|
|
328
|
-
}
|
|
329
|
-
get nodes() {
|
|
330
|
-
return this._nodes;
|
|
331
|
-
}
|
|
332
|
-
set nodes(v) {
|
|
333
|
-
this._nodes = v;
|
|
334
|
-
}
|
|
335
|
-
get edges() {
|
|
336
|
-
return this._edges;
|
|
337
|
-
}
|
|
338
|
-
set edges(v) {
|
|
339
|
-
this._edges = v;
|
|
340
|
-
}
|
|
341
|
-
get confidence() {
|
|
342
|
-
return this._confidence;
|
|
343
|
-
}
|
|
344
|
-
set confidence(v) {
|
|
345
|
-
this._confidence = v;
|
|
346
|
-
}
|
|
347
|
-
get outlier() {
|
|
348
|
-
return this._outlier;
|
|
349
|
-
}
|
|
350
|
-
set outlier(v) {
|
|
351
|
-
this._outlier = v;
|
|
352
|
-
}
|
|
353
|
-
get groups() {
|
|
354
|
-
return this._groups;
|
|
355
|
-
}
|
|
356
|
-
set groups(v) {
|
|
357
|
-
this._groups = v;
|
|
358
|
-
}
|
|
359
|
-
get trajectories() {
|
|
360
|
-
return this._trajectories;
|
|
361
|
-
}
|
|
362
|
-
set trajectories(v) {
|
|
363
|
-
this._trajectories = v;
|
|
364
|
-
}
|
|
365
|
-
get dimensions() {
|
|
366
|
-
return this._dimensions;
|
|
367
|
-
}
|
|
368
|
-
set dimensions(v) {
|
|
369
|
-
this._dimensions = v;
|
|
370
|
-
}
|
|
371
|
-
get params() {
|
|
372
|
-
return this._params;
|
|
373
|
-
}
|
|
374
|
-
set params(v) {
|
|
375
|
-
this._params = v;
|
|
376
|
-
}
|
|
377
|
-
point(id) {
|
|
378
|
-
return this._points.row(id);
|
|
379
|
-
}
|
|
380
|
-
setByKey(key, value) {
|
|
381
|
-
this[key] = value;
|
|
382
|
-
}
|
|
383
|
-
};
|
|
384
|
-
__name(_Model, "Model");
|
|
385
|
-
let Model = _Model;
|
|
386
|
-
const DEBUG = globalThis.__QEVIZ_DEBUG__ === true;
|
|
387
|
-
function dbg(...args) {
|
|
388
|
-
if (DEBUG) console.log(...args);
|
|
389
|
-
}
|
|
390
|
-
__name(dbg, "dbg");
|
|
391
|
-
const vizENA = {
|
|
392
|
-
get: /* @__PURE__ */ __name((n) => {
|
|
393
|
-
const elements = [...document.querySelectorAll("qe-graph")];
|
|
394
|
-
if (typeof n === "number" && n >= 0) {
|
|
395
|
-
return elements[n];
|
|
396
|
-
}
|
|
397
|
-
return elements;
|
|
398
|
-
}, "get")
|
|
399
|
-
};
|
|
400
|
-
const _QEVisualElement = class _QEVisualElement extends HTMLElement {
|
|
401
|
-
constructor() {
|
|
402
|
-
super();
|
|
403
|
-
this._isVisible = true;
|
|
404
|
-
this.output = "";
|
|
405
|
-
this._updated = "";
|
|
406
|
-
this._active_points = [];
|
|
407
|
-
this._points = /* @__PURE__ */ new Map();
|
|
408
|
-
this._edges = /* @__PURE__ */ new Map();
|
|
409
|
-
this._labels = /* @__PURE__ */ new Map();
|
|
410
|
-
this._model = new Model();
|
|
411
|
-
const shadow = this.attachShadow({ mode: "open" });
|
|
412
|
-
const style = document.createElement("style");
|
|
413
|
-
style.textContent = _QEVisualElement.styles;
|
|
414
|
-
shadow.appendChild(style);
|
|
415
|
-
this._outputElement = document.createElement("div");
|
|
416
|
-
shadow.appendChild(this._outputElement);
|
|
417
|
-
}
|
|
418
|
-
static get observedAttributes() {
|
|
419
|
-
return ["updated"];
|
|
420
|
-
}
|
|
421
|
-
/** Public accessor so ena-graph (and external code) can read the model. */
|
|
422
|
-
get model() {
|
|
423
|
-
return this._model;
|
|
424
|
-
}
|
|
425
|
-
get updated() {
|
|
426
|
-
return this._updated;
|
|
427
|
-
}
|
|
428
|
-
set updated(val) {
|
|
429
|
-
this._updated = val;
|
|
430
|
-
this.setAttribute("updated", val);
|
|
431
|
-
this.dispatchEvent(new CustomEvent("model-updated", {
|
|
432
|
-
detail: this._model,
|
|
433
|
-
bubbles: true,
|
|
434
|
-
composed: true
|
|
435
|
-
}));
|
|
436
|
-
}
|
|
437
|
-
get points() {
|
|
438
|
-
return this._points;
|
|
439
|
-
}
|
|
440
|
-
set points(pts) {
|
|
441
|
-
this._points.clear();
|
|
442
|
-
if (pts instanceof Map) {
|
|
443
|
-
this._points = pts;
|
|
444
|
-
} else if (Array.isArray(pts)) {
|
|
445
|
-
pts.forEach((p) => this._points.set(p.ID, p));
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
get active_points() {
|
|
449
|
-
return Array.from(this._active_points.values());
|
|
450
|
-
}
|
|
451
|
-
get edges() {
|
|
452
|
-
return this._edges;
|
|
453
|
-
}
|
|
454
|
-
set edges(edges) {
|
|
455
|
-
this._edges.clear();
|
|
456
|
-
if (edges instanceof Map) {
|
|
457
|
-
this._edges = edges;
|
|
458
|
-
} else if (Array.isArray(edges)) {
|
|
459
|
-
this._edges = /* @__PURE__ */ new Map();
|
|
460
|
-
edges.forEach((e) => this._edges.set(e.ID, e));
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
get labels() {
|
|
464
|
-
return this._labels;
|
|
465
|
-
}
|
|
466
|
-
connectedCallback() {
|
|
467
|
-
dbg("QEVisualElement connected");
|
|
468
|
-
this.render();
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Accept pre-fetched ENA model data and update the visualization.
|
|
472
|
-
* Call this directly when data is available from any source —
|
|
473
|
-
* rENA R package, Python package, or static JSON.
|
|
474
|
-
*/
|
|
475
|
-
setModelData(data) {
|
|
476
|
-
var _a, _b, _c, _d;
|
|
477
|
-
const frameKeys = ["nodes", "edges", "points", "groups", "confidence", "outlier", "trajectories"];
|
|
478
|
-
frameKeys.forEach((name) => {
|
|
479
|
-
var _a2;
|
|
480
|
-
const raw = data[name];
|
|
481
|
-
if (!((_a2 = raw == null ? void 0 : raw.data) == null ? void 0 : _a2.length)) return;
|
|
482
|
-
const rows = raw.data, types = raw.types || {}, colNames = Object.keys(rows[0]), colValues = rows.map((v) => Object.values(v)), classes = colNames.map((col) => types[col] ?? "character");
|
|
483
|
-
let idCol;
|
|
484
|
-
if (name === "nodes") {
|
|
485
|
-
idCol = data.node_id_col ?? colNames.find((c) => (types[c] ?? "character") === "character");
|
|
486
|
-
} else if (name === "edges" || name === "points" || name === "trajectories") {
|
|
487
|
-
idCol = data.id_col ?? colNames.find((c) => (types[c] ?? "character") === "character");
|
|
488
|
-
} else {
|
|
489
|
-
idCol = data.group_col ?? colNames.find((c) => (types[c] ?? "character") === "character");
|
|
490
|
-
}
|
|
491
|
-
const removalCol = idCol ? colNames.indexOf(idCol) : 0;
|
|
492
|
-
const rowNames = colValues.map((v) => String(v[removalCol]));
|
|
493
|
-
this._model.setByKey(name, new DataFrame(colNames, colValues, rowNames, classes));
|
|
494
|
-
});
|
|
495
|
-
if (data.updated !== void 0) this._model.setByKey("updated", data.updated);
|
|
496
|
-
if (data.directed !== void 0) this._model.directed = data.directed;
|
|
497
|
-
const nodesDF = this._model.nodes;
|
|
498
|
-
this._model.node_id_col = data.node_id_col ?? ((_a = nodesDF == null ? void 0 : nodesDF.names) == null ? void 0 : _a.find((n) => {
|
|
499
|
-
var _a2;
|
|
500
|
-
return ((_a2 = nodesDF.col(n)) == null ? void 0 : _a2.type) === "character";
|
|
501
|
-
})) ?? "id";
|
|
502
|
-
const pointsDF = this._model.points;
|
|
503
|
-
this._model.unit_id_col = data.id_col ?? ((_b = pointsDF == null ? void 0 : pointsDF.names) == null ? void 0 : _b.find((n) => {
|
|
504
|
-
var _a2;
|
|
505
|
-
return ((_a2 = pointsDF.col(n)) == null ? void 0 : _a2.type) === "character";
|
|
506
|
-
})) ?? "id";
|
|
507
|
-
const unitId = this._model.unit_id_col;
|
|
508
|
-
this._model.group_col = data.group_col ?? ((_c = pointsDF == null ? void 0 : pointsDF.names) == null ? void 0 : _c.find((n) => {
|
|
509
|
-
var _a2;
|
|
510
|
-
return n !== unitId && ((_a2 = pointsDF.col(n)) == null ? void 0 : _a2.type) === "character";
|
|
511
|
-
})) ?? null;
|
|
512
|
-
if ((_d = nodesDF == null ? void 0 : nodesDF.names) == null ? void 0 : _d.length) {
|
|
513
|
-
const nodeId = this._model.node_id_col;
|
|
514
|
-
const xColOvr = data.x_col;
|
|
515
|
-
const yColOvr = data.y_col;
|
|
516
|
-
if (xColOvr && yColOvr) {
|
|
517
|
-
this._model.dimensions = [xColOvr, yColOvr];
|
|
518
|
-
} else {
|
|
519
|
-
const numCols = nodesDF.names.filter((n) => {
|
|
520
|
-
if (n === nodeId) return false;
|
|
521
|
-
const col = nodesDF.col(n);
|
|
522
|
-
return col && col.type !== "character" && col.type !== "logical";
|
|
523
|
-
});
|
|
524
|
-
if (numCols.length >= 2) {
|
|
525
|
-
this._model.dimensions = [xColOvr ?? numCols[0], yColOvr ?? numCols[1]];
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
this.updated = this._model.updated !== void 0 ? String(this._model.updated) : String(Date.now());
|
|
530
|
-
dbg("Model updated via setModelData:", this.updated);
|
|
531
|
-
this.render();
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* Base implementation is a no-op. Subclasses (e.g. RQEVisualElement) override
|
|
535
|
-
* this to fetch data from a backend and call setModelData().
|
|
536
|
-
*/
|
|
537
|
-
async calculate() {
|
|
538
|
-
}
|
|
539
|
-
render() {
|
|
540
|
-
var _a;
|
|
541
|
-
if (!this._isVisible) {
|
|
542
|
-
this.classList.add("hidden");
|
|
543
|
-
} else {
|
|
544
|
-
this.classList.remove("hidden");
|
|
545
|
-
}
|
|
546
|
-
if (((_a = this._model) == null ? void 0 : _a.updated) !== void 0 && this._model.updated !== null) {
|
|
547
|
-
this._outputElement.innerHTML = `${this.output}<slot></slot>`;
|
|
548
|
-
} else {
|
|
549
|
-
this._outputElement.innerHTML = "Define the model on the left.";
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
};
|
|
553
|
-
__name(_QEVisualElement, "QEVisualElement");
|
|
554
|
-
_QEVisualElement.tagName = "qe-visual";
|
|
555
|
-
_QEVisualElement.styles = `
|
|
1
|
+
(function(S,B){typeof exports=="object"&&typeof module<"u"?B(exports):typeof define=="function"&&define.amd?define(["exports"],B):(S=typeof globalThis<"u"?globalThis:S||self,B(S.QEViz={}))})(this,(function(S){"use strict";var Ri=Object.defineProperty;var ni=S=>{throw TypeError(S)};var u=(S,B)=>Ri(S,"name",{value:B,configurable:!0});var ri=(S,B,_t)=>B.has(S)||ni("Cannot "+_t);var C=(S,B,_t)=>(ri(S,B,"read from private field"),_t?_t.call(S):B.get(S)),it=(S,B,_t)=>B.has(S)?ni("Cannot add the same private member more than once"):B instanceof WeakSet?B.add(S):B.set(S,_t),W=(S,B,_t,It)=>(ri(S,B,"write to private field"),It?It.call(S,_t):B.set(S,_t),_t);var ge,me,fe,pt,pe,be,bt,Ut,Ct,St,at,ye,Tt,Et,Xt,Wt,Se;const ns=class ns extends Array{constructor(e,s,i,n,r){super(...s);it(this,ge);it(this,me);it(this,fe);it(this,pt);it(this,pe);W(this,fe,e),W(this,me,i),W(this,pt,n),W(this,pe,n==null?void 0:n.classes),W(this,ge,r)}get parent(){return C(this,pt)}get names(){return C(this,fe)}get rowName(){return C(this,me)}get types(){if(!C(this,pt))throw new Error("No parent DataFrame attached to this row.");return C(this,pt).types}get classes(){return C(this,pe)}get rowNumber(){return C(this,ge)}col(e){if(!C(this,pt))throw new Error("No parent DataFrame attached to this row.");return C(this,pt).col(e)}cols(...e){if(!C(this,pt))throw new Error("No parent DataFrame attached to this row.");return C(this,pt).cols(...e)}filter(e){console.error("DataFrameRow does not currently support filtering.")}};ge=new WeakMap,me=new WeakMap,fe=new WeakMap,pt=new WeakMap,pe=new WeakMap,u(ns,"DataFrameRow");let B=ns;var _t=(d=>(d.Character="character",d.Double="double",d.Logical="logical",d.Integer="integer",d))(_t||{});const rs=class rs extends Array{constructor(e,s,i,n){super(s.length);it(this,be);it(this,bt);it(this,Ut);it(this,Ct);for(let r=0;r<s.length;r++)this[r]=s[r];if(W(this,be,e),s.type!==void 0?W(this,bt,s.type):s.every(r=>typeof r=="string"||r===null||r===void 0)?W(this,bt,"character"):s.every(r=>Number.isInteger(r)||r===null||r===void 0)?s.every(r=>r===0||r===1||r===null||r===void 0)?W(this,bt,"logical"):W(this,bt,"integer"):s.every(r=>typeof r=="number"||r===null||r===void 0)?W(this,bt,"double"):s.every(r=>typeof r=="boolean"||r===null||r===void 0)?W(this,bt,"logical"):W(this,bt,"character"),W(this,Ct,n),i&&i.length!==this.length)throw new Error("Row names length must match the number of rows in the DataFrameColumn.");i&&i.length>0?W(this,Ut,i):W(this,Ut,void 0)}get name(){return C(this,be)}get type(){return C(this,bt)}get rowNames(){return C(this,Ut)}row(e){if(!C(this,Ct))throw new Error("No parent DataFrame attached to this column.");return C(this,Ct).row(e)}rows(...e){if(!C(this,Ct))throw new Error("No parent DataFrame attached to this column.");return C(this,Ct).rows(...e)}};be=new WeakMap,bt=new WeakMap,Ut=new WeakMap,Ct=new WeakMap,u(rs,"DataFrameColumn");let It=rs;const xe=class xe extends Array{constructor(e,s,i,n){if((!e||!s)&&(s=[],e=[]),s.map(r=>r.length).every(r=>r===e.length)){const r=[];for(let a=0;a<e.length;a++){const h=[];for(let o=0;o<s.length;o++)h.push(s[o][a]);r.push(h)}s=r}super(s.length);it(this,St);it(this,at);it(this,ye);if(s.forEach((r,a)=>{r instanceof It?this[a]=r:this[a]=new It(e[a],r,i,this)}),W(this,St,e),i&&this[0]&&i.length!==this[0].length)throw new Error("Row names length must match the number of rows in the DataFrame.");if(i&&i.length>0&&W(this,at,i),n&&n.length!==this.length)throw new Error("Classes length must match the number of columns in the DataFrame.");n&&n.length>0&&W(this,ye,n)}get classes(){return C(this,ye)}getColumnByName(e){const s=C(this,St).indexOf(e);return s>=0?this[s]:void 0}getRowByIndex(e){if(this&&this.length===0)return console.warn("DataFrame is empty, cannot get row by index",e),new B(C(this,St),[],void 0,this,e);const s=[];for(let i of this){let n=i[e];s.push(n)}return new B(C(this,St),s,C(this,at)?C(this,at)[e]:void 0,this,e)}getRowByName(e){if(!C(this,at))return;const s=C(this,at).indexOf(e);if(s!==-1)return this.getRowByIndex(s)}get types(){return this.map(e=>e.type)}type(e){var s;if(typeof e=="number")return(s=this[e])==null?void 0:s.type;if(typeof e=="string"){const i=this.getColumnByName(e);return i?i.type:void 0}}row(e){if(typeof e=="number")return this.getRowByIndex(e);if(typeof e=="string")return this.getRowByName(e)}rows(...e){let s,i=[],n=[];if(e.length===0){if(!this[0]||this.length===0)return[];const r=this[0].length;i=Array.from({length:r},(a,h)=>this.getRowByIndex(h)),n=C(this,at)}else e.length===1&&Array.isArray(e[0])?s=e[0]:s=e,i=s.map((r,a)=>{let h=this.row(r);return C(this,at)&&h&&(n==null||n.push(C(this,at)[a])),h}).filter(r=>r!==void 0);return i}col(e){if(typeof e=="number")return this[e];if(typeof e=="string")return this.getColumnByName(e)}cols(...e){let s,i,n=[];return e.length===0?(i=this.slice(),n=C(this,St)):(e.length===1&&Array.isArray(e[0])?s=e[0]:s=e,i=s.map(r=>this.col(r)).filter(r=>r!==void 0),n=i.map(r=>r.name)),new xe(n,i,C(this,at))}subset(e,s){const i=s&&s.length>0?this.cols(...s):this.slice();return new xe(i.map(n=>n.name),i.map(n=>n.values),C(this,at))}get names(){return C(this,St)}get rowNames(){return C(this,at)}get nrow(){return this[0]?this[0].length:0}get ncol(){return this.length}};St=new WeakMap,at=new WeakMap,ye=new WeakMap,u(xe,"DataFrame");let $t=xe;const os=class os{constructor(t={}){this.unit_id_col="id",this.node_id_col="id",this.group_col=null,this.directed=!1,this.palette=[],this._points=t.points??new $t,this._nodes=t.nodes??new $t,this._edges=t.edges??new $t,this._dimensions=t.dimensions??[],this._confidence=void 0,this._outlier=void 0,this._groups=void 0}get updated(){return this._updated}set updated(t){this._updated=t}get points(){return this._points}set points(t){this._points=t}get nodes(){return this._nodes}set nodes(t){this._nodes=t}get edges(){return this._edges}set edges(t){this._edges=t}get confidence(){return this._confidence}set confidence(t){this._confidence=t}get outlier(){return this._outlier}set outlier(t){this._outlier=t}get groups(){return this._groups}set groups(t){this._groups=t}get trajectories(){return this._trajectories}set trajectories(t){this._trajectories=t}get networks(){return this._networks}set networks(t){this._networks=t}get pointsets(){return this._pointsets}set pointsets(t){this._pointsets=t}get dimensions(){return this._dimensions}set dimensions(t){this._dimensions=t}get params(){return this._params}set params(t){this._params=t}point(t){return this._points.row(t)}setByKey(t,e){this[t]=e}};u(os,"Model");let Ve=os;const oi=globalThis.__QEVIZ_DEBUG__===!0;function Ss(...d){oi&&console.log(...d)}u(Ss,"dbg");const ai={get:u(d=>{const t=[...document.querySelectorAll("qe-graph")];return typeof d=="number"&&d>=0?t[d]:t},"get")},Bt=class Bt extends HTMLElement{constructor(){super(),this._isVisible=!0,this.output="",this._updated="",this._active_points=[],this._points=new Map,this._edges=new Map,this._labels=new Map,this._model=new Ve;const t=this.attachShadow({mode:"open"}),e=document.createElement("style");e.textContent=Bt.styles,t.appendChild(e),this._outputElement=document.createElement("div"),t.appendChild(this._outputElement)}static get observedAttributes(){return["updated"]}get model(){return this._model}get updated(){return this._updated}set updated(t){this._updated=t,this.setAttribute("updated",t),this.dispatchEvent(new CustomEvent("model-updated",{detail:this._model,bubbles:!0,composed:!0}))}get points(){return this._points}set points(t){this._points.clear(),t instanceof Map?this._points=t:Array.isArray(t)&&t.forEach(e=>this._points.set(e.ID,e))}get active_points(){return Array.from(this._active_points.values())}get edges(){return this._edges}set edges(t){this._edges.clear(),t instanceof Map?this._edges=t:Array.isArray(t)&&(this._edges=new Map,t.forEach(e=>this._edges.set(e.ID,e)))}get labels(){return this._labels}connectedCallback(){Ss("QEVisualElement connected"),this.render()}setModelData(t){var r,a,h,o;["nodes","edges","points","groups","confidence","outlier","trajectories","networks","pointsets"].forEach(l=>{var v;const _=t[l];if(!((v=_==null?void 0:_.data)!=null&&v.length))return;const g=_.data,c=_.types||{},E=Object.keys(g[0]),p=g.map(Y=>Object.values(Y)),A=E.map(Y=>c[Y]??"character");let R;l==="networks"?R="name":l==="pointsets"?R="id":l==="nodes"?R=t.node_id_col??E.find(Y=>(c[Y]??"character")==="character"):l==="edges"||l==="points"||l==="trajectories"?R=t.id_col??E.find(Y=>(c[Y]??"character")==="character"):R=t.group_col??E.find(Y=>(c[Y]??"character")==="character");const q=R?E.indexOf(R):0,G=p.map(Y=>String(Y[q]));this._model.setByKey(l,new $t(E,p,G,A))}),t.updated!==void 0&&this._model.setByKey("updated",t.updated),t.directed!==void 0&&(this._model.directed=t.directed),Array.isArray(t.palette)&&(this._model.palette=t.palette.map(String));const s=this._model.nodes;this._model.node_id_col=t.node_id_col??((r=s==null?void 0:s.names)==null?void 0:r.find(l=>{var _;return((_=s.col(l))==null?void 0:_.type)==="character"}))??"id";const i=this._model.points;this._model.unit_id_col=t.id_col??((a=i==null?void 0:i.names)==null?void 0:a.find(l=>{var _;return((_=i.col(l))==null?void 0:_.type)==="character"}))??"id";const n=this._model.unit_id_col;if(this._model.group_col=t.group_col??((h=i==null?void 0:i.names)==null?void 0:h.find(l=>{var _;return l!==n&&((_=i.col(l))==null?void 0:_.type)==="character"}))??null,(o=s==null?void 0:s.names)!=null&&o.length){const l=this._model.node_id_col,_=t.x_col,g=t.y_col;if(_&&g)this._model.dimensions=[_,g];else{const c=s.names.filter(E=>{if(E===l)return!1;const p=s.col(E);return p&&p.type!=="character"&&p.type!=="logical"});c.length>=2&&(this._model.dimensions=[_??c[0],g??c[1]])}}this.updated=this._model.updated!==void 0?String(this._model.updated):String(Date.now()),Ss("Model updated via setModelData:",this.updated),this.render()}async calculate(){}render(){var t;this._isVisible?this.classList.remove("hidden"):this.classList.add("hidden"),((t=this._model)==null?void 0:t.updated)!==void 0&&this._model.updated!==null?this._outputElement.innerHTML=`${this.output}<slot></slot>`:this._outputElement.innerHTML="Define the model on the left."}};u(Bt,"QEVisualElement"),Bt.tagName="qe-visual",Bt.styles=`
|
|
556
2
|
:host { display: block; width: 100%; }
|
|
557
3
|
:host(.hidden) { display: none !important; }
|
|
558
4
|
/* The output wrapper and the slotted graph fill the host so the plot
|
|
559
5
|
stretches to its container instead of collapsing to intrinsic size. */
|
|
560
6
|
div { display: block; width: 100%; height: 100%; }
|
|
561
7
|
::slotted(qe-graph) { display: block; width: 100%; height: 100%; }
|
|
562
|
-
`;
|
|
563
|
-
let QEVisualElement = _QEVisualElement;
|
|
564
|
-
customElements.define(QEVisualElement.tagName, QEVisualElement);
|
|
565
|
-
const _Color = class _Color {
|
|
566
|
-
constructor(base) {
|
|
567
|
-
this.base = typeof base === "string" ? base : base.base;
|
|
568
|
-
return new Proxy(this, {
|
|
569
|
-
get(target, prop) {
|
|
570
|
-
if (typeof prop === "string" && /^[0-2]$/.test(prop)) {
|
|
571
|
-
const { r, g, b } = _Color.parseColor(target.base);
|
|
572
|
-
return [r, g, b][Number(prop)];
|
|
573
|
-
}
|
|
574
|
-
return target[prop];
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
toString() {
|
|
579
|
-
return this.base;
|
|
580
|
-
}
|
|
581
|
-
setBase(base) {
|
|
582
|
-
this.base = base;
|
|
583
|
-
}
|
|
584
|
-
static parseColor(color) {
|
|
585
|
-
if (color.startsWith("#")) {
|
|
586
|
-
const bigint = parseInt(color.slice(1), 16);
|
|
587
|
-
return {
|
|
588
|
-
r: bigint >> 16 & 255,
|
|
589
|
-
g: bigint >> 8 & 255,
|
|
590
|
-
b: bigint & 255
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
throw new Error("Unsupported color format");
|
|
594
|
-
}
|
|
595
|
-
static rgb(r, g, b) {
|
|
596
|
-
return `rgb(${r}, ${g}, ${b})`;
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
__name(_Color, "Color");
|
|
600
|
-
let Color = _Color;
|
|
601
|
-
const _WeightedColor = class _WeightedColor extends Color {
|
|
602
|
-
constructor(base, weight) {
|
|
603
|
-
super(base);
|
|
604
|
-
this.weight = weight;
|
|
605
|
-
}
|
|
606
|
-
// Parse hex → HSV (h in [0, 360), s/v in [0, 1]).
|
|
607
|
-
static toHSV(hex) {
|
|
608
|
-
const { r, g, b } = Color.parseColor(hex);
|
|
609
|
-
const rn = r / 255, gn = g / 255, bn = b / 255;
|
|
610
|
-
const max = Math.max(rn, gn, bn), min = Math.min(rn, gn, bn);
|
|
611
|
-
const d = max - min;
|
|
612
|
-
const v = max;
|
|
613
|
-
const s = max === 0 ? 0 : d / max;
|
|
614
|
-
let h = 0;
|
|
615
|
-
if (d > 0) {
|
|
616
|
-
switch (max) {
|
|
617
|
-
case rn:
|
|
618
|
-
h = ((gn - bn) / d + (gn < bn ? 6 : 0)) / 6;
|
|
619
|
-
break;
|
|
620
|
-
case gn:
|
|
621
|
-
h = ((bn - rn) / d + 2) / 6;
|
|
622
|
-
break;
|
|
623
|
-
default:
|
|
624
|
-
h = ((rn - gn) / d + 4) / 6;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
return { h: h * 360, s, v };
|
|
628
|
-
}
|
|
629
|
-
// Convert HSV + alpha → rgba() CSS string.
|
|
630
|
-
static hsvToRgba(h, s, v, a) {
|
|
631
|
-
const c = v * s;
|
|
632
|
-
const x = c * (1 - Math.abs(h / 60 % 2 - 1));
|
|
633
|
-
const m = v - c;
|
|
634
|
-
let r = 0, g = 0, b = 0;
|
|
635
|
-
if (h < 60) {
|
|
636
|
-
r = c;
|
|
637
|
-
g = x;
|
|
638
|
-
b = 0;
|
|
639
|
-
} else if (h < 120) {
|
|
640
|
-
r = x;
|
|
641
|
-
g = c;
|
|
642
|
-
b = 0;
|
|
643
|
-
} else if (h < 180) {
|
|
644
|
-
r = 0;
|
|
645
|
-
g = c;
|
|
646
|
-
b = x;
|
|
647
|
-
} else if (h < 240) {
|
|
648
|
-
r = 0;
|
|
649
|
-
g = x;
|
|
650
|
-
b = c;
|
|
651
|
-
} else if (h < 300) {
|
|
652
|
-
r = x;
|
|
653
|
-
g = 0;
|
|
654
|
-
b = c;
|
|
655
|
-
} else {
|
|
656
|
-
r = c;
|
|
657
|
-
g = 0;
|
|
658
|
-
b = x;
|
|
659
|
-
}
|
|
660
|
-
return `rgba(${Math.round((r + m) * 255)},${Math.round((g + m) * 255)},${Math.round((b + m) * 255)},${a.toFixed(4)})`;
|
|
661
|
-
}
|
|
662
|
-
// Returns rgba(...) matching rENA's edge-color convention (ena.plot.network):
|
|
663
|
-
// • hue and value (brightness) are preserved from the base color
|
|
664
|
-
// • HSV saturation is set to |weight| directly (0 = grey, 1 = fully vivid)
|
|
665
|
-
// • alpha is also set to |weight|
|
|
666
|
-
//
|
|
667
|
-
// rENA converts the input color to HSV, replaces the S component with the
|
|
668
|
-
// normalized edge weight, and additionally sets plotly element opacity to the
|
|
669
|
-
// same value. Working in HSV (not HSL) is essential: palette colors like
|
|
670
|
-
// #EE6677 have HSL lightness ≈ 67%, so 100% HSL saturation still looks
|
|
671
|
-
// washed-out, whereas HSV value ≈ 0.93 gives the expected vivid output.
|
|
672
|
-
toString() {
|
|
673
|
-
const { h, v } = _WeightedColor.toHSV(this.base);
|
|
674
|
-
const w = Math.min(1, Math.abs(this.weight));
|
|
675
|
-
return _WeightedColor.hsvToRgba(h, w, v, w);
|
|
676
|
-
}
|
|
677
|
-
};
|
|
678
|
-
__name(_WeightedColor, "WeightedColor");
|
|
679
|
-
let WeightedColor = _WeightedColor;
|
|
680
|
-
const _Transform = class _Transform {
|
|
681
|
-
constructor(vals = null) {
|
|
682
|
-
this._values = [1, 0, 0, 1, 0, 0];
|
|
683
|
-
this._keys = ["a", "b", "c", "d", "e", "f"];
|
|
684
|
-
if (vals) {
|
|
685
|
-
this.values = vals;
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
get values() {
|
|
689
|
-
return this._values;
|
|
690
|
-
}
|
|
691
|
-
set values(vals) {
|
|
692
|
-
if (vals && vals.length === 6) {
|
|
693
|
-
this._values = vals;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
get keys() {
|
|
697
|
-
return this._keys;
|
|
698
|
-
}
|
|
699
|
-
set keys(vals) {
|
|
700
|
-
if (vals && vals.length === 6) {
|
|
701
|
-
this._keys = vals;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
toString() {
|
|
705
|
-
let matrix_str = this.keys.map((k, i) => this.values[i]).join(" ");
|
|
706
|
-
return `matrix(${matrix_str})`;
|
|
707
|
-
}
|
|
708
|
-
toMatrix() {
|
|
709
|
-
return Object.fromEntries(this._keys.map((k, i) => [k, this._values[i]]));
|
|
710
|
-
}
|
|
711
|
-
toArray() {
|
|
712
|
-
return this._values;
|
|
713
|
-
}
|
|
714
|
-
set(wh, val) {
|
|
715
|
-
if (val !== 75e-4 && val !== 0) {
|
|
716
|
-
this._values[this._keys.findIndex((k) => k === wh)] = val;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
get(wh) {
|
|
720
|
-
return this._values[this._keys.findIndex((k) => k === wh)];
|
|
721
|
-
}
|
|
722
|
-
scale(a, d = a) {
|
|
723
|
-
this.a = a;
|
|
724
|
-
this.d = d;
|
|
725
|
-
}
|
|
726
|
-
zoom(z) {
|
|
727
|
-
this.a = z;
|
|
728
|
-
this.d = z;
|
|
729
|
-
}
|
|
730
|
-
pan(x, y) {
|
|
731
|
-
this.e = this.e + x;
|
|
732
|
-
this.f = this.f + y;
|
|
733
|
-
}
|
|
734
|
-
set a(x) {
|
|
735
|
-
this.set("a", x);
|
|
736
|
-
}
|
|
737
|
-
set b(x) {
|
|
738
|
-
this.set("b", x);
|
|
739
|
-
}
|
|
740
|
-
set c(x) {
|
|
741
|
-
this.set("c", x);
|
|
742
|
-
}
|
|
743
|
-
set d(x) {
|
|
744
|
-
this.set("d", x);
|
|
745
|
-
}
|
|
746
|
-
set e(x) {
|
|
747
|
-
this.set("e", x);
|
|
748
|
-
}
|
|
749
|
-
set f(x) {
|
|
750
|
-
this.set("f", x);
|
|
751
|
-
}
|
|
752
|
-
get a() {
|
|
753
|
-
return this.get("a");
|
|
754
|
-
}
|
|
755
|
-
get b() {
|
|
756
|
-
return this.get("b");
|
|
757
|
-
}
|
|
758
|
-
get c() {
|
|
759
|
-
return this.get("c");
|
|
760
|
-
}
|
|
761
|
-
get d() {
|
|
762
|
-
return this.get("d");
|
|
763
|
-
}
|
|
764
|
-
get e() {
|
|
765
|
-
return this.get("e");
|
|
766
|
-
}
|
|
767
|
-
get f() {
|
|
768
|
-
return this.get("f");
|
|
769
|
-
}
|
|
770
|
-
};
|
|
771
|
-
__name(_Transform, "Transform");
|
|
772
|
-
let Transform = _Transform;
|
|
773
|
-
var Tools;
|
|
774
|
-
((Tools2) => {
|
|
775
|
-
((Matrix2) => {
|
|
776
|
-
function matrixString(matrix) {
|
|
777
|
-
const matrixStr = ["a", "b", "c", "d", "e", "f"].map((l) => matrix[l]).join(" ");
|
|
778
|
-
return `matrix(${matrixStr})`;
|
|
779
|
-
}
|
|
780
|
-
__name(matrixString, "matrixString");
|
|
781
|
-
Matrix2.matrixString = matrixString;
|
|
782
|
-
})(Tools2.Matrix || (Tools2.Matrix = {}));
|
|
783
|
-
((Geometry2) => {
|
|
784
|
-
((Point2) => {
|
|
785
|
-
function translate(point, angle, distance) {
|
|
786
|
-
const r = Angle.toRad(angle);
|
|
787
|
-
return [point[0] + distance * Math.cos(r), point[1] + distance * Math.sin(r)];
|
|
788
|
-
}
|
|
789
|
-
__name(translate, "translate");
|
|
790
|
-
Point2.translate = translate;
|
|
791
|
-
function rotate(point, angle, origin) {
|
|
792
|
-
const r = Angle.toRad(angle);
|
|
793
|
-
function rotatePoint(p, a) {
|
|
794
|
-
return [
|
|
795
|
-
p[0] * Math.cos(a) - p[1] * Math.sin(a),
|
|
796
|
-
p[0] * Math.sin(a) + p[1] * Math.cos(a)
|
|
797
|
-
];
|
|
798
|
-
}
|
|
799
|
-
__name(rotatePoint, "rotatePoint");
|
|
800
|
-
if (!origin || origin[0] === 0 && origin[1] === 0) {
|
|
801
|
-
return rotatePoint(point, r);
|
|
802
|
-
} else {
|
|
803
|
-
const p0 = point.map((c, i) => c - origin[i]);
|
|
804
|
-
const rotated = rotatePoint(p0, r);
|
|
805
|
-
return rotated.map((c, i) => c + origin[i]);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
__name(rotate, "rotate");
|
|
809
|
-
Point2.rotate = rotate;
|
|
810
|
-
})(Geometry2.Point || (Geometry2.Point = {}));
|
|
811
|
-
((Line2) => {
|
|
812
|
-
function slope(p1, p2) {
|
|
813
|
-
return (p2[1] - p1[1]) / (p2[0] - p1[0]);
|
|
814
|
-
}
|
|
815
|
-
__name(slope, "slope");
|
|
816
|
-
Line2.slope = slope;
|
|
817
|
-
function intercept(p1, p2) {
|
|
818
|
-
const m = slope(p1, p2);
|
|
819
|
-
return p1[1] - m * p1[0];
|
|
820
|
-
}
|
|
821
|
-
__name(intercept, "intercept");
|
|
822
|
-
Line2.intercept = intercept;
|
|
823
|
-
function slopeIntercept(p1, p2) {
|
|
824
|
-
return {
|
|
825
|
-
slope: slope(p1, p2),
|
|
826
|
-
intercept: intercept(p1, p2)
|
|
827
|
-
};
|
|
828
|
-
}
|
|
829
|
-
__name(slopeIntercept, "slopeIntercept");
|
|
830
|
-
Line2.slopeIntercept = slopeIntercept;
|
|
831
|
-
function point_along(line, distance = 0) {
|
|
832
|
-
const ratio = distance;
|
|
833
|
-
const Xt = (1 - ratio) * line[0][0] + ratio * line[1][0];
|
|
834
|
-
const Yt = (1 - ratio) * line[0][1] + ratio * line[1][1];
|
|
835
|
-
return [Xt, Yt];
|
|
836
|
-
}
|
|
837
|
-
__name(point_along, "point_along");
|
|
838
|
-
Line2.point_along = point_along;
|
|
839
|
-
function midpoint(p1, p2, w = 0.5) {
|
|
840
|
-
if (Array.isArray(p1[0])) {
|
|
841
|
-
p2 = p1[1];
|
|
842
|
-
p1 = p1[0];
|
|
843
|
-
}
|
|
844
|
-
return [0, 1].map((i) => (parseFloat(p1[i]) + parseFloat(p2[i])) * w);
|
|
845
|
-
}
|
|
846
|
-
__name(midpoint, "midpoint");
|
|
847
|
-
Line2.midpoint = midpoint;
|
|
848
|
-
function length(p1, p2) {
|
|
849
|
-
if (Array.isArray(p1[0])) {
|
|
850
|
-
p2 = p1[1];
|
|
851
|
-
p1 = p1[0];
|
|
852
|
-
}
|
|
853
|
-
return Math.sqrt(
|
|
854
|
-
[0, 1].map((i) => Math.pow(p2[i] - p1[i], 2)).reduce((a, b) => a + b, 0)
|
|
855
|
-
);
|
|
856
|
-
}
|
|
857
|
-
__name(length, "length");
|
|
858
|
-
Line2.length = length;
|
|
859
|
-
function rotate(line, by = [0, 0]) {
|
|
860
|
-
const translated = [
|
|
861
|
-
line[1][0] - by[0],
|
|
862
|
-
line[1][1] - by[1]
|
|
863
|
-
];
|
|
864
|
-
const rotated = [
|
|
865
|
-
-translated[1],
|
|
866
|
-
translated[0]
|
|
867
|
-
];
|
|
868
|
-
const rotated_reflection = [
|
|
869
|
-
-rotated[0],
|
|
870
|
-
-rotated[1]
|
|
871
|
-
];
|
|
872
|
-
const untranslated = [
|
|
873
|
-
rotated[0] + by[0],
|
|
874
|
-
rotated[1] + by[1]
|
|
875
|
-
];
|
|
876
|
-
const untranslated2 = [
|
|
877
|
-
rotated_reflection[0] + by[0],
|
|
878
|
-
rotated_reflection[1] + by[1]
|
|
879
|
-
];
|
|
880
|
-
return [untranslated, untranslated2];
|
|
881
|
-
}
|
|
882
|
-
__name(rotate, "rotate");
|
|
883
|
-
Line2.rotate = rotate;
|
|
884
|
-
function rotate2(line, fixed, angle = 90) {
|
|
885
|
-
const m = Tools2.Geometry.Line.slope(line[0], line[1]);
|
|
886
|
-
const n = Tools2.Geometry.Line.intercept(line[0], line[1]);
|
|
887
|
-
const P = [0, n];
|
|
888
|
-
const Q = [1, m + n];
|
|
889
|
-
line = [P, Q];
|
|
890
|
-
const xx = [line[0][0], line[1][0]];
|
|
891
|
-
const yy = [line[0][1], line[1][1]];
|
|
892
|
-
const x_fixed = fixed[0];
|
|
893
|
-
const y_fixed = fixed[1];
|
|
894
|
-
const angle_rad = -2 * Math.PI * angle / 360;
|
|
895
|
-
const xx_new = xx.map(
|
|
896
|
-
(x, i) => (x - x_fixed) * Math.cos(angle_rad) - (yy[i] - y_fixed) * Math.sin(angle_rad) + x_fixed
|
|
897
|
-
);
|
|
898
|
-
const yy_new = yy.map(
|
|
899
|
-
(y, i) => (xx[i] - x_fixed) * Math.sin(angle_rad) - (y - y_fixed) * Math.cos(angle_rad) + y_fixed
|
|
900
|
-
);
|
|
901
|
-
const object_new = [
|
|
902
|
-
[xx_new[0], yy_new[0]],
|
|
903
|
-
[xx_new[1], yy_new[1]]
|
|
904
|
-
];
|
|
905
|
-
return object_new;
|
|
906
|
-
}
|
|
907
|
-
__name(rotate2, "rotate2");
|
|
908
|
-
Line2.rotate2 = rotate2;
|
|
909
|
-
function intersection(lineA, lineB) {
|
|
910
|
-
const [[x1, y1], [x2, y2]] = lineA, [[x3, y3], [x4, y4]] = lineB, D = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4), num1 = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4), num2 = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4);
|
|
911
|
-
return [num1 / D, num2 / D];
|
|
912
|
-
}
|
|
913
|
-
__name(intersection, "intersection");
|
|
914
|
-
Line2.intersection = intersection;
|
|
915
|
-
function intersect_circle(line, circle_xy, circle_r) {
|
|
916
|
-
let { slope: m, intercept: n } = Tools2.Geometry.Line.slopeIntercept(line[0], line[1]);
|
|
917
|
-
let a = 1 + Math.pow(m, 2), b = 2 * m * n - 2 * circle_xy[1] * m - 2 * circle_xy[0], c = Math.pow(circle_xy[0], 2) + Math.pow(n, 2) + Math.pow(circle_xy[1], 2) - 2 * circle_xy[1] * n - Math.pow(circle_r, 2), int = [[Infinity, Infinity], [Infinity, Infinity]];
|
|
918
|
-
if (Math.sqrt(Math.pow(b, 2) - 4 * a * c) >= 0) {
|
|
919
|
-
let x1 = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a), x2 = (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a), y1 = m * x1 + n, y2 = m * x2 + n;
|
|
920
|
-
int = [[x1, y1], [x2, y2]];
|
|
921
|
-
} else {
|
|
922
|
-
console.error("The line and the circumference do not intersect");
|
|
923
|
-
}
|
|
924
|
-
return int;
|
|
925
|
-
}
|
|
926
|
-
__name(intersect_circle, "intersect_circle");
|
|
927
|
-
Line2.intersect_circle = intersect_circle;
|
|
928
|
-
function interpolate(line) {
|
|
929
|
-
return (t) => t === 0 ? line[0] : t === 1 ? line[1] : Tools2.Geometry.Point.translate(line[0], Tools2.Geometry.Angle.line(line), Tools2.Geometry.Line.length(line) * t);
|
|
930
|
-
}
|
|
931
|
-
__name(interpolate, "interpolate");
|
|
932
|
-
Line2.interpolate = interpolate;
|
|
933
|
-
})(Geometry2.Line || (Geometry2.Line = {}));
|
|
934
|
-
let Angle;
|
|
935
|
-
((Angle2) => {
|
|
936
|
-
function toRad(angle) {
|
|
937
|
-
return angle / 180 * Math.PI;
|
|
938
|
-
}
|
|
939
|
-
__name(toRad, "toRad");
|
|
940
|
-
Angle2.toRad = toRad;
|
|
941
|
-
function toDeg(angle) {
|
|
942
|
-
return angle * 180 / Math.PI;
|
|
943
|
-
}
|
|
944
|
-
__name(toDeg, "toDeg");
|
|
945
|
-
Angle2.toDeg = toDeg;
|
|
946
|
-
function line(line2) {
|
|
947
|
-
if (line2.length !== 2 || !Array.isArray(line2[0]) || !Array.isArray(line2[1]) || line2[0].length !== 2 || line2[1].length !== 2) {
|
|
948
|
-
throw new Error("Invalid line format. Expected [[x1, y1], [x2, y2]].");
|
|
949
|
-
}
|
|
950
|
-
return Tools2.Geometry.Angle.toDeg(
|
|
951
|
-
Math.atan2(line2[1][1] - line2[0][1], line2[1][0] - line2[0][0])
|
|
952
|
-
);
|
|
953
|
-
}
|
|
954
|
-
__name(line, "line");
|
|
955
|
-
Angle2.line = line;
|
|
956
|
-
})(Angle = Geometry2.Angle || (Geometry2.Angle = {}));
|
|
957
|
-
})(Tools2.Geometry || (Tools2.Geometry = {}));
|
|
958
|
-
((ArrayTools2) => {
|
|
959
|
-
function unique(arr) {
|
|
960
|
-
return [...new Set(arr)];
|
|
961
|
-
}
|
|
962
|
-
__name(unique, "unique");
|
|
963
|
-
ArrayTools2.unique = unique;
|
|
964
|
-
function divide(a, b) {
|
|
965
|
-
if (Array.isArray(a)) {
|
|
966
|
-
if (Array.isArray(b)) {
|
|
967
|
-
if (a.length !== b.length) throw new Error("Arrays must be of equal length");
|
|
968
|
-
return a.map((val, i) => val / b[i]);
|
|
969
|
-
}
|
|
970
|
-
return a.map((val) => val / b);
|
|
971
|
-
}
|
|
972
|
-
return a / b;
|
|
973
|
-
}
|
|
974
|
-
__name(divide, "divide");
|
|
975
|
-
ArrayTools2.divide = divide;
|
|
976
|
-
function isArray(obj) {
|
|
977
|
-
return typeof Array.isArray === "function" ? Array.isArray(obj) : obj && typeof obj === "object" && obj.constructor.name === "Array";
|
|
978
|
-
}
|
|
979
|
-
__name(isArray, "isArray");
|
|
980
|
-
ArrayTools2.isArray = isArray;
|
|
981
|
-
})(Tools2.ArrayTools || (Tools2.ArrayTools = {}));
|
|
982
|
-
((Mathematics2) => {
|
|
983
|
-
function sum(arr) {
|
|
984
|
-
return arr.reduce((a, b) => a + b, 0);
|
|
985
|
-
}
|
|
986
|
-
__name(sum, "sum");
|
|
987
|
-
Mathematics2.sum = sum;
|
|
988
|
-
function mean(arr) {
|
|
989
|
-
return sum(arr) / arr.length;
|
|
990
|
-
}
|
|
991
|
-
__name(mean, "mean");
|
|
992
|
-
Mathematics2.mean = mean;
|
|
993
|
-
function round(value, decimals) {
|
|
994
|
-
const factor = Math.pow(10, decimals);
|
|
995
|
-
return Math.round(value * factor) / factor;
|
|
996
|
-
}
|
|
997
|
-
__name(round, "round");
|
|
998
|
-
Mathematics2.round = round;
|
|
999
|
-
})(Tools2.Mathematics || (Tools2.Mathematics = {}));
|
|
1000
|
-
((Events2) => {
|
|
1001
|
-
function createEvent(name, element, data) {
|
|
1002
|
-
return new CustomEvent(name, {
|
|
1003
|
-
bubbles: true,
|
|
1004
|
-
cancelable: true,
|
|
1005
|
-
detail: {
|
|
1006
|
-
element,
|
|
1007
|
-
data: data || (element ? element.__data__ : void 0)
|
|
1008
|
-
}
|
|
1009
|
-
});
|
|
1010
|
-
}
|
|
1011
|
-
__name(createEvent, "createEvent");
|
|
1012
|
-
Events2.createEvent = createEvent;
|
|
1013
|
-
})(Tools2.Events || (Tools2.Events = {}));
|
|
1014
|
-
((Hash2) => {
|
|
1015
|
-
function parts() {
|
|
1016
|
-
return location.hash.replace(/#/, "").split(/\//).filter((a) => a).map((a) => a.split(/:/));
|
|
1017
|
-
}
|
|
1018
|
-
__name(parts, "parts");
|
|
1019
|
-
Hash2.parts = parts;
|
|
1020
|
-
function exists(key) {
|
|
1021
|
-
return parts().flat().findIndex((a) => a === key) >= 0;
|
|
1022
|
-
}
|
|
1023
|
-
__name(exists, "exists");
|
|
1024
|
-
Hash2.exists = exists;
|
|
1025
|
-
})(Tools2.Hash || (Tools2.Hash = {}));
|
|
1026
|
-
((Objects2) => {
|
|
1027
|
-
function proxy(obj, handler2, deep = false) {
|
|
1028
|
-
if (!deep) {
|
|
1029
|
-
return new Proxy(obj, handler2);
|
|
1030
|
-
} else {
|
|
1031
|
-
if (typeof obj !== "object" || obj === null) {
|
|
1032
|
-
return obj;
|
|
1033
|
-
}
|
|
1034
|
-
for (const key in obj) {
|
|
1035
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1036
|
-
obj[key] = proxy(obj[key], handler2, deep);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
return new Proxy(obj, handler2);
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
__name(proxy, "proxy");
|
|
1043
|
-
Objects2.proxy = proxy;
|
|
1044
|
-
Objects2.handler = {
|
|
1045
|
-
set(target, property, value) {
|
|
1046
|
-
target[property] = value;
|
|
1047
|
-
window.dispatchEvent(
|
|
1048
|
-
Tools2.Events.createEvent("settingUpdate", window, { target, property, value })
|
|
1049
|
-
);
|
|
1050
|
-
return true;
|
|
1051
|
-
},
|
|
1052
|
-
get(target, property) {
|
|
1053
|
-
return target[property];
|
|
1054
|
-
}
|
|
1055
|
-
};
|
|
1056
|
-
function get(obj, key) {
|
|
1057
|
-
const parts = key.split(".");
|
|
1058
|
-
let current = obj;
|
|
1059
|
-
for (const part of parts) {
|
|
1060
|
-
if (current && typeof current === "object" && Object.prototype.hasOwnProperty.call(current, part)) {
|
|
1061
|
-
current = current[part];
|
|
1062
|
-
} else {
|
|
1063
|
-
return void 0;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
return current;
|
|
1067
|
-
}
|
|
1068
|
-
__name(get, "get");
|
|
1069
|
-
Objects2.get = get;
|
|
1070
|
-
function set(obj, key, value) {
|
|
1071
|
-
const parts = key.split(".");
|
|
1072
|
-
let current = obj;
|
|
1073
|
-
let i;
|
|
1074
|
-
for (i = 0; i < parts.length - 1; i++) {
|
|
1075
|
-
const part = parts[i];
|
|
1076
|
-
if (current && typeof current === "object") {
|
|
1077
|
-
if (!Object.prototype.hasOwnProperty.call(current, part)) {
|
|
1078
|
-
current[part] = {};
|
|
1079
|
-
}
|
|
1080
|
-
current = current[part];
|
|
1081
|
-
} else {
|
|
1082
|
-
return false;
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
if (current && typeof current === "object") {
|
|
1086
|
-
current[parts[i]] = value;
|
|
1087
|
-
return true;
|
|
1088
|
-
} else {
|
|
1089
|
-
return false;
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
__name(set, "set");
|
|
1093
|
-
Objects2.set = set;
|
|
1094
|
-
})(Tools2.Objects || (Tools2.Objects = {}));
|
|
1095
|
-
((URL2) => {
|
|
1096
|
-
function parse(location2 = window.location) {
|
|
1097
|
-
return Object.fromEntries(new URLSearchParams(location2.search));
|
|
1098
|
-
}
|
|
1099
|
-
__name(parse, "parse");
|
|
1100
|
-
URL2.parse = parse;
|
|
1101
|
-
((Query2) => {
|
|
1102
|
-
function parse2(location2 = window.location.search) {
|
|
1103
|
-
return Object.fromEntries(
|
|
1104
|
-
location2.replace(/^\?/, "").split(/&/).map((i) => i.split(/=/))
|
|
1105
|
-
);
|
|
1106
|
-
}
|
|
1107
|
-
__name(parse2, "parse2");
|
|
1108
|
-
Query2.parse = parse2;
|
|
1109
|
-
function keys(location2 = window.location.search) {
|
|
1110
|
-
return location2.replace(/^\?/, "").split(/&/).map((i) => i.split(/=/)[0]);
|
|
1111
|
-
}
|
|
1112
|
-
__name(keys, "keys");
|
|
1113
|
-
Query2.keys = keys;
|
|
1114
|
-
function has(key, location2 = window.location.search) {
|
|
1115
|
-
return keys(location2).findIndex((i) => i === key) >= 0;
|
|
1116
|
-
}
|
|
1117
|
-
__name(has, "has");
|
|
1118
|
-
Query2.has = has;
|
|
1119
|
-
})(URL2.Query || (URL2.Query = {}));
|
|
1120
|
-
})(Tools2.URL || (Tools2.URL = {}));
|
|
1121
|
-
})(Tools || (Tools = {}));
|
|
1122
|
-
const _EventBus = class _EventBus {
|
|
1123
|
-
constructor() {
|
|
1124
|
-
this._state = /* @__PURE__ */ new Map();
|
|
1125
|
-
this.listeners = /* @__PURE__ */ new Map();
|
|
1126
|
-
}
|
|
1127
|
-
get state() {
|
|
1128
|
-
return this._state;
|
|
1129
|
-
}
|
|
1130
|
-
hasVariable(key) {
|
|
1131
|
-
return this._state.has(key);
|
|
1132
|
-
}
|
|
1133
|
-
getVariable(key) {
|
|
1134
|
-
return this._state.get(key);
|
|
1135
|
-
}
|
|
1136
|
-
setVariable(key, value, options) {
|
|
1137
|
-
const oldValue = this._state.get(key);
|
|
1138
|
-
this._state.set(key, value);
|
|
1139
|
-
if (!(options == null ? void 0 : options.lazy)) {
|
|
1140
|
-
this.notifyListeners(key, value, oldValue);
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
addListener(key, type, listener) {
|
|
1144
|
-
if (!this.listeners.has(key)) this.listeners.set(key, /* @__PURE__ */ new Map());
|
|
1145
|
-
const typeMap = this.listeners.get(key);
|
|
1146
|
-
if (!typeMap.has(type)) typeMap.set(type, /* @__PURE__ */ new Set());
|
|
1147
|
-
typeMap.get(type).add(listener);
|
|
1148
|
-
}
|
|
1149
|
-
removeListener(key, type, listener) {
|
|
1150
|
-
var _a, _b;
|
|
1151
|
-
(_b = (_a = this.listeners.get(key)) == null ? void 0 : _a.get(type)) == null ? void 0 : _b.delete(listener);
|
|
1152
|
-
}
|
|
1153
|
-
getListeners(key, type) {
|
|
1154
|
-
var _a;
|
|
1155
|
-
return Array.from(((_a = this.listeners.get(key)) == null ? void 0 : _a.get(type)) ?? []);
|
|
1156
|
-
}
|
|
1157
|
-
notifyListeners(key, newValue, oldValue) {
|
|
1158
|
-
const typeMap = this.listeners.get(key);
|
|
1159
|
-
if (!typeMap) return;
|
|
1160
|
-
for (const set of typeMap.values()) {
|
|
1161
|
-
set.forEach((listener) => {
|
|
1162
|
-
if (typeof listener === "function") {
|
|
1163
|
-
listener({ key, newValue, oldValue });
|
|
1164
|
-
} else if (typeof listener.calculate === "function") {
|
|
1165
|
-
listener.calculate.call(listener, { key, newValue, oldValue });
|
|
1166
|
-
}
|
|
1167
|
-
});
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
};
|
|
1171
|
-
__name(_EventBus, "EventBus");
|
|
1172
|
-
let EventBus = _EventBus;
|
|
1173
|
-
const { ArrayTools: ArrayTools$1 } = Tools;
|
|
1174
|
-
const _LayerArray = class _LayerArray extends Array {
|
|
1175
|
-
constructor(...args) {
|
|
1176
|
-
super(...args);
|
|
1177
|
-
}
|
|
1178
|
-
search(key, name) {
|
|
1179
|
-
let found;
|
|
1180
|
-
function fn(a) {
|
|
1181
|
-
return a.name === name ? a : void 0;
|
|
1182
|
-
}
|
|
1183
|
-
__name(fn, "fn");
|
|
1184
|
-
function recurse(obj, i, parent = null) {
|
|
1185
|
-
if (ArrayTools$1.isArray(obj)) {
|
|
1186
|
-
for (const [i2, o] of obj.entries()) {
|
|
1187
|
-
found = recurse(o, i2, parent);
|
|
1188
|
-
if (found) {
|
|
1189
|
-
return found;
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
} else {
|
|
1193
|
-
found = fn(obj);
|
|
1194
|
-
if (!found) {
|
|
1195
|
-
if (obj && ArrayTools$1.isArray(obj[key])) {
|
|
1196
|
-
for (const [i2, o] of obj[key].entries()) {
|
|
1197
|
-
found = recurse(o, i2, obj);
|
|
1198
|
-
if (found) {
|
|
1199
|
-
return found;
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
} else {
|
|
1204
|
-
return found;
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
return found;
|
|
1208
|
-
}
|
|
1209
|
-
__name(recurse, "recurse");
|
|
1210
|
-
return recurse(this);
|
|
1211
|
-
}
|
|
1212
|
-
flatten() {
|
|
1213
|
-
return this.reduce((a, l) => {
|
|
1214
|
-
a.push(l);
|
|
1215
|
-
if (l.layers && Array.isArray(l.layers)) {
|
|
1216
|
-
a.push(...l.layers);
|
|
1217
|
-
}
|
|
1218
|
-
return a;
|
|
1219
|
-
}, []);
|
|
1220
|
-
}
|
|
1221
|
-
recurse(key, callback, parent = null, depth = 0) {
|
|
1222
|
-
let results = new _LayerArray();
|
|
1223
|
-
for (const layer of this) {
|
|
1224
|
-
let result = callback(layer, parent, depth);
|
|
1225
|
-
if (layer[key] && Array.isArray(layer[key])) {
|
|
1226
|
-
let r = new _LayerArray(...layer[key]).recurse(key, callback, layer, depth + 1);
|
|
1227
|
-
if (r !== void 0) {
|
|
1228
|
-
results.push(...r);
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
results.push(result);
|
|
1232
|
-
}
|
|
1233
|
-
console.log("Recurse results: ", results);
|
|
1234
|
-
return results;
|
|
1235
|
-
}
|
|
1236
|
-
};
|
|
1237
|
-
__name(_LayerArray, "LayerArray");
|
|
1238
|
-
let LayerArray = _LayerArray;
|
|
1239
|
-
const _Layer = class _Layer {
|
|
1240
|
-
constructor(ID, o, parent) {
|
|
1241
|
-
this.__state__ = new EventBus();
|
|
1242
|
-
this.scale_x = 1;
|
|
1243
|
-
this.scale_y = 1;
|
|
1244
|
-
this.scale_objects = true;
|
|
1245
|
-
this.layers = new LayerArray();
|
|
1246
|
-
this.objects = /* @__PURE__ */ new Map();
|
|
1247
|
-
this.visible = true;
|
|
1248
|
-
this.ID = ID;
|
|
1249
|
-
this.name = o.name || `layer-${ID}`;
|
|
1250
|
-
this.tabindex = o.tabindex;
|
|
1251
|
-
this.parent = parent;
|
|
1252
|
-
this._transform = new Transform();
|
|
1253
|
-
parent == null ? void 0 : parent.__state__.addListener("graph_updated", "live", ({ key, newValue, oldValue }) => {
|
|
1254
|
-
});
|
|
1255
|
-
parent == null ? void 0 : parent.__state__.addListener(`graph_updated_${this.name}`, "live", ({ key, newValue, oldValue }) => {
|
|
1256
|
-
this.objects = newValue;
|
|
1257
|
-
this.__state__.setVariable(`layer_updated`, this);
|
|
1258
|
-
});
|
|
1259
|
-
}
|
|
1260
|
-
get transform() {
|
|
1261
|
-
return this._transform;
|
|
1262
|
-
}
|
|
1263
|
-
set transform(t) {
|
|
1264
|
-
this._transform = t;
|
|
1265
|
-
}
|
|
1266
|
-
};
|
|
1267
|
-
__name(_Layer, "Layer");
|
|
1268
|
-
let Layer = _Layer;
|
|
1269
|
-
const _DimensionVector = class _DimensionVector extends Array {
|
|
1270
|
-
constructor(...args) {
|
|
1271
|
-
super(arguments.length);
|
|
1272
|
-
__privateAdd(this, _flipped, false);
|
|
1273
|
-
__privateAdd(this, _names3);
|
|
1274
|
-
for (let i = 0; i < args.length; i++) {
|
|
1275
|
-
this[i] = args[i];
|
|
1276
|
-
}
|
|
1277
|
-
__privateSet(this, _flipped, false);
|
|
1278
|
-
}
|
|
1279
|
-
static fromArray(arr) {
|
|
1280
|
-
const vec = new _DimensionVector();
|
|
1281
|
-
arr.forEach((v, i) => {
|
|
1282
|
-
vec.push(v);
|
|
1283
|
-
});
|
|
1284
|
-
__privateSet(vec, _names3, arr.names);
|
|
1285
|
-
return vec;
|
|
1286
|
-
}
|
|
1287
|
-
flip() {
|
|
1288
|
-
__privateSet(this, _flipped, !__privateGet(this, _flipped));
|
|
1289
|
-
for (let i = 0; i < this.length; i++) {
|
|
1290
|
-
this[i] = -this[i];
|
|
1291
|
-
}
|
|
1292
|
-
return this;
|
|
1293
|
-
}
|
|
1294
|
-
get(wh) {
|
|
1295
|
-
if (typeof wh === "number") {
|
|
1296
|
-
return this[wh];
|
|
1297
|
-
} else if (__privateGet(this, _names3) && __privateGet(this, _names3).includes(wh)) {
|
|
1298
|
-
return this[__privateGet(this, _names3).indexOf(wh)];
|
|
1299
|
-
} else {
|
|
1300
|
-
return void 0;
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
get flipped() {
|
|
1304
|
-
return __privateGet(this, _flipped);
|
|
1305
|
-
}
|
|
1306
|
-
get names() {
|
|
1307
|
-
if (__privateGet(this, _names3)) {
|
|
1308
|
-
return __privateGet(this, _names3);
|
|
1309
|
-
} else {
|
|
1310
|
-
return this.map((_, i) => `V${i + 1}`);
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
};
|
|
1314
|
-
_flipped = new WeakMap();
|
|
1315
|
-
_names3 = new WeakMap();
|
|
1316
|
-
__name(_DimensionVector, "DimensionVector");
|
|
1317
|
-
let DimensionVector = _DimensionVector;
|
|
1318
|
-
const _PlottedObject = class _PlottedObject {
|
|
1319
|
-
constructor(dimensions, o) {
|
|
1320
|
-
this.scale_x = 1;
|
|
1321
|
-
this.scale_y = 1;
|
|
1322
|
-
this.scale_size = 0.05;
|
|
1323
|
-
this.active = false;
|
|
1324
|
-
this.visible = false;
|
|
1325
|
-
this.highlighting = false;
|
|
1326
|
-
this.meta = {};
|
|
1327
|
-
this._x = 0;
|
|
1328
|
-
this._y = 0;
|
|
1329
|
-
this._highlight_default = new Color("#000000");
|
|
1330
|
-
this._size = 0;
|
|
1331
|
-
this.ID = o.ID;
|
|
1332
|
-
this._transform = new Transform();
|
|
1333
|
-
if (dimensions instanceof DimensionVector) {
|
|
1334
|
-
this._dimensions = dimensions;
|
|
1335
|
-
} else if (dimensions instanceof DataFrameRow) {
|
|
1336
|
-
this._dimensions = DimensionVector.fromArray(dimensions);
|
|
1337
|
-
} else if (Array.isArray(dimensions)) {
|
|
1338
|
-
this._dimensions = new DimensionVector(...dimensions);
|
|
1339
|
-
} else {
|
|
1340
|
-
console.warn("Invalid dimensions provided, using default DimensionVector(0, 0)");
|
|
1341
|
-
this._dimensions = new DimensionVector(0, 0);
|
|
1342
|
-
}
|
|
1343
|
-
let data = { ...o };
|
|
1344
|
-
this._original = { ...data };
|
|
1345
|
-
this.ID = data.ID;
|
|
1346
|
-
this.x = data.x || this._dimensions[0];
|
|
1347
|
-
this.y = data.y || this._dimensions[1];
|
|
1348
|
-
this._size = data.size || 1;
|
|
1349
|
-
this._color = data.color || new Color("#000000");
|
|
1350
|
-
this.active = data.active || false;
|
|
1351
|
-
this.shape = data.shape || null;
|
|
1352
|
-
this.meta = data.meta || {};
|
|
1353
|
-
this._highlight = this._highlight_default;
|
|
1354
|
-
if (data.highlight) {
|
|
1355
|
-
this._highlight = data.highlight;
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
get dimensions() {
|
|
1359
|
-
return this._dimensions;
|
|
1360
|
-
}
|
|
1361
|
-
get color() {
|
|
1362
|
-
return (
|
|
1363
|
-
// This was expecting hightight to be an object with a color property
|
|
1364
|
-
// but now it is just a Color object, so we can simplify this.
|
|
1365
|
-
this.highlighting && this._highlight ? this._highlight : this._color
|
|
1366
|
-
);
|
|
1367
|
-
}
|
|
1368
|
-
set color(c) {
|
|
1369
|
-
this._color = c;
|
|
1370
|
-
}
|
|
1371
|
-
get highlight() {
|
|
1372
|
-
return this._highlight || this._highlight_default;
|
|
1373
|
-
}
|
|
1374
|
-
set highlight(h) {
|
|
1375
|
-
this._highlight = h;
|
|
1376
|
-
}
|
|
1377
|
-
get size() {
|
|
1378
|
-
return this._size;
|
|
1379
|
-
}
|
|
1380
|
-
set size(s) {
|
|
1381
|
-
this._size = s;
|
|
1382
|
-
}
|
|
1383
|
-
get original() {
|
|
1384
|
-
return this._original;
|
|
1385
|
-
}
|
|
1386
|
-
get x() {
|
|
1387
|
-
return this._x;
|
|
1388
|
-
}
|
|
1389
|
-
get y() {
|
|
1390
|
-
return this._y;
|
|
1391
|
-
}
|
|
1392
|
-
set x(x_) {
|
|
1393
|
-
this._x = x_;
|
|
1394
|
-
}
|
|
1395
|
-
set y(y_) {
|
|
1396
|
-
this._y = y_;
|
|
1397
|
-
}
|
|
1398
|
-
dimension(wh) {
|
|
1399
|
-
return this._dimensions.get(wh);
|
|
1400
|
-
}
|
|
1401
|
-
get transform() {
|
|
1402
|
-
return this._transform;
|
|
1403
|
-
}
|
|
1404
|
-
set transform(t) {
|
|
1405
|
-
this._transform = t;
|
|
1406
|
-
}
|
|
1407
|
-
};
|
|
1408
|
-
__name(_PlottedObject, "PlottedObject");
|
|
1409
|
-
let PlottedObject = _PlottedObject;
|
|
1410
|
-
const _Line = class _Line extends PlottedObject {
|
|
1411
|
-
// constructor(x: LineOptions) {
|
|
1412
|
-
// super([], x);
|
|
1413
|
-
// // const data = Object.assign({}, x);
|
|
1414
|
-
// const { x1, y1, x2, y2, width, color, shape } = x;
|
|
1415
|
-
// // console.log("Line constructor data:", data);
|
|
1416
|
-
// // console.warn(" this was using `meta` but it is deprecated now - should be using `original` instead");
|
|
1417
|
-
// // this.meta = Object.keys(data)
|
|
1418
|
-
// // .filter(k => ['ID', 'x1', 'y1', 'x2', 'y2', 'size', 'color'].indexOf(k) < 0)
|
|
1419
|
-
// // .reduce((n: any, k: string) => { n[k] = data[k]; return n; }, {});
|
|
1420
|
-
// this.x1 = parseFloat(x1 as string);
|
|
1421
|
-
// this.y1 = parseFloat(y1 as string);
|
|
1422
|
-
// this.x2 = parseFloat(x2 as string);
|
|
1423
|
-
// this.y2 = parseFloat(y2 as string);
|
|
1424
|
-
// this.width = width;
|
|
1425
|
-
// this._color = color || new Color('#000000');
|
|
1426
|
-
// this.shape = shape || 'line';
|
|
1427
|
-
// }
|
|
1428
|
-
constructor(data, from, to) {
|
|
1429
|
-
super([], {});
|
|
1430
|
-
this.from = from;
|
|
1431
|
-
this.to = to;
|
|
1432
|
-
}
|
|
1433
|
-
get line() {
|
|
1434
|
-
return [[this.from.x, this.from.y], [this.to.x, this.to.y]];
|
|
1435
|
-
}
|
|
1436
|
-
get midpoint() {
|
|
1437
|
-
return [
|
|
1438
|
-
(this.from.x + this.to.x) / 2,
|
|
1439
|
-
(this.from.y + this.to.y) / 2
|
|
1440
|
-
];
|
|
1441
|
-
}
|
|
1442
|
-
get length() {
|
|
1443
|
-
return Math.sqrt(
|
|
1444
|
-
Math.pow(this.to.x - this.from.x, 2) + Math.pow(this.to.y - this.from.y, 2)
|
|
1445
|
-
);
|
|
1446
|
-
}
|
|
1447
|
-
get color() {
|
|
1448
|
-
return this._color;
|
|
1449
|
-
}
|
|
1450
|
-
set color(c) {
|
|
1451
|
-
this._color = c;
|
|
1452
|
-
}
|
|
1453
|
-
};
|
|
1454
|
-
__name(_Line, "Line");
|
|
1455
|
-
let Line = _Line;
|
|
1456
|
-
const _Point = class _Point extends PlottedObject {
|
|
1457
|
-
// constructor(dimensions: DimensionType, o: PointOptions) { //, graph?: any) {
|
|
1458
|
-
// super(dimensions, o);
|
|
1459
|
-
// this.active = o.active || false;
|
|
1460
|
-
// this.visible = o.visible || false;
|
|
1461
|
-
// this.size = o.size || 1;
|
|
1462
|
-
// this.color = o.color || new Color('#000000');
|
|
1463
|
-
// this.shape = o.shape ? o.shape : "circle";
|
|
1464
|
-
// this.scale_size = 2;
|
|
1465
|
-
// this._x = dimensions[0];
|
|
1466
|
-
// this._y = dimensions[1];
|
|
1467
|
-
// this.label = new Label(this.ID, this);
|
|
1468
|
-
// }
|
|
1469
|
-
constructor(data) {
|
|
1470
|
-
var _a, _b;
|
|
1471
|
-
let dimensions, meta, ID;
|
|
1472
|
-
if (data) {
|
|
1473
|
-
if (data instanceof DataFrameRow) {
|
|
1474
|
-
dimensions = (_a = data.classes) == null ? void 0 : _a.map((c, i) => c === "ena.co.occurrence" || c === "ena.dimension" ? data[i] : -1).filter((a) => a !== -1);
|
|
1475
|
-
meta = (_b = data.classes) == null ? void 0 : _b.map((c, i) => c === "ena.metadata" ? [data.names[i], data[i]] : null).filter((a) => a !== null).reduce((n, c) => {
|
|
1476
|
-
n[c[0]] = c[1];
|
|
1477
|
-
return n;
|
|
1478
|
-
}, {});
|
|
1479
|
-
ID = data.rowName || `point-${Math.random().toString(36).substring(2, 9)}`;
|
|
1480
|
-
} else if (typeof data === "object") {
|
|
1481
|
-
dimensions = data.dimensions || [];
|
|
1482
|
-
meta = data.meta || {};
|
|
1483
|
-
ID = data.ID || `point-${Math.random().toString(36).substring(2, 9)}`;
|
|
1484
|
-
} else {
|
|
1485
|
-
console.warn("Invalid data provided for Point, using default values");
|
|
1486
|
-
dimensions = [];
|
|
1487
|
-
meta = {};
|
|
1488
|
-
ID = `point-${Math.random().toString(36).substring(2, 9)}`;
|
|
1489
|
-
}
|
|
1490
|
-
} else {
|
|
1491
|
-
dimensions = [];
|
|
1492
|
-
meta = {};
|
|
1493
|
-
ID = `point-${Math.random().toString(36).substring(2, 9)}`;
|
|
1494
|
-
}
|
|
1495
|
-
super(dimensions ?? [], { meta, ID });
|
|
1496
|
-
this.edges = /* @__PURE__ */ new Map();
|
|
1497
|
-
this.shape = _Point.SHAPES.CIRCLE;
|
|
1498
|
-
}
|
|
1499
|
-
set label(l) {
|
|
1500
|
-
this._label = l;
|
|
1501
|
-
}
|
|
1502
|
-
get label() {
|
|
1503
|
-
return this._label;
|
|
1504
|
-
}
|
|
1505
|
-
get x() {
|
|
1506
|
-
return this._x;
|
|
1507
|
-
}
|
|
1508
|
-
get y() {
|
|
1509
|
-
return this._y;
|
|
1510
|
-
}
|
|
1511
|
-
set x(x_) {
|
|
1512
|
-
this._x = parseFloat(x_);
|
|
1513
|
-
}
|
|
1514
|
-
set y(y_) {
|
|
1515
|
-
this._y = parseFloat(y_);
|
|
1516
|
-
}
|
|
1517
|
-
};
|
|
1518
|
-
__name(_Point, "Point");
|
|
1519
|
-
_Point.SHAPES = { CIRCLE: "circle", SQUARE: "rect" };
|
|
1520
|
-
let Point = _Point;
|
|
1521
|
-
const _Label = class _Label extends PlottedObject {
|
|
1522
|
-
constructor(txt, object) {
|
|
1523
|
-
super(object.dimensions, object);
|
|
1524
|
-
this._visible = false;
|
|
1525
|
-
this.offset = 0;
|
|
1526
|
-
this.text = txt;
|
|
1527
|
-
this.ID = object.ID;
|
|
1528
|
-
this.object = object;
|
|
1529
|
-
this.x = this.dimensions[0];
|
|
1530
|
-
this.y = this.dimensions[1];
|
|
1531
|
-
this.offset = object.size || 0;
|
|
1532
|
-
this.size = this.offset / 4;
|
|
1533
|
-
this.visible = false;
|
|
1534
|
-
this._transform.set("e", 1);
|
|
1535
|
-
this._transform.set("f", 1);
|
|
1536
|
-
}
|
|
1537
|
-
get x() {
|
|
1538
|
-
return parseFloat(this._x);
|
|
1539
|
-
}
|
|
1540
|
-
get y() {
|
|
1541
|
-
return parseFloat(this._y);
|
|
1542
|
-
}
|
|
1543
|
-
set x(x_) {
|
|
1544
|
-
this._x = x_;
|
|
1545
|
-
}
|
|
1546
|
-
set y(y_) {
|
|
1547
|
-
this._y = y_;
|
|
1548
|
-
}
|
|
1549
|
-
get transform() {
|
|
1550
|
-
console.warn("transform is disabled - need updated reference for the graph options");
|
|
1551
|
-
return this._transform;
|
|
1552
|
-
}
|
|
1553
|
-
set transform(t) {
|
|
1554
|
-
this._transform = t;
|
|
1555
|
-
}
|
|
1556
|
-
};
|
|
1557
|
-
__name(_Label, "Label");
|
|
1558
|
-
_Label.DISPLAY_TYPES = { OFF: 0, AUTO: 1, CLICK: 2, ON: 3 };
|
|
1559
|
-
_Label.HIGHLIGHT = { OFF: 0, ON: 2 };
|
|
1560
|
-
_Label.POSITION = { OBJECT: 1, STATIC: 2, CONTAINER: 3, CUSTOM: 4 };
|
|
1561
|
-
let Label = _Label;
|
|
1562
|
-
const _Extremes = class _Extremes {
|
|
1563
|
-
// _point_max?: Point;
|
|
1564
|
-
// _node_max?: Point;
|
|
1565
|
-
constructor(x, y) {
|
|
1566
|
-
this.x_max = x;
|
|
1567
|
-
this.y_max = y;
|
|
1568
|
-
}
|
|
1569
|
-
as_viewBox(p = 1.2) {
|
|
1570
|
-
let x = this.x_max * p;
|
|
1571
|
-
let y = this.y_max * p;
|
|
1572
|
-
return `${x * -1} ${y * -1} ${x * 2} ${y * 2}`;
|
|
1573
|
-
}
|
|
1574
|
-
// get point_max(): Point {
|
|
1575
|
-
// return this._point_max || { x: 1, y: 1 };
|
|
1576
|
-
// }
|
|
1577
|
-
// get node_max(): Point {
|
|
1578
|
-
// return this._node_max || { x: 1, y: 1 };
|
|
1579
|
-
// }
|
|
1580
|
-
get height() {
|
|
1581
|
-
return this.y_max * 2;
|
|
1582
|
-
}
|
|
1583
|
-
get width() {
|
|
1584
|
-
return this.x_max * 2;
|
|
1585
|
-
}
|
|
1586
|
-
get top() {
|
|
1587
|
-
return this.y_max * -1;
|
|
1588
|
-
}
|
|
1589
|
-
get bottom() {
|
|
1590
|
-
return this.y_max;
|
|
1591
|
-
}
|
|
1592
|
-
get left() {
|
|
1593
|
-
return this.x_max * -1;
|
|
1594
|
-
}
|
|
1595
|
-
get right() {
|
|
1596
|
-
return this.x_max;
|
|
1597
|
-
}
|
|
1598
|
-
};
|
|
1599
|
-
__name(_Extremes, "Extremes");
|
|
1600
|
-
let Extremes = _Extremes;
|
|
1601
|
-
const _AxisPoint = class _AxisPoint extends PlottedObject {
|
|
1602
|
-
constructor(dimensions, o) {
|
|
1603
|
-
super(dimensions, o);
|
|
1604
|
-
this.visible = true;
|
|
1605
|
-
this.size = o.size;
|
|
1606
|
-
}
|
|
1607
|
-
set size(s) {
|
|
1608
|
-
this._size = s;
|
|
1609
|
-
}
|
|
1610
|
-
get size() {
|
|
1611
|
-
return this._size;
|
|
1612
|
-
}
|
|
1613
|
-
get x() {
|
|
1614
|
-
return this._x;
|
|
1615
|
-
}
|
|
1616
|
-
get y() {
|
|
1617
|
-
return this._y;
|
|
1618
|
-
}
|
|
1619
|
-
set x(x_) {
|
|
1620
|
-
this._x = x_;
|
|
1621
|
-
}
|
|
1622
|
-
set y(y_) {
|
|
1623
|
-
this._y = y_;
|
|
1624
|
-
}
|
|
1625
|
-
get transform() {
|
|
1626
|
-
return this._transform;
|
|
1627
|
-
}
|
|
1628
|
-
};
|
|
1629
|
-
__name(_AxisPoint, "AxisPoint");
|
|
1630
|
-
let AxisPoint = _AxisPoint;
|
|
1631
|
-
let DefaultGraphOptions = {
|
|
1632
|
-
GRAPH: {
|
|
1633
|
-
ratio: 1,
|
|
1634
|
-
x_max: 1,
|
|
1635
|
-
y_max: 1,
|
|
1636
|
-
selector: "body",
|
|
1637
|
-
width: 1,
|
|
1638
|
-
height: 1,
|
|
1639
|
-
axes: true,
|
|
1640
|
-
SIZE_EFFECT: 1,
|
|
1641
|
-
dimensions: [0, 1]
|
|
1642
|
-
},
|
|
1643
|
-
NODE: {
|
|
1644
|
-
size: 1,
|
|
1645
|
-
highlight: {
|
|
1646
|
-
color: "yellow",
|
|
1647
|
-
labels: Label.DISPLAY_TYPES.ON
|
|
1648
|
-
},
|
|
1649
|
-
labels: Label.DISPLAY_TYPES.ON,
|
|
1650
|
-
labelposition: Label.POSITION.OBJECT
|
|
1651
|
-
},
|
|
1652
|
-
POINT: {
|
|
1653
|
-
active: 2,
|
|
1654
|
-
size: 0.05,
|
|
1655
|
-
color: "#000",
|
|
1656
|
-
shape: Point.SHAPES.CIRCLE,
|
|
1657
|
-
labels: Label.DISPLAY_TYPES.AUTO,
|
|
1658
|
-
labelposition: Label.POSITION.OBJECT
|
|
1659
|
-
},
|
|
1660
|
-
MEAN: {
|
|
1661
|
-
shape: Point.SHAPES.SQUARE,
|
|
1662
|
-
labels: Label.DISPLAY_TYPES.AUTO
|
|
1663
|
-
},
|
|
1664
|
-
LABEL: {
|
|
1665
|
-
highlight: Label.HIGHLIGHT.OFF,
|
|
1666
|
-
position: ["top", "left"],
|
|
1667
|
-
container: "#label-container"
|
|
1668
|
-
},
|
|
1669
|
-
EDGE: {
|
|
1670
|
-
multiplier: 1
|
|
1671
|
-
}
|
|
1672
|
-
};
|
|
1673
|
-
const _Graph = class _Graph {
|
|
1674
|
-
constructor(options = { ...DefaultGraphOptions }) {
|
|
1675
|
-
this.__state__ = new EventBus();
|
|
1676
|
-
this.name = "unnamed-graph";
|
|
1677
|
-
this.origin = void 0;
|
|
1678
|
-
this.points = /* @__PURE__ */ new Map();
|
|
1679
|
-
this.nodes = /* @__PURE__ */ new Map();
|
|
1680
|
-
this.edges = /* @__PURE__ */ new Map();
|
|
1681
|
-
this.trajectories = /* @__PURE__ */ new Map();
|
|
1682
|
-
this.labels = /* @__PURE__ */ new Map();
|
|
1683
|
-
this.transform = new Transform();
|
|
1684
|
-
this.scale_x = 1;
|
|
1685
|
-
this.scale_y = 1;
|
|
1686
|
-
this.SIZE_EFFECT = 1;
|
|
1687
|
-
this._mirror_y = true;
|
|
1688
|
-
this._mirror_x = false;
|
|
1689
|
-
this._layers = new LayerArray(
|
|
1690
|
-
{ name: "graph", tabindex: 0, layers: [
|
|
1691
|
-
{
|
|
1692
|
-
name: "axes",
|
|
1693
|
-
layers: [
|
|
1694
|
-
{
|
|
1695
|
-
name: "axis_lines",
|
|
1696
|
-
tabindex: 0,
|
|
1697
|
-
layers: [],
|
|
1698
|
-
objects: []
|
|
1699
|
-
},
|
|
1700
|
-
{
|
|
1701
|
-
name: "axis_labels",
|
|
1702
|
-
tabindex: 0,
|
|
1703
|
-
layers: [],
|
|
1704
|
-
objects: []
|
|
1705
|
-
},
|
|
1706
|
-
{
|
|
1707
|
-
name: "axis_points",
|
|
1708
|
-
tabindex: 0,
|
|
1709
|
-
layers: [],
|
|
1710
|
-
objects: [
|
|
1711
|
-
this.origin
|
|
1712
|
-
]
|
|
1713
|
-
}
|
|
1714
|
-
]
|
|
1715
|
-
},
|
|
1716
|
-
{
|
|
1717
|
-
name: "network",
|
|
1718
|
-
layers: [
|
|
1719
|
-
{ name: "edges", layers: [], tabindex: 0 },
|
|
1720
|
-
{ name: "nodes", layers: [], tabindex: 0 },
|
|
1721
|
-
{ name: "edgenodes", layers: [], tabindex: 0 }
|
|
1722
|
-
]
|
|
1723
|
-
},
|
|
1724
|
-
{ name: "trajectories", layers: [], tabindex: 0 },
|
|
1725
|
-
{ name: "points", layers: [], tabindex: 0 },
|
|
1726
|
-
{ name: "labels", layers: [], tabindex: 0 }
|
|
1727
|
-
] }
|
|
1728
|
-
);
|
|
1729
|
-
this.options = options;
|
|
1730
|
-
this.origin = new AxisPoint(
|
|
1731
|
-
new DimensionVector(0, 0),
|
|
1732
|
-
{
|
|
1733
|
-
ID: "origin",
|
|
1734
|
-
x: 0,
|
|
1735
|
-
y: 0,
|
|
1736
|
-
size: 0,
|
|
1737
|
-
meta: {},
|
|
1738
|
-
graph: this,
|
|
1739
|
-
color: new Color("#FFFFFF"),
|
|
1740
|
-
highlight: new Color("#FFFFFF"),
|
|
1741
|
-
active: false
|
|
1742
|
-
}
|
|
1743
|
-
);
|
|
1744
|
-
let layer_id = 1;
|
|
1745
|
-
function buildLayerTree(layerData, parent, graph) {
|
|
1746
|
-
const new_layer = new Layer(`${layer_id}`, layerData, graph);
|
|
1747
|
-
layer_id += 1;
|
|
1748
|
-
new_layer.parent = parent || void 0;
|
|
1749
|
-
if (layerData.layers && Array.isArray(layerData.layers)) {
|
|
1750
|
-
new_layer.layers = new LayerArray(...layerData.layers.map((child) => buildLayerTree(child, new_layer, graph)));
|
|
1751
|
-
}
|
|
1752
|
-
return new_layer;
|
|
1753
|
-
}
|
|
1754
|
-
__name(buildLayerTree, "buildLayerTree");
|
|
1755
|
-
this.layers = new LayerArray(...this._layers.map((l) => buildLayerTree(l, null, this)));
|
|
1756
|
-
let axisPointLayer = this.layers.search("layers", "axis_points");
|
|
1757
|
-
if (axisPointLayer) {
|
|
1758
|
-
axisPointLayer.objects.set(this.origin.ID, this.origin);
|
|
1759
|
-
}
|
|
1760
|
-
let axisLineLayer = this.layers.search("layers", "axis_lines");
|
|
1761
|
-
if (axisLineLayer) {
|
|
1762
|
-
let extremes = this.extremes || new Extremes(1, 1);
|
|
1763
|
-
let axis_x = new Line(
|
|
1764
|
-
{},
|
|
1765
|
-
new Point({ ID: "axis-x-start", dimensions: [-extremes.x_max, 0], classes: ["ena.dimension", "ena.dimension"] }),
|
|
1766
|
-
new Point({ ID: "axis-x-end", dimensions: [extremes.x_max, 0], classes: ["ena.dimension", "ena.dimension"] })
|
|
1767
|
-
);
|
|
1768
|
-
axis_x.ID = "axis-x";
|
|
1769
|
-
axisLineLayer.objects.set(axis_x.ID, axis_x);
|
|
1770
|
-
let axis_y = new Line(
|
|
1771
|
-
{},
|
|
1772
|
-
new Point({ ID: "axis-y-start", dimensions: [0, -extremes.y_max], classes: ["ena.dimension", "ena.dimension"] }),
|
|
1773
|
-
new Point({ ID: "axis-y-end", dimensions: [0, extremes.y_max], classes: ["ena.dimension", "ena.dimension"] })
|
|
1774
|
-
);
|
|
1775
|
-
axis_y.ID = "axis-y";
|
|
1776
|
-
axisLineLayer.objects.set(axis_y.ID, axis_y);
|
|
1777
|
-
console.log("Added axis lines to layer: ", axisLineLayer);
|
|
1778
|
-
}
|
|
1779
|
-
this.extremes = new Extremes(options.GRAPH.x_max, options.GRAPH.y_max);
|
|
1780
|
-
}
|
|
1781
|
-
set extremes(e) {
|
|
1782
|
-
this._extremes = e;
|
|
1783
|
-
}
|
|
1784
|
-
get extremes() {
|
|
1785
|
-
return this._extremes;
|
|
1786
|
-
}
|
|
1787
|
-
get mirror_x() {
|
|
1788
|
-
return this._mirror_x;
|
|
1789
|
-
}
|
|
1790
|
-
set mirror_x(m) {
|
|
1791
|
-
this._mirror_x = m;
|
|
1792
|
-
}
|
|
1793
|
-
get mirror_y() {
|
|
1794
|
-
return this._mirror_y;
|
|
1795
|
-
}
|
|
1796
|
-
set mirror_y(m) {
|
|
1797
|
-
this._mirror_y = m;
|
|
1798
|
-
}
|
|
1799
|
-
x_mirror() {
|
|
1800
|
-
return this.mirror_x ? -1 : 1;
|
|
1801
|
-
}
|
|
1802
|
-
y_mirror() {
|
|
1803
|
-
return this.mirror_y ? -1 : 1;
|
|
1804
|
-
}
|
|
1805
|
-
add_point(p) {
|
|
1806
|
-
const point = new Point(p);
|
|
1807
|
-
this.points.set(point.ID, point);
|
|
1808
|
-
}
|
|
1809
|
-
add_points(ps) {
|
|
1810
|
-
let g_ = this;
|
|
1811
|
-
ps.rows().forEach((p) => {
|
|
1812
|
-
g_.add_point(p);
|
|
1813
|
-
});
|
|
1814
|
-
}
|
|
1815
|
-
add_nodes(ns) {
|
|
1816
|
-
let g_ = this;
|
|
1817
|
-
ns.forEach((new_node) => {
|
|
1818
|
-
new_node.label = new Label(new_node.ID, new_node);
|
|
1819
|
-
g_.labels.set(new_node.label.ID, new_node.label);
|
|
1820
|
-
g_.nodes.set(new_node.ID, new_node);
|
|
1821
|
-
const nodesLayer = g_.layers.search("layers", "nodes");
|
|
1822
|
-
if (nodesLayer) {
|
|
1823
|
-
nodesLayer.objects.push(new_node);
|
|
1824
|
-
}
|
|
1825
|
-
});
|
|
1826
|
-
g_.update_extremes();
|
|
1827
|
-
}
|
|
1828
|
-
add_edge(e, from, to) {
|
|
1829
|
-
let g_ = this;
|
|
1830
|
-
g_.edges.set(e.ID, e);
|
|
1831
|
-
this.add_nodes([from || e.from, to || e.to]);
|
|
1832
|
-
return e;
|
|
1833
|
-
}
|
|
1834
|
-
add_edges(es) {
|
|
1835
|
-
let added = es.map((e) => this.add_edge(e));
|
|
1836
|
-
const edgesLayer = this.layers.search("layers", "edges");
|
|
1837
|
-
if (edgesLayer) {
|
|
1838
|
-
edgesLayer.objects.push(...added);
|
|
1839
|
-
}
|
|
1840
|
-
return added;
|
|
1841
|
-
}
|
|
1842
|
-
update_extremes() {
|
|
1843
|
-
const search_layers = [
|
|
1844
|
-
this.layers.search("layers", "points"),
|
|
1845
|
-
this.layers.search("layers", "nodes")
|
|
1846
|
-
].filter((l) => l !== void 0);
|
|
1847
|
-
if (search_layers.length === 0) {
|
|
1848
|
-
this.extremes = new Extremes(1, 1);
|
|
1849
|
-
} else {
|
|
1850
|
-
const content_max = Math.max(
|
|
1851
|
-
...search_layers.map((l) => Math.max(
|
|
1852
|
-
...[...l.objects.values()].map((o) => Math.max(Math.abs(o.x), Math.abs(o.y)))
|
|
1853
|
-
)).filter((a) => Math.abs(a) !== Infinity)
|
|
1854
|
-
);
|
|
1855
|
-
const found_max = (Number.isFinite(content_max) && content_max > 0 ? content_max : 1) * 1.3;
|
|
1856
|
-
this.extremes = new Extremes(found_max, found_max);
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
base_point_size(scale = 8) {
|
|
1860
|
-
let minDim = Math.min(this.extremes.x_max, this.extremes.y_max);
|
|
1861
|
-
let n = this.points.size + this.nodes.size;
|
|
1862
|
-
return Math.min(1, minDim / (Math.sqrt(n) * scale));
|
|
1863
|
-
}
|
|
1864
|
-
};
|
|
1865
|
-
__name(_Graph, "Graph");
|
|
1866
|
-
let Graph = _Graph;
|
|
1867
|
-
const _DrawableElement = class _DrawableElement extends HTMLElement {
|
|
1868
|
-
constructor() {
|
|
1869
|
-
super();
|
|
1870
|
-
this.element = null;
|
|
1871
|
-
this.object = null;
|
|
1872
|
-
const element = this, shadow = element.attachShadow({ mode: "open" }), style = document.createElement("style"), wrapper = document.createElement("div");
|
|
1873
|
-
style.textContent = this.constructor.style;
|
|
1874
|
-
shadow.appendChild(style);
|
|
1875
|
-
wrapper.setAttribute("class", "wrapper");
|
|
1876
|
-
shadow.appendChild(wrapper);
|
|
1877
|
-
}
|
|
1878
|
-
get wrapper() {
|
|
1879
|
-
const element = this, shadow = element.shadowRoot, wrapper = shadow == null ? void 0 : shadow.querySelector(".wrapper");
|
|
1880
|
-
return wrapper;
|
|
1881
|
-
}
|
|
1882
|
-
};
|
|
1883
|
-
__name(_DrawableElement, "DrawableElement");
|
|
1884
|
-
_DrawableElement.style = `
|
|
8
|
+
`;let Zt=Bt;customElements.define(Zt.tagName,Zt);const Re=class Re{constructor(t){return this.base=typeof t=="string"?t:t.base,new Proxy(this,{get(e,s){if(typeof s=="string"&&/^[0-2]$/.test(s)){const{r:i,g:n,b:r}=Re.parseColor(e.base);return[i,n,r][Number(s)]}return e[s]}})}toString(){return this.base}setBase(t){this.base=t}static parseColor(t){if(t.startsWith("#")){const e=parseInt(t.slice(1),16);return{r:e>>16&255,g:e>>8&255,b:e&255}}throw new Error("Unsupported color format")}static rgb(t,e,s){return`rgb(${t}, ${e}, ${s})`}};u(Re,"Color");let tt=Re;const we=class we extends tt{constructor(t,e,s){super(t),this.weight=e,this.alpha=s}static toHSV(t){const{r:e,g:s,b:i}=tt.parseColor(t),n=e/255,r=s/255,a=i/255,h=Math.max(n,r,a),o=Math.min(n,r,a),l=h-o,_=h,g=h===0?0:l/h;let c=0;if(l>0)switch(h){case n:c=((r-a)/l+(r<a?6:0))/6;break;case r:c=((a-n)/l+2)/6;break;default:c=((n-r)/l+4)/6}return{h:c*360,s:g,v:_}}static hsvToRgba(t,e,s,i){const n=s*e,r=n*(1-Math.abs(t/60%2-1)),a=s-n;let h=0,o=0,l=0;return t<60?(h=n,o=r,l=0):t<120?(h=r,o=n,l=0):t<180?(h=0,o=n,l=r):t<240?(h=0,o=r,l=n):t<300?(h=r,o=0,l=n):(h=n,o=0,l=r),`rgba(${Math.round((h+a)*255)},${Math.round((o+a)*255)},${Math.round((l+a)*255)},${i.toFixed(4)})`}toString(){const{h:t,v:e}=we.toHSV(this.base),s=Math.min(1,Math.abs(this.weight)),i=this.alpha===void 0?s:Math.min(1,Math.max(0,this.alpha));return we.hsvToRgba(t,s,e,i)}};u(we,"WeightedColor");let Qt=we;const as=class as{constructor(t=null){this._values=[1,0,0,1,0,0],this._keys=["a","b","c","d","e","f"],t&&(this.values=t)}get values(){return this._values}set values(t){t&&t.length===6&&(this._values=t)}get keys(){return this._keys}set keys(t){t&&t.length===6&&(this._keys=t)}toString(){return`matrix(${this.keys.map((e,s)=>this.values[s]).join(" ")})`}toMatrix(){return Object.fromEntries(this._keys.map((t,e)=>[t,this._values[e]]))}toArray(){return this._values}set(t,e){e!==.0075&&e!==0&&(this._values[this._keys.findIndex(s=>s===t)]=e)}get(t){return this._values[this._keys.findIndex(e=>e===t)]}scale(t,e=t){this.a=t,this.d=e}zoom(t){this.a=t,this.d=t}pan(t,e){this.e=this.e+t,this.f=this.f+e}set a(t){this.set("a",t)}set b(t){this.set("b",t)}set c(t){this.set("c",t)}set d(t){this.set("d",t)}set e(t){this.set("e",t)}set f(t){this.set("f",t)}get a(){return this.get("a")}get b(){return this.get("b")}get c(){return this.get("c")}get d(){return this.get("d")}get e(){return this.get("e")}get f(){return this.get("f")}};u(as,"Transform");let te=as;var ee;(d=>{(t=>{function e(s){return`matrix(${["a","b","c","d","e","f"].map(n=>s[n]).join(" ")})`}u(e,"matrixString"),t.matrixString=e})(d.Matrix||(d.Matrix={})),(t=>{(s=>{function i(r,a,h){const o=e.toRad(a);return[r[0]+h*Math.cos(o),r[1]+h*Math.sin(o)]}u(i,"translate"),s.translate=i;function n(r,a,h){const o=e.toRad(a);function l(_,g){return[_[0]*Math.cos(g)-_[1]*Math.sin(g),_[0]*Math.sin(g)+_[1]*Math.cos(g)]}if(u(l,"rotatePoint"),!h||h[0]===0&&h[1]===0)return l(r,o);{const _=r.map((c,E)=>c-h[E]);return l(_,o).map((c,E)=>c+h[E])}}u(n,"rotate"),s.rotate=n})(t.Point||(t.Point={})),(s=>{function i(p,A){return(A[1]-p[1])/(A[0]-p[0])}u(i,"slope"),s.slope=i;function n(p,A){const R=i(p,A);return p[1]-R*p[0]}u(n,"intercept"),s.intercept=n;function r(p,A){return{slope:i(p,A),intercept:n(p,A)}}u(r,"slopeIntercept"),s.slopeIntercept=r;function a(p,A=0){const R=A,q=(1-R)*p[0][0]+R*p[1][0],G=(1-R)*p[0][1]+R*p[1][1];return[q,G]}u(a,"point_along"),s.point_along=a;function h(p,A,R=.5){return Array.isArray(p[0])&&(A=p[1],p=p[0]),[0,1].map(q=>(parseFloat(p[q])+parseFloat(A[q]))*R)}u(h,"midpoint"),s.midpoint=h;function o(p,A){return Array.isArray(p[0])&&(A=p[1],p=p[0]),Math.sqrt([0,1].map(R=>Math.pow(A[R]-p[R],2)).reduce((R,q)=>R+q,0))}u(o,"length"),s.length=o;function l(p,A=[0,0]){const R=[p[1][0]-A[0],p[1][1]-A[1]],q=[-R[1],R[0]],G=[-q[0],-q[1]],v=[q[0]+A[0],q[1]+A[1]],Y=[G[0]+A[0],G[1]+A[1]];return[v,Y]}u(l,"rotate"),s.rotate=l;function _(p,A,R=90){const q=d.Geometry.Line.slope(p[0],p[1]),G=d.Geometry.Line.intercept(p[0],p[1]),v=[0,G],Y=[1,q+G];p=[v,Y];const rt=[p[0][0],p[1][0]],ht=[p[0][1],p[1][1]],nt=A[0],dt=A[1],Z=-2*Math.PI*R/360,Ot=rt.map((He,gt)=>(He-nt)*Math.cos(Z)-(ht[gt]-dt)*Math.sin(Z)+nt),Dt=ht.map((He,gt)=>(rt[gt]-nt)*Math.sin(Z)-(He-dt)*Math.cos(Z)+dt);return[[Ot[0],Dt[0]],[Ot[1],Dt[1]]]}u(_,"rotate2"),s.rotate2=_;function g(p,A){const[[R,q],[G,v]]=p,[[Y,rt],[ht,nt]]=A,dt=(R-G)*(rt-nt)-(q-v)*(Y-ht),Z=(R*v-q*G)*(Y-ht)-(R-G)*(Y*nt-rt*ht),Ot=(R*v-q*G)*(rt-nt)-(q-v)*(Y*nt-rt*ht);return[Z/dt,Ot/dt]}u(g,"intersection"),s.intersection=g;function c(p,A,R){let{slope:q,intercept:G}=d.Geometry.Line.slopeIntercept(p[0],p[1]),v=1+Math.pow(q,2),Y=2*q*G-2*A[1]*q-2*A[0],rt=Math.pow(A[0],2)+Math.pow(G,2)+Math.pow(A[1],2)-2*A[1]*G-Math.pow(R,2),ht=[[1/0,1/0],[1/0,1/0]];if(Math.sqrt(Math.pow(Y,2)-4*v*rt)>=0){let nt=(-Y+Math.sqrt(Math.pow(Y,2)-4*v*rt))/(2*v),dt=(-Y-Math.sqrt(Math.pow(Y,2)-4*v*rt))/(2*v),Z=q*nt+G,Ot=q*dt+G;ht=[[nt,Z],[dt,Ot]]}else console.error("The line and the circumference do not intersect");return ht}u(c,"intersect_circle"),s.intersect_circle=c;function E(p){return A=>A===0?p[0]:A===1?p[1]:d.Geometry.Point.translate(p[0],d.Geometry.Angle.line(p),d.Geometry.Line.length(p)*A)}u(E,"interpolate"),s.interpolate=E})(t.Line||(t.Line={}));let e;(s=>{function i(a){return a/180*Math.PI}u(i,"toRad"),s.toRad=i;function n(a){return a*180/Math.PI}u(n,"toDeg"),s.toDeg=n;function r(a){if(a.length!==2||!Array.isArray(a[0])||!Array.isArray(a[1])||a[0].length!==2||a[1].length!==2)throw new Error("Invalid line format. Expected [[x1, y1], [x2, y2]].");return d.Geometry.Angle.toDeg(Math.atan2(a[1][1]-a[0][1],a[1][0]-a[0][0]))}u(r,"line"),s.line=r})(e=t.Angle||(t.Angle={}))})(d.Geometry||(d.Geometry={})),(t=>{function e(n){return[...new Set(n)]}u(e,"unique"),t.unique=e;function s(n,r){if(Array.isArray(n)){if(Array.isArray(r)){if(n.length!==r.length)throw new Error("Arrays must be of equal length");return n.map((a,h)=>a/r[h])}return n.map(a=>a/r)}return n/r}u(s,"divide"),t.divide=s;function i(n){return typeof Array.isArray=="function"?Array.isArray(n):n&&typeof n=="object"&&n.constructor.name==="Array"}u(i,"isArray"),t.isArray=i})(d.ArrayTools||(d.ArrayTools={})),(t=>{function e(n){return n.reduce((r,a)=>r+a,0)}u(e,"sum"),t.sum=e;function s(n){return e(n)/n.length}u(s,"mean"),t.mean=s;function i(n,r){const a=Math.pow(10,r);return Math.round(n*a)/a}u(i,"round"),t.round=i})(d.Mathematics||(d.Mathematics={})),(t=>{function e(s,i,n){return new CustomEvent(s,{bubbles:!0,cancelable:!0,detail:{element:i,data:n||(i?i.__data__:void 0)}})}u(e,"createEvent"),t.createEvent=e})(d.Events||(d.Events={})),(t=>{function e(){return location.hash.replace(/#/,"").split(/\//).filter(i=>i).map(i=>i.split(/:/))}u(e,"parts"),t.parts=e;function s(i){return e().flat().findIndex(n=>n===i)>=0}u(s,"exists"),t.exists=s})(d.Hash||(d.Hash={})),(t=>{function e(n,r,a=!1){if(a){if(typeof n!="object"||n===null)return n;for(const h in n)Object.prototype.hasOwnProperty.call(n,h)&&(n[h]=e(n[h],r,a));return new Proxy(n,r)}else return new Proxy(n,r)}u(e,"proxy"),t.proxy=e,t.handler={set(n,r,a){return n[r]=a,window.dispatchEvent(d.Events.createEvent("settingUpdate",window,{target:n,property:r,value:a})),!0},get(n,r){return n[r]}};function s(n,r){const a=r.split(".");let h=n;for(const o of a)if(h&&typeof h=="object"&&Object.prototype.hasOwnProperty.call(h,o))h=h[o];else return;return h}u(s,"get"),t.get=s;function i(n,r,a){const h=r.split(".");let o=n,l;for(l=0;l<h.length-1;l++){const _=h[l];if(o&&typeof o=="object")Object.prototype.hasOwnProperty.call(o,_)||(o[_]={}),o=o[_];else return!1}return o&&typeof o=="object"?(o[h[l]]=a,!0):!1}u(i,"set"),t.set=i})(d.Objects||(d.Objects={})),(t=>{function e(s=window.location){return Object.fromEntries(new URLSearchParams(s.search))}u(e,"parse"),t.parse=e,(s=>{function i(a=window.location.search){return Object.fromEntries(a.replace(/^\?/,"").split(/&/).map(h=>h.split(/=/)))}u(i,"parse2"),s.parse=i;function n(a=window.location.search){return a.replace(/^\?/,"").split(/&/).map(h=>h.split(/=/)[0])}u(n,"keys"),s.keys=n;function r(a,h=window.location.search){return n(h).findIndex(o=>o===a)>=0}u(r,"has"),s.has=r})(t.Query||(t.Query={}))})(d.URL||(d.URL={}))})(ee||(ee={}));const hs=class hs{constructor(){this._state=new Map,this.listeners=new Map}get state(){return this._state}hasVariable(t){return this._state.has(t)}getVariable(t){return this._state.get(t)}setVariable(t,e,s){const i=this._state.get(t);this._state.set(t,e),s!=null&&s.lazy||this.notifyListeners(t,e,i)}addListener(t,e,s){this.listeners.has(t)||this.listeners.set(t,new Map);const i=this.listeners.get(t);i.has(e)||i.set(e,new Set),i.get(e).add(s)}removeListener(t,e,s){var i,n;(n=(i=this.listeners.get(t))==null?void 0:i.get(e))==null||n.delete(s)}getListeners(t,e){var s;return Array.from(((s=this.listeners.get(t))==null?void 0:s.get(e))??[])}notifyListeners(t,e,s){const i=this.listeners.get(t);if(i)for(const n of i.values())n.forEach(r=>{typeof r=="function"?r({key:t,newValue:e,oldValue:s}):typeof r.calculate=="function"&&r.calculate.call(r,{key:t,newValue:e,oldValue:s})})}};u(hs,"EventBus");let Me=hs;const{ArrayTools:Es}=ee,Ae=class Ae extends Array{constructor(...t){super(...t)}search(t,e){let s;function i(r){return r.name===e?r:void 0}u(i,"fn");function n(r,a,h=null){if(Es.isArray(r)){for(const[o,l]of r.entries())if(s=n(l,o,h),s)return s}else{if(s=i(r),s)return s;if(r&&Es.isArray(r[t])){for(const[o,l]of r[t].entries())if(s=n(l,o,r),s)return s}}return s}return u(n,"recurse"),n(this)}flatten(){return this.reduce((t,e)=>(t.push(e),e.layers&&Array.isArray(e.layers)&&t.push(...e.layers),t),[])}recurse(t,e,s=null,i=0){let n=new Ae;for(const r of this){let a=e(r,s,i);if(r[t]&&Array.isArray(r[t])){let h=new Ae(...r[t]).recurse(t,e,r,i+1);h!==void 0&&n.push(...h)}n.push(a)}return console.log("Recurse results: ",n),n}};u(Ae,"LayerArray");let jt=Ae;const ls=class ls{constructor(t,e,s){this.__state__=new Me,this.scale_x=1,this.scale_y=1,this.scale_objects=!0,this.layers=new jt,this.objects=new Map,this.visible=!0,this.ID=t,this.name=e.name||`layer-${t}`,this.tabindex=e.tabindex,this.parent=s,this._transform=new te,s==null||s.__state__.addListener("graph_updated","live",({key:i,newValue:n,oldValue:r})=>{}),s==null||s.__state__.addListener(`graph_updated_${this.name}`,"live",({key:i,newValue:n,oldValue:r})=>{this.objects=n,this.__state__.setVariable("layer_updated",this)})}get transform(){return this._transform}set transform(t){this._transform=t}};u(ls,"Layer");let Ke=ls;const Le=class Le extends Array{constructor(...e){super(arguments.length);it(this,Tt,!1);it(this,Et);for(let s=0;s<e.length;s++)this[s]=e[s];W(this,Tt,!1)}static fromArray(e){const s=new Le;return e.forEach((i,n)=>{s.push(i)}),W(s,Et,e.names),s}flip(){W(this,Tt,!C(this,Tt));for(let e=0;e<this.length;e++)this[e]=-this[e];return this}get(e){return typeof e=="number"?this[e]:C(this,Et)&&C(this,Et).includes(e)?this[C(this,Et).indexOf(e)]:void 0}get flipped(){return C(this,Tt)}get names(){return C(this,Et)?C(this,Et):this.map((e,s)=>`V${s+1}`)}};Tt=new WeakMap,Et=new WeakMap,u(Le,"DimensionVector");let Pt=Le;const cs=class cs{constructor(t,e){this.scale_x=1,this.scale_y=1,this.scale_size=.05,this.active=!1,this.visible=!1,this.highlighting=!1,this.meta={},this._x=0,this._y=0,this._highlight_default=new tt("#000000"),this._size=0,this.ID=e.ID,this._transform=new te,t instanceof Pt?this._dimensions=t:t instanceof B?this._dimensions=Pt.fromArray(t):Array.isArray(t)?this._dimensions=new Pt(...t):(console.warn("Invalid dimensions provided, using default DimensionVector(0, 0)"),this._dimensions=new Pt(0,0));let s={...e};this._original={...s},this.ID=s.ID,this.x=s.x||this._dimensions[0],this.y=s.y||this._dimensions[1],this._size=s.size||1,this._color=s.color||new tt("#000000"),this.active=s.active||!1,this.shape=s.shape||null,this.meta=s.meta||{},this._highlight=this._highlight_default,s.highlight&&(this._highlight=s.highlight)}get dimensions(){return this._dimensions}get color(){return this.highlighting&&this._highlight?this._highlight:this._color}set color(t){this._color=t}get highlight(){return this._highlight||this._highlight_default}set highlight(t){this._highlight=t}get size(){return this._size}set size(t){this._size=t}get original(){return this._original}get x(){return this._x}get y(){return this._y}set x(t){this._x=t}set y(t){this._y=t}dimension(t){return this._dimensions.get(t)}get transform(){return this._transform}set transform(t){this._transform=t}};u(cs,"PlottedObject");let Nt=cs;const _s=class _s extends Nt{constructor(t,e,s){super([],{}),this.from=e,this.to=s}get line(){return[[this.from.x,this.from.y],[this.to.x,this.to.y]]}get midpoint(){return[(this.from.x+this.to.x)/2,(this.from.y+this.to.y)/2]}get length(){return Math.sqrt(Math.pow(this.to.x-this.from.x,2)+Math.pow(this.to.y-this.from.y,2))}get color(){return this._color}set color(t){this._color=t}};u(_s,"Line");let Yt=_s;const ve=class ve extends Nt{constructor(t){var n,r;let e,s,i;t?t instanceof B?(e=(n=t.classes)==null?void 0:n.map((a,h)=>a==="ena.co.occurrence"||a==="ena.dimension"?t[h]:-1).filter(a=>a!==-1),s=(r=t.classes)==null?void 0:r.map((a,h)=>a==="ena.metadata"?[t.names[h],t[h]]:null).filter(a=>a!==null).reduce((a,h)=>(a[h[0]]=h[1],a),{}),i=t.rowName||`point-${Math.random().toString(36).substring(2,9)}`):typeof t=="object"?(e=t.dimensions||[],s=t.meta||{},i=t.ID||`point-${Math.random().toString(36).substring(2,9)}`):(console.warn("Invalid data provided for Point, using default values"),e=[],s={},i=`point-${Math.random().toString(36).substring(2,9)}`):(e=[],s={},i=`point-${Math.random().toString(36).substring(2,9)}`),super(e??[],{meta:s,ID:i}),this.edges=new Map,this.shape=ve.SHAPES.CIRCLE}set label(t){this._label=t}get label(){return this._label}get x(){return this._x}get y(){return this._y}set x(t){this._x=parseFloat(t)}set y(t){this._y=parseFloat(t)}};u(ve,"Point"),ve.SHAPES={CIRCLE:"circle",SQUARE:"rect"};let J=ve;const Ht=class Ht extends Nt{constructor(t,e){super(e.dimensions,e),this._visible=!1,this.offset=0,this.text=t,this.ID=e.ID,this.object=e,this.x=this.dimensions[0],this.y=this.dimensions[1],this.offset=e.size||0,this.size=this.offset/4,this.visible=!1,this._transform.set("e",1),this._transform.set("f",1)}get x(){return parseFloat(this._x)}get y(){return parseFloat(this._y)}set x(t){this._x=t}set y(t){this._y=t}get transform(){return console.warn("transform is disabled - need updated reference for the graph options"),this._transform}set transform(t){this._transform=t}};u(Ht,"Label"),Ht.DISPLAY_TYPES={OFF:0,AUTO:1,CLICK:2,ON:3},Ht.HIGHLIGHT={OFF:0,ON:2},Ht.POSITION={OBJECT:1,STATIC:2,CONTAINER:3,CUSTOM:4};let H=Ht;const us=class us{constructor(t,e,s=0,i=0){this.x_max=t,this.y_max=e,this.cx=s,this.cy=i}as_viewBox(t=1.2){let e=this.x_max*t,s=this.y_max*t;return`${this.cx-e} ${this.cy-s} ${e*2} ${s*2}`}get height(){return this.y_max*2}get width(){return this.x_max*2}get top(){return this.y_max*-1}get bottom(){return this.y_max}get left(){return this.x_max*-1}get right(){return this.x_max}};u(us,"Extremes");let Rt=us;const ds=class ds extends Nt{constructor(t,e){super(t,e),this.visible=!0,this.size=e.size}set size(t){this._size=t}get size(){return this._size}get x(){return this._x}get y(){return this._y}set x(t){this._x=t}set y(t){this._y=t}get transform(){return this._transform}};u(ds,"AxisPoint");let Je=ds,Ms={GRAPH:{ratio:1,x_max:1,y_max:1,selector:"body",width:1,height:1,axes:!0,SIZE_EFFECT:1,dimensions:[0,1]},NODE:{size:1,highlight:{color:"yellow",labels:H.DISPLAY_TYPES.ON},labels:H.DISPLAY_TYPES.ON,labelposition:H.POSITION.OBJECT},POINT:{active:2,size:.05,color:"#000",shape:J.SHAPES.CIRCLE,labels:H.DISPLAY_TYPES.AUTO,labelposition:H.POSITION.OBJECT},MEAN:{shape:J.SHAPES.SQUARE,labels:H.DISPLAY_TYPES.AUTO},LABEL:{highlight:H.HIGHLIGHT.OFF,position:["top","left"],container:"#label-container"},EDGE:{multiplier:1}};const gs=class gs{constructor(t={...Ms}){this.__state__=new Me,this.name="unnamed-graph",this.origin=void 0,this.points=new Map,this.nodes=new Map,this.edges=new Map,this.trajectories=new Map,this.labels=new Map,this.transform=new te,this.scale_x=1,this.scale_y=1,this.SIZE_EFFECT=1,this._mirror_y=!0,this._mirror_x=!1,this._layers=new jt({name:"graph",tabindex:0,layers:[{name:"axes",layers:[{name:"axis_lines",tabindex:0,layers:[],objects:[]},{name:"axis_labels",tabindex:0,layers:[],objects:[]},{name:"axis_points",tabindex:0,layers:[],objects:[this.origin]}]},{name:"network",layers:[{name:"edges",layers:[],tabindex:0},{name:"nodes",layers:[],tabindex:0},{name:"edgenodes",layers:[],tabindex:0}]},{name:"trajectories",layers:[],tabindex:0},{name:"points",layers:[],tabindex:0},{name:"labels",layers:[],tabindex:0}]}),this.options=t,this.origin=new Je(new Pt(0,0),{ID:"origin",x:0,y:0,size:0,meta:{},graph:this,color:new tt("#FFFFFF"),highlight:new tt("#FFFFFF"),active:!1});let e=1;function s(r,a,h){const o=new Ke(`${e}`,r,h);return e+=1,o.parent=a||void 0,r.layers&&Array.isArray(r.layers)&&(o.layers=new jt(...r.layers.map(l=>s(l,o,h)))),o}u(s,"buildLayerTree"),this.layers=new jt(...this._layers.map(r=>s(r,null,this)));let i=this.layers.search("layers","axis_points");i&&i.objects.set(this.origin.ID,this.origin);let n=this.layers.search("layers","axis_lines");if(n){let r=this.extremes||new Rt(1,1),a=new Yt({},new J({ID:"axis-x-start",dimensions:[-r.x_max,0],classes:["ena.dimension","ena.dimension"]}),new J({ID:"axis-x-end",dimensions:[r.x_max,0],classes:["ena.dimension","ena.dimension"]}));a.ID="axis-x",n.objects.set(a.ID,a);let h=new Yt({},new J({ID:"axis-y-start",dimensions:[0,-r.y_max],classes:["ena.dimension","ena.dimension"]}),new J({ID:"axis-y-end",dimensions:[0,r.y_max],classes:["ena.dimension","ena.dimension"]}));h.ID="axis-y",n.objects.set(h.ID,h),console.log("Added axis lines to layer: ",n)}this.extremes=new Rt(t.GRAPH.x_max,t.GRAPH.y_max)}set extremes(t){this._extremes=t}get extremes(){return this._extremes}get mirror_x(){return this._mirror_x}set mirror_x(t){this._mirror_x=t}get mirror_y(){return this._mirror_y}set mirror_y(t){this._mirror_y=t}x_mirror(){return this.mirror_x?-1:1}y_mirror(){return this.mirror_y?-1:1}add_point(t){const e=new J(t);this.points.set(e.ID,e)}add_points(t){let e=this;t.rows().forEach(s=>{e.add_point(s)})}add_nodes(t){let e=this;t.forEach(s=>{s.label=new H(s.ID,s),e.labels.set(s.label.ID,s.label),e.nodes.set(s.ID,s);const i=e.layers.search("layers","nodes");i&&i.objects.push(s)}),e.update_extremes()}add_edge(t,e,s){return this.edges.set(t.ID,t),this.add_nodes([e||t.from,s||t.to]),t}add_edges(t){let e=t.map(i=>this.add_edge(i));const s=this.layers.search("layers","edges");return s&&s.objects.push(...e),e}update_extremes(t=!1){const e=[this.layers.search("layers","points"),this.layers.search("layers","nodes")].filter(s=>s!==void 0);if(e.length===0)this.extremes=new Rt(1,1);else{let s=1/0,i=-1/0,n=1/0,r=-1/0;e.forEach(g=>g.objects.forEach(c=>{Number.isFinite(c.x)&&(s=Math.min(s,c.x),i=Math.max(i,c.x)),Number.isFinite(c.y)&&(n=Math.min(n,c.y),r=Math.max(r,c.y))}));const a=Number.isFinite(s)&&Number.isFinite(n),h=t&&a?(s+i)/2:0,o=t&&a?(n+r)/2:0,l=a?Math.max(Math.abs(s-h),Math.abs(i-h),Math.abs(n-o),Math.abs(r-o)):0,_=(l>0?l:1)*1.3;this.extremes=new Rt(_,_,h,o)}}nodeExtentFrom(t,e){const s=this.layers.search("layers","nodes");let i=0;return s==null||s.objects.forEach(n=>{Number.isFinite(n.x)&&Number.isFinite(n.y)&&(i=Math.max(i,Math.abs(n.x-t),Math.abs(n.y-e)))}),i}base_point_size(t=8){let e=Math.min(this.extremes.x_max,this.extremes.y_max),s=this.points.size+this.nodes.size;return Math.min(1,e/(Math.sqrt(s)*t))}};u(gs,"Graph");let Ie=gs;const Te=class Te extends HTMLElement{constructor(){super(),this.element=null,this.object=null;const t=this,e=t.attachShadow({mode:"open"}),s=document.createElement("style"),i=document.createElement("div");s.textContent=this.constructor.style,e.appendChild(s),i.setAttribute("class","wrapper"),e.appendChild(i)}get wrapper(){const t=this,e=t.shadowRoot;return e==null?void 0:e.querySelector(".wrapper")}};u(Te,"DrawableElement"),Te.style=`
|
|
1885
9
|
:host {
|
|
1886
10
|
max-width: 100%;
|
|
1887
11
|
display: block;
|
|
@@ -1891,2174 +15,8 @@ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "
|
|
|
1891
15
|
display: flex;
|
|
1892
16
|
justify-content: center;
|
|
1893
17
|
}
|
|
1894
|
-
`;
|
|
1895
|
-
|
|
1896
|
-
const TRAJECTORY_ZERO_EPS = 1e-8;
|
|
1897
|
-
function nearOriginFilter(pts, eps = TRAJECTORY_ZERO_EPS) {
|
|
1898
|
-
return pts.filter((p) => Math.abs(p.x) > eps || Math.abs(p.y) > eps);
|
|
1899
|
-
}
|
|
1900
|
-
__name(nearOriginFilter, "nearOriginFilter");
|
|
1901
|
-
function normalizedT(n) {
|
|
1902
|
-
if (n <= 0) return [];
|
|
1903
|
-
if (n === 1) return [0];
|
|
1904
|
-
const t = new Array(n);
|
|
1905
|
-
for (let i = 0; i < n; i++) t[i] = i / (n - 1);
|
|
1906
|
-
return t;
|
|
1907
|
-
}
|
|
1908
|
-
__name(normalizedT, "normalizedT");
|
|
1909
|
-
function design(t, degree) {
|
|
1910
|
-
return t.map((ti) => {
|
|
1911
|
-
const row = new Array(degree + 1);
|
|
1912
|
-
let p = 1;
|
|
1913
|
-
for (let k = 0; k <= degree; k++) {
|
|
1914
|
-
row[k] = p;
|
|
1915
|
-
p *= ti;
|
|
1916
|
-
}
|
|
1917
|
-
return row;
|
|
1918
|
-
});
|
|
1919
|
-
}
|
|
1920
|
-
__name(design, "design");
|
|
1921
|
-
function qr(A) {
|
|
1922
|
-
const n = A.length;
|
|
1923
|
-
const m = A[0].length;
|
|
1924
|
-
const Q = A.map((row) => row.slice());
|
|
1925
|
-
const R = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
1926
|
-
for (let j = 0; j < m; j++) {
|
|
1927
|
-
let norm = 0;
|
|
1928
|
-
for (let i = 0; i < n; i++) norm += Q[i][j] * Q[i][j];
|
|
1929
|
-
norm = Math.sqrt(norm);
|
|
1930
|
-
R[j][j] = norm;
|
|
1931
|
-
if (norm > 1e-300) {
|
|
1932
|
-
for (let i = 0; i < n; i++) Q[i][j] /= norm;
|
|
1933
|
-
}
|
|
1934
|
-
for (let k = j + 1; k < m; k++) {
|
|
1935
|
-
let dot = 0;
|
|
1936
|
-
for (let i = 0; i < n; i++) dot += Q[i][j] * Q[i][k];
|
|
1937
|
-
R[j][k] = dot;
|
|
1938
|
-
for (let i = 0; i < n; i++) Q[i][k] -= dot * Q[i][j];
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
return { Q, R };
|
|
1942
|
-
}
|
|
1943
|
-
__name(qr, "qr");
|
|
1944
|
-
function qtY(Q, y) {
|
|
1945
|
-
const n = Q.length;
|
|
1946
|
-
const m = Q[0].length;
|
|
1947
|
-
const out = new Array(m).fill(0);
|
|
1948
|
-
for (let j = 0; j < m; j++) {
|
|
1949
|
-
let s = 0;
|
|
1950
|
-
for (let i = 0; i < n; i++) s += Q[i][j] * y[i];
|
|
1951
|
-
out[j] = s;
|
|
1952
|
-
}
|
|
1953
|
-
return out;
|
|
1954
|
-
}
|
|
1955
|
-
__name(qtY, "qtY");
|
|
1956
|
-
function backSolve(R, b) {
|
|
1957
|
-
const m = b.length;
|
|
1958
|
-
const c = new Array(m).fill(0);
|
|
1959
|
-
for (let i = m - 1; i >= 0; i--) {
|
|
1960
|
-
let s = b[i];
|
|
1961
|
-
for (let j = i + 1; j < m; j++) s -= R[i][j] * c[j];
|
|
1962
|
-
c[i] = Math.abs(R[i][i]) > 1e-12 ? s / R[i][i] : 0;
|
|
1963
|
-
}
|
|
1964
|
-
return c;
|
|
1965
|
-
}
|
|
1966
|
-
__name(backSolve, "backSolve");
|
|
1967
|
-
function leverages(Q) {
|
|
1968
|
-
return Q.map((row) => {
|
|
1969
|
-
let s = 0;
|
|
1970
|
-
for (let j = 0; j < row.length; j++) s += row[j] * row[j];
|
|
1971
|
-
return s;
|
|
1972
|
-
});
|
|
1973
|
-
}
|
|
1974
|
-
__name(leverages, "leverages");
|
|
1975
|
-
function fitCoeffs(t, y, degree) {
|
|
1976
|
-
const X = design(t, degree);
|
|
1977
|
-
const { Q, R } = qr(X);
|
|
1978
|
-
return backSolve(R, qtY(Q, y));
|
|
1979
|
-
}
|
|
1980
|
-
__name(fitCoeffs, "fitCoeffs");
|
|
1981
|
-
function evalPoly(coeffs, t) {
|
|
1982
|
-
let v = 0;
|
|
1983
|
-
let p = 1;
|
|
1984
|
-
for (let k = 0; k < coeffs.length; k++) {
|
|
1985
|
-
v += coeffs[k] * p;
|
|
1986
|
-
p *= t;
|
|
1987
|
-
}
|
|
1988
|
-
return v;
|
|
1989
|
-
}
|
|
1990
|
-
__name(evalPoly, "evalPoly");
|
|
1991
|
-
function loocv2d(t, x, y, degree) {
|
|
1992
|
-
const X = design(t, degree);
|
|
1993
|
-
const { Q, R } = qr(X);
|
|
1994
|
-
const h = leverages(Q);
|
|
1995
|
-
const cx = backSolve(R, qtY(Q, x));
|
|
1996
|
-
const cy = backSolve(R, qtY(Q, y));
|
|
1997
|
-
let press = 0;
|
|
1998
|
-
for (let i = 0; i < t.length; i++) {
|
|
1999
|
-
const denom = 1 - h[i];
|
|
2000
|
-
if (denom <= 0) return Infinity;
|
|
2001
|
-
const ex = x[i] - evalPoly(cx, t[i]);
|
|
2002
|
-
const ey = y[i] - evalPoly(cy, t[i]);
|
|
2003
|
-
press += (ex / denom) ** 2 + (ey / denom) ** 2;
|
|
2004
|
-
}
|
|
2005
|
-
return press;
|
|
2006
|
-
}
|
|
2007
|
-
__name(loocv2d, "loocv2d");
|
|
2008
|
-
function selectDegree(fitPts, maxDegree, mode) {
|
|
2009
|
-
const n = fitPts.length;
|
|
2010
|
-
const cap = Math.min(Math.max(1, Math.floor(maxDegree)), Math.max(1, n - 1));
|
|
2011
|
-
if (mode === "fixed" || n < 3) return cap;
|
|
2012
|
-
const t = normalizedT(n);
|
|
2013
|
-
const x = fitPts.map((p) => p.x);
|
|
2014
|
-
const y = fitPts.map((p) => p.y);
|
|
2015
|
-
let best = 1;
|
|
2016
|
-
let bestVal = Infinity;
|
|
2017
|
-
for (let deg = 1; deg <= cap; deg++) {
|
|
2018
|
-
const v = loocv2d(t, x, y, deg);
|
|
2019
|
-
if (v < bestVal) {
|
|
2020
|
-
bestVal = v;
|
|
2021
|
-
best = deg;
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
return best;
|
|
2025
|
-
}
|
|
2026
|
-
__name(selectDegree, "selectDegree");
|
|
2027
|
-
function fitTrajectory(activePts, opts) {
|
|
2028
|
-
const fitPts = nearOriginFilter(activePts);
|
|
2029
|
-
if (fitPts.length < 3) return null;
|
|
2030
|
-
const selBasis = opts.selectionSet ? nearOriginFilter(opts.selectionSet) : fitPts;
|
|
2031
|
-
const basis = selBasis.length >= 3 ? selBasis : fitPts;
|
|
2032
|
-
let degree = selectDegree(basis, opts.maxDegree, opts.degreeSelection);
|
|
2033
|
-
degree = Math.min(degree, Math.max(1, fitPts.length - 1));
|
|
2034
|
-
const t = normalizedT(fitPts.length);
|
|
2035
|
-
const coeffsX = fitCoeffs(t, fitPts.map((p) => p.x), degree);
|
|
2036
|
-
const coeffsY = fitCoeffs(t, fitPts.map((p) => p.y), degree);
|
|
2037
|
-
return { degree, coeffsX, coeffsY };
|
|
2038
|
-
}
|
|
2039
|
-
__name(fitTrajectory, "fitTrajectory");
|
|
2040
|
-
function sampleCurve(fit, steps = 100) {
|
|
2041
|
-
const out = [];
|
|
2042
|
-
for (let s = 0; s <= steps; s++) {
|
|
2043
|
-
const t = s / steps;
|
|
2044
|
-
out.push({ x: evalPoly(fit.coeffsX, t), y: evalPoly(fit.coeffsY, t) });
|
|
2045
|
-
}
|
|
2046
|
-
return out;
|
|
2047
|
-
}
|
|
2048
|
-
__name(sampleCurve, "sampleCurve");
|
|
2049
|
-
const TRAJECTORY_CURVE_STEPS = 100;
|
|
2050
|
-
const _Trajectory = class _Trajectory extends PlottedObject {
|
|
2051
|
-
constructor(options = {}) {
|
|
2052
|
-
const defaultColor = options.color instanceof Color ? options.color : new Color(typeof options.color === "string" ? options.color : "#000000");
|
|
2053
|
-
super([], {
|
|
2054
|
-
ID: options.ID || `traj-${Math.random().toString(36).substring(2, 9)}`,
|
|
2055
|
-
size: options.size || 1,
|
|
2056
|
-
color: defaultColor,
|
|
2057
|
-
highlight: null,
|
|
2058
|
-
active: options.active || false,
|
|
2059
|
-
meta: options.meta || {},
|
|
2060
|
-
...options
|
|
2061
|
-
});
|
|
2062
|
-
this._typeName = "Trajectory";
|
|
2063
|
-
this.trajPoints = [];
|
|
2064
|
-
this.smooth = "none";
|
|
2065
|
-
this.maxDegree = 3;
|
|
2066
|
-
this.degreeSelection = "loocv_2d";
|
|
2067
|
-
this.selectedDegree = -1;
|
|
2068
|
-
this.polyCoeffsX = [];
|
|
2069
|
-
this.polyCoeffsY = [];
|
|
2070
|
-
this.currentTime = Infinity;
|
|
2071
|
-
this.showPoints = true;
|
|
2072
|
-
this.showTips = true;
|
|
2073
|
-
this.lineStyle = "uniform";
|
|
2074
|
-
this.strokeWidth = 2;
|
|
2075
|
-
this.strokeWidthRange = [1, 6];
|
|
2076
|
-
this.opacityRange = [0.3, 1];
|
|
2077
|
-
this.smooth = options.smooth || "none";
|
|
2078
|
-
this.maxDegree = options.maxDegree !== void 0 ? options.maxDegree : 3;
|
|
2079
|
-
this.degreeSelection = options.degreeSelection || "loocv_2d";
|
|
2080
|
-
this.polyCoeffsX = options.polyCoeffsX || [];
|
|
2081
|
-
this.polyCoeffsY = options.polyCoeffsY || [];
|
|
2082
|
-
this.currentTime = options.currentTime !== void 0 ? options.currentTime : Infinity;
|
|
2083
|
-
this.showPoints = options.showPoints !== void 0 ? options.showPoints : true;
|
|
2084
|
-
this.showTips = options.showTips !== void 0 ? options.showTips : true;
|
|
2085
|
-
this.lineStyle = options.lineStyle || "uniform";
|
|
2086
|
-
this.strokeWidth = options.strokeWidth || 2;
|
|
2087
|
-
this.strokeWidthRange = options.strokeWidthRange || [1, 6];
|
|
2088
|
-
this.opacityRange = options.opacityRange || [0.3, 1];
|
|
2089
|
-
if (options.points && Array.isArray(options.points)) {
|
|
2090
|
-
this.trajPoints = options.points.map((p) => {
|
|
2091
|
-
if (p instanceof Point) return p;
|
|
2092
|
-
const pt = new Point({ dimensions: [p.x, p.y], meta: { time: p.time, label: p.label } });
|
|
2093
|
-
pt.x = p.x;
|
|
2094
|
-
pt.y = p.y;
|
|
2095
|
-
return pt;
|
|
2096
|
-
});
|
|
2097
|
-
}
|
|
2098
|
-
}
|
|
2099
|
-
get activePoints() {
|
|
2100
|
-
if (this.currentTime === Infinity) {
|
|
2101
|
-
return this.trajPoints;
|
|
2102
|
-
}
|
|
2103
|
-
return this.trajPoints.filter((p) => {
|
|
2104
|
-
const t = p.meta && typeof p.meta.time === "number" ? p.meta.time : 0;
|
|
2105
|
-
return t <= this.currentTime;
|
|
2106
|
-
});
|
|
2107
|
-
}
|
|
2108
|
-
get path() {
|
|
2109
|
-
return this.pathPoints.reduce((acc, pt, idx) => {
|
|
2110
|
-
return idx === 0 ? `M${pt.x},${pt.y}` : `${acc} L${pt.x},${pt.y}`;
|
|
2111
|
-
}, "");
|
|
2112
|
-
}
|
|
2113
|
-
get pathPoints() {
|
|
2114
|
-
const pts = this.activePoints;
|
|
2115
|
-
if (pts.length < 2) return [];
|
|
2116
|
-
if (this.smooth === "poly") {
|
|
2117
|
-
if (this.polyCoeffsX.length > 0 && this.polyCoeffsY.length > 0) {
|
|
2118
|
-
return sampleCurve(
|
|
2119
|
-
{ degree: this.polyCoeffsX.length - 1, coeffsX: this.polyCoeffsX, coeffsY: this.polyCoeffsY },
|
|
2120
|
-
TRAJECTORY_CURVE_STEPS
|
|
2121
|
-
);
|
|
2122
|
-
}
|
|
2123
|
-
const fit = fitTrajectory(
|
|
2124
|
-
pts.map((p) => ({ x: p.x, y: p.y })),
|
|
2125
|
-
{
|
|
2126
|
-
maxDegree: this.maxDegree,
|
|
2127
|
-
degreeSelection: this.degreeSelection,
|
|
2128
|
-
selectionSet: this.trajPoints.map((p) => ({ x: p.x, y: p.y }))
|
|
2129
|
-
}
|
|
2130
|
-
);
|
|
2131
|
-
if (fit) {
|
|
2132
|
-
this.selectedDegree = fit.degree;
|
|
2133
|
-
return sampleCurve(fit, TRAJECTORY_CURVE_STEPS);
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
return pts.map((pt) => ({ x: pt.x, y: pt.y }));
|
|
2137
|
-
}
|
|
2138
|
-
};
|
|
2139
|
-
__name(_Trajectory, "Trajectory");
|
|
2140
|
-
let Trajectory = _Trajectory;
|
|
2141
|
-
const zoom_level = 1;
|
|
2142
|
-
const _Edge = class _Edge extends Line {
|
|
2143
|
-
constructor(data, from, to, weight = 0) {
|
|
2144
|
-
super(data, from, to);
|
|
2145
|
-
this._totalweight = 0;
|
|
2146
|
-
this._weight = weight;
|
|
2147
|
-
}
|
|
2148
|
-
get base_color() {
|
|
2149
|
-
return this._color;
|
|
2150
|
-
}
|
|
2151
|
-
get color() {
|
|
2152
|
-
const base = this._color || new Color("#000000");
|
|
2153
|
-
return new WeightedColor(base, Math.abs(this.weight));
|
|
2154
|
-
}
|
|
2155
|
-
set color(c) {
|
|
2156
|
-
this._color = c;
|
|
2157
|
-
}
|
|
2158
|
-
base_weight() {
|
|
2159
|
-
return this._weight;
|
|
2160
|
-
}
|
|
2161
|
-
get weight() {
|
|
2162
|
-
let w = Array.isArray(this._weight) ? this._weight[0] - this._weight[1] : this._weight;
|
|
2163
|
-
return w;
|
|
2164
|
-
}
|
|
2165
|
-
set weight(w) {
|
|
2166
|
-
this._weight = w;
|
|
2167
|
-
}
|
|
2168
|
-
get totalweight() {
|
|
2169
|
-
return this.weight;
|
|
2170
|
-
}
|
|
2171
|
-
set totalweight(w) {
|
|
2172
|
-
this._totalweight = w;
|
|
2173
|
-
}
|
|
2174
|
-
};
|
|
2175
|
-
__name(_Edge, "Edge");
|
|
2176
|
-
let Edge = _Edge;
|
|
2177
|
-
const _EdgeArrow = class _EdgeArrow extends PlottedObject {
|
|
2178
|
-
constructor(edge) {
|
|
2179
|
-
super(edge.dimensions || [], edge);
|
|
2180
|
-
__privateAdd(this, _edge);
|
|
2181
|
-
__privateSet(this, _edge, edge);
|
|
2182
|
-
}
|
|
2183
|
-
get edge() {
|
|
2184
|
-
return __privateGet(this, _edge);
|
|
2185
|
-
}
|
|
2186
|
-
get path() {
|
|
2187
|
-
let _this = __privateGet(this, _edge);
|
|
2188
|
-
let _mid = _this.from_point, head = Tools.Geometry.Line.point_along([[_this.to.x, _this.to.y], _mid], 0.2), nock = Tools.Geometry.Line.point_along([[_this.to.x, _this.to.y], _mid], 0.35), mid = Tools.Geometry.Line.midpoint(head, nock), rot_mid = Tools.Geometry.Line.rotate(_this.line, mid), rot_nock = Tools.Geometry.Line.rotate(_this.line, nock), mid_int0 = Tools.Geometry.Line.intersection([_mid, _this.base_pts[0]], rot_mid), mid_int1 = Tools.Geometry.Line.intersection([_mid, _this.base_pts[1]], rot_mid), nock_int0 = Tools.Geometry.Line.intersection([_mid, _this.base_pts[0]], rot_nock), nock_int1 = Tools.Geometry.Line.intersection([_mid, _this.base_pts[1]], rot_nock);
|
|
2189
|
-
let p = `M${head.join(" ")} ${mid_int0.join(" ")} ${nock_int0.join(" ")} ${mid.join(" ")} ${nock_int1.join(" ")} ${mid_int1.join(" ")}z`;
|
|
2190
|
-
return p;
|
|
2191
|
-
}
|
|
2192
|
-
};
|
|
2193
|
-
_edge = new WeakMap();
|
|
2194
|
-
__name(_EdgeArrow, "EdgeArrow");
|
|
2195
|
-
let EdgeArrow = _EdgeArrow;
|
|
2196
|
-
const _TaperedEdge = class _TaperedEdge extends Edge {
|
|
2197
|
-
constructor(data, from, to) {
|
|
2198
|
-
super(data, from, to);
|
|
2199
|
-
__privateAdd(this, _with_arrow);
|
|
2200
|
-
__privateAdd(this, _arrow);
|
|
2201
|
-
this._path = "";
|
|
2202
|
-
__privateSet(this, _with_arrow, false);
|
|
2203
|
-
this._directions = [
|
|
2204
|
-
"from",
|
|
2205
|
-
"to"
|
|
2206
|
-
/* TO */
|
|
2207
|
-
];
|
|
2208
|
-
this.towards = "to";
|
|
2209
|
-
if (__privateGet(this, _with_arrow) === true) {
|
|
2210
|
-
__privateSet(this, _arrow, new EdgeArrow(this));
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
get path() {
|
|
2214
|
-
return `M${this.from.x} ${this.from.y} L${this.base_pts[0].join(" ")} L${this.base_pts[1].join(" ")}z`;
|
|
2215
|
-
}
|
|
2216
|
-
static calculate_base_points(edg) {
|
|
2217
|
-
const top = edg.towards;
|
|
2218
|
-
const base = edg._directions.find((d) => d !== edg.towards);
|
|
2219
|
-
const bx = edg[base].x, by = edg[base].y;
|
|
2220
|
-
const tx = edg[top].x, ty = edg[top].y;
|
|
2221
|
-
const dx = tx - bx, dy = ty - by;
|
|
2222
|
-
const L = Math.hypot(dx, dy);
|
|
2223
|
-
const wt = (edg.weight ?? 0) * zoom_level;
|
|
2224
|
-
if (L === 0 || !isFinite(wt) || wt === 0) {
|
|
2225
|
-
return [[tx, ty], [tx, ty]];
|
|
2226
|
-
}
|
|
2227
|
-
const px = -dy / L, py = dx / L;
|
|
2228
|
-
const halfW = wt / 2;
|
|
2229
|
-
return [
|
|
2230
|
-
[tx + px * halfW, ty + py * halfW],
|
|
2231
|
-
[tx - px * halfW, ty - py * halfW]
|
|
2232
|
-
];
|
|
2233
|
-
}
|
|
2234
|
-
get base_pts() {
|
|
2235
|
-
return _TaperedEdge.calculate_base_points(this);
|
|
2236
|
-
}
|
|
2237
|
-
get arrow() {
|
|
2238
|
-
return __privateGet(this, _arrow);
|
|
2239
|
-
}
|
|
2240
|
-
get with_arrow() {
|
|
2241
|
-
return __privateGet(this, _with_arrow);
|
|
2242
|
-
}
|
|
2243
|
-
get from_point() {
|
|
2244
|
-
return [this.from.x, this.from.y];
|
|
2245
|
-
}
|
|
2246
|
-
};
|
|
2247
|
-
_with_arrow = new WeakMap();
|
|
2248
|
-
_arrow = new WeakMap();
|
|
2249
|
-
__name(_TaperedEdge, "TaperedEdge");
|
|
2250
|
-
let TaperedEdge = _TaperedEdge;
|
|
2251
|
-
const _TaperedWeightedMidpointEdge = class _TaperedWeightedMidpointEdge extends TaperedEdge {
|
|
2252
|
-
constructor(data, from, to) {
|
|
2253
|
-
super(data, from, to);
|
|
2254
|
-
this._dataWeight = 0;
|
|
2255
|
-
this._totalweight = data.totalweight ?? 0;
|
|
2256
|
-
this._dataWeight = data.weight ?? this._weight;
|
|
2257
|
-
}
|
|
2258
|
-
get weighted_midpoint() {
|
|
2259
|
-
return Tools.Geometry.Line.interpolate(this.line)(1 - this._dataWeight / this._totalweight);
|
|
2260
|
-
}
|
|
2261
|
-
get base_pts() {
|
|
2262
|
-
return TaperedEdge.calculate_base_points(this);
|
|
2263
|
-
}
|
|
2264
|
-
static build_path(edg) {
|
|
2265
|
-
if (edg._totalweight > 0) {
|
|
2266
|
-
let p = `M${edg.weighted_midpoint[0]} ${edg.weighted_midpoint[1]} L${edg.base_pts[0].join(" ")} L${edg.base_pts[1].join(" ")}z`;
|
|
2267
|
-
return p;
|
|
2268
|
-
} else {
|
|
2269
|
-
console.error("TaperedWeightedMidpointEdge: No totalweight, returning empty path");
|
|
2270
|
-
return "";
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
get path() {
|
|
2274
|
-
return _TaperedWeightedMidpointEdge.build_path(this);
|
|
2275
|
-
}
|
|
2276
|
-
get from_point() {
|
|
2277
|
-
return this.weighted_midpoint;
|
|
2278
|
-
}
|
|
2279
|
-
};
|
|
2280
|
-
__name(_TaperedWeightedMidpointEdge, "TaperedWeightedMidpointEdge");
|
|
2281
|
-
let TaperedWeightedMidpointEdge = _TaperedWeightedMidpointEdge;
|
|
2282
|
-
const _NodeEdge = class _NodeEdge extends Edge {
|
|
2283
|
-
constructor(data, from, to) {
|
|
2284
|
-
super(data, from, to);
|
|
2285
|
-
}
|
|
2286
|
-
static build_path(weight, to) {
|
|
2287
|
-
let R = weight / 2, CX = to.x - R, R2 = R * 2, p = `M ${CX}, ${to.y} a ${R},${R} 0 1,0 ${R2},0 a ${R},${R} 0 1,0 -${R2},0`;
|
|
2288
|
-
return p;
|
|
2289
|
-
}
|
|
2290
|
-
get path() {
|
|
2291
|
-
let wt = this.weight * zoom_level;
|
|
2292
|
-
return _NodeEdge.build_path(wt, this.to);
|
|
2293
|
-
}
|
|
2294
|
-
};
|
|
2295
|
-
__name(_NodeEdge, "NodeEdge");
|
|
2296
|
-
let NodeEdge = _NodeEdge;
|
|
2297
|
-
const _Drawable = class _Drawable {
|
|
2298
|
-
constructor(__data__, parent, graph, __children__ = new QEArray()) {
|
|
2299
|
-
this.__data__ = __data__;
|
|
2300
|
-
this.parent = parent;
|
|
2301
|
-
this.graph = graph;
|
|
2302
|
-
this.__children__ = __children__;
|
|
2303
|
-
this.svg_element = this.create();
|
|
2304
|
-
}
|
|
2305
|
-
get_size() {
|
|
2306
|
-
return this.__data__.size;
|
|
2307
|
-
}
|
|
2308
|
-
draw() {
|
|
2309
|
-
var _a;
|
|
2310
|
-
(_a = this.parent) == null ? void 0 : _a.appendChild(this.svg_element);
|
|
2311
|
-
}
|
|
2312
|
-
update(elem, animate = true) {
|
|
2313
|
-
}
|
|
2314
|
-
animateSVGAttribute(elem, attr, to) {
|
|
2315
|
-
const from = parseFloat(elem.getAttribute(attr) || "0");
|
|
2316
|
-
if (from === to) return;
|
|
2317
|
-
const duration = 5e3;
|
|
2318
|
-
const start = performance.now();
|
|
2319
|
-
function animate(now) {
|
|
2320
|
-
const t = Math.min(1, (now - start) / duration);
|
|
2321
|
-
const value = from + (to - from) * t;
|
|
2322
|
-
elem.setAttribute(attr, value.toString());
|
|
2323
|
-
if (t < 1) requestAnimationFrame(animate);
|
|
2324
|
-
else elem.setAttribute(attr, to.toString());
|
|
2325
|
-
}
|
|
2326
|
-
__name(animate, "animate");
|
|
2327
|
-
requestAnimationFrame(animate);
|
|
2328
|
-
}
|
|
2329
|
-
};
|
|
2330
|
-
__name(_Drawable, "Drawable");
|
|
2331
|
-
let Drawable = _Drawable;
|
|
2332
|
-
const _QELine = class _QELine extends Drawable {
|
|
2333
|
-
constructor(__data__, parent, graph, __children__ = new QEArray()) {
|
|
2334
|
-
super(__data__, parent, graph, __children__);
|
|
2335
|
-
this.__data__ = __data__;
|
|
2336
|
-
this.parent = parent;
|
|
2337
|
-
this.graph = graph;
|
|
2338
|
-
this.__children__ = __children__;
|
|
2339
|
-
this.__name__ = "unnamed-line";
|
|
2340
|
-
this._arrow_el = null;
|
|
2341
|
-
this.svg_element = this.create();
|
|
2342
|
-
}
|
|
2343
|
-
create() {
|
|
2344
|
-
if (this.__data__ instanceof NodeEdge) {
|
|
2345
|
-
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
2346
|
-
path.setAttribute("fill", this.__data__.color.toString());
|
|
2347
|
-
path.setAttribute("stroke", "none");
|
|
2348
|
-
this.svg_element = path;
|
|
2349
|
-
return path;
|
|
2350
|
-
}
|
|
2351
|
-
if (this.__data__ instanceof TaperedEdge) {
|
|
2352
|
-
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
2353
|
-
path.setAttribute("fill", this.__data__.color.toString());
|
|
2354
|
-
path.setAttribute("stroke", "none");
|
|
2355
|
-
this.svg_element = path;
|
|
2356
|
-
return path;
|
|
2357
|
-
}
|
|
2358
|
-
const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
2359
|
-
line.setAttribute("x1", this.__data__.from.x.toString());
|
|
2360
|
-
line.setAttribute("y1", this.__data__.from.y.toString());
|
|
2361
|
-
line.setAttribute("x2", this.__data__.to.x.toString());
|
|
2362
|
-
line.setAttribute("y2", this.__data__.to.y.toString());
|
|
2363
|
-
line.setAttribute("stroke-width", this.get_size().toString());
|
|
2364
|
-
line.setAttribute("stroke", this.__data__.color.toString());
|
|
2365
|
-
this.svg_element = line;
|
|
2366
|
-
return line;
|
|
2367
|
-
}
|
|
2368
|
-
update() {
|
|
2369
|
-
var _a;
|
|
2370
|
-
if (!this.svg_element) {
|
|
2371
|
-
this.create();
|
|
2372
|
-
}
|
|
2373
|
-
if (!this.svg_element.parentElement) {
|
|
2374
|
-
this.parent.appendChild(this.svg_element);
|
|
2375
|
-
}
|
|
2376
|
-
const extent = ((_a = this.graph.__data__.extremes) == null ? void 0 : _a.x_max) ?? 1;
|
|
2377
|
-
const meta = this.__data__.meta ?? {};
|
|
2378
|
-
if (meta.isMeanEdge) {
|
|
2379
|
-
const weight = typeof meta.weight === "number" ? meta.weight : 0;
|
|
2380
|
-
const maxW = typeof meta.maxWeight === "number" ? meta.maxWeight : 1;
|
|
2381
|
-
const opacity = typeof meta.opacity === "number" ? meta.opacity : Math.min(1, weight / (maxW || 1));
|
|
2382
|
-
const sw = (extent > 0 ? extent : 1) * 0.011 * (weight / (maxW || 1));
|
|
2383
|
-
const baseColor = this.__data__._color || new Color("#000000");
|
|
2384
|
-
const edgeColor = new WeightedColor(baseColor, opacity).toString();
|
|
2385
|
-
if (this.__data__ instanceof NodeEdge) {
|
|
2386
|
-
const nodeSize = typeof meta.nodeSize === "number" ? meta.nodeSize : 2;
|
|
2387
|
-
const nodeR = extent * 6e-3 * nodeSize;
|
|
2388
|
-
this.__data__.weight = 2 * nodeR * 0.55 * opacity;
|
|
2389
|
-
this.svg_element.setAttribute("d", this.__data__.path);
|
|
2390
|
-
this.svg_element.setAttribute("fill", edgeColor);
|
|
2391
|
-
this.svg_element.setAttribute("stroke", "none");
|
|
2392
|
-
} else if (this.__data__ instanceof TaperedEdge) {
|
|
2393
|
-
this.__data__.weight = sw * 4;
|
|
2394
|
-
this.svg_element.setAttribute("d", this.__data__.path);
|
|
2395
|
-
this.svg_element.setAttribute("fill", edgeColor);
|
|
2396
|
-
this.svg_element.setAttribute("stroke", "none");
|
|
2397
|
-
if (meta.isDirected) {
|
|
2398
|
-
try {
|
|
2399
|
-
const arrow = new EdgeArrow(this.__data__);
|
|
2400
|
-
const arrowPath = arrow.path;
|
|
2401
|
-
if (arrowPath && !arrowPath.includes("NaN") && !arrowPath.includes("Infinity")) {
|
|
2402
|
-
if (!this._arrow_el) {
|
|
2403
|
-
this._arrow_el = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
2404
|
-
this._arrow_el.setAttribute("stroke", "none");
|
|
2405
|
-
}
|
|
2406
|
-
if (!this._arrow_el.parentElement) {
|
|
2407
|
-
this.parent.appendChild(this._arrow_el);
|
|
2408
|
-
}
|
|
2409
|
-
this._arrow_el.setAttribute("d", arrowPath);
|
|
2410
|
-
const arrowColor = baseColor.toString();
|
|
2411
|
-
this._arrow_el.setAttribute("fill", arrowColor);
|
|
2412
|
-
}
|
|
2413
|
-
} catch (_) {
|
|
2414
|
-
}
|
|
2415
|
-
}
|
|
2416
|
-
} else {
|
|
2417
|
-
this.svg_element.setAttribute("x1", this.__data__.from.x.toString());
|
|
2418
|
-
this.svg_element.setAttribute("y1", this.__data__.from.y.toString());
|
|
2419
|
-
this.svg_element.setAttribute("x2", this.__data__.to.x.toString());
|
|
2420
|
-
this.svg_element.setAttribute("y2", this.__data__.to.y.toString());
|
|
2421
|
-
this.svg_element.setAttribute("stroke-width", sw.toString());
|
|
2422
|
-
this.svg_element.setAttribute("stroke", edgeColor);
|
|
2423
|
-
this.svg_element.removeAttribute("marker-end");
|
|
2424
|
-
}
|
|
2425
|
-
} else {
|
|
2426
|
-
this.svg_element.setAttribute("x1", this.__data__.from.x.toString());
|
|
2427
|
-
this.svg_element.setAttribute("y1", this.__data__.from.y.toString());
|
|
2428
|
-
this.svg_element.setAttribute("x2", this.__data__.to.x.toString());
|
|
2429
|
-
this.svg_element.setAttribute("y2", this.__data__.to.y.toString());
|
|
2430
|
-
const sw = (extent > 0 ? extent : 1) * 4e-3 * this.get_size();
|
|
2431
|
-
this.svg_element.setAttribute("stroke-width", sw.toString());
|
|
2432
|
-
this.svg_element.setAttribute("stroke-opacity", "1");
|
|
2433
|
-
this.svg_element.setAttribute("stroke", this.__data__.color.toString());
|
|
2434
|
-
}
|
|
2435
|
-
}
|
|
2436
|
-
draw() {
|
|
2437
|
-
var _a, _b;
|
|
2438
|
-
(_a = this.parent) == null ? void 0 : _a.appendChild(this.svg_element);
|
|
2439
|
-
if (this._arrow_el) {
|
|
2440
|
-
(_b = this.parent) == null ? void 0 : _b.appendChild(this._arrow_el);
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
};
|
|
2444
|
-
__name(_QELine, "QELine");
|
|
2445
|
-
let QELine = _QELine;
|
|
2446
|
-
const _QEPoint = class _QEPoint extends Drawable {
|
|
2447
|
-
constructor(__data__, parent, graph, __children__ = new QEArray()) {
|
|
2448
|
-
super(__data__, parent, graph, __children__);
|
|
2449
|
-
this.__data__ = __data__;
|
|
2450
|
-
this.parent = parent;
|
|
2451
|
-
this.graph = graph;
|
|
2452
|
-
this.__children__ = __children__;
|
|
2453
|
-
this.__name__ = "unnamed-point";
|
|
2454
|
-
this.svg_element = this.create();
|
|
2455
|
-
}
|
|
2456
|
-
get x() {
|
|
2457
|
-
return this.__data__.dimensions[this.graph.__data__.options.GRAPH.dimensions[0]];
|
|
2458
|
-
}
|
|
2459
|
-
get y() {
|
|
2460
|
-
return this.__data__.dimensions[this.graph.__data__.options.GRAPH.dimensions[1]];
|
|
2461
|
-
}
|
|
2462
|
-
get isSquare() {
|
|
2463
|
-
return this.__data__.shape === "rect";
|
|
2464
|
-
}
|
|
2465
|
-
/** Half-side length for squares / radius for circles, in SVG user units.
|
|
2466
|
-
* Factor 0.006 keeps code-node diameters in the same visual range as rENA
|
|
2467
|
-
* (≈ 1–2 % of the coordinate half-extent for a typical ENA network).
|
|
2468
|
-
*/
|
|
2469
|
-
computeRadius() {
|
|
2470
|
-
const extent = this.graph.__data__.extremes.x_max;
|
|
2471
|
-
return (extent > 0 ? extent : 1) * 6e-3 * this.__data__.size;
|
|
2472
|
-
}
|
|
2473
|
-
/** Optional halo stroke (e.g. white outline on unit points to separate
|
|
2474
|
-
* overlapping dots in dense clusters). Width scales with the dot so it holds
|
|
2475
|
-
* up at any zoom. No-op unless the object requests it via meta.stroke. */
|
|
2476
|
-
applyStroke(el) {
|
|
2477
|
-
var _a;
|
|
2478
|
-
const stroke = (_a = this.__data__.meta) == null ? void 0 : _a.stroke;
|
|
2479
|
-
if (!stroke) return;
|
|
2480
|
-
el.setAttribute("stroke", stroke);
|
|
2481
|
-
el.setAttribute("stroke-width", (this.computeRadius() * 0.22).toString());
|
|
2482
|
-
}
|
|
2483
|
-
create() {
|
|
2484
|
-
const tag = this.isSquare ? "rect" : "circle";
|
|
2485
|
-
const el = document.createElementNS("http://www.w3.org/2000/svg", tag);
|
|
2486
|
-
el.setAttribute("data-point-id", this.__data__.ID);
|
|
2487
|
-
el.setAttribute("fill", this.__data__.color.toString());
|
|
2488
|
-
this.applyStroke(el);
|
|
2489
|
-
const r = this.computeRadius();
|
|
2490
|
-
if (this.isSquare) {
|
|
2491
|
-
el.setAttribute("x", (this.x - r).toString());
|
|
2492
|
-
el.setAttribute("y", (this.y - r).toString());
|
|
2493
|
-
el.setAttribute("width", (r * 2).toString());
|
|
2494
|
-
el.setAttribute("height", (r * 2).toString());
|
|
2495
|
-
} else {
|
|
2496
|
-
el.setAttribute("cx", this.x.toString());
|
|
2497
|
-
el.setAttribute("cy", this.y.toString());
|
|
2498
|
-
el.setAttribute("r", r.toString());
|
|
2499
|
-
}
|
|
2500
|
-
this.svg_element = el;
|
|
2501
|
-
el.addEventListener("click", (event) => {
|
|
2502
|
-
console.log("Point clicked: ", this.__data__);
|
|
2503
|
-
event.stopPropagation();
|
|
2504
|
-
this.__data__.active = !this.__data__.active;
|
|
2505
|
-
this.update();
|
|
2506
|
-
const pointEvent = new CustomEvent("point-clicked", {
|
|
2507
|
-
detail: { pointData: this.__data__ },
|
|
2508
|
-
bubbles: true,
|
|
2509
|
-
composed: true
|
|
2510
|
-
});
|
|
2511
|
-
this.svg_element.dispatchEvent(pointEvent);
|
|
2512
|
-
});
|
|
2513
|
-
el.addEventListener("mouseover", () => {
|
|
2514
|
-
});
|
|
2515
|
-
return el;
|
|
2516
|
-
}
|
|
2517
|
-
update() {
|
|
2518
|
-
if (!this.svg_element) {
|
|
2519
|
-
this.parent.__data__.__children__.push(this.create());
|
|
2520
|
-
}
|
|
2521
|
-
if (!this.svg_element.parentElement) {
|
|
2522
|
-
this.parent.appendChild(this.svg_element);
|
|
2523
|
-
}
|
|
2524
|
-
const r = this.computeRadius();
|
|
2525
|
-
this.svg_element.setAttribute("fill", this.__data__.color.toString());
|
|
2526
|
-
this.applyStroke(this.svg_element);
|
|
2527
|
-
if (this.isSquare) {
|
|
2528
|
-
this.svg_element.setAttribute("x", (this.x - r).toString());
|
|
2529
|
-
this.svg_element.setAttribute("y", (this.y - r).toString());
|
|
2530
|
-
this.svg_element.setAttribute("width", (r * 2).toString());
|
|
2531
|
-
this.svg_element.setAttribute("height", (r * 2).toString());
|
|
2532
|
-
} else {
|
|
2533
|
-
this.svg_element.setAttribute("cx", this.x.toString());
|
|
2534
|
-
this.svg_element.setAttribute("cy", this.y.toString());
|
|
2535
|
-
this.svg_element.setAttribute("r", r.toString());
|
|
2536
|
-
}
|
|
2537
|
-
}
|
|
2538
|
-
draw() {
|
|
2539
|
-
var _a;
|
|
2540
|
-
(_a = this.parent) == null ? void 0 : _a.appendChild(this.svg_element);
|
|
2541
|
-
}
|
|
2542
|
-
};
|
|
2543
|
-
__name(_QEPoint, "QEPoint");
|
|
2544
|
-
let QEPoint = _QEPoint;
|
|
2545
|
-
const _QETrajectory = class _QETrajectory extends Drawable {
|
|
2546
|
-
constructor(__data__, parent, graph, __children__ = new QEArray()) {
|
|
2547
|
-
super(__data__, parent, graph, __children__);
|
|
2548
|
-
this.__data__ = __data__;
|
|
2549
|
-
this.parent = parent;
|
|
2550
|
-
this.graph = graph;
|
|
2551
|
-
this.__children__ = __children__;
|
|
2552
|
-
this.__name__ = "trajectory";
|
|
2553
|
-
this._path_el = null;
|
|
2554
|
-
this._segments_group = null;
|
|
2555
|
-
this._tip_el = null;
|
|
2556
|
-
this._points_group = null;
|
|
2557
|
-
this.svg_element = this.create();
|
|
2558
|
-
}
|
|
2559
|
-
// Trajectory styling is specified in display pixels, while SVG paths use
|
|
2560
|
-
// graph coordinates. Convert at render time so marks stay legible at any scale.
|
|
2561
|
-
graphUnitsForPixels(pixels) {
|
|
2562
|
-
var _a;
|
|
2563
|
-
const extent = this.graph.__data__.extremes.x_max || 1;
|
|
2564
|
-
const width = ((_a = this.graph.svg_element) == null ? void 0 : _a.getBoundingClientRect().width) || 0;
|
|
2565
|
-
return width > 0 ? pixels * (2 * extent / width) : pixels * extent * 6e-3;
|
|
2566
|
-
}
|
|
2567
|
-
create() {
|
|
2568
|
-
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
2569
|
-
group.setAttribute("class", "qe-trajectory-group");
|
|
2570
|
-
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
2571
|
-
path.setAttribute("fill", "none");
|
|
2572
|
-
path.setAttribute("stroke", this.__data__.color.toString());
|
|
2573
|
-
path.setAttribute("stroke-width", this.graphUnitsForPixels(this.__data__.strokeWidth).toString());
|
|
2574
|
-
group.appendChild(path);
|
|
2575
|
-
this._path_el = path;
|
|
2576
|
-
const segmentsGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
2577
|
-
segmentsGroup.setAttribute("class", "qe-trajectory-segments");
|
|
2578
|
-
group.appendChild(segmentsGroup);
|
|
2579
|
-
this._segments_group = segmentsGroup;
|
|
2580
|
-
const pointsGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
2581
|
-
pointsGroup.setAttribute("class", "qe-trajectory-points");
|
|
2582
|
-
group.appendChild(pointsGroup);
|
|
2583
|
-
this._points_group = pointsGroup;
|
|
2584
|
-
if (this.__data__.showTips) {
|
|
2585
|
-
const tip = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
2586
|
-
tip.setAttribute("fill", this.__data__.color.toString());
|
|
2587
|
-
tip.setAttribute("r", this.graphUnitsForPixels(4).toString());
|
|
2588
|
-
tip.setAttribute("stroke", "#ffffff");
|
|
2589
|
-
tip.setAttribute("stroke-width", this.graphUnitsForPixels(1.5).toString());
|
|
2590
|
-
group.appendChild(tip);
|
|
2591
|
-
this._tip_el = tip;
|
|
2592
|
-
}
|
|
2593
|
-
this.svg_element = group;
|
|
2594
|
-
return group;
|
|
2595
|
-
}
|
|
2596
|
-
update() {
|
|
2597
|
-
if (!this.svg_element) {
|
|
2598
|
-
this.create();
|
|
2599
|
-
}
|
|
2600
|
-
if (!this.svg_element.parentElement) {
|
|
2601
|
-
this.parent.appendChild(this.svg_element);
|
|
2602
|
-
}
|
|
2603
|
-
const dStr = this.__data__.path;
|
|
2604
|
-
if (this._path_el) {
|
|
2605
|
-
this._path_el.setAttribute("d", dStr);
|
|
2606
|
-
this._path_el.setAttribute("stroke", this.__data__.color.toString());
|
|
2607
|
-
this._path_el.setAttribute("stroke-width", this.graphUnitsForPixels(this.__data__.strokeWidth).toString());
|
|
2608
|
-
this._path_el.style.display = this.__data__.lineStyle === "tapered" ? "none" : "block";
|
|
2609
|
-
}
|
|
2610
|
-
if (this._segments_group) {
|
|
2611
|
-
this._segments_group.innerHTML = "";
|
|
2612
|
-
if (this.__data__.lineStyle === "tapered") {
|
|
2613
|
-
const pathPts = this.__data__.pathPoints;
|
|
2614
|
-
const nSegments = pathPts.length - 1;
|
|
2615
|
-
const [minWidth, maxWidth] = this.__data__.strokeWidthRange;
|
|
2616
|
-
const [minOpacity, maxOpacity] = this.__data__.opacityRange;
|
|
2617
|
-
for (let i = 0; i < nSegments; i++) {
|
|
2618
|
-
const start = pathPts[i];
|
|
2619
|
-
const end = pathPts[i + 1];
|
|
2620
|
-
const progress = nSegments <= 1 ? 1 : i / (nSegments - 1);
|
|
2621
|
-
const width = minWidth + (maxWidth - minWidth) * progress;
|
|
2622
|
-
const opacity = minOpacity + (maxOpacity - minOpacity) * progress;
|
|
2623
|
-
const segment = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
2624
|
-
segment.setAttribute("d", `M${start.x},${start.y} L${end.x},${end.y}`);
|
|
2625
|
-
segment.setAttribute("fill", "none");
|
|
2626
|
-
segment.setAttribute("stroke", this.__data__.color.toString());
|
|
2627
|
-
segment.setAttribute("stroke-linecap", "round");
|
|
2628
|
-
segment.setAttribute("stroke-linejoin", "round");
|
|
2629
|
-
segment.setAttribute("stroke-width", this.graphUnitsForPixels(width).toString());
|
|
2630
|
-
segment.setAttribute("opacity", opacity.toString());
|
|
2631
|
-
this._segments_group.appendChild(segment);
|
|
2632
|
-
}
|
|
2633
|
-
this._segments_group.style.display = "block";
|
|
2634
|
-
} else {
|
|
2635
|
-
this._segments_group.style.display = "none";
|
|
2636
|
-
}
|
|
2637
|
-
}
|
|
2638
|
-
const pts = this.__data__.activePoints;
|
|
2639
|
-
if (this._points_group) {
|
|
2640
|
-
if (this.__data__.showPoints && pts.length > 0) {
|
|
2641
|
-
this._points_group.innerHTML = "";
|
|
2642
|
-
pts.forEach((pt) => {
|
|
2643
|
-
var _a;
|
|
2644
|
-
const dot = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
2645
|
-
dot.setAttribute("cx", pt.x.toString());
|
|
2646
|
-
dot.setAttribute("cy", pt.y.toString());
|
|
2647
|
-
dot.setAttribute("r", this.graphUnitsForPixels(2.5).toString());
|
|
2648
|
-
dot.setAttribute("fill", this.__data__.color.toString());
|
|
2649
|
-
dot.setAttribute("opacity", "0.7");
|
|
2650
|
-
(_a = this._points_group) == null ? void 0 : _a.appendChild(dot);
|
|
2651
|
-
});
|
|
2652
|
-
this._points_group.style.display = "block";
|
|
2653
|
-
} else {
|
|
2654
|
-
this._points_group.style.display = "none";
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
if (this._tip_el && this.__data__.showTips) {
|
|
2658
|
-
if (pts.length > 0) {
|
|
2659
|
-
const lastPt = pts[pts.length - 1];
|
|
2660
|
-
this._tip_el.setAttribute("cx", lastPt.x.toString());
|
|
2661
|
-
this._tip_el.setAttribute("cy", lastPt.y.toString());
|
|
2662
|
-
this._tip_el.setAttribute("fill", this.__data__.color.toString());
|
|
2663
|
-
this._tip_el.setAttribute("r", this.graphUnitsForPixels(4).toString());
|
|
2664
|
-
this._tip_el.setAttribute("stroke-width", this.graphUnitsForPixels(1.5).toString());
|
|
2665
|
-
this._tip_el.style.display = "block";
|
|
2666
|
-
} else {
|
|
2667
|
-
this._tip_el.style.display = "none";
|
|
2668
|
-
}
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
draw() {
|
|
2672
|
-
if (this.svg_element && !this.svg_element.parentElement) {
|
|
2673
|
-
this.parent.appendChild(this.svg_element);
|
|
2674
|
-
}
|
|
2675
|
-
this.update();
|
|
2676
|
-
}
|
|
2677
|
-
};
|
|
2678
|
-
__name(_QETrajectory, "QETrajectory");
|
|
2679
|
-
let QETrajectory = _QETrajectory;
|
|
2680
|
-
const { ArrayTools } = Tools;
|
|
2681
|
-
const _QEArray = class _QEArray extends Array {
|
|
2682
|
-
constructor(...args) {
|
|
2683
|
-
super(...args);
|
|
2684
|
-
}
|
|
2685
|
-
search(key, name) {
|
|
2686
|
-
let found;
|
|
2687
|
-
function fn(a) {
|
|
2688
|
-
return a.name === name ? a : void 0;
|
|
2689
|
-
}
|
|
2690
|
-
__name(fn, "fn");
|
|
2691
|
-
function recurse(obj, i, parent = null) {
|
|
2692
|
-
if (ArrayTools.isArray(obj)) {
|
|
2693
|
-
for (const [i2, o] of obj.entries()) {
|
|
2694
|
-
found = recurse(o, i2, parent);
|
|
2695
|
-
if (found) {
|
|
2696
|
-
return found;
|
|
2697
|
-
}
|
|
2698
|
-
}
|
|
2699
|
-
} else {
|
|
2700
|
-
found = fn(obj);
|
|
2701
|
-
if (!found) {
|
|
2702
|
-
if (obj && ArrayTools.isArray(obj[key])) {
|
|
2703
|
-
for (const [i2, o] of obj[key].entries()) {
|
|
2704
|
-
found = recurse(o, i2, obj);
|
|
2705
|
-
if (found) {
|
|
2706
|
-
return found;
|
|
2707
|
-
}
|
|
2708
|
-
}
|
|
2709
|
-
}
|
|
2710
|
-
} else {
|
|
2711
|
-
return found;
|
|
2712
|
-
}
|
|
2713
|
-
}
|
|
2714
|
-
return found;
|
|
2715
|
-
}
|
|
2716
|
-
__name(recurse, "recurse");
|
|
2717
|
-
return recurse(this);
|
|
2718
|
-
}
|
|
2719
|
-
flatten() {
|
|
2720
|
-
return this.reduce((a, l) => {
|
|
2721
|
-
a.push(l);
|
|
2722
|
-
if (l.layers && Array.isArray(l.layers)) {
|
|
2723
|
-
a.push(...l.layers);
|
|
2724
|
-
}
|
|
2725
|
-
return a;
|
|
2726
|
-
}, []);
|
|
2727
|
-
}
|
|
2728
|
-
};
|
|
2729
|
-
__name(_QEArray, "QEArray");
|
|
2730
|
-
let QEArray = _QEArray;
|
|
2731
|
-
const QEElementConstructors = {
|
|
2732
|
-
"AxisPoint": QEPoint,
|
|
2733
|
-
"AxisLine": QELine,
|
|
2734
|
-
"Point": QEPoint,
|
|
2735
|
-
"Line": QELine,
|
|
2736
|
-
"Edge": QELine,
|
|
2737
|
-
"TaperedEdge": QELine,
|
|
2738
|
-
"TaperedWeightedMidpointEdge": QELine,
|
|
2739
|
-
"NodeEdge": QELine,
|
|
2740
|
-
"Trajectory": QETrajectory
|
|
2741
|
-
};
|
|
2742
|
-
const _QELayer = class _QELayer {
|
|
2743
|
-
constructor(__data__, parent, graph, __children__ = new QEArray()) {
|
|
2744
|
-
this.__data__ = __data__;
|
|
2745
|
-
this.parent = parent;
|
|
2746
|
-
this.graph = graph;
|
|
2747
|
-
this.__children__ = __children__;
|
|
2748
|
-
this.__name__ = __data__.name || "unnamed-layer";
|
|
2749
|
-
__data__.__state__.addListener(`layer_updated`, "live", ({ key, newValue, oldValue }) => {
|
|
2750
|
-
const childId = /* @__PURE__ */ __name((child) => {
|
|
2751
|
-
var _a;
|
|
2752
|
-
return (_a = child.__data__) == null ? void 0 : _a.ID;
|
|
2753
|
-
}, "childId");
|
|
2754
|
-
const removing = this.__children__.filter(
|
|
2755
|
-
(child) => !newValue.objects.has(childId(child))
|
|
2756
|
-
);
|
|
2757
|
-
const updating = this.__children__.filter(
|
|
2758
|
-
(child) => newValue.objects.has(childId(child))
|
|
2759
|
-
);
|
|
2760
|
-
const adding = [...newValue.objects.values()].filter(
|
|
2761
|
-
(obj) => !this.__children__.some((child) => childId(child) === obj.ID)
|
|
2762
|
-
);
|
|
2763
|
-
adding.forEach((obj) => {
|
|
2764
|
-
const obj_name = obj._typeName || obj.constructor.name;
|
|
2765
|
-
let constructor = QEElementConstructors[obj_name];
|
|
2766
|
-
if (!constructor) {
|
|
2767
|
-
if (obj instanceof Trajectory) constructor = QETrajectory;
|
|
2768
|
-
else if (obj instanceof Point) constructor = QEPoint;
|
|
2769
|
-
else constructor = QELine;
|
|
2770
|
-
}
|
|
2771
|
-
const ena_element = new constructor(obj, this.svg_element, this.graph);
|
|
2772
|
-
this.__children__.push(ena_element);
|
|
2773
|
-
});
|
|
2774
|
-
updating.forEach((child) => {
|
|
2775
|
-
const newData = newValue.objects.get(childId(child));
|
|
2776
|
-
if (newData) child.__data__ = newData;
|
|
2777
|
-
child.update();
|
|
2778
|
-
});
|
|
2779
|
-
removing.forEach((child) => {
|
|
2780
|
-
if (child.svg_element.parentElement) {
|
|
2781
|
-
child.svg_element.parentElement.removeChild(child.svg_element);
|
|
2782
|
-
}
|
|
2783
|
-
const idx = this.__children__.indexOf(child);
|
|
2784
|
-
if (idx >= 0) this.__children__.splice(idx, 1);
|
|
2785
|
-
});
|
|
2786
|
-
this.update();
|
|
2787
|
-
});
|
|
2788
|
-
this.svg_element = this.create();
|
|
2789
|
-
}
|
|
2790
|
-
get name() {
|
|
2791
|
-
return this.__name__;
|
|
2792
|
-
}
|
|
2793
|
-
create() {
|
|
2794
|
-
if (!this.__data__) {
|
|
2795
|
-
throw new Error("Layer is null");
|
|
2796
|
-
}
|
|
2797
|
-
let layer = this.__data__;
|
|
2798
|
-
this.svg_element = document.createElementNS("http://www.w3.org/2000/svg", _QELayer.tagName);
|
|
2799
|
-
this.svg_element.setAttribute("data-layer-name", layer.name);
|
|
2800
|
-
this.svg_element.setAttribute("data-layer-id", layer.ID);
|
|
2801
|
-
this.svg_element.__data__ = layer;
|
|
2802
|
-
this.svg_element.classList.add("ena-layer");
|
|
2803
|
-
if (this.__data__.layers && this.__data__.layers.length > 0) {
|
|
2804
|
-
this.__data__.layers.forEach((sublayer) => {
|
|
2805
|
-
const layer_g = new _QELayer(sublayer, this.svg_element, this.graph);
|
|
2806
|
-
this.__children__.push(layer_g);
|
|
2807
|
-
});
|
|
2808
|
-
}
|
|
2809
|
-
return this.svg_element;
|
|
2810
|
-
}
|
|
2811
|
-
update() {
|
|
2812
|
-
if (!this.__data__) {
|
|
2813
|
-
throw new Error("Layer is null");
|
|
2814
|
-
}
|
|
2815
|
-
if (this.__data__.visible) {
|
|
2816
|
-
if (this.parent.nodeName.toLowerCase() === "svg") ;
|
|
2817
|
-
this.__children__.forEach((child) => {
|
|
2818
|
-
child.update();
|
|
2819
|
-
});
|
|
2820
|
-
if (this.__data__.scale_objects === true) {
|
|
2821
|
-
if (this.__name__ === "points") ;
|
|
2822
|
-
}
|
|
2823
|
-
}
|
|
2824
|
-
}
|
|
2825
|
-
draw() {
|
|
2826
|
-
var _a;
|
|
2827
|
-
(_a = this.parent) == null ? void 0 : _a.appendChild(this.svg_element);
|
|
2828
|
-
this.__children__.forEach((child) => {
|
|
2829
|
-
child.draw();
|
|
2830
|
-
});
|
|
2831
|
-
}
|
|
2832
|
-
add(child) {
|
|
2833
|
-
this.__children__.push(child);
|
|
2834
|
-
}
|
|
2835
|
-
};
|
|
2836
|
-
__name(_QELayer, "QELayer");
|
|
2837
|
-
_QELayer.tagName = "g";
|
|
2838
|
-
let QELayer = _QELayer;
|
|
2839
|
-
const _QELabel = class _QELabel {
|
|
2840
|
-
constructor(text, point, parent, graph, displayMode = Label.DISPLAY_TYPES.ON, position = Label.POSITION.OBJECT, customX, customY) {
|
|
2841
|
-
this.text = text;
|
|
2842
|
-
this.point = point;
|
|
2843
|
-
this.parent = parent;
|
|
2844
|
-
this.graph = graph;
|
|
2845
|
-
this.displayMode = displayMode;
|
|
2846
|
-
this.position = position;
|
|
2847
|
-
this.customX = customX;
|
|
2848
|
-
this.customY = customY;
|
|
2849
|
-
this._visible = false;
|
|
2850
|
-
this.svg_element = this._create();
|
|
2851
|
-
if (displayMode === Label.DISPLAY_TYPES.ON) {
|
|
2852
|
-
this._visible = true;
|
|
2853
|
-
this.svg_element.setAttribute("display", "block");
|
|
2854
|
-
} else {
|
|
2855
|
-
this._visible = false;
|
|
2856
|
-
this.svg_element.setAttribute("display", "none");
|
|
2857
|
-
}
|
|
2858
|
-
}
|
|
2859
|
-
_create() {
|
|
2860
|
-
const el = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
2861
|
-
el.textContent = this.text;
|
|
2862
|
-
el.setAttribute("data-label-for", this.point.ID);
|
|
2863
|
-
el.setAttribute("pointer-events", "none");
|
|
2864
|
-
this.parent.appendChild(el);
|
|
2865
|
-
return el;
|
|
2866
|
-
}
|
|
2867
|
-
/**
|
|
2868
|
-
* Recompute position and font-size from current graph extents.
|
|
2869
|
-
* No-ops when the label is hidden (AUTO/CLICK modes while not hovered/clicked).
|
|
2870
|
-
*/
|
|
2871
|
-
update() {
|
|
2872
|
-
var _a;
|
|
2873
|
-
if (!this._visible) return;
|
|
2874
|
-
const extent = this.graph.__data__.extremes.x_max;
|
|
2875
|
-
if (extent <= 0) return;
|
|
2876
|
-
const fontSize = extent * 0.06;
|
|
2877
|
-
const offset = fontSize * 1.2;
|
|
2878
|
-
let x, y, anchor;
|
|
2879
|
-
switch (this.position) {
|
|
2880
|
-
case Label.POSITION.STATIC: {
|
|
2881
|
-
x = this.point.x;
|
|
2882
|
-
y = this.point.y - offset * 0.3;
|
|
2883
|
-
anchor = "middle";
|
|
2884
|
-
break;
|
|
2885
|
-
}
|
|
2886
|
-
case Label.POSITION.CONTAINER: {
|
|
2887
|
-
const px = this.point.x;
|
|
2888
|
-
const py = this.point.y;
|
|
2889
|
-
const dist = Math.sqrt(px * px + py * py) || 1;
|
|
2890
|
-
const scale = extent * 0.93 / dist;
|
|
2891
|
-
x = px * scale;
|
|
2892
|
-
y = py * scale - offset * 0.3;
|
|
2893
|
-
anchor = px >= 0 ? "start" : "end";
|
|
2894
|
-
break;
|
|
2895
|
-
}
|
|
2896
|
-
case Label.POSITION.CUSTOM: {
|
|
2897
|
-
if (this.customX != null && this.customY != null) {
|
|
2898
|
-
x = this.customX;
|
|
2899
|
-
y = this.customY;
|
|
2900
|
-
anchor = "start";
|
|
2901
|
-
break;
|
|
2902
|
-
}
|
|
2903
|
-
}
|
|
2904
|
-
default:
|
|
2905
|
-
case Label.POSITION.OBJECT: {
|
|
2906
|
-
const dx = this.point.x >= 0 ? offset : -offset;
|
|
2907
|
-
anchor = this.point.x >= 0 ? "start" : "end";
|
|
2908
|
-
x = this.point.x + dx;
|
|
2909
|
-
y = this.point.y - offset * 0.4;
|
|
2910
|
-
break;
|
|
2911
|
-
}
|
|
2912
|
-
}
|
|
2913
|
-
this.svg_element.setAttribute("x", x.toString());
|
|
2914
|
-
this.svg_element.setAttribute("y", y.toString());
|
|
2915
|
-
this.svg_element.setAttribute("font-size", fontSize.toString());
|
|
2916
|
-
this.svg_element.setAttribute("font-family", "system-ui, sans-serif");
|
|
2917
|
-
this.svg_element.setAttribute("font-weight", "500");
|
|
2918
|
-
this.svg_element.setAttribute("text-anchor", anchor);
|
|
2919
|
-
this.svg_element.setAttribute("fill", ((_a = this.point.color) == null ? void 0 : _a.toString()) ?? "#333333");
|
|
2920
|
-
}
|
|
2921
|
-
/** Make the label visible and position it immediately. */
|
|
2922
|
-
show() {
|
|
2923
|
-
this._visible = true;
|
|
2924
|
-
this.svg_element.setAttribute("display", "block");
|
|
2925
|
-
this.update();
|
|
2926
|
-
}
|
|
2927
|
-
hide() {
|
|
2928
|
-
this._visible = false;
|
|
2929
|
-
this.svg_element.setAttribute("display", "none");
|
|
2930
|
-
}
|
|
2931
|
-
toggle() {
|
|
2932
|
-
this._visible ? this.hide() : this.show();
|
|
2933
|
-
}
|
|
2934
|
-
get visible() {
|
|
2935
|
-
return this._visible;
|
|
2936
|
-
}
|
|
2937
|
-
remove() {
|
|
2938
|
-
this.svg_element.remove();
|
|
2939
|
-
}
|
|
2940
|
-
};
|
|
2941
|
-
__name(_QELabel, "QELabel");
|
|
2942
|
-
let QELabel = _QELabel;
|
|
2943
|
-
const _QENodesElement = class _QENodesElement extends HTMLElement {
|
|
2944
|
-
};
|
|
2945
|
-
__name(_QENodesElement, "QENodesElement");
|
|
2946
|
-
_QENodesElement.tagName = "qe-nodes";
|
|
2947
|
-
let QENodesElement = _QENodesElement;
|
|
2948
|
-
const _QEMeansElement = class _QEMeansElement extends HTMLElement {
|
|
2949
|
-
};
|
|
2950
|
-
__name(_QEMeansElement, "QEMeansElement");
|
|
2951
|
-
_QEMeansElement.tagName = "qe-means";
|
|
2952
|
-
let QEMeansElement = _QEMeansElement;
|
|
2953
|
-
const _QEPointsElement = class _QEPointsElement extends HTMLElement {
|
|
2954
|
-
};
|
|
2955
|
-
__name(_QEPointsElement, "QEPointsElement");
|
|
2956
|
-
_QEPointsElement.tagName = "qe-points";
|
|
2957
|
-
let QEPointsElement = _QEPointsElement;
|
|
2958
|
-
const _QEEdgesElement = class _QEEdgesElement extends HTMLElement {
|
|
2959
|
-
};
|
|
2960
|
-
__name(_QEEdgesElement, "QEEdgesElement");
|
|
2961
|
-
_QEEdgesElement.tagName = "qe-edges";
|
|
2962
|
-
let QEEdgesElement = _QEEdgesElement;
|
|
2963
|
-
const _QETrajectoriesElement = class _QETrajectoriesElement extends HTMLElement {
|
|
2964
|
-
};
|
|
2965
|
-
__name(_QETrajectoriesElement, "QETrajectoriesElement");
|
|
2966
|
-
_QETrajectoriesElement.tagName = "qe-trajectories";
|
|
2967
|
-
let QETrajectoriesElement = _QETrajectoriesElement;
|
|
2968
|
-
const _QEAxesElement = class _QEAxesElement extends HTMLElement {
|
|
2969
|
-
};
|
|
2970
|
-
__name(_QEAxesElement, "QEAxesElement");
|
|
2971
|
-
_QEAxesElement.tagName = "qe-axes";
|
|
2972
|
-
let QEAxesElement = _QEAxesElement;
|
|
2973
|
-
customElements.define(QENodesElement.tagName, QENodesElement);
|
|
2974
|
-
customElements.define(QEMeansElement.tagName, QEMeansElement);
|
|
2975
|
-
customElements.define(QEPointsElement.tagName, QEPointsElement);
|
|
2976
|
-
customElements.define(QEEdgesElement.tagName, QEEdgesElement);
|
|
2977
|
-
customElements.define(QETrajectoriesElement.tagName, QETrajectoriesElement);
|
|
2978
|
-
customElements.define(QEAxesElement.tagName, QEAxesElement);
|
|
2979
|
-
const GROUP_PALETTE = [
|
|
2980
|
-
"#4477AA",
|
|
2981
|
-
"#EE6677",
|
|
2982
|
-
"#228833",
|
|
2983
|
-
"#CCBB44",
|
|
2984
|
-
"#66CCEE",
|
|
2985
|
-
"#AA3377",
|
|
2986
|
-
"#BBBBBB",
|
|
2987
|
-
"#000000"
|
|
2988
|
-
];
|
|
2989
|
-
function parseEdgePair(colName, codes) {
|
|
2990
|
-
for (const c of codes) {
|
|
2991
|
-
if (colName === `${c}.${c}`) return [c, c];
|
|
2992
|
-
}
|
|
2993
|
-
for (const c1 of codes) {
|
|
2994
|
-
if (colName.startsWith(c1 + ".")) {
|
|
2995
|
-
const c2 = colName.slice(c1.length + 1);
|
|
2996
|
-
if (codes.includes(c2)) return [c1, c2];
|
|
2997
|
-
}
|
|
2998
|
-
}
|
|
2999
|
-
return null;
|
|
3000
|
-
}
|
|
3001
|
-
__name(parseEdgePair, "parseEdgePair");
|
|
3002
|
-
function computeCIRect(varX, varY, n, pointScale) {
|
|
3003
|
-
const df = Math.max(1, n - 1);
|
|
3004
|
-
const t95 = df >= 120 ? 1.96 : df >= 60 ? 2 : df >= 30 ? 2.042 : df >= 20 ? 2.086 : df >= 10 ? 2.228 : df >= 5 ? 2.571 : 4.303;
|
|
3005
|
-
const seX = Math.sqrt(Math.max(0, varX) / n) * pointScale;
|
|
3006
|
-
const seY = Math.sqrt(Math.max(0, varY) / n) * pointScale;
|
|
3007
|
-
return { halfW: t95 * seX, halfH: t95 * seY };
|
|
3008
|
-
}
|
|
3009
|
-
__name(computeCIRect, "computeCIRect");
|
|
3010
|
-
function readIntervalBounds(row, dim0, dim1) {
|
|
3011
|
-
const get = /* @__PURE__ */ __name((col) => {
|
|
3012
|
-
const i = row.names.indexOf(col);
|
|
3013
|
-
return i >= 0 ? Number(row[i]) : void 0;
|
|
3014
|
-
}, "get");
|
|
3015
|
-
const xLow = get(`${dim0}.low`) ?? get(`${dim0}_low`);
|
|
3016
|
-
const xHigh = get(`${dim0}.high`) ?? get(`${dim0}_high`);
|
|
3017
|
-
const yLow = get(`${dim1}.low`) ?? get(`${dim1}_low`);
|
|
3018
|
-
const yHigh = get(`${dim1}.high`) ?? get(`${dim1}_high`);
|
|
3019
|
-
if (xLow == null || xHigh == null || yLow == null || yHigh == null) return null;
|
|
3020
|
-
return { x_low: xLow, x_high: xHigh, y_low: yLow, y_high: yHigh };
|
|
3021
|
-
}
|
|
3022
|
-
__name(readIntervalBounds, "readIntervalBounds");
|
|
3023
|
-
function parseLabelMode(attr, defaultMode) {
|
|
3024
|
-
switch (attr == null ? void 0 : attr.toLowerCase()) {
|
|
3025
|
-
case "on":
|
|
3026
|
-
return 3;
|
|
3027
|
-
case "off":
|
|
3028
|
-
return 0;
|
|
3029
|
-
case "click":
|
|
3030
|
-
return 2;
|
|
3031
|
-
case "auto":
|
|
3032
|
-
return 1;
|
|
3033
|
-
default:
|
|
3034
|
-
return defaultMode;
|
|
3035
|
-
}
|
|
3036
|
-
}
|
|
3037
|
-
__name(parseLabelMode, "parseLabelMode");
|
|
3038
|
-
const _QEGraphElement = class _QEGraphElement extends DrawableElement {
|
|
3039
|
-
constructor() {
|
|
3040
|
-
super();
|
|
3041
|
-
this.zoom_level = 1;
|
|
3042
|
-
this.__children__ = new QEArray();
|
|
3043
|
-
this._hasModel = false;
|
|
3044
|
-
this._renderPending = false;
|
|
3045
|
-
this._childObserver = null;
|
|
3046
|
-
this._ciRects = /* @__PURE__ */ new Map();
|
|
3047
|
-
this._outlierRects = /* @__PURE__ */ new Map();
|
|
3048
|
-
this._labelsGroup = null;
|
|
3049
|
-
this._nodeLabels = /* @__PURE__ */ new Map();
|
|
3050
|
-
this._meanLabels = /* @__PURE__ */ new Map();
|
|
3051
|
-
this._pointLabels = /* @__PURE__ */ new Map();
|
|
3052
|
-
this._showAxes = false;
|
|
3053
|
-
this._axisXText = null;
|
|
3054
|
-
this._axisYText = null;
|
|
3055
|
-
this._axisLabelEls = /* @__PURE__ */ new Map();
|
|
3056
|
-
this.graph = this;
|
|
3057
|
-
this.parent = null;
|
|
3058
|
-
this.__data__ = new Graph(DefaultGraphOptions);
|
|
3059
|
-
this.__name__ = this.__data__.name || "unnamed-graph";
|
|
3060
|
-
this.svg_element = this.create();
|
|
3061
|
-
console.log("Created ena-graph svg element: ", this.svg_element);
|
|
3062
|
-
document.addEventListener("model-updated", (e) => {
|
|
3063
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
3064
|
-
if (this._vizena && e.target !== this._vizena) return;
|
|
3065
|
-
const model = e.detail;
|
|
3066
|
-
if (!model) return;
|
|
3067
|
-
this._hasModel = true;
|
|
3068
|
-
const dims = model.dimensions;
|
|
3069
|
-
const unitIdCol = model.unit_id_col;
|
|
3070
|
-
const nodeIdCol = model.node_id_col;
|
|
3071
|
-
const groupColName = model.group_col;
|
|
3072
|
-
const config = this._readLayerConfig();
|
|
3073
|
-
this._showAxes = config.showAxes;
|
|
3074
|
-
this._axisXText = config.axisXLabel === null ? null : config.axisXLabel || String((dims == null ? void 0 : dims[0]) ?? "x");
|
|
3075
|
-
this._axisYText = config.axisYLabel === null ? null : config.axisYLabel || String((dims == null ? void 0 : dims[1]) ?? "y");
|
|
3076
|
-
const groupColorMap = {};
|
|
3077
|
-
if (groupColName && ((_a = model.points) == null ? void 0 : _a.names)) {
|
|
3078
|
-
const groupCol = model.points.col(groupColName);
|
|
3079
|
-
if (groupCol) {
|
|
3080
|
-
const uniqueGroups = [...new Set([...groupCol].map(String))];
|
|
3081
|
-
uniqueGroups.forEach((g, i) => {
|
|
3082
|
-
groupColorMap[g] = GROUP_PALETTE[i % GROUP_PALETTE.length];
|
|
3083
|
-
});
|
|
3084
|
-
}
|
|
3085
|
-
} else if (((_b = model.groups) == null ? void 0 : _b.rows) && model.groups.rows().length > 0) {
|
|
3086
|
-
model.groups.rows().forEach((row, i) => {
|
|
3087
|
-
const g = row.rowName ?? String(row[0]);
|
|
3088
|
-
if (!groupColorMap[g]) groupColorMap[g] = GROUP_PALETTE[i % GROUP_PALETTE.length];
|
|
3089
|
-
});
|
|
3090
|
-
}
|
|
3091
|
-
const _allGroupNames_ = Object.keys(groupColorMap);
|
|
3092
|
-
const activeMeanGroups = config.activeMeanGroups && config.activeMeanGroups.trim() ? new Set(
|
|
3093
|
-
config.activeMeanGroups.split(",").map((s) => s.trim()).filter((g) => groupColorMap[g])
|
|
3094
|
-
// silently drop names not in model
|
|
3095
|
-
) : new Set(_allGroupNames_);
|
|
3096
|
-
const scalePointsEnabled = config.scalePoints;
|
|
3097
|
-
const getExtent = /* @__PURE__ */ __name((rows) => {
|
|
3098
|
-
let max = 0;
|
|
3099
|
-
rows.forEach((row) => {
|
|
3100
|
-
const xIdx = row.names.indexOf(dims[0]);
|
|
3101
|
-
const yIdx = dims.length > 1 ? row.names.indexOf(dims[1]) : -1;
|
|
3102
|
-
if (xIdx >= 0) max = Math.max(max, Math.abs(Number(row[xIdx])));
|
|
3103
|
-
if (yIdx >= 0) max = Math.max(max, Math.abs(Number(row[yIdx])));
|
|
3104
|
-
});
|
|
3105
|
-
return max;
|
|
3106
|
-
}, "getExtent");
|
|
3107
|
-
const maxNodeExtent = ((_c = model.nodes) == null ? void 0 : _c.rows) ? getExtent(model.nodes.rows()) : 0;
|
|
3108
|
-
const maxPointExtent = ((_d = model.points) == null ? void 0 : _d.rows) ? getExtent(model.points.rows()) : 0;
|
|
3109
|
-
const maxTrajExtent = ((_e = model.trajectories) == null ? void 0 : _e.rows) ? getExtent(model.trajectories.rows()) : 0;
|
|
3110
|
-
const effectivePointExtent = maxPointExtent > 0 ? maxPointExtent : maxTrajExtent;
|
|
3111
|
-
const pointScale = scalePointsEnabled && effectivePointExtent > 0 && maxNodeExtent > 0 ? maxNodeExtent / effectivePointExtent : 1;
|
|
3112
|
-
const labelNodes = config.labelNodes;
|
|
3113
|
-
const labelMeans = config.labelMeans;
|
|
3114
|
-
const labelPoints = config.labelPoints;
|
|
3115
|
-
const labelSvg = this._labelsGroup;
|
|
3116
|
-
const rowToPoint = /* @__PURE__ */ __name((row, idCol, colorStr, scale = 1) => {
|
|
3117
|
-
const idIdx = row.names.indexOf(idCol);
|
|
3118
|
-
const xIdx = row.names.indexOf(dims[0]);
|
|
3119
|
-
const yIdx = dims.length > 1 ? row.names.indexOf(dims[1]) : -1;
|
|
3120
|
-
const pt = new Point({
|
|
3121
|
-
ID: idIdx >= 0 ? String(row[idIdx]) : row.rowName || `pt-${Math.random().toString(36).slice(2)}`,
|
|
3122
|
-
dimensions: [
|
|
3123
|
-
xIdx >= 0 ? Number(row[xIdx]) * scale : 0,
|
|
3124
|
-
yIdx >= 0 ? -Number(row[yIdx]) * scale : 0
|
|
3125
|
-
// negate Y: SVG y-down vs ENA y-up
|
|
3126
|
-
],
|
|
3127
|
-
meta: {}
|
|
3128
|
-
});
|
|
3129
|
-
if (colorStr) pt.color = new Color(colorStr);
|
|
3130
|
-
return pt;
|
|
3131
|
-
}, "rowToPoint");
|
|
3132
|
-
const groupSums = {};
|
|
3133
|
-
const showUnitPoints = config.showPoints;
|
|
3134
|
-
if ((_f = model.points) == null ? void 0 : _f.rows) {
|
|
3135
|
-
const pointsLayer = this.__children__.search("__children__", "points");
|
|
3136
|
-
if (pointsLayer) {
|
|
3137
|
-
model.points.rows().forEach((row) => {
|
|
3138
|
-
const groupColIdx = groupColName ? row.names.indexOf(groupColName) : -1;
|
|
3139
|
-
const group = groupColIdx >= 0 ? String(row[groupColIdx]) : null;
|
|
3140
|
-
const colorStr = group ? groupColorMap[group] ?? "#888888" : "#888888";
|
|
3141
|
-
if (showUnitPoints) {
|
|
3142
|
-
const pt = rowToPoint(row, unitIdCol, colorStr, pointScale);
|
|
3143
|
-
pt.size = 2.5;
|
|
3144
|
-
pt.meta = { ...pt.meta ?? {}, stroke: "#ffffff" };
|
|
3145
|
-
this.__data__.points.set(pt.ID, pt);
|
|
3146
|
-
pointsLayer.__data__.objects.set(pt.ID, pt);
|
|
3147
|
-
}
|
|
3148
|
-
if (group) {
|
|
3149
|
-
const xIdx = row.names.indexOf(dims[0]);
|
|
3150
|
-
const yIdx = dims.length > 1 ? row.names.indexOf(dims[1]) : -1;
|
|
3151
|
-
if (!groupSums[group]) groupSums[group] = { x: 0, y: 0, x2: 0, y2: 0, xy: 0, n: 0, color: colorStr };
|
|
3152
|
-
const rx = xIdx >= 0 ? Number(row[xIdx]) : 0;
|
|
3153
|
-
const ry = yIdx >= 0 ? Number(row[yIdx]) : 0;
|
|
3154
|
-
groupSums[group].x += rx;
|
|
3155
|
-
groupSums[group].y += ry;
|
|
3156
|
-
groupSums[group].x2 += rx * rx;
|
|
3157
|
-
groupSums[group].y2 += ry * ry;
|
|
3158
|
-
groupSums[group].xy += rx * ry;
|
|
3159
|
-
groupSums[group].n += 1;
|
|
3160
|
-
}
|
|
3161
|
-
});
|
|
3162
|
-
const hasGroupsFrame = !!(((_g = model.groups) == null ? void 0 : _g.rows) && model.groups.rows().length > 0);
|
|
3163
|
-
const activeGroupRows = config.showMeans && hasGroupsFrame ? model.groups.rows().filter((r) => {
|
|
3164
|
-
const g = r.rowName ?? String(r[0]);
|
|
3165
|
-
return activeMeanGroups.size === 0 || activeMeanGroups.has(g);
|
|
3166
|
-
}) : [];
|
|
3167
|
-
if (config.showMeans) {
|
|
3168
|
-
const pointsLayerSvg = pointsLayer.svg_element;
|
|
3169
|
-
const sw = (maxNodeExtent > 0 ? maxNodeExtent : 1) * 8e-3;
|
|
3170
|
-
if (hasGroupsFrame) {
|
|
3171
|
-
const activeNames = new Set(activeGroupRows.map((r) => r.rowName ?? String(r[0])));
|
|
3172
|
-
this._ciRects.forEach((el, g) => {
|
|
3173
|
-
if (!activeNames.has(g)) {
|
|
3174
|
-
el.remove();
|
|
3175
|
-
this._ciRects.delete(g);
|
|
3176
|
-
}
|
|
3177
|
-
});
|
|
3178
|
-
this._outlierRects.forEach((el, g) => {
|
|
3179
|
-
if (!activeNames.has(g)) {
|
|
3180
|
-
el.remove();
|
|
3181
|
-
this._outlierRects.delete(g);
|
|
3182
|
-
}
|
|
3183
|
-
});
|
|
3184
|
-
activeGroupRows.forEach((row) => {
|
|
3185
|
-
const group = row.rowName ?? String(row[0]);
|
|
3186
|
-
const color = groupColorMap[group] ?? "#888888";
|
|
3187
|
-
const xIdx = row.names.indexOf(dims[0]);
|
|
3188
|
-
const yIdx = dims.length > 1 ? row.names.indexOf(dims[1]) : -1;
|
|
3189
|
-
const mx = xIdx >= 0 ? Number(row[xIdx]) * pointScale : 0;
|
|
3190
|
-
const my = yIdx >= 0 ? -Number(row[yIdx]) * pointScale : 0;
|
|
3191
|
-
const meanPt = new Point({
|
|
3192
|
-
ID: `mean-${group}`,
|
|
3193
|
-
dimensions: [mx, my],
|
|
3194
|
-
meta: { group }
|
|
3195
|
-
});
|
|
3196
|
-
meanPt.color = new Color(color);
|
|
3197
|
-
meanPt.size = 4;
|
|
3198
|
-
meanPt.shape = "rect";
|
|
3199
|
-
this.__data__.points.set(meanPt.ID, meanPt);
|
|
3200
|
-
pointsLayer.__data__.objects.set(meanPt.ID, meanPt);
|
|
3201
|
-
const bounds = readIntervalBounds(row, dims[0], dims[1]);
|
|
3202
|
-
if (bounds) {
|
|
3203
|
-
const rect_x = bounds.x_low * pointScale;
|
|
3204
|
-
const rect_y = -bounds.y_high * pointScale;
|
|
3205
|
-
const rect_width = (bounds.x_high - bounds.x_low) * pointScale;
|
|
3206
|
-
const rect_height = (bounds.y_high - bounds.y_low) * pointScale;
|
|
3207
|
-
let el = this._ciRects.get(group);
|
|
3208
|
-
if (!el) {
|
|
3209
|
-
el = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
3210
|
-
el.setAttribute("data-ci-group", group);
|
|
3211
|
-
this._ciRects.set(group, el);
|
|
3212
|
-
}
|
|
3213
|
-
el.setAttribute("x", rect_x.toString());
|
|
3214
|
-
el.setAttribute("y", rect_y.toString());
|
|
3215
|
-
el.setAttribute("width", rect_width.toString());
|
|
3216
|
-
el.setAttribute("height", rect_height.toString());
|
|
3217
|
-
el.setAttribute("fill", "none");
|
|
3218
|
-
el.setAttribute("stroke", color);
|
|
3219
|
-
el.setAttribute("stroke-width", sw.toString());
|
|
3220
|
-
el.setAttribute("stroke-opacity", "0.8");
|
|
3221
|
-
el.setAttribute("stroke-dasharray", `${sw * 4} ${sw * 3}`);
|
|
3222
|
-
if (pointsLayerSvg && !el.parentElement) {
|
|
3223
|
-
pointsLayerSvg.insertBefore(el, pointsLayerSvg.firstChild);
|
|
3224
|
-
}
|
|
3225
|
-
}
|
|
3226
|
-
});
|
|
3227
|
-
} else {
|
|
3228
|
-
Object.entries(groupSums).forEach(([group, { x, y, n, color }]) => {
|
|
3229
|
-
const meanPt = new Point({
|
|
3230
|
-
ID: `mean-${group}`,
|
|
3231
|
-
dimensions: [x / n * pointScale, -(y / n) * pointScale],
|
|
3232
|
-
meta: { group }
|
|
3233
|
-
});
|
|
3234
|
-
meanPt.color = new Color(color);
|
|
3235
|
-
meanPt.size = 4;
|
|
3236
|
-
meanPt.shape = "rect";
|
|
3237
|
-
this.__data__.points.set(meanPt.ID, meanPt);
|
|
3238
|
-
pointsLayer.__data__.objects.set(meanPt.ID, meanPt);
|
|
3239
|
-
});
|
|
3240
|
-
const showCI = config.showCI;
|
|
3241
|
-
if (showCI) {
|
|
3242
|
-
this._ciRects.forEach((el, g) => {
|
|
3243
|
-
if (!groupSums[g]) {
|
|
3244
|
-
el.remove();
|
|
3245
|
-
this._ciRects.delete(g);
|
|
3246
|
-
}
|
|
3247
|
-
});
|
|
3248
|
-
if ((_h = model.confidence) == null ? void 0 : _h.rows) {
|
|
3249
|
-
model.confidence.rows().forEach((row) => {
|
|
3250
|
-
const groupIdx = row.names.indexOf(groupColName ?? "group");
|
|
3251
|
-
const group = groupIdx >= 0 ? String(row[groupIdx]) : row.rowName ?? null;
|
|
3252
|
-
if (!group) return;
|
|
3253
|
-
const color = groupColorMap[group] ?? "#888888";
|
|
3254
|
-
const bounds = readIntervalBounds(row, dims[0], dims[1]);
|
|
3255
|
-
if (!bounds) return;
|
|
3256
|
-
const rect_x = bounds.x_low * pointScale;
|
|
3257
|
-
const rect_y = -bounds.y_high * pointScale;
|
|
3258
|
-
const rect_width = (bounds.x_high - bounds.x_low) * pointScale;
|
|
3259
|
-
const rect_height = (bounds.y_high - bounds.y_low) * pointScale;
|
|
3260
|
-
let el = this._ciRects.get(group);
|
|
3261
|
-
if (!el) {
|
|
3262
|
-
el = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
3263
|
-
el.setAttribute("data-ci-group", group);
|
|
3264
|
-
this._ciRects.set(group, el);
|
|
3265
|
-
}
|
|
3266
|
-
el.setAttribute("x", rect_x.toString());
|
|
3267
|
-
el.setAttribute("y", rect_y.toString());
|
|
3268
|
-
el.setAttribute("width", rect_width.toString());
|
|
3269
|
-
el.setAttribute("height", rect_height.toString());
|
|
3270
|
-
el.setAttribute("fill", "none");
|
|
3271
|
-
el.setAttribute("stroke", color);
|
|
3272
|
-
el.setAttribute("stroke-width", sw.toString());
|
|
3273
|
-
el.setAttribute("stroke-opacity", "0.8");
|
|
3274
|
-
el.setAttribute("stroke-dasharray", `${sw * 4} ${sw * 3}`);
|
|
3275
|
-
if (pointsLayerSvg && !el.parentElement) {
|
|
3276
|
-
pointsLayerSvg.insertBefore(el, pointsLayerSvg.firstChild);
|
|
3277
|
-
}
|
|
3278
|
-
});
|
|
3279
|
-
} else {
|
|
3280
|
-
Object.entries(groupSums).forEach(([group, { x, y, x2, y2, n, color }]) => {
|
|
3281
|
-
if (n < 2) return;
|
|
3282
|
-
const μx = x / n, μy = y / n;
|
|
3283
|
-
const rawVarX = x2 / n - μx * μx;
|
|
3284
|
-
const rawVarY = y2 / n - μy * μy;
|
|
3285
|
-
const { halfW, halfH } = computeCIRect(rawVarX, rawVarY, n, pointScale);
|
|
3286
|
-
const cx = μx * pointScale, cy = -μy * pointScale;
|
|
3287
|
-
let el = this._ciRects.get(group);
|
|
3288
|
-
if (!el) {
|
|
3289
|
-
el = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
3290
|
-
el.setAttribute("data-ci-group", group);
|
|
3291
|
-
this._ciRects.set(group, el);
|
|
3292
|
-
}
|
|
3293
|
-
el.setAttribute("x", (cx - halfW).toString());
|
|
3294
|
-
el.setAttribute("y", (cy - halfH).toString());
|
|
3295
|
-
el.setAttribute("width", (halfW * 2).toString());
|
|
3296
|
-
el.setAttribute("height", (halfH * 2).toString());
|
|
3297
|
-
el.setAttribute("fill", "none");
|
|
3298
|
-
el.setAttribute("stroke", color);
|
|
3299
|
-
el.setAttribute("stroke-width", sw.toString());
|
|
3300
|
-
el.setAttribute("stroke-opacity", "0.8");
|
|
3301
|
-
el.setAttribute("stroke-dasharray", `${sw * 4} ${sw * 3}`);
|
|
3302
|
-
if (pointsLayerSvg && !el.parentElement) {
|
|
3303
|
-
pointsLayerSvg.insertBefore(el, pointsLayerSvg.firstChild);
|
|
3304
|
-
}
|
|
3305
|
-
});
|
|
3306
|
-
}
|
|
3307
|
-
}
|
|
3308
|
-
if ((_i = model.outlier) == null ? void 0 : _i.rows) {
|
|
3309
|
-
this._outlierRects.forEach((el, g) => {
|
|
3310
|
-
if (!groupColorMap[g]) {
|
|
3311
|
-
el.remove();
|
|
3312
|
-
this._outlierRects.delete(g);
|
|
3313
|
-
}
|
|
3314
|
-
});
|
|
3315
|
-
model.outlier.rows().forEach((row) => {
|
|
3316
|
-
const groupIdx = row.names.indexOf(groupColName ?? "group");
|
|
3317
|
-
const group = groupIdx >= 0 ? String(row[groupIdx]) : row.rowName ?? null;
|
|
3318
|
-
if (!group) return;
|
|
3319
|
-
const color = groupColorMap[group] ?? "#888888";
|
|
3320
|
-
const bounds = readIntervalBounds(row, dims[0], dims[1]);
|
|
3321
|
-
if (!bounds) return;
|
|
3322
|
-
const rect_x = bounds.x_low * pointScale;
|
|
3323
|
-
const rect_y = -bounds.y_high * pointScale;
|
|
3324
|
-
const rect_width = (bounds.x_high - bounds.x_low) * pointScale;
|
|
3325
|
-
const rect_height = (bounds.y_high - bounds.y_low) * pointScale;
|
|
3326
|
-
let el = this._outlierRects.get(group);
|
|
3327
|
-
if (!el) {
|
|
3328
|
-
el = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
3329
|
-
el.setAttribute("data-outlier-group", group);
|
|
3330
|
-
this._outlierRects.set(group, el);
|
|
3331
|
-
}
|
|
3332
|
-
el.setAttribute("x", rect_x.toString());
|
|
3333
|
-
el.setAttribute("y", rect_y.toString());
|
|
3334
|
-
el.setAttribute("width", rect_width.toString());
|
|
3335
|
-
el.setAttribute("height", rect_height.toString());
|
|
3336
|
-
el.setAttribute("fill", "none");
|
|
3337
|
-
el.setAttribute("stroke", color);
|
|
3338
|
-
el.setAttribute("stroke-width", sw.toString());
|
|
3339
|
-
el.setAttribute("stroke-opacity", "0.5");
|
|
3340
|
-
el.setAttribute("stroke-dasharray", `${sw * 2} ${sw * 2}`);
|
|
3341
|
-
if (pointsLayerSvg && !el.parentElement) {
|
|
3342
|
-
pointsLayerSvg.insertBefore(el, pointsLayerSvg.firstChild);
|
|
3343
|
-
}
|
|
3344
|
-
});
|
|
3345
|
-
}
|
|
3346
|
-
}
|
|
3347
|
-
}
|
|
3348
|
-
if (labelSvg) {
|
|
3349
|
-
this._pointLabels.forEach((lbl, id) => {
|
|
3350
|
-
if (!pointsLayer.__data__.objects.get(id)) {
|
|
3351
|
-
lbl.remove();
|
|
3352
|
-
this._pointLabels.delete(id);
|
|
3353
|
-
}
|
|
3354
|
-
});
|
|
3355
|
-
this._meanLabels.forEach((lbl, id) => {
|
|
3356
|
-
if (!pointsLayer.__data__.objects.get(`mean-${id}`)) {
|
|
3357
|
-
lbl.remove();
|
|
3358
|
-
this._meanLabels.delete(id);
|
|
3359
|
-
}
|
|
3360
|
-
});
|
|
3361
|
-
if (labelPoints !== 0) {
|
|
3362
|
-
model.points.rows().forEach((row) => {
|
|
3363
|
-
const qIdx = row.names.indexOf(unitIdCol);
|
|
3364
|
-
const unitId = qIdx >= 0 ? String(row[qIdx]) : null;
|
|
3365
|
-
if (!unitId) return;
|
|
3366
|
-
const pt = pointsLayer.__data__.objects.get(unitId);
|
|
3367
|
-
if (!pt) return;
|
|
3368
|
-
const displayText = unitId;
|
|
3369
|
-
let lbl = this._pointLabels.get(unitId);
|
|
3370
|
-
if (!lbl) {
|
|
3371
|
-
lbl = new QELabel(displayText, pt, labelSvg, this, labelPoints);
|
|
3372
|
-
this._pointLabels.set(unitId, lbl);
|
|
3373
|
-
} else {
|
|
3374
|
-
labelPoints === Label.DISPLAY_TYPES.ON ? lbl.show() : lbl.hide();
|
|
3375
|
-
}
|
|
3376
|
-
});
|
|
3377
|
-
}
|
|
3378
|
-
if (labelMeans !== 0) {
|
|
3379
|
-
const meanGroupNames = hasGroupsFrame ? activeGroupRows.map((r) => r.rowName ?? String(r[0])) : Object.keys(groupSums);
|
|
3380
|
-
meanGroupNames.forEach((group) => {
|
|
3381
|
-
const meanId = `mean-${group}`;
|
|
3382
|
-
const pt = pointsLayer.__data__.objects.get(meanId);
|
|
3383
|
-
if (!pt) return;
|
|
3384
|
-
let lbl = this._meanLabels.get(group);
|
|
3385
|
-
if (!lbl) {
|
|
3386
|
-
lbl = new QELabel(group, pt, labelSvg, this, labelMeans);
|
|
3387
|
-
this._meanLabels.set(group, lbl);
|
|
3388
|
-
} else {
|
|
3389
|
-
labelMeans === Label.DISPLAY_TYPES.ON ? lbl.show() : lbl.hide();
|
|
3390
|
-
}
|
|
3391
|
-
});
|
|
3392
|
-
}
|
|
3393
|
-
}
|
|
3394
|
-
pointsLayer.__data__.__state__.setVariable("layer_updated", pointsLayer.__data__);
|
|
3395
|
-
}
|
|
3396
|
-
}
|
|
3397
|
-
const trajectoriesLayer = this.__children__.search("__children__", "trajectories");
|
|
3398
|
-
const trajectoriesEnabled = config.showTrajectories;
|
|
3399
|
-
if (trajectoriesEnabled && trajectoriesLayer) {
|
|
3400
|
-
trajectoriesLayer.__data__.objects.clear();
|
|
3401
|
-
this.__data__.trajectories.clear();
|
|
3402
|
-
const trajSource = ((_j = model.trajectories) == null ? void 0 : _j.rows) ? model.trajectories : model.points;
|
|
3403
|
-
if (trajSource == null ? void 0 : trajSource.rows) {
|
|
3404
|
-
const unitRows = {};
|
|
3405
|
-
const selectedUnits = config.trajectoryUnits ? config.trajectoryUnits.split(",").map((s) => s.trim()) : null;
|
|
3406
|
-
trajSource.rows().forEach((row) => {
|
|
3407
|
-
const uIdx = row.names.indexOf(unitIdCol) >= 0 ? row.names.indexOf(unitIdCol) : row.names.indexOf("unit") >= 0 ? row.names.indexOf("unit") : row.names.indexOf("ENA_UNIT") >= 0 ? row.names.indexOf("ENA_UNIT") : -1;
|
|
3408
|
-
const unit = uIdx >= 0 ? String(row[uIdx]) : row.rowName || "unit-1";
|
|
3409
|
-
if (selectedUnits && !selectedUnits.includes(unit)) return;
|
|
3410
|
-
const xIdx = row.names.indexOf(dims[0]);
|
|
3411
|
-
const yIdx = dims.length > 1 ? row.names.indexOf(dims[1]) : -1;
|
|
3412
|
-
const tIdx = row.names.indexOf("time") >= 0 ? row.names.indexOf("time") : row.names.indexOf("ActivityNumber") >= 0 ? row.names.indexOf("ActivityNumber") : row.names.indexOf("RowID") >= 0 ? row.names.indexOf("RowID") : -1;
|
|
3413
|
-
const time = tIdx >= 0 ? Number(row[tIdx]) : unitRows[unit] ? unitRows[unit].length + 1 : 1;
|
|
3414
|
-
if (xIdx >= 0 && yIdx >= 0) {
|
|
3415
|
-
if (!unitRows[unit]) unitRows[unit] = [];
|
|
3416
|
-
unitRows[unit].push({
|
|
3417
|
-
x: Number(row[xIdx]) * pointScale,
|
|
3418
|
-
y: -Number(row[yIdx]) * pointScale,
|
|
3419
|
-
time
|
|
3420
|
-
});
|
|
3421
|
-
}
|
|
3422
|
-
});
|
|
3423
|
-
const unitKeys = Object.keys(unitRows);
|
|
3424
|
-
unitKeys.forEach((unitKey, uIdx) => {
|
|
3425
|
-
const rawPts = unitRows[unitKey];
|
|
3426
|
-
if (rawPts.length === 0) return;
|
|
3427
|
-
const colorStr = GROUP_PALETTE[uIdx % GROUP_PALETTE.length];
|
|
3428
|
-
const trajObj = new Trajectory({
|
|
3429
|
-
ID: `traj-${unitKey}`,
|
|
3430
|
-
unitId: unitKey,
|
|
3431
|
-
color: new Color(colorStr),
|
|
3432
|
-
lineStyle: config.trajectoryLineStyle,
|
|
3433
|
-
strokeWidth: config.trajectoryStrokeWidth,
|
|
3434
|
-
strokeWidthRange: config.trajectoryStrokeWidthRange,
|
|
3435
|
-
opacityRange: config.trajectoryOpacityRange,
|
|
3436
|
-
smooth: config.trajectorySmooth,
|
|
3437
|
-
maxDegree: config.trajectoryMaxDegree,
|
|
3438
|
-
degreeSelection: config.trajectoryDegreeSelection,
|
|
3439
|
-
currentTime: config.trajectoryPlayhead ?? Infinity,
|
|
3440
|
-
showPoints: config.trajectoryShowPoints,
|
|
3441
|
-
showTips: config.trajectoryShowTips,
|
|
3442
|
-
points: rawPts.map((p) => ({ x: p.x, y: p.y, time: p.time }))
|
|
3443
|
-
});
|
|
3444
|
-
this.__data__.trajectories.set(unitKey, trajObj);
|
|
3445
|
-
trajectoriesLayer.__data__.objects.set(trajObj.ID, trajObj);
|
|
3446
|
-
});
|
|
3447
|
-
}
|
|
3448
|
-
trajectoriesLayer.__data__.__state__.setVariable("layer_updated", trajectoriesLayer.__data__);
|
|
3449
|
-
}
|
|
3450
|
-
const networkLayer = this.__children__.search("__children__", "network");
|
|
3451
|
-
const edgeLayer = networkLayer == null ? void 0 : networkLayer.__children__.search("__children__", "edges");
|
|
3452
|
-
const nodeLayer = networkLayer == null ? void 0 : networkLayer.__children__.search("__children__", "nodes");
|
|
3453
|
-
const edgenodeLayer = networkLayer == null ? void 0 : networkLayer.__children__.search("__children__", "edgenodes");
|
|
3454
|
-
const edgesEnabled = config.showEdges;
|
|
3455
|
-
if (((_k = model.nodes) == null ? void 0 : _k.rows) && nodeLayer) {
|
|
3456
|
-
model.nodes.rows().forEach((row) => {
|
|
3457
|
-
const pt = rowToPoint(row, nodeIdCol, "#444444");
|
|
3458
|
-
pt.size = 2;
|
|
3459
|
-
nodeLayer.__data__.objects.set(pt.ID, pt);
|
|
3460
|
-
});
|
|
3461
|
-
if (edgesEnabled && edgeLayer && ((_l = model.edges) == null ? void 0 : _l.rows)) {
|
|
3462
|
-
const unitGroupMap = {};
|
|
3463
|
-
if (groupColName && ((_m = model.points) == null ? void 0 : _m.rows)) {
|
|
3464
|
-
model.points.rows().forEach((row) => {
|
|
3465
|
-
const qIdx = row.names.indexOf(unitIdCol);
|
|
3466
|
-
const gIdx = row.names.indexOf(groupColName);
|
|
3467
|
-
if (qIdx >= 0 && gIdx >= 0) unitGroupMap[String(row[qIdx])] = String(row[gIdx]);
|
|
3468
|
-
});
|
|
3469
|
-
}
|
|
3470
|
-
const codeNames = model.nodes.rows().map((r) => {
|
|
3471
|
-
const idx = r.names.indexOf(nodeIdCol);
|
|
3472
|
-
return idx >= 0 ? String(r[idx]) : "";
|
|
3473
|
-
}).filter(Boolean);
|
|
3474
|
-
const edgePairs = [];
|
|
3475
|
-
(model.edges.names ?? []).forEach((col) => {
|
|
3476
|
-
const pair = parseEdgePair(col, codeNames);
|
|
3477
|
-
if (pair) edgePairs.push({ col, pair });
|
|
3478
|
-
});
|
|
3479
|
-
const getUnitEdges = /* @__PURE__ */ __name((unitId) => {
|
|
3480
|
-
const result = {};
|
|
3481
|
-
model.edges.rows().forEach((row) => {
|
|
3482
|
-
const qIdx = row.names.indexOf(unitIdCol);
|
|
3483
|
-
if (qIdx < 0 || String(row[qIdx]) !== unitId) return;
|
|
3484
|
-
edgePairs.forEach(({ col }) => {
|
|
3485
|
-
const colIdx = row.names.indexOf(col);
|
|
3486
|
-
if (colIdx >= 0) result[col] = Number(row[colIdx]) || 0;
|
|
3487
|
-
});
|
|
3488
|
-
});
|
|
3489
|
-
return result;
|
|
3490
|
-
}, "getUnitEdges");
|
|
3491
|
-
const getGroupEdges = /* @__PURE__ */ __name((groupName) => {
|
|
3492
|
-
const sums = {};
|
|
3493
|
-
let count = 0;
|
|
3494
|
-
model.edges.rows().forEach((row) => {
|
|
3495
|
-
const qIdx = row.names.indexOf(unitIdCol);
|
|
3496
|
-
const unitId = qIdx >= 0 ? String(row[qIdx]) : null;
|
|
3497
|
-
const gColIdx = groupColName ? row.names.indexOf(groupColName) : -1;
|
|
3498
|
-
const group = gColIdx >= 0 ? String(row[gColIdx]) : unitId ? unitGroupMap[unitId] : null;
|
|
3499
|
-
if (group !== groupName) return;
|
|
3500
|
-
count++;
|
|
3501
|
-
edgePairs.forEach(({ col }) => {
|
|
3502
|
-
const colIdx = row.names.indexOf(col);
|
|
3503
|
-
if (colIdx >= 0) {
|
|
3504
|
-
const v = Number(row[colIdx]);
|
|
3505
|
-
if (!isNaN(v)) sums[col] = (sums[col] ?? 0) + v;
|
|
3506
|
-
}
|
|
3507
|
-
});
|
|
3508
|
-
});
|
|
3509
|
-
if (count === 0) return {};
|
|
3510
|
-
const result = {};
|
|
3511
|
-
edgePairs.forEach(({ col }) => {
|
|
3512
|
-
result[col] = (sums[col] ?? 0) / count;
|
|
3513
|
-
});
|
|
3514
|
-
return result;
|
|
3515
|
-
}, "getGroupEdges");
|
|
3516
|
-
const resolve = /* @__PURE__ */ __name((id) => {
|
|
3517
|
-
if (groupColorMap[id]) {
|
|
3518
|
-
return { weights: getGroupEdges(id), color: groupColorMap[id], label: id };
|
|
3519
|
-
}
|
|
3520
|
-
const groupOfUnit = unitGroupMap[id] ?? null;
|
|
3521
|
-
const color = groupOfUnit ? groupColorMap[groupOfUnit] ?? "#888888" : "#888888";
|
|
3522
|
-
return { weights: getUnitEdges(id), color, label: id };
|
|
3523
|
-
}, "resolve");
|
|
3524
|
-
const unitAttr = config.edgeUnit;
|
|
3525
|
-
const groupAttr = config.edgeGroup;
|
|
3526
|
-
const compareAttr = config.edgeCompare;
|
|
3527
|
-
const alsoAttr = config.edgeAlso;
|
|
3528
|
-
const primaryId = unitAttr ?? groupAttr ?? null;
|
|
3529
|
-
const primary = primaryId ? resolve(primaryId) : null;
|
|
3530
|
-
const secondaryId = compareAttr ?? alsoAttr ?? null;
|
|
3531
|
-
const secondary = secondaryId ? resolve(secondaryId) : null;
|
|
3532
|
-
const isSubtract = !!compareAttr;
|
|
3533
|
-
const isOverlay = !!alsoAttr;
|
|
3534
|
-
const drawEdges = [];
|
|
3535
|
-
if (primary && (isSubtract || isOverlay) && secondary) {
|
|
3536
|
-
if (isSubtract) {
|
|
3537
|
-
edgePairs.forEach(({ col, pair }) => {
|
|
3538
|
-
const diff = (primary.weights[col] ?? 0) - (secondary.weights[col] ?? 0);
|
|
3539
|
-
if (Math.abs(diff) < 1e-6) return;
|
|
3540
|
-
drawEdges.push({ col, pair, weight: Math.abs(diff), color: diff > 0 ? primary.color : secondary.color });
|
|
3541
|
-
});
|
|
3542
|
-
} else {
|
|
3543
|
-
edgePairs.forEach(({ col, pair }) => {
|
|
3544
|
-
const wA = primary.weights[col] ?? 0;
|
|
3545
|
-
const wB = secondary.weights[col] ?? 0;
|
|
3546
|
-
if (wA > 0) drawEdges.push({ col: col + "-a", pair, weight: wA, color: primary.color });
|
|
3547
|
-
if (wB > 0) drawEdges.push({ col: col + "-b", pair, weight: wB, color: secondary.color });
|
|
3548
|
-
});
|
|
3549
|
-
}
|
|
3550
|
-
} else if (primary) {
|
|
3551
|
-
edgePairs.forEach(({ col, pair }) => {
|
|
3552
|
-
const w = primary.weights[col] ?? 0;
|
|
3553
|
-
if (w > 0) drawEdges.push({ col, pair, weight: w, color: primary.color });
|
|
3554
|
-
});
|
|
3555
|
-
}
|
|
3556
|
-
const isDirected = !!model.directed;
|
|
3557
|
-
const nonSelfWeights = drawEdges.filter((e2) => e2.pair[0] !== e2.pair[1]).map((e2) => e2.weight);
|
|
3558
|
-
const maxEdgeWeight = nonSelfWeights.length > 0 ? Math.max(...nonSelfWeights) : 1e-9;
|
|
3559
|
-
const selfWeights = drawEdges.filter((e2) => e2.pair[0] === e2.pair[1]).map((e2) => e2.weight);
|
|
3560
|
-
const maxSelfWeight = selfWeights.length > 0 ? Math.max(...selfWeights) : 0;
|
|
3561
|
-
const nodeWeightSum = {};
|
|
3562
|
-
drawEdges.forEach(({ pair, weight }) => {
|
|
3563
|
-
const isSelf = pair[0] === pair[1];
|
|
3564
|
-
if (isSelf && !isDirected) return;
|
|
3565
|
-
nodeWeightSum[pair[0]] = (nodeWeightSum[pair[0]] ?? 0) + weight;
|
|
3566
|
-
if (!isSelf) {
|
|
3567
|
-
nodeWeightSum[pair[1]] = (nodeWeightSum[pair[1]] ?? 0) + weight;
|
|
3568
|
-
}
|
|
3569
|
-
});
|
|
3570
|
-
const maxNodeWeight = Math.max(1, ...Object.values(nodeWeightSum));
|
|
3571
|
-
const nodeSizes = {};
|
|
3572
|
-
model.nodes.rows().forEach((row) => {
|
|
3573
|
-
const codeIdx = row.names.indexOf(nodeIdCol);
|
|
3574
|
-
const id = codeIdx >= 0 ? String(row[codeIdx]) : "";
|
|
3575
|
-
if (!id) return;
|
|
3576
|
-
const pt = nodeLayer.__data__.objects.get(id);
|
|
3577
|
-
if (!pt) return;
|
|
3578
|
-
const w = nodeWeightSum[id] ?? 0;
|
|
3579
|
-
pt.size = 2 + w / maxNodeWeight * 3;
|
|
3580
|
-
nodeSizes[id] = pt.size;
|
|
3581
|
-
});
|
|
3582
|
-
const totalWeightByPair = {};
|
|
3583
|
-
if (isDirected) {
|
|
3584
|
-
drawEdges.forEach(({ pair, weight }) => {
|
|
3585
|
-
const key = `${pair[0]}.${pair[1]}`;
|
|
3586
|
-
totalWeightByPair[key] = (totalWeightByPair[key] ?? 0) + weight;
|
|
3587
|
-
});
|
|
3588
|
-
}
|
|
3589
|
-
drawEdges.forEach(({ col, pair, weight, color }) => {
|
|
3590
|
-
const fromNode = nodeLayer.__data__.objects.get(pair[0]);
|
|
3591
|
-
const toNode = nodeLayer.__data__.objects.get(pair[1]);
|
|
3592
|
-
if (!fromNode || !toNode) return;
|
|
3593
|
-
const isSelf = pair[0] === pair[1];
|
|
3594
|
-
if (isSelf && !isDirected) return;
|
|
3595
|
-
const classMax = isSelf ? Math.max(maxSelfWeight, 1e-9) : maxEdgeWeight;
|
|
3596
|
-
const opacity = Math.min(1, weight / classMax);
|
|
3597
|
-
const fromPt = new Point({ ID: `${pair[0]}-src`, dimensions: [fromNode.x, fromNode.y], meta: {} });
|
|
3598
|
-
const toPt = new Point({ ID: `${pair[1]}-dst`, dimensions: [toNode.x, toNode.y], meta: {} });
|
|
3599
|
-
let edgeLine;
|
|
3600
|
-
if (isSelf) {
|
|
3601
|
-
edgeLine = new NodeEdge({}, fromPt, toPt);
|
|
3602
|
-
edgeLine.weight = 0;
|
|
3603
|
-
} else if (isDirected) {
|
|
3604
|
-
const fwd = totalWeightByPair[`${pair[0]}.${pair[1]}`] ?? weight;
|
|
3605
|
-
const bwd = totalWeightByPair[`${pair[1]}.${pair[0]}`] ?? 0;
|
|
3606
|
-
const totalweight = fwd + bwd;
|
|
3607
|
-
edgeLine = new TaperedWeightedMidpointEdge(
|
|
3608
|
-
{ weight, totalweight },
|
|
3609
|
-
fromPt,
|
|
3610
|
-
toPt
|
|
3611
|
-
);
|
|
3612
|
-
} else {
|
|
3613
|
-
edgeLine = new Line({}, fromPt, toPt);
|
|
3614
|
-
}
|
|
3615
|
-
edgeLine.ID = `edge-${col}`;
|
|
3616
|
-
edgeLine.color = new Color(color);
|
|
3617
|
-
edgeLine.meta = {
|
|
3618
|
-
isMeanEdge: true,
|
|
3619
|
-
weight,
|
|
3620
|
-
// NodeEdge compares within the self-loop class; cross-pair edges
|
|
3621
|
-
// compare within their own class. Store the correct denominator
|
|
3622
|
-
// so QELine.update() can compute opacity and display size properly.
|
|
3623
|
-
maxWeight: isSelf ? maxSelfWeight : maxEdgeWeight,
|
|
3624
|
-
opacity,
|
|
3625
|
-
isDirected,
|
|
3626
|
-
isSelf,
|
|
3627
|
-
// nodeSize is needed by QELine.update() to compute the NodeEdge
|
|
3628
|
-
// display radius at update time (when extremes.x_max is available).
|
|
3629
|
-
nodeSize: isSelf ? nodeSizes[pair[0]] ?? 2 : void 0
|
|
3630
|
-
};
|
|
3631
|
-
const targetLayer = isSelf ? edgenodeLayer ?? edgeLayer : edgeLayer;
|
|
3632
|
-
targetLayer.__data__.objects.set(edgeLine.ID, edgeLine);
|
|
3633
|
-
});
|
|
3634
|
-
edgeLayer.__data__.__state__.setVariable("layer_updated", edgeLayer.__data__);
|
|
3635
|
-
if (edgenodeLayer) edgenodeLayer.__data__.__state__.setVariable("layer_updated", edgenodeLayer.__data__);
|
|
3636
|
-
}
|
|
3637
|
-
if (labelSvg && labelNodes !== 0) {
|
|
3638
|
-
this._nodeLabels.forEach((lbl, id) => {
|
|
3639
|
-
if (!nodeLayer.__data__.objects.get(id)) {
|
|
3640
|
-
lbl.remove();
|
|
3641
|
-
this._nodeLabels.delete(id);
|
|
3642
|
-
}
|
|
3643
|
-
});
|
|
3644
|
-
model.nodes.rows().forEach((row) => {
|
|
3645
|
-
const codeIdx = row.names.indexOf(nodeIdCol);
|
|
3646
|
-
const id = codeIdx >= 0 ? String(row[codeIdx]) : "";
|
|
3647
|
-
if (!id) return;
|
|
3648
|
-
const pt = nodeLayer.__data__.objects.get(id);
|
|
3649
|
-
if (!pt) return;
|
|
3650
|
-
let lbl = this._nodeLabels.get(id);
|
|
3651
|
-
if (!lbl) {
|
|
3652
|
-
lbl = new QELabel(id, pt, labelSvg, this, labelNodes);
|
|
3653
|
-
this._nodeLabels.set(id, lbl);
|
|
3654
|
-
} else {
|
|
3655
|
-
labelNodes === Label.DISPLAY_TYPES.ON ? lbl.show() : lbl.hide();
|
|
3656
|
-
}
|
|
3657
|
-
});
|
|
3658
|
-
}
|
|
3659
|
-
nodeLayer.__data__.__state__.setVariable("layer_updated", nodeLayer.__data__);
|
|
3660
|
-
}
|
|
3661
|
-
const axisPointsLayer = this.__children__.search("__children__", "axis_points");
|
|
3662
|
-
const axisLinesLayer = this.__children__.search("__children__", "axis_lines");
|
|
3663
|
-
if (axisPointsLayer) this.__data__.__state__.setVariable("graph_updated_axis_points", axisPointsLayer.__data__.objects);
|
|
3664
|
-
if (axisLinesLayer) this.__data__.__state__.setVariable("graph_updated_axis_lines", axisLinesLayer.__data__.objects);
|
|
3665
|
-
this.update();
|
|
3666
|
-
});
|
|
3667
|
-
}
|
|
3668
|
-
static get observedAttributes() {
|
|
3669
|
-
return [
|
|
3670
|
-
"width",
|
|
3671
|
-
"height",
|
|
3672
|
-
"for",
|
|
3673
|
-
"scale-points",
|
|
3674
|
-
"labels",
|
|
3675
|
-
"label-nodes",
|
|
3676
|
-
"label-means",
|
|
3677
|
-
"label-points"
|
|
3678
|
-
];
|
|
3679
|
-
}
|
|
3680
|
-
get vizena() {
|
|
3681
|
-
return this._vizena;
|
|
3682
|
-
}
|
|
3683
|
-
// ── Shared re-render scheduler ───────────────────────────────────────────────
|
|
3684
|
-
// Batches synchronous attribute / child-list changes into a single microtask
|
|
3685
|
-
// so that e.g. adding <qe-edges> and setting its attributes in the same tick
|
|
3686
|
-
// only triggers one render cycle.
|
|
3687
|
-
_scheduleRerender() {
|
|
3688
|
-
if (!this._vizena || !this._hasModel) return;
|
|
3689
|
-
if (this._renderPending) return;
|
|
3690
|
-
this._renderPending = true;
|
|
3691
|
-
queueMicrotask(() => {
|
|
3692
|
-
var _a;
|
|
3693
|
-
this._renderPending = false;
|
|
3694
|
-
(_a = this._vizena) == null ? void 0 : _a.dispatchEvent(new CustomEvent("model-updated", {
|
|
3695
|
-
detail: this._vizena.model,
|
|
3696
|
-
bubbles: true,
|
|
3697
|
-
composed: true
|
|
3698
|
-
}));
|
|
3699
|
-
});
|
|
3700
|
-
}
|
|
3701
|
-
// ── Layer configuration reader ────────────────────────────────────────────────
|
|
3702
|
-
// Reads child element presence / attributes to determine what each layer
|
|
3703
|
-
// should render. Called once at the top of every model-updated handler so
|
|
3704
|
-
// all rendering decisions are derived from a single snapshot.
|
|
3705
|
-
_readLayerConfig() {
|
|
3706
|
-
const nodesEl = this.querySelector("qe-nodes");
|
|
3707
|
-
const meansEl = this.querySelector("qe-means");
|
|
3708
|
-
const pointsEl = this.querySelector("qe-points");
|
|
3709
|
-
const edgesEl = this.querySelector("qe-edges");
|
|
3710
|
-
const trajectoriesEl = this.querySelector("qe-trajectories");
|
|
3711
|
-
const axesEl = this.querySelector("qe-axes");
|
|
3712
|
-
const labelsShorthand = this.getAttribute("labels");
|
|
3713
|
-
return {
|
|
3714
|
-
// Nodes — always rendered (coordinate anchors); <qe-nodes> controls labels.
|
|
3715
|
-
labelNodes: parseLabelMode(
|
|
3716
|
-
(nodesEl == null ? void 0 : nodesEl.getAttribute("label")) ?? this.getAttribute("label-nodes") ?? labelsShorthand,
|
|
3717
|
-
Label.DISPLAY_TYPES.ON
|
|
3718
|
-
),
|
|
3719
|
-
scalePoints: this.getAttribute("scale-points") !== "false",
|
|
3720
|
-
// Means — presence of <qe-means> = show; absence = hide.
|
|
3721
|
-
showMeans: !!meansEl,
|
|
3722
|
-
activeMeanGroups: (meansEl == null ? void 0 : meansEl.getAttribute("groups")) ?? null,
|
|
3723
|
-
showCI: !!meansEl && meansEl.hasAttribute("confidence"),
|
|
3724
|
-
labelMeans: parseLabelMode(
|
|
3725
|
-
(meansEl == null ? void 0 : meansEl.getAttribute("label")) ?? this.getAttribute("label-means") ?? labelsShorthand,
|
|
3726
|
-
Label.DISPLAY_TYPES.ON
|
|
3727
|
-
),
|
|
3728
|
-
// Points — presence of <qe-points> = show unit dots.
|
|
3729
|
-
showPoints: !!pointsEl,
|
|
3730
|
-
labelPoints: parseLabelMode(
|
|
3731
|
-
(pointsEl == null ? void 0 : pointsEl.getAttribute("label")) ?? this.getAttribute("label-points") ?? labelsShorthand,
|
|
3732
|
-
Label.DISPLAY_TYPES.OFF
|
|
3733
|
-
),
|
|
3734
|
-
// Edges — presence of <qe-edges> = draw a network.
|
|
3735
|
-
showEdges: !!edgesEl,
|
|
3736
|
-
edgeGroup: (edgesEl == null ? void 0 : edgesEl.getAttribute("group")) ?? null,
|
|
3737
|
-
edgeUnit: (edgesEl == null ? void 0 : edgesEl.getAttribute("unit")) ?? null,
|
|
3738
|
-
edgeCompare: (edgesEl == null ? void 0 : edgesEl.getAttribute("compare")) ?? null,
|
|
3739
|
-
edgeAlso: (edgesEl == null ? void 0 : edgesEl.getAttribute("also")) ?? null,
|
|
3740
|
-
// Trajectories — presence of <qe-trajectories> = draw cognitive trajectories
|
|
3741
|
-
showTrajectories: !!trajectoriesEl,
|
|
3742
|
-
trajectoryUnits: (trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("units")) ?? null,
|
|
3743
|
-
trajectorySmooth: (trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("smooth")) ?? "none",
|
|
3744
|
-
trajectoryMaxDegree: (trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("max-degree")) ? parseInt(trajectoriesEl.getAttribute("max-degree"), 10) : 3,
|
|
3745
|
-
trajectoryDegreeSelection: (trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("degree-selection")) ?? "loocv_2d",
|
|
3746
|
-
trajectoryShowPoints: (trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("points")) !== "false",
|
|
3747
|
-
trajectoryShowTips: (trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("tips")) !== "false",
|
|
3748
|
-
trajectoryPlayhead: (trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("playhead")) ? parseFloat(trajectoriesEl.getAttribute("playhead")) : null,
|
|
3749
|
-
trajectoryLineStyle: (trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("line-style")) ?? "uniform",
|
|
3750
|
-
trajectoryStrokeWidth: (trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("stroke-width")) ? parseFloat(trajectoriesEl.getAttribute("stroke-width")) : 2,
|
|
3751
|
-
trajectoryStrokeWidthRange: this._parseNumberPair(trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("stroke-width-range"), [1, 6]),
|
|
3752
|
-
trajectoryOpacityRange: this._parseNumberPair(trajectoriesEl == null ? void 0 : trajectoriesEl.getAttribute("opacity-range"), [0.3, 1]),
|
|
3753
|
-
// Axes — presence of <qe-axes> = draw axis lines. The x / y attributes add
|
|
3754
|
-
// a per-axis label: a value is used verbatim, an empty attribute falls back
|
|
3755
|
-
// to the dimension name (resolved later, where dims are known). null = no
|
|
3756
|
-
// label for that axis.
|
|
3757
|
-
showAxes: !!axesEl,
|
|
3758
|
-
axisXLabel: (axesEl == null ? void 0 : axesEl.hasAttribute("x")) ? axesEl.getAttribute("x") ?? "" : null,
|
|
3759
|
-
axisYLabel: (axesEl == null ? void 0 : axesEl.hasAttribute("y")) ? axesEl.getAttribute("y") ?? "" : null
|
|
3760
|
-
};
|
|
3761
|
-
}
|
|
3762
|
-
_parseNumberPair(value, fallback) {
|
|
3763
|
-
if (!value) return fallback;
|
|
3764
|
-
const parts = value.split(",").map((part) => Number(part.trim()));
|
|
3765
|
-
if (parts.length < 2 || !parts.every(Number.isFinite)) return fallback;
|
|
3766
|
-
return [parts[0], parts[1]];
|
|
3767
|
-
}
|
|
3768
|
-
attributeChangedCallback(_name2, oldValue, newValue) {
|
|
3769
|
-
if (oldValue === newValue) return;
|
|
3770
|
-
this._scheduleRerender();
|
|
3771
|
-
}
|
|
3772
|
-
connectedCallback() {
|
|
3773
|
-
var _a;
|
|
3774
|
-
const w = this.getAttribute("width");
|
|
3775
|
-
const h = this.getAttribute("height");
|
|
3776
|
-
this.style.display = "block";
|
|
3777
|
-
if (w) this.style.width = isNaN(Number(w)) ? w : `${w}px`;
|
|
3778
|
-
if (h) this.style.height = isNaN(Number(h)) ? h : `${h}px`;
|
|
3779
|
-
this.appendChild(this.svg_element);
|
|
3780
|
-
this._childObserver = new MutationObserver(() => this._scheduleRerender());
|
|
3781
|
-
this._childObserver.observe(this, {
|
|
3782
|
-
childList: true,
|
|
3783
|
-
attributes: true,
|
|
3784
|
-
subtree: true,
|
|
3785
|
-
attributeFilter: [
|
|
3786
|
-
"group",
|
|
3787
|
-
"unit",
|
|
3788
|
-
"compare",
|
|
3789
|
-
"also",
|
|
3790
|
-
"groups",
|
|
3791
|
-
"confidence",
|
|
3792
|
-
"label",
|
|
3793
|
-
"scale-points",
|
|
3794
|
-
"labels",
|
|
3795
|
-
"label-nodes",
|
|
3796
|
-
"label-means",
|
|
3797
|
-
"label-points",
|
|
3798
|
-
"units",
|
|
3799
|
-
"smooth",
|
|
3800
|
-
"degree",
|
|
3801
|
-
"points",
|
|
3802
|
-
"tips",
|
|
3803
|
-
"playhead",
|
|
3804
|
-
"line-style",
|
|
3805
|
-
"stroke-width",
|
|
3806
|
-
"stroke-width-range",
|
|
3807
|
-
"opacity-range",
|
|
3808
|
-
"x",
|
|
3809
|
-
"y"
|
|
3810
|
-
]
|
|
3811
|
-
});
|
|
3812
|
-
const forId = this.getAttribute("for");
|
|
3813
|
-
this._vizena = (forId ? document.getElementById(forId) : null) ?? this.closest("qe-visual") ?? ((_a = this.parentElement) == null ? void 0 : _a.closest("qe-visual")) ?? document.querySelector("qe-visual");
|
|
3814
|
-
this.draw();
|
|
3815
|
-
const labelsLayer = this.__children__.search("__children__", "labels");
|
|
3816
|
-
if (labelsLayer == null ? void 0 : labelsLayer.svg_element) {
|
|
3817
|
-
this._labelsGroup = labelsLayer.svg_element;
|
|
3818
|
-
} else {
|
|
3819
|
-
console.warn("[ena-graph] labels layer not found in layer tree; creating fallback <g>");
|
|
3820
|
-
const graphLayer = this.__children__[0];
|
|
3821
|
-
if (graphLayer == null ? void 0 : graphLayer.svg_element) {
|
|
3822
|
-
this._labelsGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
3823
|
-
this._labelsGroup.setAttribute("data-layer-name", "labels-fallback");
|
|
3824
|
-
graphLayer.svg_element.appendChild(this._labelsGroup);
|
|
3825
|
-
}
|
|
3826
|
-
}
|
|
3827
|
-
}
|
|
3828
|
-
disconnectedCallback() {
|
|
3829
|
-
var _a;
|
|
3830
|
-
(_a = this._childObserver) == null ? void 0 : _a.disconnect();
|
|
3831
|
-
this._childObserver = null;
|
|
3832
|
-
}
|
|
3833
|
-
create() {
|
|
3834
|
-
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
3835
|
-
svg.classList.add("graph");
|
|
3836
|
-
svg.style.display = "block";
|
|
3837
|
-
svg.style.width = "100%";
|
|
3838
|
-
svg.style.height = "100%";
|
|
3839
|
-
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
3840
|
-
svg.setAttribute("viewBox", this.__data__.extremes.as_viewBox());
|
|
3841
|
-
svg.setAttribute("transform", this.__data__.transform.toString());
|
|
3842
|
-
svg.setAttribute("role", "figure");
|
|
3843
|
-
svg.setAttribute("data-graph-size", `${Math.min(this.__data__.extremes.width, this.__data__.extremes.height)}`);
|
|
3844
|
-
this.svg_element = svg;
|
|
3845
|
-
const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
|
|
3846
|
-
const AW = 0.22, AH = 0.15;
|
|
3847
|
-
const makeArrow = /* @__PURE__ */ __name((id, fill) => {
|
|
3848
|
-
const m = document.createElementNS("http://www.w3.org/2000/svg", "marker");
|
|
3849
|
-
m.setAttribute("id", id);
|
|
3850
|
-
m.setAttribute("markerWidth", String(AW));
|
|
3851
|
-
m.setAttribute("markerHeight", String(AH));
|
|
3852
|
-
m.setAttribute("refX", String(AW));
|
|
3853
|
-
m.setAttribute("refY", String(AH / 2));
|
|
3854
|
-
m.setAttribute("orient", "auto");
|
|
3855
|
-
m.setAttribute("markerUnits", "userSpaceOnUse");
|
|
3856
|
-
const p = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3857
|
-
p.setAttribute("d", `M0,0 L0,${AH} L${AW},${AH / 2} z`);
|
|
3858
|
-
p.setAttribute("fill", fill);
|
|
3859
|
-
m.appendChild(p);
|
|
3860
|
-
defs.appendChild(m);
|
|
3861
|
-
}, "makeArrow");
|
|
3862
|
-
GROUP_PALETTE.forEach((color) => makeArrow(`qe-arrow-${color.slice(1)}`, color));
|
|
3863
|
-
svg.appendChild(defs);
|
|
3864
|
-
this.__data__.layers.forEach((layer) => {
|
|
3865
|
-
const layer_g = new QELayer(layer, this.svg_element, this);
|
|
3866
|
-
this.__children__.push(layer_g);
|
|
3867
|
-
});
|
|
3868
|
-
this.__data__.__state__.setVariable("graph_updated", this.__data__);
|
|
3869
|
-
this.attach_events();
|
|
3870
|
-
return svg;
|
|
3871
|
-
}
|
|
3872
|
-
attach_events() {
|
|
3873
|
-
this.svg_element.addEventListener("wheel", (ev) => {
|
|
3874
|
-
console.log("Wheel event: ", ev);
|
|
3875
|
-
ev.preventDefault();
|
|
3876
|
-
const delta = Math.sign(ev.deltaY);
|
|
3877
|
-
if (delta < 0) {
|
|
3878
|
-
this.zoom_level *= 1.1;
|
|
3879
|
-
} else {
|
|
3880
|
-
this.zoom_level /= 1.1;
|
|
3881
|
-
}
|
|
3882
|
-
this.__data__.transform.zoom(this.zoom_level);
|
|
3883
|
-
this.update();
|
|
3884
|
-
});
|
|
3885
|
-
let isPanning = false;
|
|
3886
|
-
let startX, startY;
|
|
3887
|
-
this.svg_element.addEventListener("mousedown", (ev) => {
|
|
3888
|
-
isPanning = true;
|
|
3889
|
-
startX = ev.clientX;
|
|
3890
|
-
startY = ev.clientY;
|
|
3891
|
-
});
|
|
3892
|
-
let panAnimationFrame = null;
|
|
3893
|
-
let pendingPan = null;
|
|
3894
|
-
const panUpdate = /* @__PURE__ */ __name(() => {
|
|
3895
|
-
if (pendingPan) {
|
|
3896
|
-
this.__data__.transform.pan(pendingPan.dx, pendingPan.dy);
|
|
3897
|
-
this.__children__[0].svg_element.setAttribute("transform", this.__data__.transform.toString());
|
|
3898
|
-
pendingPan = null;
|
|
3899
|
-
}
|
|
3900
|
-
panAnimationFrame = null;
|
|
3901
|
-
}, "panUpdate");
|
|
3902
|
-
this.svg_element.addEventListener("mousemove", (ev) => {
|
|
3903
|
-
if (!isPanning) return;
|
|
3904
|
-
const dx = ev.clientX - startX, dy = ev.clientY - startY;
|
|
3905
|
-
pendingPan = { dx: dx / 100, dy: dy / 100 };
|
|
3906
|
-
startX = ev.clientX;
|
|
3907
|
-
startY = ev.clientY;
|
|
3908
|
-
if (panAnimationFrame === null) {
|
|
3909
|
-
panAnimationFrame = requestAnimationFrame(panUpdate);
|
|
3910
|
-
}
|
|
3911
|
-
});
|
|
3912
|
-
this.svg_element.addEventListener("mouseup", (ev) => {
|
|
3913
|
-
isPanning = false;
|
|
3914
|
-
});
|
|
3915
|
-
this.svg_element.addEventListener("point-clicked", ((ev) => {
|
|
3916
|
-
var _a, _b;
|
|
3917
|
-
const id = (_b = (_a = ev.detail) == null ? void 0 : _a.pointData) == null ? void 0 : _b.ID;
|
|
3918
|
-
if (!id) return;
|
|
3919
|
-
const lbl = this._pointLabels.get(id) ?? this._meanLabels.get(id.replace("mean-", "")) ?? this._nodeLabels.get(id);
|
|
3920
|
-
if (lbl && lbl.displayMode === Label.DISPLAY_TYPES.CLICK) lbl.toggle();
|
|
3921
|
-
}));
|
|
3922
|
-
const findPointId = /* @__PURE__ */ __name((el) => {
|
|
3923
|
-
var _a;
|
|
3924
|
-
while (el && el !== this.svg_element) {
|
|
3925
|
-
const id = (_a = el.getAttribute) == null ? void 0 : _a.call(el, "data-point-id");
|
|
3926
|
-
if (id) return id;
|
|
3927
|
-
el = el.parentElement;
|
|
3928
|
-
}
|
|
3929
|
-
return null;
|
|
3930
|
-
}, "findPointId");
|
|
3931
|
-
const getAutoLabel = /* @__PURE__ */ __name((id) => {
|
|
3932
|
-
return this._pointLabels.get(id) ?? this._meanLabels.get(id.replace(/^mean-/, "")) ?? this._nodeLabels.get(id);
|
|
3933
|
-
}, "getAutoLabel");
|
|
3934
|
-
this.svg_element.addEventListener("mouseover", (ev) => {
|
|
3935
|
-
const id = findPointId(ev.target);
|
|
3936
|
-
if (!id) return;
|
|
3937
|
-
const lbl = getAutoLabel(id);
|
|
3938
|
-
if ((lbl == null ? void 0 : lbl.displayMode) === Label.DISPLAY_TYPES.AUTO) lbl.show();
|
|
3939
|
-
});
|
|
3940
|
-
this.svg_element.addEventListener("mouseout", (ev) => {
|
|
3941
|
-
const id = findPointId(ev.target);
|
|
3942
|
-
if (!id) return;
|
|
3943
|
-
const related = ev.relatedTarget;
|
|
3944
|
-
const relatedId = findPointId(related);
|
|
3945
|
-
if (relatedId === id) return;
|
|
3946
|
-
const lbl = getAutoLabel(id);
|
|
3947
|
-
if ((lbl == null ? void 0 : lbl.displayMode) === Label.DISPLAY_TYPES.AUTO) lbl.hide();
|
|
3948
|
-
});
|
|
3949
|
-
}
|
|
3950
|
-
draw() {
|
|
3951
|
-
var _a;
|
|
3952
|
-
if (!this.svg_element) {
|
|
3953
|
-
console.error("No element to draw to: ", this);
|
|
3954
|
-
return;
|
|
3955
|
-
}
|
|
3956
|
-
(_a = this.wrapper) == null ? void 0 : _a.appendChild(this.svg_element);
|
|
3957
|
-
this.__children__.forEach((enaLayer) => {
|
|
3958
|
-
enaLayer.draw();
|
|
3959
|
-
});
|
|
3960
|
-
}
|
|
3961
|
-
update() {
|
|
3962
|
-
this.update_extremes();
|
|
3963
|
-
this.update_layers();
|
|
3964
|
-
this.update_labels();
|
|
3965
|
-
this.update_extremes();
|
|
3966
|
-
this.update_axes();
|
|
3967
|
-
}
|
|
3968
|
-
/**
|
|
3969
|
-
* Axes (<qe-axes>): toggle the axis-line cross by presence, and draw/position
|
|
3970
|
-
* per-axis labels at the positive ends using the current extent. Labels are
|
|
3971
|
-
* cached SVG <text> nodes in the labels group; null text removes them.
|
|
3972
|
-
*/
|
|
3973
|
-
update_axes() {
|
|
3974
|
-
const axesLayer = this.__children__.search("__children__", "axes");
|
|
3975
|
-
if (axesLayer == null ? void 0 : axesLayer.svg_element) {
|
|
3976
|
-
axesLayer.svg_element.style.display = this._showAxes ? "" : "none";
|
|
3977
|
-
}
|
|
3978
|
-
const parent = this._labelsGroup;
|
|
3979
|
-
const extent = this.__data__.extremes.x_max;
|
|
3980
|
-
if (!parent || extent <= 0) return;
|
|
3981
|
-
const fontSize = extent * 0.06;
|
|
3982
|
-
const gap = fontSize * 0.6;
|
|
3983
|
-
const place = /* @__PURE__ */ __name((axis, text) => {
|
|
3984
|
-
let el = this._axisLabelEls.get(axis);
|
|
3985
|
-
if (!this._showAxes || text == null) {
|
|
3986
|
-
if (el) {
|
|
3987
|
-
el.remove();
|
|
3988
|
-
this._axisLabelEls.delete(axis);
|
|
3989
|
-
}
|
|
3990
|
-
return;
|
|
3991
|
-
}
|
|
3992
|
-
if (!el) {
|
|
3993
|
-
el = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
3994
|
-
el.setAttribute("data-axis-label", axis);
|
|
3995
|
-
el.setAttribute("pointer-events", "none");
|
|
3996
|
-
parent.appendChild(el);
|
|
3997
|
-
this._axisLabelEls.set(axis, el);
|
|
3998
|
-
}
|
|
3999
|
-
el.textContent = text;
|
|
4000
|
-
el.setAttribute("font-size", fontSize.toString());
|
|
4001
|
-
el.setAttribute("font-family", "system-ui, sans-serif");
|
|
4002
|
-
el.setAttribute("font-weight", "600");
|
|
4003
|
-
el.setAttribute("fill", "#556");
|
|
4004
|
-
if (axis === "x") {
|
|
4005
|
-
el.setAttribute("x", (extent + gap).toString());
|
|
4006
|
-
el.setAttribute("y", (fontSize * 0.35).toString());
|
|
4007
|
-
el.setAttribute("text-anchor", "start");
|
|
4008
|
-
} else {
|
|
4009
|
-
el.setAttribute("x", "0");
|
|
4010
|
-
el.setAttribute("y", (-extent - gap).toString());
|
|
4011
|
-
el.setAttribute("text-anchor", "middle");
|
|
4012
|
-
}
|
|
4013
|
-
}, "place");
|
|
4014
|
-
place("x", this._axisXText);
|
|
4015
|
-
place("y", this._axisYText);
|
|
4016
|
-
}
|
|
4017
|
-
update_labels() {
|
|
4018
|
-
this._nodeLabels.forEach((lbl) => lbl.update());
|
|
4019
|
-
this._meanLabels.forEach((lbl) => lbl.update());
|
|
4020
|
-
this._pointLabels.forEach((lbl) => lbl.update());
|
|
4021
|
-
}
|
|
4022
|
-
update_extremes() {
|
|
4023
|
-
var _a;
|
|
4024
|
-
this.__data__.update_extremes();
|
|
4025
|
-
const svgRect = (_a = this.svg_element) == null ? void 0 : _a.getBoundingClientRect();
|
|
4026
|
-
if (this.svg_element && svgRect) {
|
|
4027
|
-
console.log("SVG rect: ", svgRect);
|
|
4028
|
-
let w, h;
|
|
4029
|
-
if (svgRect.width === 0 || svgRect.height === 0) {
|
|
4030
|
-
w = 1;
|
|
4031
|
-
h = 1;
|
|
4032
|
-
} else {
|
|
4033
|
-
w = svgRect.width;
|
|
4034
|
-
h = svgRect.height;
|
|
4035
|
-
}
|
|
4036
|
-
this.__data__.scale_x = 1 / (w / (4 * this.__data__.extremes.x_max));
|
|
4037
|
-
this.__data__.scale_y = 1 / (h / (4 * this.__data__.extremes.y_max));
|
|
4038
|
-
this.__children__[0].svg_element.setAttribute("transform", this.__data__.transform.toString());
|
|
4039
|
-
this.svg_element.setAttribute("viewBox", this.__data__.extremes.as_viewBox());
|
|
4040
|
-
let axisLineLayer = this.__data__.layers.search("layers", "axis_lines");
|
|
4041
|
-
if (axisLineLayer) {
|
|
4042
|
-
let axis_x = axisLineLayer.objects.get("axis-x"), axis_y = axisLineLayer.objects.get("axis-y");
|
|
4043
|
-
if (axis_x && axis_y) {
|
|
4044
|
-
axis_x.from = new Point({ ID: "axis-x-start", dimensions: [-this.__data__.extremes.x_max, 0], classes: ["ena.dimension", "ena.dimension"] });
|
|
4045
|
-
axis_x.to = new Point({ ID: "axis-x-end", dimensions: [this.__data__.extremes.x_max, 0], classes: ["ena.dimension", "ena.dimension"] });
|
|
4046
|
-
axis_y.from = new Point({ ID: "axis-y-start", dimensions: [0, -this.__data__.extremes.y_max], classes: ["ena.dimension", "ena.dimension"] });
|
|
4047
|
-
axis_y.to = new Point({ ID: "axis-y-end", dimensions: [0, this.__data__.extremes.y_max], classes: ["ena.dimension", "ena.dimension"] });
|
|
4048
|
-
}
|
|
4049
|
-
}
|
|
4050
|
-
}
|
|
4051
|
-
}
|
|
4052
|
-
update_layers() {
|
|
4053
|
-
this.__children__.forEach((enaLayer) => {
|
|
4054
|
-
enaLayer.update();
|
|
4055
|
-
});
|
|
4056
|
-
}
|
|
4057
|
-
};
|
|
4058
|
-
__name(_QEGraphElement, "QEGraphElement");
|
|
4059
|
-
_QEGraphElement.tagName = "qe-graph";
|
|
4060
|
-
_QEGraphElement.style = `
|
|
4061
|
-
${DrawableElement.style}
|
|
18
|
+
`;let Ne=Te;const Is=1e-8;function Ze(d,t=Is){return d.filter(e=>Math.abs(e.x)>t||Math.abs(e.y)>t)}u(Ze,"nearOriginFilter");function Ns(d){if(d<=0)return[];if(d===1)return[0];const t=new Array(d);for(let e=0;e<d;e++)t[e]=e/(d-1);return t}u(Ns,"normalizedT");function ks(d,t){return d.map(e=>{const s=new Array(t+1);let i=1;for(let n=0;n<=t;n++)s[n]=i,i*=e;return s})}u(ks,"design");function Cs(d){const t=d.length,e=d[0].length,s=d.map(n=>n.slice()),i=Array.from({length:e},()=>new Array(e).fill(0));for(let n=0;n<e;n++){let r=0;for(let a=0;a<t;a++)r+=s[a][n]*s[a][n];if(r=Math.sqrt(r),i[n][n]=r,r>1e-300)for(let a=0;a<t;a++)s[a][n]/=r;for(let a=n+1;a<e;a++){let h=0;for(let o=0;o<t;o++)h+=s[o][n]*s[o][a];i[n][a]=h;for(let o=0;o<t;o++)s[o][a]-=h*s[o][n]}}return{Q:s,R:i}}u(Cs,"qr");function Qe(d,t){const e=d.length,s=d[0].length,i=new Array(s).fill(0);for(let n=0;n<s;n++){let r=0;for(let a=0;a<e;a++)r+=d[a][n]*t[a];i[n]=r}return i}u(Qe,"qtY");function ts(d,t){const e=t.length,s=new Array(e).fill(0);for(let i=e-1;i>=0;i--){let n=t[i];for(let r=i+1;r<e;r++)n-=d[i][r]*s[r];s[i]=Math.abs(d[i][i])>1e-12?n/d[i][i]:0}return s}u(ts,"backSolve");function hi(d){return d.map(t=>{let e=0;for(let s=0;s<t.length;s++)e+=t[s]*t[s];return e})}u(hi,"leverages");function Os(d,t,e){const s=ks(d,e),{Q:i,R:n}=Cs(s);return ts(n,Qe(i,t))}u(Os,"fitCoeffs");function ke(d,t){let e=0,s=1;for(let i=0;i<d.length;i++)e+=d[i]*s,s*=t;return e}u(ke,"evalPoly");function li(d,t,e,s){const i=ks(d,s),{Q:n,R:r}=Cs(i),a=hi(n),h=ts(r,Qe(n,t)),o=ts(r,Qe(n,e));let l=0;for(let _=0;_<d.length;_++){const g=1-a[_];if(g<=0)return 1/0;const c=t[_]-ke(h,d[_]),E=e[_]-ke(o,d[_]);l+=(c/g)**2+(E/g)**2}return l}u(li,"loocv2d");function $s(d,t,e){const s=d.length,i=Math.min(Math.max(1,Math.floor(t)),Math.max(1,s-1));if(e==="fixed"||s<3)return i;const n=Ns(s),r=d.map(l=>l.x),a=d.map(l=>l.y);let h=1,o=1/0;for(let l=1;l<=i;l++){const _=li(n,r,a,l);_<o&&(o=_,h=l)}return h}u($s,"selectDegree");function Ps(d,t){const e=Ze(d);if(e.length<3)return null;const s=t.selectionSet?Ze(t.selectionSet):e,i=s.length>=3?s:e;let n=$s(i,t.maxDegree,t.degreeSelection);n=Math.min(n,Math.max(1,e.length-1));const r=Ns(e.length),a=Os(r,e.map(o=>o.x),n),h=Os(r,e.map(o=>o.y),n);return{degree:n,coeffsX:a,coeffsY:h}}u(Ps,"fitTrajectory");function es(d,t=100){const e=[];for(let s=0;s<=t;s++){const i=s/t;e.push({x:ke(d.coeffsX,i),y:ke(d.coeffsY,i)})}return e}u(es,"sampleCurve");const Rs=100,ms=class ms extends Nt{constructor(t={}){const e=t.color instanceof tt?t.color:new tt(typeof t.color=="string"?t.color:"#000000");super([],{ID:t.ID||`traj-${Math.random().toString(36).substring(2,9)}`,size:t.size||1,color:e,highlight:null,active:t.active||!1,meta:t.meta||{},...t}),this._typeName="Trajectory",this.trajPoints=[],this.smooth="none",this.maxDegree=3,this.degreeSelection="loocv_2d",this.selectedDegree=-1,this.polyCoeffsX=[],this.polyCoeffsY=[],this.currentTime=1/0,this.showPoints=!0,this.showTips=!0,this.lineStyle="uniform",this.strokeWidth=2,this.strokeWidthRange=[1,6],this.opacityRange=[.3,1],this.smooth=t.smooth||"none",this.maxDegree=t.maxDegree!==void 0?t.maxDegree:3,this.degreeSelection=t.degreeSelection||"loocv_2d",this.polyCoeffsX=t.polyCoeffsX||[],this.polyCoeffsY=t.polyCoeffsY||[],this.currentTime=t.currentTime!==void 0?t.currentTime:1/0,this.showPoints=t.showPoints!==void 0?t.showPoints:!0,this.showTips=t.showTips!==void 0?t.showTips:!0,this.lineStyle=t.lineStyle||"uniform",this.strokeWidth=t.strokeWidth||2,this.strokeWidthRange=t.strokeWidthRange||[1,6],this.opacityRange=t.opacityRange||[.3,1],t.points&&Array.isArray(t.points)&&(this.trajPoints=t.points.map(s=>{if(s instanceof J)return s;const i=new J({dimensions:[s.x,s.y],meta:{time:s.time,label:s.label}});return i.x=s.x,i.y=s.y,i}))}get activePoints(){return this.currentTime===1/0?this.trajPoints:this.trajPoints.filter(t=>(t.meta&&typeof t.meta.time=="number"?t.meta.time:0)<=this.currentTime)}get path(){return this.pathPoints.reduce((t,e,s)=>s===0?`M${e.x},${e.y}`:`${t} L${e.x},${e.y}`,"")}get pathPoints(){const t=this.activePoints;if(t.length<2)return[];if(this.smooth==="poly"){if(this.polyCoeffsX.length>0&&this.polyCoeffsY.length>0)return es({degree:this.polyCoeffsX.length-1,coeffsX:this.polyCoeffsX,coeffsY:this.polyCoeffsY},Rs);const e=Ps(t.map(s=>({x:s.x,y:s.y})),{maxDegree:this.maxDegree,degreeSelection:this.degreeSelection,selectionSet:this.trajPoints.map(s=>({x:s.x,y:s.y}))});if(e)return this.selectedDegree=e.degree,es(e,Rs)}return t.map(e=>({x:e.x,y:e.y}))}};u(ms,"Trajectory");let se=ms;const Ls=1,fs=class fs extends Yt{constructor(t,e,s,i=0){super(t,e,s),this._totalweight=0,this._weight=i}get base_color(){return this._color}get color(){const t=this._color||new tt("#000000");return new Qt(t,Math.abs(this.weight))}set color(t){this._color=t}base_weight(){return this._weight}get weight(){return Array.isArray(this._weight)?this._weight[0]-this._weight[1]:this._weight}set weight(t){this._weight=t}get totalweight(){return this.weight}set totalweight(t){this._totalweight=t}};u(fs,"Edge");let ie=fs;const ps=class ps extends Nt{constructor(e){super(e.dimensions||[],e);it(this,Xt);W(this,Xt,e)}get edge(){return C(this,Xt)}get path(){const e=C(this,Xt),s=[e.to.x,e.to.y],i=e.from_point,[n,r]=e.base_pts,a=Math.hypot(i[0]-s[0],i[1]-s[1]),h=Math.hypot(n[0]-r[0],n[1]-r[1]);if(!(a>0)||!(h>0))return"";const o=[(i[0]-s[0])/a,(i[1]-s[1])/a],l=Math.hypot(n[0]-s[0],n[1]-s[1]),_=[(n[0]-s[0])/l,(n[1]-s[1])/l],g=u(G=>h/2*Math.max(0,1-G/a),"halfW"),c=u((G,v)=>`${s[0]+o[0]*G+_[0]*v} ${s[1]+o[1]*G+_[1]*v}`,"at"),E=.2*a,p=Math.min(.15*a,.8*2*g(E)),A=E+p/2,R=E+p;return`M${c(E,0)} L${c(A,g(A))} L${c(R,g(R))} L${c(A,0)} L${c(R,-g(R))} L${c(A,-g(A))}z`}};Xt=new WeakMap,u(ps,"EdgeArrow");let Ce=ps;const De=class De extends ie{constructor(e,s,i){super(e,s,i);it(this,Wt);it(this,Se);this._path="",W(this,Wt,!1),this._directions=["from","to"],this.towards="to",C(this,Wt)===!0&&W(this,Se,new Ce(this))}get path(){return`M${this.from.x} ${this.from.y} L${this.base_pts[0].join(" ")} L${this.base_pts[1].join(" ")}z`}static calculate_base_points(e){const s=e.towards,i=e._directions.find(A=>A!==e.towards),n=e[i].x,r=e[i].y,a=e[s].x,h=e[s].y,o=a-n,l=h-r,_=Math.hypot(o,l),g=(e.weight??0)*Ls;if(_===0||!isFinite(g)||g===0)return[[a,h],[a,h]];const c=-l/_,E=o/_,p=g/2;return[[a+c*p,h+E*p],[a-c*p,h-E*p]]}get base_pts(){return De.calculate_base_points(this)}get arrow(){return C(this,Se)}get with_arrow(){return C(this,Wt)}get from_point(){return[this.from.x,this.from.y]}};Wt=new WeakMap,Se=new WeakMap,u(De,"TaperedEdge");let qt=De;const ze=class ze extends qt{constructor(t,e,s){super(t,e,s),this._dataWeight=0,this._totalweight=t.totalweight??0,this._dataWeight=t.weight??this._weight}get weighted_midpoint(){return ee.Geometry.Line.interpolate(this.line)(1-this._dataWeight/this._totalweight)}get base_pts(){return qt.calculate_base_points(this)}static build_path(t){return t._totalweight>0?`M${t.weighted_midpoint[0]} ${t.weighted_midpoint[1]} L${t.base_pts[0].join(" ")} L${t.base_pts[1].join(" ")}z`:(console.error("TaperedWeightedMidpointEdge: No totalweight, returning empty path"),"")}get path(){return ze.build_path(this)}get from_point(){return this.weighted_midpoint}};u(ze,"TaperedWeightedMidpointEdge");let ss=ze;const Fe=class Fe extends ie{constructor(t,e,s){super(t,e,s)}static build_path(t,e){let s=t/2,i=e.x-s,n=s*2;return`M ${i}, ${e.y} a ${s},${s} 0 1,0 ${n},0 a ${s},${s} 0 1,0 -${n},0`}get path(){let t=this.weight*Ls;return Fe.build_path(t,this.to)}};u(Fe,"NodeEdge");let ne=Fe;const bs=class bs{constructor(t,e,s,i=new kt){this.__data__=t,this.parent=e,this.graph=s,this.__children__=i,this.svg_element=this.create()}get_size(){return this.__data__.size}draw(){var t;(t=this.parent)==null||t.appendChild(this.svg_element)}update(t,e=!0){}animateSVGAttribute(t,e,s){const i=parseFloat(t.getAttribute(e)||"0");if(i===s)return;const n=5e3,r=performance.now();function a(h){const o=Math.min(1,(h-r)/n),l=i+(s-i)*o;t.setAttribute(e,l.toString()),o<1?requestAnimationFrame(a):t.setAttribute(e,s.toString())}u(a,"animate"),requestAnimationFrame(a)}};u(bs,"Drawable");let re=bs;const ci=.04,_i=[.25,1],ui=[.3,1];function Ts(d,t,e,s){const i=Math.abs(d);if(!(i>0))return 0;if(!(e>t))return s[1];const n=Math.min(1,Math.max(0,(i-t)/(e-t)));return s[0]+n*(s[1]-s[0])}u(Ts,"rampFor");const di=.011,gi=.75,mi=.8,fi=.75,Ds=.006,pi=.6;function bi(d){return 2*d}u(bi,"widthPerWeight");function yi(d,t){return d*t/(2*Ds)}u(yi,"nodeSizeForEdges");function xi(d){const t=/rgba?\(([^)]+)\)/.exec(d);if(!t)return d;const[e,s,i,n=1]=t[1].split(",").map(Number),r=u(a=>Math.round(255+(a-255)*n),"f");return`rgb(${r(e)},${r(s)},${r(i)})`}u(xi,"flattenOnWhite");function wi(d,t){const e=/rgba?\(([^)]+)\)/.exec(d);if(!e)return d;const[s,i,n,r=1]=e[1].split(",").map(Number);return`rgba(${Math.round(s*t)},${Math.round(i*t)},${Math.round(n*t)},${r})`}u(wi,"darkenRgba");const ys=class ys extends re{constructor(t,e,s,i=new kt){super(t,e,s,i),this.__data__=t,this.parent=e,this.graph=s,this.__children__=i,this.__name__="unnamed-line",this._arrow_el=null,this._hit_el=null,this.svg_element=this.create()}_stampEdge(t){const e=this.__data__.meta??{};e.isMeanEdge&&(t.setAttribute("data-edge-source",String(e.source??"")),t.setAttribute("data-edge-target",String(e.target??"")),t.setAttribute("data-edge-weight",String(e.weight??0)),t.setAttribute("data-edge-directed",e.isDirected?"true":"false"),e.isSelf&&t.setAttribute("data-edge-self","true"),e.group!=null&&t.setAttribute("data-edge-group",String(e.group)),e.unit!=null&&t.setAttribute("data-edge-unit",String(e.unit)))}create(){if(this.__data__ instanceof ne){const e=document.createElementNS("http://www.w3.org/2000/svg","path");return e.setAttribute("fill",this.__data__.color.toString()),e.setAttribute("stroke","none"),this.svg_element=e,e}if(this.__data__ instanceof qt){const e=document.createElementNS("http://www.w3.org/2000/svg","path");return e.setAttribute("fill",this.__data__.color.toString()),e.setAttribute("stroke","none"),this.svg_element=e,e}const t=document.createElementNS("http://www.w3.org/2000/svg","line");return t.setAttribute("x1",this.__data__.from.x.toString()),t.setAttribute("y1",this.__data__.from.y.toString()),t.setAttribute("x2",this.__data__.to.x.toString()),t.setAttribute("y2",this.__data__.to.y.toString()),t.setAttribute("stroke-width",this.get_size().toString()),t.setAttribute("stroke",this.__data__.color.toString()),this.svg_element=t,t}update(){var s;this.svg_element||this.create(),this.svg_element.parentElement||this.parent.appendChild(this.svg_element);const t=((s=this.graph.__data__.extremes)==null?void 0:s.x_max)??1,e=this.__data__.meta??{};if(e.isMeanEdge){this._stampEdge(this.svg_element);const i=typeof e.weight=="number"?e.weight:0,n=typeof e.maxWeight=="number"?e.maxWeight:1,r=typeof e.opacity=="number"?e.opacity:Math.min(1,i/(n||1)),a=t>0?t:1,h=typeof e.widthFrac=="number"?a*e.widthFrac*i:a*di*(i/(n||1)),o=this.__data__._color||new tt("#000000"),l=typeof e.saturation=="number"?e.saturation:r,_=new Qt(o,l,r).toString();if(this.__data__ instanceof ne)this.__data__.weight=h,this.svg_element.setAttribute("d",this.__data__.path),this.svg_element.setAttribute("fill",_),this.svg_element.setAttribute("stroke","none");else if(this.__data__ instanceof qt){if(this.__data__.weight=h,this.svg_element.setAttribute("d",this.__data__.path),this.svg_element.setAttribute("fill",_),this.svg_element.setAttribute("stroke",_),this.svg_element.setAttribute("stroke-width",String(gi)),this.svg_element.setAttribute("vector-effect","non-scaling-stroke"),this.svg_element.setAttribute("stroke-linejoin","round"),e.isDirected)try{const c=new Ce(this.__data__).path;c&&!c.includes("NaN")&&!c.includes("Infinity")&&(this._arrow_el||(this._arrow_el=document.createElementNS("http://www.w3.org/2000/svg","path"),this._arrow_el.setAttribute("stroke","none")),this._arrow_el.parentElement||this.parent.appendChild(this._arrow_el),this._arrow_el.setAttribute("d",c),this._arrow_el.setAttribute("fill",wi(xi(_),mi)),this._arrow_el.setAttribute("stroke","#ffffff"),this._arrow_el.setAttribute("stroke-width",String(fi)),this._arrow_el.setAttribute("vector-effect","non-scaling-stroke"),this._arrow_el.setAttribute("stroke-linejoin","round"))}catch{}}else{const g=this.__data__.from.x,c=this.__data__.from.y,E=this.__data__.to.x,p=this.__data__.to.y;this.svg_element.setAttribute("x1",g.toString()),this.svg_element.setAttribute("y1",c.toString()),this.svg_element.setAttribute("x2",E.toString()),this.svg_element.setAttribute("y2",p.toString()),this.svg_element.setAttribute("stroke-width",h.toString()),this.svg_element.setAttribute("stroke",_),this.svg_element.setAttribute("pointer-events","stroke"),this.svg_element.removeAttribute("marker-end"),this._hit_el||(this._hit_el=document.createElementNS("http://www.w3.org/2000/svg","line"),this._hit_el.setAttribute("stroke","transparent"),this._hit_el.setAttribute("stroke-linecap","round"),this._hit_el.setAttribute("pointer-events","stroke")),this._hit_el.parentElement||this.parent.appendChild(this._hit_el),this._hit_el.setAttribute("x1",g.toString()),this._hit_el.setAttribute("y1",c.toString()),this._hit_el.setAttribute("x2",E.toString()),this._hit_el.setAttribute("y2",p.toString()),this._hit_el.setAttribute("stroke-width",Math.max(h,t*.03).toString()),this._stampEdge(this._hit_el)}}else{this.svg_element.setAttribute("x1",this.__data__.from.x.toString()),this.svg_element.setAttribute("y1",this.__data__.from.y.toString()),this.svg_element.setAttribute("x2",this.__data__.to.x.toString()),this.svg_element.setAttribute("y2",this.__data__.to.y.toString());const i=(t>0?t:1)*.004*this.get_size();this.svg_element.setAttribute("stroke-width",i.toString()),this.svg_element.setAttribute("stroke-opacity","1"),this.svg_element.setAttribute("stroke",this.__data__.color.toString())}}draw(){var t,e,s;this._hit_el&&((t=this.parent)==null||t.appendChild(this._hit_el)),(e=this.parent)==null||e.appendChild(this.svg_element),this._arrow_el&&((s=this.parent)==null||s.appendChild(this._arrow_el))}};u(ys,"QELine");let wt=ys;const xs=class xs extends re{constructor(t,e,s,i=new kt){super(t,e,s,i),this.__data__=t,this.parent=e,this.graph=s,this.__children__=i,this.__name__="unnamed-point",this.svg_element=this.create()}get x(){return this.__data__.dimensions[this.graph.__data__.options.GRAPH.dimensions[0]]}get y(){return this.__data__.dimensions[this.graph.__data__.options.GRAPH.dimensions[1]]}get isSquare(){return this.__data__.shape==="rect"}get shapeKind(){const t=this.__data__.shape;return t==="rect"||t==="square"?"rect":t==="triangle"||t==="diamond"?t:"circle"}get tag(){const t=this.shapeKind;return t==="circle"?"circle":t==="rect"?"rect":"path"}setGeometry(t,e){const s=this.x,i=this.y;switch(this.shapeKind){case"rect":t.setAttribute("x",(s-e).toString()),t.setAttribute("y",(i-e).toString()),t.setAttribute("width",(e*2).toString()),t.setAttribute("height",(e*2).toString());break;case"triangle":{const n=e*1.15;t.setAttribute("d",`M${s} ${i-n} L${s+n*.866} ${i+n*.5} L${s-n*.866} ${i+n*.5}Z`);break}case"diamond":t.setAttribute("d",`M${s} ${i-e*1.2} L${s+e} ${i} L${s} ${i+e*1.2} L${s-e} ${i}Z`);break;default:t.setAttribute("cx",s.toString()),t.setAttribute("cy",i.toString()),t.setAttribute("r",e.toString())}}computeRadius(){var s;const t=this.baseRadius(),e=(s=this.__data__.meta)==null?void 0:s.maxRadius;return typeof e=="number"&&e>0?Math.min(t,e):t}baseRadius(){var s,i,n,r;const t=this.graph.__data__.extremes.x_max||1,e=((s=this.__data__.meta)==null?void 0:s.sizeScale)??1;if((i=this.__data__.meta)!=null&&i.fixedSize){const a=(r=(n=this.graph.svg_element)==null?void 0:n.getBoundingClientRect)==null?void 0:r.call(n),h=this.graph.zoom_level||1,o=a&&a.width>0?a.width/(2*t):1;return this.__data__.size*2*e/o/h}return t*Ds*this.__data__.size*e}applyStroke(t){var s;const e=(s=this.__data__.meta)==null?void 0:s.stroke;e&&(t.setAttribute("stroke",e),t.setAttribute("stroke-width",(this.computeRadius()*.22).toString()))}create(){const t=document.createElementNS("http://www.w3.org/2000/svg",this.tag);t.setAttribute("data-point-id",this.__data__.ID);const e=this.__data__.meta??{};return e.kind&&t.setAttribute("data-kind",e.kind),e.name!=null&&t.setAttribute("data-name",String(e.name)),e.group!=null&&t.setAttribute("data-group",String(e.group)),e.unit!=null&&t.setAttribute("data-unit",String(e.unit)),t.setAttribute("fill",this.__data__.color.toString()),this.applyStroke(t),this.setGeometry(t,this.computeRadius()),this.svg_element=t,t.addEventListener("click",()=>{this.__data__.active=!this.__data__.active,this.update();const s=new CustomEvent("point-clicked",{detail:{pointData:this.__data__},bubbles:!0,composed:!0});this.svg_element.dispatchEvent(s)}),t.addEventListener("mouseover",()=>{}),t}update(){this.svg_element||this.parent.__data__.__children__.push(this.create()),this.svg_element.parentElement||this.parent.appendChild(this.svg_element),this.svg_element.setAttribute("fill",this.__data__.color.toString()),this.applyStroke(this.svg_element),this.setGeometry(this.svg_element,this.computeRadius())}draw(){var t;(t=this.parent)==null||t.appendChild(this.svg_element)}};u(xs,"QEPoint");let Gt=xs;const ws=class ws extends re{constructor(t,e,s,i=new kt){super(t,e,s,i),this.__data__=t,this.parent=e,this.graph=s,this.__children__=i,this.__name__="trajectory",this._path_el=null,this._segments_group=null,this._tip_el=null,this._points_group=null,this.svg_element=this.create()}graphUnitsForPixels(t){var i;const e=this.graph.__data__.extremes.x_max||1,s=((i=this.graph.svg_element)==null?void 0:i.getBoundingClientRect().width)||0;return s>0?t*(2*e/s):t*e*.006}create(){const t=document.createElementNS("http://www.w3.org/2000/svg","g");t.setAttribute("class","qe-trajectory-group");const e=document.createElementNS("http://www.w3.org/2000/svg","path");e.setAttribute("fill","none"),e.setAttribute("stroke",this.__data__.color.toString()),e.setAttribute("stroke-width",this.graphUnitsForPixels(this.__data__.strokeWidth).toString()),t.appendChild(e),this._path_el=e;const s=document.createElementNS("http://www.w3.org/2000/svg","g");s.setAttribute("class","qe-trajectory-segments"),t.appendChild(s),this._segments_group=s;const i=document.createElementNS("http://www.w3.org/2000/svg","g");if(i.setAttribute("class","qe-trajectory-points"),t.appendChild(i),this._points_group=i,this.__data__.showTips){const n=document.createElementNS("http://www.w3.org/2000/svg","circle");n.setAttribute("fill",this.__data__.color.toString()),n.setAttribute("r",this.graphUnitsForPixels(4).toString()),n.setAttribute("stroke","#ffffff"),n.setAttribute("stroke-width",this.graphUnitsForPixels(1.5).toString()),t.appendChild(n),this._tip_el=n}return this.svg_element=t,t}update(){this.svg_element||this.create(),this.svg_element.parentElement||this.parent.appendChild(this.svg_element);const t=this.__data__.path;if(this._path_el&&(this._path_el.setAttribute("d",t),this._path_el.setAttribute("stroke",this.__data__.color.toString()),this._path_el.setAttribute("stroke-width",this.graphUnitsForPixels(this.__data__.strokeWidth).toString()),this._path_el.style.display=this.__data__.lineStyle==="tapered"?"none":"block"),this._segments_group)if(this._segments_group.innerHTML="",this.__data__.lineStyle==="tapered"){const s=this.__data__.pathPoints,i=s.length-1,[n,r]=this.__data__.strokeWidthRange,[a,h]=this.__data__.opacityRange;for(let o=0;o<i;o++){const l=s[o],_=s[o+1],g=i<=1?1:o/(i-1),c=n+(r-n)*g,E=a+(h-a)*g,p=document.createElementNS("http://www.w3.org/2000/svg","path");p.setAttribute("d",`M${l.x},${l.y} L${_.x},${_.y}`),p.setAttribute("fill","none"),p.setAttribute("stroke",this.__data__.color.toString()),p.setAttribute("stroke-linecap","round"),p.setAttribute("stroke-linejoin","round"),p.setAttribute("stroke-width",this.graphUnitsForPixels(c).toString()),p.setAttribute("opacity",E.toString()),this._segments_group.appendChild(p)}this._segments_group.style.display="block"}else this._segments_group.style.display="none";const e=this.__data__.activePoints;if(this._points_group&&(this.__data__.showPoints&&e.length>0?(this._points_group.innerHTML="",e.forEach(s=>{var n;const i=document.createElementNS("http://www.w3.org/2000/svg","circle");i.setAttribute("cx",s.x.toString()),i.setAttribute("cy",s.y.toString()),i.setAttribute("r",this.graphUnitsForPixels(2.5).toString()),i.setAttribute("fill",this.__data__.color.toString()),i.setAttribute("opacity","0.7"),(n=this._points_group)==null||n.appendChild(i)}),this._points_group.style.display="block"):this._points_group.style.display="none"),this._tip_el&&this.__data__.showTips)if(e.length>0){const s=e[e.length-1];this._tip_el.setAttribute("cx",s.x.toString()),this._tip_el.setAttribute("cy",s.y.toString()),this._tip_el.setAttribute("fill",this.__data__.color.toString()),this._tip_el.setAttribute("r",this.graphUnitsForPixels(4).toString()),this._tip_el.setAttribute("stroke-width",this.graphUnitsForPixels(1.5).toString()),this._tip_el.style.display="block"}else this._tip_el.style.display="none"}draw(){this.svg_element&&!this.svg_element.parentElement&&this.parent.appendChild(this.svg_element),this.update()}};u(ws,"QETrajectory");let oe=ws;const{ArrayTools:zs}=ee,As=class As extends Array{constructor(...t){super(...t)}search(t,e){let s;function i(r){return r.name===e?r:void 0}u(i,"fn");function n(r,a,h=null){if(zs.isArray(r)){for(const[o,l]of r.entries())if(s=n(l,o,h),s)return s}else{if(s=i(r),s)return s;if(r&&zs.isArray(r[t])){for(const[o,l]of r[t].entries())if(s=n(l,o,r),s)return s}}return s}return u(n,"recurse"),n(this)}flatten(){return this.reduce((t,e)=>(t.push(e),e.layers&&Array.isArray(e.layers)&&t.push(...e.layers),t),[])}};u(As,"QEArray");let kt=As;const Ai={AxisPoint:Gt,AxisLine:wt,Point:Gt,Line:wt,Edge:wt,TaperedEdge:wt,TaperedWeightedMidpointEdge:wt,NodeEdge:wt,Trajectory:oe},Vt=class Vt{constructor(t,e,s,i=new kt){this.__data__=t,this.parent=e,this.graph=s,this.__children__=i,this.__name__=t.name||"unnamed-layer",t.__state__.addListener("layer_updated","live",({key:n,newValue:r,oldValue:a})=>{const h=u(g=>{var c;return(c=g.__data__)==null?void 0:c.ID},"childId"),o=this.__children__.filter(g=>!r.objects.has(h(g))),l=this.__children__.filter(g=>r.objects.has(h(g)));[...r.objects.values()].filter(g=>!this.__children__.some(c=>h(c)===g.ID)).forEach(g=>{const c=g._typeName||g.constructor.name;let E=Ai[c];E||(g instanceof se?E=oe:g instanceof J?E=Gt:E=wt);const p=new E(g,this.svg_element,this.graph);this.__children__.push(p)}),l.forEach(g=>{const c=r.objects.get(h(g));c&&(g.__data__=c),g.update()}),o.forEach(g=>{g.svg_element.parentElement&&g.svg_element.parentElement.removeChild(g.svg_element);const c=this.__children__.indexOf(g);c>=0&&this.__children__.splice(c,1)}),this.update()}),this.svg_element=this.create()}get name(){return this.__name__}create(){if(!this.__data__)throw new Error("Layer is null");let t=this.__data__;return this.svg_element=document.createElementNS("http://www.w3.org/2000/svg",Vt.tagName),this.svg_element.setAttribute("data-layer-name",t.name),this.svg_element.setAttribute("data-layer-id",t.ID),this.svg_element.__data__=t,this.svg_element.classList.add("ena-layer"),this.__data__.layers&&this.__data__.layers.length>0&&this.__data__.layers.forEach(e=>{const s=new Vt(e,this.svg_element,this.graph);this.__children__.push(s)}),this.svg_element}update(){if(!this.__data__)throw new Error("Layer is null");this.__data__.visible&&(this.parent.nodeName.toLowerCase(),this.__children__.forEach(t=>{t.update()}),this.__data__.scale_objects===!0&&this.__name__)}draw(){var t;(t=this.parent)==null||t.appendChild(this.svg_element),this.__children__.forEach(e=>{e.draw()})}add(t){this.__children__.push(t)}};u(Vt,"QELayer"),Vt.tagName="g";let Oe=Vt;const vs=class vs{constructor(t,e,s,i,n=H.DISPLAY_TYPES.ON,r=H.POSITION.OBJECT,a,h){this.text=t,this.point=e,this.parent=s,this.graph=i,this.displayMode=n,this.position=r,this.customX=a,this.customY=h,this._visible=!1,this._offsetX=0,this._offsetY=0,this.pinned=!1,this.svg_element=this._create(),n===H.DISPLAY_TYPES.ON?(this._visible=!0,this.svg_element.setAttribute("display","block")):(this._visible=!1,this.svg_element.setAttribute("display","none"))}_create(){const t=document.createElementNS("http://www.w3.org/2000/svg","text");return t.textContent=this.text,t.setAttribute("data-label-for",this.point.ID),t.setAttribute("pointer-events","auto"),t.style.cursor="grab",this._attachDrag(t),this.parent.appendChild(t),t}_attachDrag(t){t.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation();const s=t.ownerSVGElement;if(!s)return;const i=u((l,_)=>{const g=s.createSVGPoint();g.x=l,g.y=_;const c=s.getScreenCTM();return c?g.matrixTransform(c.inverse()):{x:0,y:0}},"toUser"),n=i(e.clientX,e.clientY),r=this._offsetX,a=this._offsetY;t.style.cursor="grabbing";const h=u(l=>{const _=i(l.clientX,l.clientY);this._offsetX=r+(_.x-n.x),this._offsetY=a+(_.y-n.y),this.pinned=!0,this._visible=!0,this.svg_element.setAttribute("display","block"),this.update()},"onMove"),o=u(()=>{document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",o),t.style.cursor="grab",this.graph.dispatchEvent(new CustomEvent("qe-label-move",{detail:{id:this.point.ID,transform:{x:this._offsetX,y:this._offsetY}},bubbles:!0,composed:!0}))},"onUp");document.addEventListener("mousemove",h),document.addEventListener("mouseup",o)})}update(){var h;if(!this._visible)return;const t=this.graph.__data__.extremes.x_max;if(t<=0)return;const e=this.graph._labelFont??{},s=e.size?e.size*this.graph.unitsPerPixel():t*.06,i=s*1.2;let n,r,a;switch(this.position){case H.POSITION.STATIC:{n=this.point.x,r=this.point.y-i*.3,a="middle";break}case H.POSITION.CONTAINER:{const{cx:o,cy:l}=this.graph.__data__.extremes,_=this.point.x-o,g=this.point.y-l,c=Math.sqrt(_*_+g*g)||1,E=t*.93/c;n=o+_*E,r=l+g*E-i*.3,a=_>=0?"start":"end";break}case H.POSITION.CUSTOM:if(this.customX!=null&&this.customY!=null){n=this.customX,r=this.customY,a="start";break}default:case H.POSITION.OBJECT:{const o=this.point.x>=0?i:-i;a=this.point.x>=0?"start":"end",n=this.point.x+o,r=this.point.y-i*.4;break}}this.svg_element.setAttribute("x",n.toString()),this.svg_element.setAttribute("y",r.toString()),(this._offsetX||this._offsetY)&&this.svg_element.setAttribute("transform",`translate(${this._offsetX}, ${this._offsetY})`),this.svg_element.setAttribute("font-size",s.toString()),this.svg_element.setAttribute("font-family",e.family??"system-ui, sans-serif"),this.svg_element.setAttribute("font-weight","500"),this.svg_element.setAttribute("text-anchor",a),this.svg_element.setAttribute("fill",e.color??((h=this.point.color)==null?void 0:h.toString())??"#333333")}show(){this._visible=!0,this.svg_element.setAttribute("display","block"),this.update()}hide(){this.pinned||(this._visible=!1,this.svg_element.setAttribute("display","none"))}toggle(){this._visible?this.hide():this.show()}get visible(){return this._visible}remove(){this.svg_element.remove()}};u(vs,"QELabel");let ae=vs;const je=class je extends HTMLElement{};u(je,"QENodesElement"),je.tagName="qe-nodes";let he=je;const Ye=class Ye extends HTMLElement{};u(Ye,"QEMeansElement"),Ye.tagName="qe-means";let le=Ye;const qe=class qe extends HTMLElement{};u(qe,"QEPointsElement"),qe.tagName="qe-points";let ce=qe;const Ge=class Ge extends HTMLElement{};u(Ge,"QEEdgesElement"),Ge.tagName="qe-edges";let _e=Ge;const Ue=class Ue extends HTMLElement{};u(Ue,"QETrajectoriesElement"),Ue.tagName="qe-trajectories";let ue=Ue;const Be=class Be extends HTMLElement{};u(Be,"QEAxesElement"),Be.tagName="qe-axes";let de=Be;customElements.define(he.tagName,he),customElements.define(le.tagName,le),customElements.define(ce.tagName,ce),customElements.define(_e.tagName,_e),customElements.define(ue.tagName,ue),customElements.define(de.tagName,de);const Fs=["#4477AA","#EE6677","#228833","#CCBB44","#66CCEE","#AA3377","#BBBBBB","#000000"];function vi(d,t){for(const e of t)if(d===`${e}.${e}`)return[e,e];for(const e of t)if(d.startsWith(e+".")){const s=d.slice(e.length+1);if(t.includes(s))return[e,s]}return null}u(vi,"parseEdgePair");function Si(d,t,e,s){const i=Math.max(1,e-1),n=i>=120?1.96:i>=60?2:i>=30?2.042:i>=20?2.086:i>=10?2.228:i>=5?2.571:4.303,r=Math.sqrt(Math.max(0,d)/e)*s,a=Math.sqrt(Math.max(0,t)/e)*s;return{halfW:n*r,halfH:n*a}}u(Si,"computeCIRect");const Ei=.5;function $e(d,t,e){if(!d)return;const s=Math.min(Math.abs(t),Math.abs(e));s>0&&(d.meta={...d.meta??{},maxRadius:s*Ei})}u($e,"capMeanToInterval");function Pe(d,t,e,s=""){const i=u(o=>{const l=d.names.indexOf(o),_=l>=0?d[l]:null;if(_==null||_==="")return;const g=Number(_);return Number.isFinite(g)?g:void 0},"get"),n=i(`${t}.${s}low`)??i(`${t}_${s}low`),r=i(`${t}.${s}high`)??i(`${t}_${s}high`),a=i(`${e}.${s}low`)??i(`${e}_${s}low`),h=i(`${e}.${s}high`)??i(`${e}_${s}high`);return n==null||r==null||a==null||h==null?null:{x_low:n,x_high:r,y_low:a,y_high:h}}u(Pe,"readIntervalBounds");function Mi(d){var i,n;const t=u(r=>d.getAttribute(r),"a"),e=((i=t("colors"))==null?void 0:i.split(",").map(r=>r.trim()).filter(Boolean))??[],s=((n=t("threshold"))==null?void 0:n.split(",").map(Number).filter(Number.isFinite))??[];return{group:t("group"),unit:t("unit"),compare:t("compare"),also:t("also"),network:t("network"),colors:e.length?[e[0],e[1]??null]:null,threshold:s.length?[s[0],s.length>1?s[1]:1/0]:null,name:t("name")}}u(Mi,"parseEdgeLayer");function Ii(d){const{r:t,g:e,b:s}=tt.parseColor(d),i=Math.max(t,e,s),n=Math.min(t,e,s),r=u(a=>(i+n-a).toString(16).padStart(2,"0"),"f");return`#${r(t)}${r(e)}${r(s)}`}u(Ii,"complementColor");function Ni(d){const t=d==null?void 0:d.trim().toLowerCase();return t==="plot"||t==="absolute"?t:"model"}u(Ni,"parseColorScale");function is(d,t){switch(d==null?void 0:d.toLowerCase()){case"on":return 3;case"off":return 0;case"click":return 2;case"auto":return 1;default:return t}}u(is,"parseLabelMode");const ut=class ut extends Ne{constructor(){super(),this.zoom_level=1,this.__children__=new kt,this._hasModel=!1,this._renderPending=!1,this._childObserver=null,this._ciRects=new Map,this._outlierRects=new Map,this._ciCross=new Map,this._labelsGroup=null,this._nodeLabels=new Map,this._meanLabels=new Map,this._pointLabels=new Map,this._showAxes=!1,this._axisXText=null,this._axisYText=null,this._axisLabelEls=new Map,this._magnifyText=null,this._magnifyEl=null,this._rangeExtent=null,this._rangeMode=null,this._centerContent=!1,this._plotTitle=null,this._titleEl=null,this._resizeObs=null,this._labelFont={size:null,family:null,color:null},this._animateMs=0,this._tweenRaf=null,this._highlight={edges:new Set,nodes:new Set},this._highlightGroup=null,this._tooltipEl=null,this.graph=this,this.parent=null,this.__data__=new Ie(Ms),this.__name__=this.__data__.name||"unnamed-graph",this.svg_element=this.create(),console.log("Created ena-graph svg element: ",this.svg_element),document.addEventListener("model-updated",t=>{var qs,Gs,Us,Bs,Hs,Xs,Ws,Vs,Ks,Js,Zs,Qs,ti,ei,si;const e=((qs=t.composedPath)==null?void 0:qs.call(t)[0])??t.target;if(this._vizena&&e!==this._vizena)return;const s=t.detail;if(!s)return;this._animateMs=this.hasAttribute("animate")?parseInt(this.getAttribute("animate")||"",10)||300:0;const i=this._animateMs>0&&this._hasModel?this._captureTween():null;this._hasModel=!0;const n=s.dimensions,r=s.unit_id_col,a=s.node_id_col,h=s.group_col,o=this._readLayerConfig();this._showAxes=o.showAxes,this._axisXText=o.axisXLabel===null?null:o.axisXLabel||String((n==null?void 0:n[0])??"x"),this._magnifyText=o.edgeMagnify==null?null:`(scaled ${o.edgeMagnify.toFixed(1)}x)`,this._axisYText=o.axisYLabel===null?null:o.axisYLabel||String((n==null?void 0:n[1])??"y");const l={},_=(Gs=s.palette)!=null&&Gs.length?s.palette:Fs;if(h&&((Us=s.points)!=null&&Us.names)){const O=s.points.col(h);O&&[...new Set([...O].map(String))].forEach(($,x)=>{l[$]=_[x%_.length]})}(Bs=s.groups)!=null&&Bs.rows&&s.groups.rows().length>0&&s.groups.rows().forEach(O=>{const I=O.rowName??String(O[0]),$=O.names.indexOf("color"),x=$>=0?O[$]:null;x&&String(x)!=="NA"?l[I]=String(x):l[I]||(l[I]=_[Object.keys(l).length%_.length])});const g=Object.keys(l),c=o.activeMeanGroups&&o.activeMeanGroups.trim()?new Set(o.activeMeanGroups.split(",").map(O=>O.trim()).filter(O=>l[O])):new Set(g),E=o.scalePoints,p=u(O=>{let I=0;return O.forEach($=>{const x=$.names.indexOf(n[0]),m=n.length>1?$.names.indexOf(n[1]):-1;x>=0&&(I=Math.max(I,Math.abs(Number($[x])))),m>=0&&(I=Math.max(I,Math.abs(Number($[m]))))}),I},"getExtent"),A=(Hs=s.nodes)!=null&&Hs.rows?p(s.nodes.rows()):0,R=(Xs=s.points)!=null&&Xs.rows?p(s.points.rows()):0,q=(Ws=s.trajectories)!=null&&Ws.rows?p(s.trajectories.rows()):0,G=R>0?R:q,v=o.pointScale!==null?o.pointScale:E&&G>0&&A>0?A/G:1;this._rangeExtent=o.range==="network"?A*1.2:o.range==="points"?G*v*1.2:typeof o.range=="number"?o.range:null,this._rangeMode=o.range==="network"||o.range==="points"?o.range:typeof o.range=="number"?"number":null,this._centerContent=o.centerContent,this._plotTitle=o.plotTitle,this._labelFont=o.labelFont;const Y=o.labelNodes,rt=o.labelMeans,ht=o.labelPoints,nt=this._labelsGroup,dt=u((O,I,$,x=1)=>{const m=O.names.indexOf(I),P=O.names.indexOf(n[0]),b=n.length>1?O.names.indexOf(n[1]):-1,y=new J({ID:m>=0?String(O[m]):O.rowName||`pt-${Math.random().toString(36).slice(2)}`,dimensions:[P>=0?Number(O[P])*x:0,b>=0?-Number(O[b])*x:0],meta:{}});return $&&(y.color=new tt($)),y},"rowToPoint"),Z={},Ot=o.showPoints,Dt=s.pointsets;if(o.pointSets.length&&(Dt!=null&&Dt.rows)){const O=this.__children__.search("__children__","points"),I=u(($,x)=>{const m=$.names.indexOf(x);return m>=0?$[m]:null},"col");o.pointSets.forEach(($,x)=>{Dt.rows().forEach(m=>{if(String(I(m,"set"))!==$.set)return;const P=String(I(m,"id")),b=I(m,"group")!=null&&String(I(m,"group"))!=="NA"?String(I(m,"group")):null,y=I(m,"color")&&String(I(m,"color"))!=="NA"?String(I(m,"color")):b&&l[b]?l[b]:_[x%_.length],M=dt(m,"id",y,v);M.ID=`${$.set}::${P}`,M.size=$.size??o.pointSize??2.5;const j=I(m,"shape");j&&String(j)!=="NA"&&(M.shape=String(j));const L=I(m,"label");M.meta={stroke:"#ffffff",kind:"point",name:L!=null&&String(L)!=="NA"?String(L):P,group:b??void 0,unit:P,set:$.set,fixedSize:$.fixedSize},this.__data__.points.set(M.ID,M),O==null||O.__data__.objects.set(M.ID,M)})})}if((Vs=s.points)!=null&&Vs.rows){const O=this.__children__.search("__children__","points");if(O){s.points.rows().forEach(x=>{const m=h?x.names.indexOf(h):-1,P=m>=0?String(x[m]):null,b=P?l[P]??"#888888":"#888888";if(Ot){const y=dt(x,r,b,v);y.size=o.pointSize??2.5,y.meta={...y.meta??{},stroke:"#ffffff",kind:"point",name:y.ID,group:P??void 0,unit:y.ID,fixedSize:o.pointFixedSize},this.__data__.points.set(y.ID,y),O.__data__.objects.set(y.ID,y)}if(P){const y=x.names.indexOf(n[0]),M=n.length>1?x.names.indexOf(n[1]):-1;Z[P]||(Z[P]={x:0,y:0,x2:0,y2:0,xy:0,n:0,color:b});const j=y>=0?Number(x[y]):0,L=M>=0?Number(x[M]):0;Z[P].x+=j,Z[P].y+=L,Z[P].x2+=j*j,Z[P].y2+=L*L,Z[P].xy+=j*L,Z[P].n+=1}});const I=!!((Ks=s.groups)!=null&&Ks.rows&&s.groups.rows().length>0),$=o.showMeans&&I?s.groups.rows().filter(x=>{const m=x.rowName??String(x[0]);return c.size===0||c.has(m)}):[];if(o.showMeans){const x=O.svg_element,m=(A>0?A:1)*.008;if(I){const P=new Set($.map(b=>b.rowName??String(b[0])));this._ciRects.forEach((b,y)=>{P.has(y)||(b.remove(),this._ciRects.delete(y))}),this._outlierRects.forEach((b,y)=>{P.has(y)||(b.remove(),this._outlierRects.delete(y))}),this._ciCross.forEach((b,y)=>{P.has(y.slice(2))||(b.remove(),this._ciCross.delete(y))}),$.forEach(b=>{var k,F,z;const y=b.rowName??String(b[0]),M=l[y]??"#888888",j=b.names.indexOf(n[0]),L=n.length>1?b.names.indexOf(n[1]):-1,V=j>=0?Number(b[j])*v:0,ft=L>=0?-Number(b[L])*v:0,Q=new J({ID:`mean-${y}`,dimensions:[V,ft],meta:{kind:"mean",name:y,group:y,fixedSize:o.meanFixedSize}});Q.color=new tt(M),Q.size=4;const mt=b.names.indexOf("shape"),T=mt>=0?b[mt]:null;Q.shape=T&&String(T)!=="NA"?String(T):"rect",this.__data__.points.set(Q.ID,Q),O.__data__.objects.set(Q.ID,Q);const zt=u(N=>{const st=b.names.indexOf(N),X=st>=0?b[st]:null;return X==null||String(X)==="NA"||String(X)===""?null:X},"cell"),At=zt("intervals"),Mt=At==="box"||At==="crosshairs"||At==="none"?At:o.intervals,Ft=zt("outlier"),U=(Ft==null?o.showOutlier:Ft===!0||String(Ft)==="true")?Pe(b,n[0],n[1],"o"):null;if(!U)(k=this._outlierRects.get(y))==null||k.remove(),this._outlierRects.delete(y);else{let N=this._outlierRects.get(y);N||(N=document.createElementNS("http://www.w3.org/2000/svg","rect"),N.setAttribute("data-outlier-group",y),this._outlierRects.set(y,N)),N.setAttribute("x",(U.x_low*v).toString()),N.setAttribute("y",(-U.y_high*v).toString()),N.setAttribute("width",((U.x_high-U.x_low)*v).toString()),N.setAttribute("height",((U.y_high-U.y_low)*v).toString()),N.setAttribute("fill","none"),N.setAttribute("stroke",M),N.setAttribute("stroke-width",m.toString()),N.setAttribute("stroke-opacity","0.5"),N.setAttribute("stroke-dasharray",`${m*2} ${m*2}`),x&&!N.parentElement&&x.insertBefore(N,x.firstChild)}const f=Mt!=="none"?Pe(b,n[0],n[1]):null,w=`x:${y}`;if((!f||Mt!=="crosshairs")&&((F=this._ciCross.get(w))==null||F.remove(),this._ciCross.delete(w)),f&&Mt==="crosshairs"){(z=this._ciRects.get(y))==null||z.remove(),this._ciRects.delete(y);const N=f.x_low*v,st=f.x_high*v,X=-f.y_high*v,ot=-f.y_low*v;$e(Q,(st-N)/2,(ot-X)/2);let D=this._ciCross.get(w);D||(D=document.createElementNS("http://www.w3.org/2000/svg","path"),D.setAttribute("data-ci-group",y),D.setAttribute("data-ci-kind","crosshairs"),this._ciCross.set(w,D)),D.setAttribute("d",`M${N} ${ft} L${st} ${ft} M${V} ${X} L${V} ${ot}`),D.setAttribute("fill","none"),D.setAttribute("stroke",M),D.setAttribute("stroke-width",(m*1.25).toString()),D.setAttribute("stroke-opacity","0.8"),x&&!D.parentElement&&x.insertBefore(D,x.firstChild)}else if(f){const N=f.x_low*v,st=-f.y_high*v,X=(f.x_high-f.x_low)*v,ot=(f.y_high-f.y_low)*v;$e(Q,X/2,ot/2);let D=this._ciRects.get(y);D||(D=document.createElementNS("http://www.w3.org/2000/svg","rect"),D.setAttribute("data-ci-group",y),this._ciRects.set(y,D)),D.setAttribute("x",N.toString()),D.setAttribute("y",st.toString()),D.setAttribute("width",X.toString()),D.setAttribute("height",ot.toString()),D.setAttribute("fill","none"),D.setAttribute("stroke",M),D.setAttribute("stroke-width",m.toString()),D.setAttribute("stroke-opacity","0.8"),D.setAttribute("stroke-dasharray",`${m*4} ${m*3}`),x&&!D.parentElement&&x.insertBefore(D,x.firstChild)}else{const N=this._ciRects.get(y);N&&(N.remove(),this._ciRects.delete(y))}})}else Object.entries(Z).forEach(([b,{x:y,y:M,n:j,color:L}])=>{const V=new J({ID:`mean-${b}`,dimensions:[y/j*v,-(M/j)*v],meta:{kind:"mean",name:b,group:b,fixedSize:o.meanFixedSize}});V.color=new tt(L),V.size=4,V.shape="rect",this.__data__.points.set(V.ID,V),O.__data__.objects.set(V.ID,V)}),o.showCI&&(this._ciRects.forEach((b,y)=>{Z[y]||(b.remove(),this._ciRects.delete(y))}),(Js=s.confidence)!=null&&Js.rows?s.confidence.rows().forEach(b=>{const y=b.names.indexOf(h??"group"),M=y>=0?String(b[y]):b.rowName??null;if(!M)return;const j=l[M]??"#888888",L=Pe(b,n[0],n[1]);if(!L)return;const V=L.x_low*v,ft=-L.y_high*v,Q=(L.x_high-L.x_low)*v,mt=(L.y_high-L.y_low)*v;$e(this.__data__.points.get(`mean-${M}`),Q/2,mt/2);let T=this._ciRects.get(M);T||(T=document.createElementNS("http://www.w3.org/2000/svg","rect"),T.setAttribute("data-ci-group",M),this._ciRects.set(M,T)),T.setAttribute("x",V.toString()),T.setAttribute("y",ft.toString()),T.setAttribute("width",Q.toString()),T.setAttribute("height",mt.toString()),T.setAttribute("fill","none"),T.setAttribute("stroke",j),T.setAttribute("stroke-width",m.toString()),T.setAttribute("stroke-opacity","0.8"),T.setAttribute("stroke-dasharray",`${m*4} ${m*3}`),x&&!T.parentElement&&x.insertBefore(T,x.firstChild)}):Object.entries(Z).forEach(([b,{x:y,y:M,x2:j,y2:L,n:V,color:ft}])=>{if(V<2)return;const Q=y/V,mt=M/V,T=j/V-Q*Q,zt=L/V-mt*mt,{halfW:At,halfH:Mt}=Si(T,zt,V,v),Ft=Q*v,Jt=-mt*v;$e(this.__data__.points.get(`mean-${b}`),At,Mt);let U=this._ciRects.get(b);U||(U=document.createElementNS("http://www.w3.org/2000/svg","rect"),U.setAttribute("data-ci-group",b),this._ciRects.set(b,U)),U.setAttribute("x",(Ft-At).toString()),U.setAttribute("y",(Jt-Mt).toString()),U.setAttribute("width",(At*2).toString()),U.setAttribute("height",(Mt*2).toString()),U.setAttribute("fill","none"),U.setAttribute("stroke",ft),U.setAttribute("stroke-width",m.toString()),U.setAttribute("stroke-opacity","0.8"),U.setAttribute("stroke-dasharray",`${m*4} ${m*3}`),x&&!U.parentElement&&x.insertBefore(U,x.firstChild)})),(Zs=s.outlier)!=null&&Zs.rows&&(this._outlierRects.forEach((b,y)=>{l[y]||(b.remove(),this._outlierRects.delete(y))}),s.outlier.rows().forEach(b=>{const y=b.names.indexOf(h??"group"),M=y>=0?String(b[y]):b.rowName??null;if(!M)return;const j=l[M]??"#888888",L=Pe(b,n[0],n[1]);if(!L)return;const V=L.x_low*v,ft=-L.y_high*v,Q=(L.x_high-L.x_low)*v,mt=(L.y_high-L.y_low)*v;let T=this._outlierRects.get(M);T||(T=document.createElementNS("http://www.w3.org/2000/svg","rect"),T.setAttribute("data-outlier-group",M),this._outlierRects.set(M,T)),T.setAttribute("x",V.toString()),T.setAttribute("y",ft.toString()),T.setAttribute("width",Q.toString()),T.setAttribute("height",mt.toString()),T.setAttribute("fill","none"),T.setAttribute("stroke",j),T.setAttribute("stroke-width",m.toString()),T.setAttribute("stroke-opacity","0.5"),T.setAttribute("stroke-dasharray",`${m*2} ${m*2}`),x&&!T.parentElement&&x.insertBefore(T,x.firstChild)}))}nt&&(this._pointLabels.forEach((x,m)=>{O.__data__.objects.get(m)||(x.remove(),this._pointLabels.delete(m))}),this._meanLabels.forEach((x,m)=>{O.__data__.objects.get(`mean-${m}`)||(x.remove(),this._meanLabels.delete(m))}),ht!==0&&s.points.rows().forEach(x=>{const m=x.names.indexOf(r),P=m>=0?String(x[m]):null;if(!P)return;const b=O.__data__.objects.get(P);if(!b)return;const y=P;let M=this._pointLabels.get(P);M?ht===H.DISPLAY_TYPES.ON?M.show():M.hide():(M=new ae(y,b,nt,this,ht),this._pointLabels.set(P,M))}),rt!==0&&(I?$.map(m=>m.rowName??String(m[0])):Object.keys(Z)).forEach(m=>{const P=`mean-${m}`,b=O.__data__.objects.get(P);if(!b)return;let y=this._meanLabels.get(m);y?rt===H.DISPLAY_TYPES.ON?y.show():y.hide():(y=new ae(m,b,nt,this,rt),this._meanLabels.set(m,y))})),O.__data__.__state__.setVariable("layer_updated",O.__data__)}}const Kt=this.__children__.search("__children__","trajectories");if(o.showTrajectories&&Kt){Kt.__data__.objects.clear(),this.__data__.trajectories.clear();const O=(Qs=s.trajectories)!=null&&Qs.rows?s.trajectories:s.points;if(O!=null&&O.rows){const I={},$=o.trajectoryUnits?o.trajectoryUnits.split(",").map(m=>m.trim()):null;O.rows().forEach(m=>{const P=m.names.indexOf(r)>=0?m.names.indexOf(r):m.names.indexOf("unit")>=0?m.names.indexOf("unit"):m.names.indexOf("ENA_UNIT")>=0?m.names.indexOf("ENA_UNIT"):-1,b=P>=0?String(m[P]):m.rowName||"unit-1";if($&&!$.includes(b))return;const y=m.names.indexOf(n[0]),M=n.length>1?m.names.indexOf(n[1]):-1,j=m.names.indexOf("time")>=0?m.names.indexOf("time"):m.names.indexOf("ActivityNumber")>=0?m.names.indexOf("ActivityNumber"):m.names.indexOf("RowID")>=0?m.names.indexOf("RowID"):-1,L=j>=0?Number(m[j]):I[b]?I[b].length+1:1;y>=0&&M>=0&&(I[b]||(I[b]=[]),I[b].push({x:Number(m[y])*v,y:-Number(m[M])*v,time:L}))}),Object.keys(I).forEach((m,P)=>{const b=I[m];if(b.length===0)return;const y=_[P%_.length],M=new se({ID:`traj-${m}`,unitId:m,color:new tt(y),lineStyle:o.trajectoryLineStyle,strokeWidth:o.trajectoryStrokeWidth,strokeWidthRange:o.trajectoryStrokeWidthRange,opacityRange:o.trajectoryOpacityRange,smooth:o.trajectorySmooth,maxDegree:o.trajectoryMaxDegree,degreeSelection:o.trajectoryDegreeSelection,currentTime:o.trajectoryPlayhead??1/0,showPoints:o.trajectoryShowPoints,showTips:o.trajectoryShowTips,points:b.map(j=>({x:j.x,y:j.y,time:j.time}))});this.__data__.trajectories.set(m,M),Kt.__data__.objects.set(M.ID,M)})}Kt.__data__.__state__.setVariable("layer_updated",Kt.__data__)}const gt=this.__children__.search("__children__","network"),Ee=gt==null?void 0:gt.__children__.search("__children__","edges"),yt=gt==null?void 0:gt.__children__.search("__children__","nodes"),Xe=gt==null?void 0:gt.__children__.search("__children__","edgenodes"),Oi=o.showEdges;if((ti=s.nodes)!=null&&ti.rows&&yt){if(s.nodes.rows().forEach(I=>{const $=dt(I,a,"#444444");$.size=2;const x=I.names.indexOf("label"),m=x>=0?I[x]:null;$.meta={...$.meta??{},kind:"node",name:m!=null&&String(m)!=="NA"&&String(m)!==""?String(m):$.ID},yt.__data__.objects.set($.ID,$)}),Oi&&Ee&&((ei=s.edges)!=null&&ei.rows)){const I={};h&&((si=s.points)!=null&&si.rows)&&s.points.rows().forEach(f=>{const w=f.names.indexOf(r),k=f.names.indexOf(h);w>=0&&k>=0&&(I[String(f[w])]=String(f[k]))});const $=s.nodes.rows().map(f=>{const w=f.names.indexOf(a);return w>=0?String(f[w]):""}).filter(Boolean),x=[];(s.edges.names??[]).forEach(f=>{const w=vi(f,$);w&&x.push({col:f,pair:w})});const m=u(f=>{const w={};return s.edges.rows().forEach(k=>{const F=k.names.indexOf(r);F<0||String(k[F])!==f||x.forEach(({col:z})=>{const N=k.names.indexOf(z);N>=0&&(w[z]=Number(k[N])||0)})}),w},"getUnitEdges"),P=u(f=>{const w={};let k=0;if(s.edges.rows().forEach(z=>{const N=z.names.indexOf(r),st=N>=0?String(z[N]):null,X=h?z.names.indexOf(h):-1;(X>=0?String(z[X]):st?I[st]:null)===f&&(k++,x.forEach(({col:D})=>{const xt=z.names.indexOf(D);if(xt>=0){const K=Number(z[xt]);isNaN(K)||(w[D]=(w[D]??0)+K)}}))}),k===0)return{};const F={};return x.forEach(({col:z})=>{F[z]=(w[z]??0)/k}),F},"getGroupEdges"),b=u(f=>{if(l[f])return{weights:P(f),color:l[f],label:f};const w=I[f]??null,k=w?l[w]??"#888888":"#888888";return{weights:m(f),color:k,label:f}},"resolve"),y=[],M=u(f=>{var z;const w=s.networks,k=(z=w==null?void 0:w.rows)==null?void 0:z.call(w).find(N=>N.rowName===f);if(!k)return null;const F={};return x.forEach(({col:N})=>{const st=k.names.indexOf(N);if(st>=0){const X=Number(k[st]);Number.isFinite(X)&&(F[N]=X)}}),F},"networkRow"),j=u((f,w)=>{if(!w)return f;const k=Math.abs(f);return k<w[0]?0:k>w[1]?Math.sign(f)*w[1]:f},"thresholded");o.edgeLayers.forEach((f,w)=>{const k=u((K,lt,et,vt,ct)=>{et=j(et,f.threshold),!(Math.abs(et)<1e-6)&&y.push({col:`${w}:${K}`,pair:lt,weight:Math.abs(et),color:vt,layer:w,...ct})},"push"),F=u((K,lt)=>f.colors?[f.colors[0],f.colors[1]??Ii(f.colors[0])]:[K,lt],"signColors");if(f.network){const K=M(f.network);if(!K)return;const[lt,et]=F(_[0],_[1]),vt={name:f.name??f.network};x.forEach(({col:ct,pair:ii})=>{const We=K[ct]??0;k(ct,ii,We,We>=0?lt:et,vt)});return}const z=f.unit??f.group??null;if(!z)return;const N=b(z),st=f.compare??f.also??null,X=st?b(st):null,ot={name:f.name??z,group:f.group??void 0,unit:f.unit??void 0},[D,xt]=F(N.color,(X==null?void 0:X.color)??N.color);X&&f.compare?x.forEach(({col:K,pair:lt})=>{const et=(N.weights[K]??0)-(X.weights[K]??0);k(K,lt,et,et>0?D:xt,ot)}):X&&f.also?x.forEach(({col:K,pair:lt})=>{const et=N.weights[K]??0,vt=X.weights[K]??0;et>0&&k(K+"-a",lt,et,D,ot),vt>0&&k(K+"-b",lt,vt,xt,{...ot,name:f.also??void 0,group:f.also??void 0})}):x.forEach(({col:K,pair:lt})=>{const et=N.weights[K]??0;et>0&&k(K,lt,et,D,ot)})}),y.sort((f,w)=>w.weight-f.weight);const L=!!s.directed,V=bi(o.edgeWidth)*(o.edgeMagnify??1),ft=u(f=>{const w=f.map(Math.abs).filter(k=>k>0);return w.length?[Math.min(...w),Math.max(...w)]:[0,0]},"rangeOf"),Q=u(f=>{const w=[];return x.forEach(({col:k,pair:F})=>{if(F[0]===F[1]!==f)return;const z=s.edges.col(k);if(z)for(const N of z)w.push(Number(N))}),ft(w)},"modelRange"),mt=u(f=>ft(y.filter(w=>w.pair[0]===w.pair[1]===f).map(w=>w.weight)),"plotRange"),T=o.edgeColorScale,zt=u(f=>T==="plot"?mt(f):Q(f),"colourRange"),At=zt(!1),Mt=zt(!0),Ft=u((f,w)=>{if(T==="absolute"){const z=Math.min(1,Math.abs(f));return{saturation:z,opacity:z}}const[k,F]=w?Mt:At;return{saturation:Ts(f,k,F,_i),opacity:Ts(f,k,F,ui)}},"colourOf"),Jt={};y.forEach(({pair:f,weight:w})=>{if(f[0]===f[1]&&!L)return;const F=u(z=>{Jt[z]=(Jt[z]??0)+Math.abs(w)},"add");if(L){F(f[1]);return}F(f[0]),F(f[1])}),s.nodes.rows().forEach(f=>{const w=f.names.indexOf(a),k=w>=0?String(f[w]):"";if(!k)return;const F=yt.__data__.objects.get(k);if(!F)return;const z=Jt[k]??0,N=!(z>0);F.size=N?o.hideUnconnectedNodes?0:pi:yi(z,V),F.meta={...F.meta??{},hidden:N&&o.hideUnconnectedNodes}});const U={};L&&y.forEach(({pair:f,weight:w,layer:k})=>{const F=`${k}:${f[0]}.${f[1]}`;U[F]=(U[F]??0)+w}),y.forEach(({col:f,pair:w,weight:k,color:F,layer:z,name:N,group:st,unit:X})=>{const ot=yt.__data__.objects.get(w[0]),D=yt.__data__.objects.get(w[1]);if(!ot||!D)return;const xt=w[0]===w[1];if(xt&&!L)return;const{saturation:K,opacity:lt}=Ft(k,xt),et=new J({ID:`${w[0]}-src`,dimensions:[ot.x,ot.y],meta:{}}),vt=new J({ID:`${w[1]}-dst`,dimensions:[D.x,D.y],meta:{}});let ct;if(xt)ct=new ne({},et,vt),ct.weight=0;else if(L){const We=U[`${z}:${w[0]}.${w[1]}`]??k,$i=U[`${z}:${w[1]}.${w[0]}`]??0,Pi=We+$i;ct=new ss({weight:k,totalweight:Pi},et,vt)}else ct=new Yt({},et,vt);ct.ID=`edge-${f}`,ct.color=new tt(F),ct.meta={isMeanEdge:!0,weight:k,widthFrac:V,saturation:K,opacity:lt,isDirected:L,isSelf:xt,source:w[0],target:w[1],group:st,unit:X,layer:N},(xt?Xe??Ee:Ee).__data__.objects.set(ct.ID,ct)}),Ee.__data__.__state__.setVariable("layer_updated",Ee.__data__),Xe&&Xe.__data__.__state__.setVariable("layer_updated",Xe.__data__)}const O=o.showNodes;yt.svg_element&&(yt.svg_element.style.display=O?"":"none"),O||(this._nodeLabels.forEach(I=>I.remove()),this._nodeLabels.clear()),nt&&Y!==0&&O&&(this._nodeLabels.forEach((I,$)=>{yt.__data__.objects.get($)||(I.remove(),this._nodeLabels.delete($))}),s.nodes.rows().forEach(I=>{var y,M,j;const $=I.names.indexOf(a),x=$>=0?String(I[$]):"";if(!x)return;const m=yt.__data__.objects.get(x);if(!m)return;if((y=m.meta)!=null&&y.hidden){(M=this._nodeLabels.get(x))==null||M.remove(),this._nodeLabels.delete(x);return}const P=String(((j=m.meta)==null?void 0:j.name)??x);let b=this._nodeLabels.get(x);b&&b.text!==P&&(b.remove(),this._nodeLabels.delete(x),b=void 0),b?Y===H.DISPLAY_TYPES.ON?b.show():b.hide():(b=new ae(P,m,nt,this,Y),this._nodeLabels.set(x,b))})),yt.__data__.__state__.setVariable("layer_updated",yt.__data__)}const js=this.__children__.search("__children__","axis_points"),Ys=this.__children__.search("__children__","axis_lines");js&&this.__data__.__state__.setVariable("graph_updated_axis_points",js.__data__.objects),Ys&&this.__data__.__state__.setVariable("graph_updated_axis_lines",Ys.__data__.objects),this.update(),i&&this._runTween(i)})}static get observedAttributes(){return["width","height","for","scale-points","point-scale","center","labels","label-nodes","label-means","label-points"]}get vizena(){return this._vizena}unitsPerPixel(){var i,n;const t=this.__data__.extremes.x_max||1,e=(n=(i=this.svg_element)==null?void 0:i.getBoundingClientRect)==null?void 0:n.call(i),s=this.zoom_level||1;return e&&e.width>0?2*t/e.width/s:t*.004}_scheduleRerender(){!this._vizena||!this._hasModel||this._renderPending||(this._renderPending=!0,queueMicrotask(()=>{var t;this._renderPending=!1,(t=this._vizena)==null||t.dispatchEvent(new CustomEvent("model-updated",{detail:this._vizena.model,bubbles:!0,composed:!0}))}))}_readLayerConfig(){var g;const t=this.querySelector("qe-nodes"),e=this.querySelector("qe-means"),s=[...this.querySelectorAll("qe-points")],i=s.find(c=>!c.hasAttribute("set"))??null,n=s.filter(c=>c.hasAttribute("set")),r=[...this.querySelectorAll("qe-edges")],a=u(c=>{var E;return((E=r.find(p=>p.hasAttribute(c)))==null?void 0:E.getAttribute(c))??null},"firstAttr"),h=r.find(c=>c.hasAttribute("magnify")),o=this.querySelector("qe-trajectories"),l=this.querySelector("qe-axes"),_=this.getAttribute("labels");return{labelNodes:is((t==null?void 0:t.getAttribute("label"))??this.getAttribute("label-nodes")??_,H.DISPLAY_TYPES.ON),showNodes:!!t,range:(()=>{const c=this.getAttribute("range");if(c==="network"||c==="points")return c;const E=Number(c);return c!=null&&Number.isFinite(E)&&E>0?E:null})(),plotTitle:this.getAttribute("plot-title")||null,labelFont:{size:(()=>{const c=Number(this.getAttribute("label-font-size"));return Number.isFinite(c)&&c>0?c:null})(),family:this.getAttribute("label-font-family")||null,color:this.getAttribute("label-font-color")||null},edgeWidth:(()=>{const c=Number(this.getAttribute("edge-width"));return Number.isFinite(c)&&c>0&&c<=1?c:ci})(),hideUnconnectedNodes:((g=t==null?void 0:t.getAttribute("unconnected"))==null?void 0:g.toLowerCase())==="hide",scalePoints:this.getAttribute("scale-points")!=="false",pointScale:(()=>{const c=Number(this.getAttribute("point-scale"));return this.hasAttribute("point-scale")&&Number.isFinite(c)&&c>0?c:null})(),centerContent:this.getAttribute("center")==="content",showMeans:!!e,activeMeanGroups:(e==null?void 0:e.getAttribute("groups"))??null,showCI:!!e&&e.hasAttribute("confidence"),intervals:(()=>{const c=e==null?void 0:e.getAttribute("intervals");return c==="box"||c==="crosshairs"||c==="none"?c:e!=null&&e.hasAttribute("confidence")?"box":"none"})(),showOutlier:!!e&&e.hasAttribute("outlier"),labelMeans:is((e==null?void 0:e.getAttribute("label"))??this.getAttribute("label-means")??_,H.DISPLAY_TYPES.ON),meanFixedSize:!!e&&e.hasAttribute("fixed-size"),showPoints:!!i,pointSets:n.map(c=>({set:c.getAttribute("set"),size:c.getAttribute("size")?parseFloat(c.getAttribute("size")):null,fixedSize:c.hasAttribute("fixed-size")})),labelPoints:is((i==null?void 0:i.getAttribute("label"))??this.getAttribute("label-points")??_,H.DISPLAY_TYPES.OFF),pointSize:i!=null&&i.getAttribute("size")?parseFloat(i.getAttribute("size")):null,pointFixedSize:!!i&&i.hasAttribute("fixed-size"),showEdges:r.length>0,edgeLayers:r.map(Mi),edgeColorScale:Ni(a("color-scale")),edgeMagnify:h?(()=>{const c=Number(h.getAttribute("magnify"));return Number.isFinite(c)&&c>0?c:1})():null,showTrajectories:!!o,trajectoryUnits:(o==null?void 0:o.getAttribute("units"))??null,trajectorySmooth:(o==null?void 0:o.getAttribute("smooth"))??"none",trajectoryMaxDegree:o!=null&&o.getAttribute("max-degree")?parseInt(o.getAttribute("max-degree"),10):3,trajectoryDegreeSelection:(o==null?void 0:o.getAttribute("degree-selection"))??"loocv_2d",trajectoryShowPoints:(o==null?void 0:o.getAttribute("points"))!=="false",trajectoryShowTips:(o==null?void 0:o.getAttribute("tips"))!=="false",trajectoryPlayhead:o!=null&&o.getAttribute("playhead")?parseFloat(o.getAttribute("playhead")):null,trajectoryLineStyle:(o==null?void 0:o.getAttribute("line-style"))??"uniform",trajectoryStrokeWidth:o!=null&&o.getAttribute("stroke-width")?parseFloat(o.getAttribute("stroke-width")):2,trajectoryStrokeWidthRange:this._parseNumberPair(o==null?void 0:o.getAttribute("stroke-width-range"),[1,6]),trajectoryOpacityRange:this._parseNumberPair(o==null?void 0:o.getAttribute("opacity-range"),[.3,1]),showAxes:!!l,axisXLabel:l!=null&&l.hasAttribute("x")?l.getAttribute("x")??"":null,axisYLabel:l!=null&&l.hasAttribute("y")?l.getAttribute("y")??"":null}}_parseNumberPair(t,e){if(!t)return e;const s=t.split(",").map(i=>Number(i.trim()));return s.length<2||!s.every(Number.isFinite)?e:[s[0],s[1]]}attributeChangedCallback(t,e,s){e!==s&&this._scheduleRerender()}connectedCallback(){var n;const t=this.getAttribute("width"),e=this.getAttribute("height");this.style.display="block",t&&(this.style.width=isNaN(Number(t))?t:`${t}px`),e&&(this.style.height=isNaN(Number(e))?e:`${e}px`),this.appendChild(this.svg_element),ut._instances.add(this),this._childObserver=new MutationObserver(()=>this._scheduleRerender()),this._childObserver.observe(this,{childList:!0,attributes:!0,subtree:!0,attributeFilter:["group","unit","compare","also","color-scale","magnify","network","colors","threshold","name","groups","confidence","label","intervals","outlier","set","unconnected","scale-points","point-scale","edge-width","labels","range","center","plot-title","label-font-size","label-font-family","label-font-color","label-nodes","label-means","label-points","units","smooth","degree","points","tips","playhead","line-style","stroke-width","stroke-width-range","opacity-range","x","y","size","fixed-size"]});const s=this.getAttribute("for");this._vizena=(s?document.getElementById(s):null)??this.closest("qe-visual")??((n=this.parentElement)==null?void 0:n.closest("qe-visual"))??document.querySelector("qe-visual"),this.draw();const i=this.__children__.search("__children__","labels");if(i!=null&&i.svg_element)this._labelsGroup=i.svg_element;else{console.warn("[ena-graph] labels layer not found in layer tree; creating fallback <g>");const r=this.__children__[0];r!=null&&r.svg_element&&(this._labelsGroup=document.createElementNS("http://www.w3.org/2000/svg","g"),this._labelsGroup.setAttribute("data-layer-name","labels-fallback"),r.svg_element.appendChild(this._labelsGroup))}}disconnectedCallback(){var t,e,s;(t=this._childObserver)==null||t.disconnect(),this._childObserver=null,(e=this._resizeObs)==null||e.disconnect(),this._resizeObs=null,ut._instances.delete(this),(s=this._tooltipEl)==null||s.remove(),this._tooltipEl=null}static instances(){return[...ut._instances]}static getGraph(t){for(const e of ut._instances)if(e.id===t||e.getAttribute("plot-group")===t)return e;return null}getNodes(){const t=this.__children__.search("__children__","nodes");return t?[...t.__data__.objects.values()].map(e=>{var s;return{id:e.ID,name:((s=e.meta)==null?void 0:s.name)??e.ID,x:e.x,y:e.y}}):[]}getEdges(){const t=u(e=>{const s=this.__children__.search("__children__",e);return s?[...s.__data__.objects.values()]:[]},"collect");return[...t("edges"),...t("edgenodes")].map(e=>{const s=e.meta??{};return{source:s.source,target:s.target,weight:s.weight??0,directed:!!s.isDirected,self:!!s.isSelf}}).filter(e=>e.source!=null&&e.target!=null)}_tweenTargets(){return[...this.svg_element.querySelectorAll("circle[data-point-id], rect[data-point-id], line[data-edge-source], path[data-edge-source]")]}_readCoords(t){const e=t.tagName.toLowerCase(),s=u(i=>parseFloat(t.getAttribute(i)||"0"),"n");if(e==="circle")return{t:"c",cx:s("cx"),cy:s("cy")};if(e==="rect")return{t:"r",x:s("x"),y:s("y")};if(e==="line")return{t:"l",x1:s("x1"),y1:s("y1"),x2:s("x2"),y2:s("y2")};if(e==="path"){const i=t.getAttribute("d")||"";return{t:"p",d:i,nums:(i.match(ut._PATH_NUM_RE)||[]).map(Number)}}return null}_captureTween(){const t=new Map;return this._tweenTargets().forEach(e=>{const s=this._readCoords(e);s&&t.set(e,s)}),t}_runTween(t){this._tweenRaf!==null&&(cancelAnimationFrame(this._tweenRaf),this._tweenRaf=null);const e=new Map;if(this._tweenTargets().forEach(h=>{if(t.has(h)){const o=this._readCoords(h);o&&e.set(h,o)}}),!e.size)return;const s=this._animateMs,i=performance.now(),n=u(h=>h<.5?2*h*h:1-Math.pow(-2*h+2,2)/2,"ease"),r=u((h,o,l)=>h+(o-h)*l,"lerp"),a=u(h=>{const o=Math.min(1,(h-i)/s),l=n(o);e.forEach((_,g)=>{const c=t.get(g);if(!(!c||c.t!==_.t))if(_.t==="c")g.setAttribute("cx",String(r(c.cx,_.cx,l))),g.setAttribute("cy",String(r(c.cy,_.cy,l)));else if(_.t==="r")g.setAttribute("x",String(r(c.x,_.x,l))),g.setAttribute("y",String(r(c.y,_.y,l)));else if(_.t==="l")g.setAttribute("x1",String(r(c.x1,_.x1,l))),g.setAttribute("y1",String(r(c.y1,_.y1,l))),g.setAttribute("x2",String(r(c.x2,_.x2,l))),g.setAttribute("y2",String(r(c.y2,_.y2,l)));else{if(!c.nums||c.nums.length!==_.nums.length)return;let E=0;const p=_.d.replace(ut._PATH_NUM_RE,()=>String(r(c.nums[E],_.nums[E++],l)));g.setAttribute("d",p)}}),this._tweenRaf=o<1?requestAnimationFrame(a):null},"step");this._tweenRaf=requestAnimationFrame(a)}toSVG(){const t=this.svg_element.cloneNode(!0);t.setAttribute("xmlns","http://www.w3.org/2000/svg"),t.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink");const e=this.svg_element.getBoundingClientRect();return e.width&&t.setAttribute("width",String(Math.round(e.width))),e.height&&t.setAttribute("height",String(Math.round(e.height))),new XMLSerializer().serializeToString(t)}toPNG(t=2){const e=this.toSVG(),s=this.svg_element.getBoundingClientRect(),i=Math.max(1,Math.round(s.width)),n=Math.max(1,Math.round(s.height));return new Promise((r,a)=>{const h=new Blob([e],{type:"image/svg+xml;charset=utf-8"}),o=URL.createObjectURL(h),l=new Image;l.onload=()=>{try{const _=document.createElement("canvas");_.width=i*t,_.height=n*t;const g=_.getContext("2d");if(!g){URL.revokeObjectURL(o),a(new Error("no 2d context"));return}g.scale(t,t),g.drawImage(l,0,0,i,n),URL.revokeObjectURL(o),r(_.toDataURL("image/png"))}catch(_){URL.revokeObjectURL(o),a(_)}},l.onerror=_=>{URL.revokeObjectURL(o),a(_)},l.src=o})}getPoints(){const t=this.__children__.search("__children__","points");return t?[...t.__data__.objects.values()].filter(e=>{var s;return((s=e.meta)==null?void 0:s.kind)==="point"}).map(e=>{var s,i,n;return{id:((s=e.meta)==null?void 0:s.unit)??e.ID,group:(i=e.meta)==null?void 0:i.group,set:(n=e.meta)==null?void 0:n.set,x:e.x,y:e.y}}):[]}pointsInRect(t){return this.getPoints().filter(e=>e.x>=t.x&&e.x<=t.x+t.w&&e.y>=t.y&&e.y<=t.y+t.h).map(e=>e.id)}_edgeKey(t,e){return t<=e?`${t}\0${e}`:`${e}\0${t}`}setHighlight(t){this._highlight.edges=new Set((t.edges??[]).map(e=>this._edgeKey(e.source,e.target))),this._highlight.nodes=new Set((t.nodes??[]).map(String)),this._applyHighlights()}clearHighlight(){this._highlight.edges.clear(),this._highlight.nodes.clear(),this._applyHighlights()}_applyHighlights(){if(!this.svg_element)return;this._highlightGroup||(this._highlightGroup=document.createElementNS("http://www.w3.org/2000/svg","g"),this._highlightGroup.setAttribute("data-layer-name","highlight"),this._highlightGroup.setAttribute("pointer-events","none")),this.svg_element.appendChild(this._highlightGroup);const t=this._highlightGroup;t.textContent="";const e=this.__data__.extremes.x_max||1,s="#f5a623",i=u((n,r)=>{const a=document.createElementNS("http://www.w3.org/2000/svg",n);for(const h in r)a.setAttribute(h,String(r[h]));return a},"mk");if(this._highlight.edges.size){const n={};this.getNodes().forEach(r=>{n[r.id]={x:r.x,y:r.y}}),this._highlight.edges.forEach(r=>{const[a,h]=r.split("\0"),o=n[a],l=n[h];!o||!l||t.appendChild(i("line",{x1:o.x,y1:o.y,x2:l.x,y2:l.y,stroke:s,"stroke-width":e*.02,"stroke-opacity":.6,"stroke-linecap":"round"}))})}this._highlight.nodes.forEach(n=>{var _;const r=this.svg_element.querySelector(`[data-point-id="${(_=window.CSS)!=null&&_.escape?CSS.escape(n):n}"]`);if(!r)return;const a=r.tagName.toLowerCase();let h,o,l;if(a==="rect"){const g=parseFloat(r.getAttribute("width")||"0");h=parseFloat(r.getAttribute("x")||"0")+g/2,o=parseFloat(r.getAttribute("y")||"0")+parseFloat(r.getAttribute("height")||"0")/2,l=g/2}else h=parseFloat(r.getAttribute("cx")||"0"),o=parseFloat(r.getAttribute("cy")||"0"),l=parseFloat(r.getAttribute("r")||"0");t.appendChild(i("circle",{cx:h,cy:o,r:l*1.7+e*.004,fill:"none",stroke:s,"stroke-width":e*.006}))})}create(){const t=document.createElementNS("http://www.w3.org/2000/svg","svg");t.classList.add("graph"),t.style.display="block",t.style.width="100%",t.style.height="100%",t.setAttribute("preserveAspectRatio","xMidYMid meet"),t.setAttribute("viewBox",this.__data__.extremes.as_viewBox()),t.setAttribute("transform",this.__data__.transform.toString()),t.setAttribute("role","figure"),t.setAttribute("data-graph-size",`${Math.min(this.__data__.extremes.width,this.__data__.extremes.height)}`),this.svg_element=t;const e=document.createElementNS("http://www.w3.org/2000/svg","defs"),s=.22,i=.15,n=u((r,a)=>{const h=document.createElementNS("http://www.w3.org/2000/svg","marker");h.setAttribute("id",r),h.setAttribute("markerWidth",String(s)),h.setAttribute("markerHeight",String(i)),h.setAttribute("refX",String(s)),h.setAttribute("refY",String(i/2)),h.setAttribute("orient","auto"),h.setAttribute("markerUnits","userSpaceOnUse");const o=document.createElementNS("http://www.w3.org/2000/svg","path");o.setAttribute("d",`M0,0 L0,${i} L${s},${i/2} z`),o.setAttribute("fill",a),h.appendChild(o),e.appendChild(h)},"makeArrow");return Fs.forEach(r=>n(`qe-arrow-${r.slice(1)}`,r)),t.appendChild(e),this.__data__.layers.forEach(r=>{const a=new Oe(r,this.svg_element,this);this.__children__.push(a)}),this.__data__.__state__.setVariable("graph_updated",this.__data__),this.attach_events(),t}attach_events(){this.svg_element.addEventListener("wheel",o=>{console.log("Wheel event: ",o),o.preventDefault(),Math.sign(o.deltaY)<0?this.zoom_level*=1.1:this.zoom_level/=1.1,this.__data__.transform.zoom(this.zoom_level),this.update()});let t=!1,e,s;this.svg_element.addEventListener("mousedown",o=>{t=!0,e=o.clientX,s=o.clientY});let i=null,n=null;const r=u(()=>{n&&(this.__data__.transform.pan(n.dx,n.dy),this.__children__[0].svg_element.setAttribute("transform",this.__data__.transform.toString()),n=null),i=null},"panUpdate");this.svg_element.addEventListener("mousemove",o=>{if(!t)return;const l=o.clientX-e,_=o.clientY-s;n={dx:l/100,dy:_/100},e=o.clientX,s=o.clientY,i===null&&(i=requestAnimationFrame(r))}),this.svg_element.addEventListener("mouseup",o=>{t=!1}),this.svg_element.addEventListener("point-clicked",(o=>{var g,c;const l=(c=(g=o.detail)==null?void 0:g.pointData)==null?void 0:c.ID;if(!l)return;const _=this._pointLabels.get(l)??this._meanLabels.get(l.replace("mean-",""))??this._nodeLabels.get(l);_&&_.displayMode===H.DISPLAY_TYPES.CLICK&&_.toggle()}));const a=u(o=>{var l;for(;o&&o!==this.svg_element;){const _=(l=o.getAttribute)==null?void 0:l.call(o,"data-point-id");if(_)return _;o=o.parentElement}return null},"findPointId"),h=u(o=>this._pointLabels.get(o)??this._meanLabels.get(o.replace(/^mean-/,""))??this._nodeLabels.get(o),"getAutoLabel");this.svg_element.addEventListener("mouseover",o=>{const l=a(o.target);if(!l)return;const _=h(l);(_==null?void 0:_.displayMode)===H.DISPLAY_TYPES.AUTO&&_.show()}),this.svg_element.addEventListener("mouseout",o=>{const l=a(o.target);if(!l)return;const _=o.relatedTarget;if(a(_)===l)return;const c=h(l);(c==null?void 0:c.displayMode)===H.DISPLAY_TYPES.AUTO&&c.hide()}),this._attachInteractionEvents()}_emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}_closestWith(t,e){var s,i;for(;t&&t!==this.svg_element;){if(((s=t.getAttribute)==null?void 0:s.call(t,e))!=null&&((i=t.hasAttribute)!=null&&i.call(t,e)))return t;t=t.parentElement}return null}_edgeDetail(t){const e=this._closestWith(t,"data-edge-source");if(!e)return null;const s={source:e.getAttribute("data-edge-source"),target:e.getAttribute("data-edge-target"),weight:parseFloat(e.getAttribute("data-edge-weight")||"0"),directed:e.getAttribute("data-edge-directed")==="true",self:e.getAttribute("data-edge-self")==="true"};return e.hasAttribute("data-edge-group")&&(s.group=e.getAttribute("data-edge-group")),e.hasAttribute("data-edge-unit")&&(s.unit=e.getAttribute("data-edge-unit")),s}_nodeDetail(t){const e=this._closestWith(t,"data-point-id");if(!e)return null;const s=e.tagName.toLowerCase();let i,n;s==="rect"?(i=parseFloat(e.getAttribute("x")||"0")+parseFloat(e.getAttribute("width")||"0")/2,n=parseFloat(e.getAttribute("y")||"0")+parseFloat(e.getAttribute("height")||"0")/2):(i=parseFloat(e.getAttribute("cx")||"0"),n=parseFloat(e.getAttribute("cy")||"0"));const r=e.getAttribute("data-point-id"),a={id:r,kind:e.getAttribute("data-kind")||"point",name:e.getAttribute("data-name")||r,x:i,y:n};return e.hasAttribute("data-group")&&(a.group=e.getAttribute("data-group")),e.hasAttribute("data-unit")&&(a.unit=e.getAttribute("data-unit")),a}_attachInteractionEvents(){const t=this.svg_element;t.addEventListener("click",i=>{const n=i.target,r=this._edgeDetail(n);if(r){this._emit("qe-edge-click",{...r,originalEvent:i});return}const a=this._nodeDetail(n);a&&this._emit("qe-node-click",{...a,originalEvent:i})});let e=null;const s=u((i,n)=>i==="edge"?`${n.source}\0${n.target}`:String(n.id),"keyOf");t.addEventListener("mousemove",i=>{const n=i.target,r=this._edgeDetail(n),a=r?null:this._nodeDetail(n),h=r?{type:"edge",detail:r}:a?{type:"node",detail:a}:null,o=h?s(h.type,h.detail):null;e&&(!h||e.key!==o)&&(this._emit(e.type==="edge"?"qe-edge-unhover":"qe-node-unhover",{key:e.key}),e=null),h&&(!e||e.key!==o)&&(this._emit(h.type==="edge"?"qe-edge-hover":"qe-node-hover",{...h.detail,originalEvent:i}),e={type:h.type,key:o}),this.hasAttribute("tooltip")&&h?this._showTooltip(this._tooltipText(h.type,h.detail),i.clientX,i.clientY):this._hideTooltip()}),t.addEventListener("mouseleave",()=>{e&&(this._emit(e.type==="edge"?"qe-edge-unhover":"qe-node-unhover",{key:e.key}),e=null),this._hideTooltip()})}_tooltipText(t,e){if(t==="edge"){const s=Number(e.weight),i=Number.isFinite(s)?` (${+s.toFixed(3)})`:"";return`${e.source} – ${e.target}${i}`}return String(e.name??e.id)}_showTooltip(t,e,s){if(!this._tooltipEl){const i=document.createElement("div");i.setAttribute("data-qe-tooltip",""),Object.assign(i.style,{position:"fixed",zIndex:"2147483647",pointerEvents:"none",background:"rgba(20,20,20,0.92)",color:"#fff",font:"12px/1.4 system-ui, sans-serif",padding:"3px 7px",borderRadius:"4px",whiteSpace:"nowrap",transform:"translate(-50%, calc(-100% - 8px))"}),document.body.appendChild(i),this._tooltipEl=i}this._tooltipEl.textContent=t,this._tooltipEl.style.left=`${e}px`,this._tooltipEl.style.top=`${s}px`,this._tooltipEl.style.display="block"}_hideTooltip(){this._tooltipEl&&(this._tooltipEl.style.display="none")}draw(){var t;if(!this.svg_element){console.error("No element to draw to: ",this);return}if((t=this.wrapper)==null||t.appendChild(this.svg_element),this.__children__.forEach(e=>{e.draw()}),!this._resizeObs&&typeof ResizeObserver<"u"&&this.svg_element){let e=0;this._resizeObs=new ResizeObserver(s=>{var n;const i=((n=s[0])==null?void 0:n.contentRect.width)??0;i>0&&Math.abs(i-e)>.5&&(e=i,this.update_labels(),this.update_axes())}),this._resizeObs.observe(this.svg_element)}}update(){this.update_extremes(),this.update_layers(),this.update_labels(),this.update_extremes(),this.update_axes(),this._applyHighlights()}update_axes(){var o,l;const t=this.__children__.search("__children__","axes");t!=null&&t.svg_element&&(t.svg_element.style.display=this._showAxes?"":"none");const e=this._labelsGroup,s=this.__data__.extremes.x_max,{cx:i,cy:n}=this.__data__.extremes;if(!e||s<=0)return;const r=s*.06,a=r*.6,h=u((_,g)=>{let c=this._axisLabelEls.get(_);if(!this._showAxes||g==null){c&&(c.remove(),this._axisLabelEls.delete(_));return}c||(c=document.createElementNS("http://www.w3.org/2000/svg","text"),c.setAttribute("data-axis-label",_),c.setAttribute("pointer-events","none"),e.appendChild(c),this._axisLabelEls.set(_,c)),c.textContent=g,c.setAttribute("font-size",r.toString()),c.setAttribute("font-family","system-ui, sans-serif"),c.setAttribute("font-weight","600"),c.setAttribute("fill","#556"),_==="x"?(c.setAttribute("x",(i+s-a).toString()),c.setAttribute("y",(-a).toString()),c.setAttribute("text-anchor","end")):(c.setAttribute("x",a.toString()),c.setAttribute("y",(n-s+r+a).toString()),c.setAttribute("text-anchor","start"))},"place");if(h("x",this._axisXText),h("y",this._axisYText),this._magnifyText==null)(o=this._magnifyEl)==null||o.remove(),this._magnifyEl=null;else{this._magnifyEl||(this._magnifyEl=document.createElementNS("http://www.w3.org/2000/svg","text"),this._magnifyEl.setAttribute("data-magnify-label",""),this._magnifyEl.setAttribute("pointer-events","none")),this._magnifyEl.parentElement||e.appendChild(this._magnifyEl);const _=this._magnifyEl;_.textContent=this._magnifyText,_.setAttribute("font-size",(r*.85).toString()),_.setAttribute("font-family","system-ui, sans-serif"),_.setAttribute("font-style","italic"),_.setAttribute("fill","#556"),_.setAttribute("x",(i-s+a).toString()),_.setAttribute("y",(n-s+r+a).toString()),_.setAttribute("text-anchor","start")}if(!this._plotTitle)(l=this._titleEl)==null||l.remove(),this._titleEl=null;else{this._titleEl||(this._titleEl=document.createElementNS("http://www.w3.org/2000/svg","text"),this._titleEl.setAttribute("data-plot-title",""),this._titleEl.setAttribute("pointer-events","none")),this._titleEl.parentElement||e.appendChild(this._titleEl);const g=(this._labelFont.size??12)*1.35*this.unitsPerPixel(),c=this._titleEl;c.textContent=this._plotTitle,c.setAttribute("font-size",g.toString()),c.setAttribute("font-family",this._labelFont.family??"system-ui, sans-serif"),c.setAttribute("font-weight","600"),c.setAttribute("fill",this._labelFont.color??"#223"),c.setAttribute("x",i.toString()),c.setAttribute("y",(n-s+g*1.1).toString()),c.setAttribute("text-anchor","middle")}}update_labels(){this._nodeLabels.forEach(t=>t.update()),this._meanLabels.forEach(t=>t.update()),this._pointLabels.forEach(t=>t.update())}update_extremes(){var s;const t=this.__data__;if(t.update_extremes(this._centerContent),this._rangeExtent&&this._rangeExtent>0){const{cx:i,cy:n}=t.extremes,r=this._centerContent&&this._rangeMode==="network"?t.nodeExtentFrom(i,n)*1.2:this._rangeExtent;t.extremes=new Rt(r,r,i,n)}const e=(s=this.svg_element)==null?void 0:s.getBoundingClientRect();if(this.svg_element&&e){console.log("SVG rect: ",e);let i,n;e.width===0||e.height===0?(i=1,n=1):(i=e.width,n=e.height),this.__data__.scale_x=1/(i/(4*this.__data__.extremes.x_max)),this.__data__.scale_y=1/(n/(4*this.__data__.extremes.y_max)),this.__children__[0].svg_element.setAttribute("transform",this.__data__.transform.toString()),this.svg_element.setAttribute("viewBox",this.__data__.extremes.as_viewBox());let r=this.__data__.layers.search("layers","axis_lines");if(r){let a=r.objects.get("axis-x"),h=r.objects.get("axis-y");if(a&&h){const o=this.__data__.extremes;a.from=new J({ID:"axis-x-start",dimensions:[o.cx-o.x_max,0],classes:["ena.dimension","ena.dimension"]}),a.to=new J({ID:"axis-x-end",dimensions:[o.cx+o.x_max,0],classes:["ena.dimension","ena.dimension"]}),h.from=new J({ID:"axis-y-start",dimensions:[0,o.cy-o.y_max],classes:["ena.dimension","ena.dimension"]}),h.to=new J({ID:"axis-y-end",dimensions:[0,o.cy+o.y_max],classes:["ena.dimension","ena.dimension"]})}}}}update_layers(){this.__children__.forEach(t=>{t.update()})}};u(ut,"QEGraphElement"),ut.tagName="qe-graph",ut.style=`
|
|
19
|
+
${Ne.style}
|
|
4062
20
|
|
|
4063
21
|
:host {
|
|
4064
22
|
display: block;
|
|
@@ -4075,36 +33,5 @@ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "
|
|
|
4075
33
|
aspect-ratio: 1 / 1;
|
|
4076
34
|
background-color: #FFF;
|
|
4077
35
|
}
|
|
4078
|
-
|
|
4079
|
-
let QEGraphElement = _QEGraphElement;
|
|
4080
|
-
customElements.define(QEGraphElement.tagName, QEGraphElement);
|
|
4081
|
-
exports2.Color = Color;
|
|
4082
|
-
exports2.DataFrame = DataFrame;
|
|
4083
|
-
exports2.DataFrameColumn = DataFrameColumn;
|
|
4084
|
-
exports2.DataFrameColumnType = DataFrameColumnType;
|
|
4085
|
-
exports2.DataFrameRow = DataFrameRow;
|
|
4086
|
-
exports2.Edge = Edge;
|
|
4087
|
-
exports2.Graph = Graph;
|
|
4088
|
-
exports2.QEAxesElement = QEAxesElement;
|
|
4089
|
-
exports2.QEEdgesElement = QEEdgesElement;
|
|
4090
|
-
exports2.QEGraphElement = QEGraphElement;
|
|
4091
|
-
exports2.QELayer = QELayer;
|
|
4092
|
-
exports2.QELine = QELine;
|
|
4093
|
-
exports2.QEMeansElement = QEMeansElement;
|
|
4094
|
-
exports2.QENodesElement = QENodesElement;
|
|
4095
|
-
exports2.QEPoint = QEPoint;
|
|
4096
|
-
exports2.QEPointsElement = QEPointsElement;
|
|
4097
|
-
exports2.QETrajectoriesElement = QETrajectoriesElement;
|
|
4098
|
-
exports2.QETrajectory = QETrajectory;
|
|
4099
|
-
exports2.QEVisualElement = QEVisualElement;
|
|
4100
|
-
exports2.TRAJECTORY_ZERO_EPS = TRAJECTORY_ZERO_EPS;
|
|
4101
|
-
exports2.Trajectory = Trajectory;
|
|
4102
|
-
exports2.WeightedColor = WeightedColor;
|
|
4103
|
-
exports2.fitTrajectory = fitTrajectory;
|
|
4104
|
-
exports2.nearOriginFilter = nearOriginFilter;
|
|
4105
|
-
exports2.sampleCurve = sampleCurve;
|
|
4106
|
-
exports2.selectDegree = selectDegree;
|
|
4107
|
-
exports2.vizENA = vizENA;
|
|
4108
|
-
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
4109
|
-
}));
|
|
36
|
+
`,ut._instances=new Set,ut._PATH_NUM_RE=/-?\d*\.?\d+(?:e[-+]?\d+)?/gi;let Lt=ut;customElements.define(Lt.tagName,Lt);const ki=u(d=>Lt.getGraph(d),"getGraph"),Ci=u(()=>Lt.instances(),"getGraphs");S.Color=tt,S.DataFrame=$t,S.DataFrameColumn=It,S.DataFrameColumnType=_t,S.DataFrameRow=B,S.Edge=ie,S.Graph=Ie,S.QEAxesElement=de,S.QEEdgesElement=_e,S.QEGraphElement=Lt,S.QELayer=Oe,S.QELine=wt,S.QEMeansElement=le,S.QENodesElement=he,S.QEPoint=Gt,S.QEPointsElement=ce,S.QETrajectoriesElement=ue,S.QETrajectory=oe,S.QEVisualElement=Zt,S.TRAJECTORY_ZERO_EPS=Is,S.Trajectory=se,S.WeightedColor=Qt,S.fitTrajectory=Ps,S.getGraph=ki,S.getGraphs=Ci,S.nearOriginFilter=Ze,S.sampleCurve=es,S.selectDegree=$s,S.vizENA=ai,Object.defineProperty(S,Symbol.toStringTag,{value:"Module"})}));
|
|
4110
37
|
//# sourceMappingURL=qeviz.umd.js.map
|