@liquidcars/atlas 0.1.21 → 0.1.22
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 +22 -7
- package/dist/liquidcars-atlas.js +100 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,7 @@ También se puede cargar el modelo desde JavaScript:
|
|
|
50
50
|
const atlas = document.querySelector('liquidcars-atlas');
|
|
51
51
|
atlas.model = model;
|
|
52
52
|
atlas.select('distribution-agreement');
|
|
53
|
+
atlas.selectRelation(0); // también acepta el id de una relación
|
|
53
54
|
atlas.setRelationMode('all'); // 'all' | 'selected' | 'none'
|
|
54
55
|
atlas.setToolbarVisible(true); // también se puede usar toolbar="on" | "off"
|
|
55
56
|
atlas.zoomIn();
|
|
@@ -76,7 +77,11 @@ atlas.removeRelation(0);
|
|
|
76
77
|
atlas.removeEntity('service');
|
|
77
78
|
|
|
78
79
|
atlas.addEventListener('lc-select', event => {
|
|
79
|
-
|
|
80
|
+
if (event.detail.kind === 'entity') {
|
|
81
|
+
console.log('Entidad seleccionada:', event.detail.id, event.detail.entity);
|
|
82
|
+
} else if (event.detail.kind === 'relation') {
|
|
83
|
+
console.log('Relación seleccionada:', event.detail.index, event.detail.relation);
|
|
84
|
+
}
|
|
80
85
|
});
|
|
81
86
|
atlas.addEventListener('lc-model-change', event => {
|
|
82
87
|
console.log('Modelo actualizado:', event.detail.kind);
|
|
@@ -90,9 +95,11 @@ por lo que una aplicación puede adaptar la apariencia sin modificar el bundle.
|
|
|
90
95
|
Las propiedades `atlas.theme` y `atlas.styles` son alias prácticos de esta configuración.
|
|
91
96
|
|
|
92
97
|
Eventos disponibles: `lc-ready`, `lc-error`, `lc-select`, `lc-model-change`,
|
|
93
|
-
`lc-relation-mode` y `lc-disconnect`. `lc-select`
|
|
94
|
-
|
|
95
|
-
|
|
98
|
+
`lc-relation-mode` y `lc-disconnect`. `lc-select` usa un detalle discriminado:
|
|
99
|
+
las entidades incluyen `{ kind: 'entity', id, entity, source }` y las relaciones
|
|
100
|
+
`{ kind: 'relation', id, index, relation, source }`. Los campos históricos `id`
|
|
101
|
+
y `entity` se conservan para las selecciones de entidad. Al volver a la vista
|
|
102
|
+
general, `kind`, `id`, `entity` y `relation` son `null`. Los eventos de selección y cambios de modelo son `bubbles` y
|
|
96
103
|
`composed`, por lo que funcionan también al integrar el componente en otras
|
|
97
104
|
capas de Web Components.
|
|
98
105
|
|
|
@@ -113,7 +120,8 @@ como `setClickBehavior()`).
|
|
|
113
120
|
El campo visual opcional `mode` admite `directed` (por defecto),
|
|
114
121
|
`bidirectional` y `broken`. En modo bidireccional los indicadores animados
|
|
115
122
|
circulan en ambos sentidos por el mismo tubo; en modo broken los dos tramos
|
|
116
|
-
|
|
123
|
+
se sustituyen por un único tubo rojo con tres anillos que vibran localmente,
|
|
124
|
+
distribuidos a lo largo del recorrido.
|
|
117
125
|
|
|
118
126
|
Geometrías incluidas en esta primera versión: `box`, `cylinder`, `sphere`, `cone`, `frustum-cone`, `frustum-pyramid`, `frustum-triangle`, `prism`, `pyramid-square`, `pyramid-triangle`, `octahedron`, `dodecahedron` e `icosahedron`. Las variantes `frustum-*` son sólidos truncados con dos caras finitas paralelas; las dimensiones `s` se aplican sobre su caja final normalizada.
|
|
119
127
|
|
|
@@ -141,9 +149,16 @@ Una vez publicado, los consumidores podrán instalarlo con `npm install @liquidc
|
|
|
141
149
|
Para probar el paquete sin publicarlo, basta con instalar el tarball generado:
|
|
142
150
|
|
|
143
151
|
```bash
|
|
144
|
-
npm install ./liquidcars-atlas-0.1.
|
|
152
|
+
npm install ./liquidcars-atlas-0.1.22.tgz
|
|
145
153
|
```
|
|
146
154
|
|
|
147
155
|
## Estado
|
|
148
156
|
|
|
149
|
-
`0.1.
|
|
157
|
+
`0.1.22` amplía la selección contextual a las relaciones. El usuario puede
|
|
158
|
+
seleccionar un tubo directamente, el componente lo realza, muestra sus extremos
|
|
159
|
+
y modo en el panel y emite el mismo evento `lc-select` con `kind: 'relation'`.
|
|
160
|
+
La API pública añade `selectRelation()`, `selectedRelation` y `selection`, y la
|
|
161
|
+
selección se conserva durante las mutaciones del modelo siempre que el elemento
|
|
162
|
+
siga existiendo. Se mantienen las correcciones de geometría, toolbar, etiquetas,
|
|
163
|
+
paleta externa, edición en caliente y los modos `directed`, `bidirectional` y
|
|
164
|
+
`broken` introducidos en las versiones anteriores.
|
package/dist/liquidcars-atlas.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! LiquidCars Atlas 0.1.
|
|
1
|
+
/*! LiquidCars Atlas 0.1.22 | MIT */
|
|
2
2
|
|
|
3
3
|
// src/three.core.js
|
|
4
4
|
/**
|
|
@@ -29595,6 +29595,7 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29595
29595
|
this.nodes = /* @__PURE__ */ new Map();
|
|
29596
29596
|
this.open = /* @__PURE__ */ new Set();
|
|
29597
29597
|
this.selected = null;
|
|
29598
|
+
this.selectedRelationIndex = null;
|
|
29598
29599
|
this.modelData = null;
|
|
29599
29600
|
this.theme = normalizeTheme();
|
|
29600
29601
|
this.relationMode = this.getAttribute("relation-mode") || "selected";
|
|
@@ -29651,6 +29652,14 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29651
29652
|
get selectedId() {
|
|
29652
29653
|
return this.selected?.id || null;
|
|
29653
29654
|
}
|
|
29655
|
+
get selectedRelation() {
|
|
29656
|
+
return this._publicRelation(this.selectedRelationIndex);
|
|
29657
|
+
}
|
|
29658
|
+
get selection() {
|
|
29659
|
+
if (this.selected) return { kind: "entity", id: this.selected.id, entity: this._publicEntity(this.selected.id) };
|
|
29660
|
+
const relation = this.selectedRelation;
|
|
29661
|
+
return relation ? { kind: "relation", id: relation.id || null, index: relation.index, relation } : null;
|
|
29662
|
+
}
|
|
29654
29663
|
get clickBehavior() {
|
|
29655
29664
|
return this.selectionMode;
|
|
29656
29665
|
}
|
|
@@ -29673,10 +29682,17 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29673
29682
|
s: Array.isArray(entity.s) ? [...entity.s] : [1, 1, 1]
|
|
29674
29683
|
} : null;
|
|
29675
29684
|
}
|
|
29685
|
+
_publicRelation(reference) {
|
|
29686
|
+
const index = this._relationIndex(reference);
|
|
29687
|
+
const relation = this.modelData?.relations?.[index];
|
|
29688
|
+
return relation ? { ...relation, index } : null;
|
|
29689
|
+
}
|
|
29676
29690
|
_commitModelChange(kind, detail = {}, options = {}) {
|
|
29677
29691
|
const selectedId = options.preserveSelection === false ? null : this.selected?.id;
|
|
29692
|
+
const selectedRelation = options.preserveSelection === false ? null : this._publicRelation(this.selectedRelationIndex);
|
|
29693
|
+
const selectedRelationReference = selectedRelation?.id ?? selectedRelation?.index ?? null;
|
|
29678
29694
|
this.modelData = normalizeModel(this.modelData);
|
|
29679
|
-
this._build({ preserveSelection: selectedId });
|
|
29695
|
+
this._build({ preserveSelection: selectedId, preserveRelation: selectedRelationReference });
|
|
29680
29696
|
this._emit("lc-model-change", {
|
|
29681
29697
|
kind,
|
|
29682
29698
|
model: this.modelData,
|
|
@@ -29735,8 +29751,11 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29735
29751
|
}
|
|
29736
29752
|
}
|
|
29737
29753
|
if (!this.modelData.entities.some((item) => item.id === id)) throw new Error(`No existe una entidad con id "${id}".`);
|
|
29754
|
+
const selectedRelation = this.modelData.relations[this.selectedRelationIndex];
|
|
29738
29755
|
this.modelData.entities = this.modelData.entities.filter((item) => !removed.has(item.id));
|
|
29739
29756
|
this.modelData.relations = this.modelData.relations.filter((relation) => !removed.has(relation.from) && !removed.has(relation.to));
|
|
29757
|
+
const nextSelectedRelationIndex = selectedRelation ? this.modelData.relations.indexOf(selectedRelation) : -1;
|
|
29758
|
+
this.selectedRelationIndex = nextSelectedRelationIndex >= 0 ? nextSelectedRelationIndex : null;
|
|
29740
29759
|
for (const removedId of removed) this.open.delete(removedId);
|
|
29741
29760
|
if (this.selected && removed.has(this.selected.id)) this.selected = null;
|
|
29742
29761
|
return this._commitModelChange("entity-remove", { id, removed: [...removed] });
|
|
@@ -29770,6 +29789,8 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29770
29789
|
const index = this._relationIndex(reference);
|
|
29771
29790
|
if (index < 0 || index >= this.modelData.relations.length) throw new Error("No existe la relaci\xF3n indicada.");
|
|
29772
29791
|
const [relation] = this.modelData.relations.splice(index, 1);
|
|
29792
|
+
if (this.selectedRelationIndex === index) this.selectedRelationIndex = null;
|
|
29793
|
+
else if (this.selectedRelationIndex > index) this.selectedRelationIndex -= 1;
|
|
29773
29794
|
return this._commitModelChange("relation-remove", { index, relation: { ...relation } }, options);
|
|
29774
29795
|
}
|
|
29775
29796
|
get palette() {
|
|
@@ -29858,6 +29879,7 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29858
29879
|
closeAllContainers() {
|
|
29859
29880
|
this.open.clear();
|
|
29860
29881
|
this.selected = null;
|
|
29882
|
+
this.selectedRelationIndex = null;
|
|
29861
29883
|
this._renderPanel();
|
|
29862
29884
|
this._rebuildRelations();
|
|
29863
29885
|
this.invalidate();
|
|
@@ -30027,6 +30049,7 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30027
30049
|
_build(options = {}) {
|
|
30028
30050
|
if (!this._ensureRenderer()) return;
|
|
30029
30051
|
const selectedId = options.preserveSelection || null;
|
|
30052
|
+
const selectedRelationReference = options.preserveRelation ?? null;
|
|
30030
30053
|
this._clearObjects();
|
|
30031
30054
|
for (const entity of this.modelData.entities) this.nodes.set(entity.id, { ...entity });
|
|
30032
30055
|
this.open = new Set([...this.open].filter((id) => this.nodes.has(id)));
|
|
@@ -30061,8 +30084,10 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30061
30084
|
node.group.add(node.label);
|
|
30062
30085
|
this.scene.add(node.group);
|
|
30063
30086
|
}
|
|
30064
|
-
this.selected = selectedId && this.nodes.has(selectedId) ? this.nodes.get(selectedId) : null;
|
|
30065
30087
|
this.relations = this.modelData.relations;
|
|
30088
|
+
this.selected = selectedId && this.nodes.has(selectedId) ? this.nodes.get(selectedId) : null;
|
|
30089
|
+
const selectedRelationIndex = this._relationIndex(selectedRelationReference);
|
|
30090
|
+
this.selectedRelationIndex = !this.selected && selectedRelationIndex >= 0 && selectedRelationIndex < this.relations.length ? selectedRelationIndex : null;
|
|
30066
30091
|
this._renderPanel();
|
|
30067
30092
|
this._rebuildRelations();
|
|
30068
30093
|
this.ready = true;
|
|
@@ -30097,7 +30122,9 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30097
30122
|
}
|
|
30098
30123
|
_activeRelationIndexes() {
|
|
30099
30124
|
if (this.relationMode === "all") return this.relations.map((_, index) => index);
|
|
30100
|
-
if (this.relationMode !== "selected"
|
|
30125
|
+
if (this.relationMode !== "selected") return [];
|
|
30126
|
+
if (this.selectedRelationIndex !== null) return [this.selectedRelationIndex];
|
|
30127
|
+
if (!this.selected) return [];
|
|
30101
30128
|
return this.relations.map((relation, index) => relation.from === this.selected.id || relation.to === this.selected.id ? index : -1).filter((index) => index >= 0);
|
|
30102
30129
|
}
|
|
30103
30130
|
_rebuildRelations() {
|
|
@@ -30114,8 +30141,14 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30114
30141
|
const delta = end.clone().sub(start);
|
|
30115
30142
|
if (delta.lengthSq() < 0.01) continue;
|
|
30116
30143
|
const visualMode = relationVisualMode(relation);
|
|
30144
|
+
const isSelected = index === this.selectedRelationIndex;
|
|
30145
|
+
const pickTube = new Mesh(new TubeGeometry(new LineCurve3(start, end), 10, 0.16, 6, false), new MeshBasicMaterial({ transparent: true, opacity: 0, depthWrite: false }));
|
|
30146
|
+
pickTube.userData.relationIndex = index;
|
|
30147
|
+
pickTube.userData.relationPick = true;
|
|
30148
|
+
this.relationGroup.add(pickTube);
|
|
30117
30149
|
const makeTube = (from2, to2, opacity = 0.82, tubeColor = color, tubeRadius = 0.045) => {
|
|
30118
|
-
const
|
|
30150
|
+
const displayColor = isSelected ? tubeColor.clone().lerp(new Color(16777215), 0.28) : tubeColor;
|
|
30151
|
+
const tube = new Mesh(new TubeGeometry(new LineCurve3(from2, to2), 10, isSelected ? tubeRadius * 1.45 : tubeRadius, 6, false), new MeshBasicMaterial({ color: displayColor, transparent: true, opacity: isSelected ? 1 : opacity }));
|
|
30119
30152
|
tube.userData.relationIndex = index;
|
|
30120
30153
|
this.relationGroup.add(tube);
|
|
30121
30154
|
};
|
|
@@ -30125,13 +30158,15 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30125
30158
|
// A broken communication remains a continuous red tube. Its rings
|
|
30126
30159
|
// oscillate locally around their positions instead of travelling
|
|
30127
30160
|
// along the connection, conveying a failed/retrying signal.
|
|
30128
|
-
const
|
|
30161
|
+
const displayBrokenColor = isSelected ? brokenColor.clone().lerp(new Color(16777215), 0.22) : brokenColor;
|
|
30162
|
+
const brokenTube = new Mesh(new TubeGeometry(new LineCurve3(start, end), 10, isSelected ? 0.08 : 0.055, 6, false), new MeshBasicMaterial({ color: displayBrokenColor, transparent: true, opacity: isSelected ? 1 : 0.88 }));
|
|
30129
30163
|
brokenTube.userData.relationIndex = index;
|
|
30130
30164
|
this.relationGroup.add(brokenTube);
|
|
30131
30165
|
const amplitude = Math.min(0.18, Math.max(0.07, delta.length() * 0.018));
|
|
30132
30166
|
for (let ringIndex = 0; ringIndex < 3; ringIndex++) {
|
|
30133
30167
|
const position = start.clone().lerp(end, (ringIndex + 1) / 4);
|
|
30134
|
-
const ring = new Mesh(new TorusGeometry(0.085, 0.024, 8, 20), new MeshBasicMaterial({ color:
|
|
30168
|
+
const ring = new Mesh(new TorusGeometry(isSelected ? 0.105 : 0.085, isSelected ? 0.03 : 0.024, 8, 20), new MeshBasicMaterial({ color: displayBrokenColor, transparent: true, opacity: 1 }));
|
|
30169
|
+
ring.userData.relationIndex = index;
|
|
30135
30170
|
ring.userData.phase = ringIndex / 3;
|
|
30136
30171
|
ring.userData.oscillate = true;
|
|
30137
30172
|
ring.userData.start = position.clone().addScaledVector(direction, -amplitude);
|
|
@@ -30143,7 +30178,9 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30143
30178
|
}
|
|
30144
30179
|
makeTube(start, end);
|
|
30145
30180
|
for (let ringIndex = 0; ringIndex < 4; ringIndex++) {
|
|
30146
|
-
const
|
|
30181
|
+
const displayColor = isSelected ? color.clone().lerp(new Color(16777215), 0.28) : color;
|
|
30182
|
+
const ring = new Mesh(new TorusGeometry(isSelected ? 0.088 : 0.068, isSelected ? 0.024 : 0.018, 8, 20), new MeshBasicMaterial({ color: displayColor, transparent: true, opacity: isSelected ? 1 : 0.9 }));
|
|
30183
|
+
ring.userData.relationIndex = index;
|
|
30147
30184
|
ring.userData.phase = ringIndex / 4;
|
|
30148
30185
|
ring.userData.direction = visualMode === "bidirectional" && ringIndex % 2 ? -1 : 1;
|
|
30149
30186
|
ring.userData.start = start.clone();
|
|
@@ -30156,6 +30193,16 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30156
30193
|
_renderPanel() {
|
|
30157
30194
|
if (!this.modelData) return;
|
|
30158
30195
|
const node = this.selected;
|
|
30196
|
+
const selectedRelation = this._publicRelation(this.selectedRelationIndex);
|
|
30197
|
+
if (selectedRelation) {
|
|
30198
|
+
const mode = relationVisualMode(selectedRelation);
|
|
30199
|
+
const title = selectedRelation.label || `${selectedRelation.from} \u2192 ${selectedRelation.to}`;
|
|
30200
|
+
this.panel.innerHTML = '<button class="back" data-action="overview">\u2190 Vista de conjunto</button><div class="eyebrow">RELACI\xD3N</div><h2>' + escapeHtml(title) + '</h2><div class="sub">' + escapeHtml(mode) + '</div><h3>ORIGEN</h3><button data-action="relation-endpoint" data-id="' + escapeHtml(selectedRelation.from) + '">' + escapeHtml(selectedRelation.from) + '</button><h3>DESTINO</h3><button data-action="relation-endpoint" data-id="' + escapeHtml(selectedRelation.to) + '">' + escapeHtml(selectedRelation.to) + '</button>';
|
|
30201
|
+
this.panel.querySelector('[data-action="overview"]')?.addEventListener("click", () => this.reset());
|
|
30202
|
+
this.panel.querySelectorAll('[data-action="relation-endpoint"]').forEach((button) => button.addEventListener("click", () => this.select(button.dataset.id)));
|
|
30203
|
+
this._applyTheme();
|
|
30204
|
+
return;
|
|
30205
|
+
}
|
|
30159
30206
|
if (!node) {
|
|
30160
30207
|
this.panel.innerHTML = '<div class="eyebrow">LIQUIDCARS ATLAS</div><h2>Explora el modelo.</h2><p>Selecciona un volumen para consultar su funci\xF3n y sus relaciones.</p><p class="note">El componente acepta un objeto JSON con palette, entities y relations.</p>';
|
|
30161
30208
|
this._applyTheme();
|
|
@@ -30205,13 +30252,38 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30205
30252
|
parent = parent.parent ? this.nodes.get(parent.parent) : null;
|
|
30206
30253
|
}
|
|
30207
30254
|
this.selected = node;
|
|
30255
|
+
this.selectedRelationIndex = null;
|
|
30208
30256
|
if (node.type === "shell") this.open.add(node.id);
|
|
30209
30257
|
this.targetFocus.copy(this._worldPosition(node));
|
|
30210
30258
|
this.targetZoom = node.parent ? 1.35 : 1.1;
|
|
30211
30259
|
this._renderPanel();
|
|
30212
30260
|
this._rebuildRelations();
|
|
30213
30261
|
this.invalidate();
|
|
30214
|
-
this._emit("lc-select", { id, entity: this._publicEntity(id), source: options.source || "api" });
|
|
30262
|
+
if (options.emit !== false) this._emit("lc-select", { kind: "entity", id, index: null, entity: this._publicEntity(id), relation: null, source: options.source || "api" });
|
|
30263
|
+
return this;
|
|
30264
|
+
}
|
|
30265
|
+
selectRelation(reference, options = {}) {
|
|
30266
|
+
const index = this._relationIndex(reference);
|
|
30267
|
+
const relation = this._publicRelation(index);
|
|
30268
|
+
if (!relation) return;
|
|
30269
|
+
for (const endpoint of [relation.from, relation.to]) {
|
|
30270
|
+
let node = this.nodes.get(endpoint);
|
|
30271
|
+
while (node?.parent) {
|
|
30272
|
+
this.open.add(node.parent);
|
|
30273
|
+
node = this.nodes.get(node.parent);
|
|
30274
|
+
}
|
|
30275
|
+
}
|
|
30276
|
+
this.selected = null;
|
|
30277
|
+
this.selectedRelationIndex = index;
|
|
30278
|
+
const from = this.nodes.get(relation.from);
|
|
30279
|
+
const to = this.nodes.get(relation.to);
|
|
30280
|
+
if (from && to) this.targetFocus.copy(this._worldPosition(from).add(this._worldPosition(to)).multiplyScalar(0.5));
|
|
30281
|
+
this.targetZoom = 1.22;
|
|
30282
|
+
this._renderPanel();
|
|
30283
|
+
this._rebuildRelations();
|
|
30284
|
+
this.invalidate();
|
|
30285
|
+
if (options.emit !== false) this._emit("lc-select", { kind: "relation", id: relation.id || null, index, entity: null, relation, source: options.source || "api" });
|
|
30286
|
+
return this;
|
|
30215
30287
|
}
|
|
30216
30288
|
setRelationMode(mode) {
|
|
30217
30289
|
this.relationMode = ["all", "selected", "none"].includes(mode) ? mode : "selected";
|
|
@@ -30230,7 +30302,9 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30230
30302
|
}
|
|
30231
30303
|
reset() {
|
|
30232
30304
|
const previousId = this.selected?.id || null;
|
|
30305
|
+
const previousRelation = this._publicRelation(this.selectedRelationIndex);
|
|
30233
30306
|
this.selected = null;
|
|
30307
|
+
this.selectedRelationIndex = null;
|
|
30234
30308
|
this.open.clear();
|
|
30235
30309
|
this.relationMode = "selected";
|
|
30236
30310
|
this.setAttribute("relation-mode", "selected");
|
|
@@ -30252,7 +30326,8 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30252
30326
|
this._renderPanel();
|
|
30253
30327
|
this._rebuildRelations();
|
|
30254
30328
|
this.invalidate();
|
|
30255
|
-
if (previousId) this._emit("lc-select", { id: null, entity: null, previousId, source: "reset" });
|
|
30329
|
+
if (previousId || previousRelation) this._emit("lc-select", { kind: null, id: null, index: null, entity: null, relation: null, previousId, previousRelation, source: "reset" });
|
|
30330
|
+
return this;
|
|
30256
30331
|
}
|
|
30257
30332
|
resize() {
|
|
30258
30333
|
if (!this.renderer) return;
|
|
@@ -30368,7 +30443,12 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30368
30443
|
if (!(node.type === "shell" && this.open.has(node.id))) meshes.push(node.mesh);
|
|
30369
30444
|
if (node.label?.visible) meshes.push(...node.label.children.filter((face) => face.visible));
|
|
30370
30445
|
}
|
|
30371
|
-
|
|
30446
|
+
const nodeHit = this.raycaster.intersectObjects(meshes, false)[0] || null;
|
|
30447
|
+
const relationTargets = this.relationGroup.children.filter((object) => object.userData.relationPick);
|
|
30448
|
+
const relationHit = this.raycaster.intersectObjects(relationTargets, false)[0] || null;
|
|
30449
|
+
if (nodeHit && (!relationHit || nodeHit.distance <= relationHit.distance + 0.12)) return { kind: "entity", node: nodeHit.object.userData.node };
|
|
30450
|
+
if (relationHit) return { kind: "relation", index: relationHit.object.userData.relationIndex };
|
|
30451
|
+
return nodeHit ? { kind: "entity", node: nodeHit.object.userData.node } : null;
|
|
30372
30452
|
}
|
|
30373
30453
|
_bindControls() {
|
|
30374
30454
|
this.shadowRoot.addEventListener("click", (event) => {
|
|
@@ -30405,11 +30485,17 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
30405
30485
|
this.drag = null;
|
|
30406
30486
|
this.canvas.style.cursor = "grab";
|
|
30407
30487
|
if (drag && !drag.moved) {
|
|
30408
|
-
const
|
|
30409
|
-
if (
|
|
30410
|
-
|
|
30488
|
+
const picked = this._pick(event);
|
|
30489
|
+
if (picked?.kind === "entity") {
|
|
30490
|
+
const node = picked.node;
|
|
30491
|
+
if (this.selectionMode === "event") this._emit("lc-select", { kind: "entity", id: node.id, index: null, entity: this._publicEntity(node.id), relation: null, source: "pointer" });
|
|
30411
30492
|
else this.select(node.id, { source: "pointer" });
|
|
30412
30493
|
}
|
|
30494
|
+
if (picked?.kind === "relation") {
|
|
30495
|
+
const relation = this._publicRelation(picked.index);
|
|
30496
|
+
if (this.selectionMode === "event") this._emit("lc-select", { kind: "relation", id: relation?.id || null, index: picked.index, entity: null, relation, source: "pointer" });
|
|
30497
|
+
else this.selectRelation(picked.index, { source: "pointer" });
|
|
30498
|
+
}
|
|
30413
30499
|
}
|
|
30414
30500
|
this.invalidate();
|
|
30415
30501
|
});
|