@liquidcars/atlas 0.1.20 → 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 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
- console.log('Entidad seleccionada:', event.detail.id, event.detail.entity);
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` incluye `{ id, entity,
94
- source }` en `event.detail`; cuando se vuelve a la vista general emite `id:
95
- null`. Los eventos de selección y cambios de modelo son `bubbles` y
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
- aparecen en rojo, con una X y un anillo detenido en el punto de interrupción.
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.20.tgz
152
+ npm install ./liquidcars-atlas-0.1.22.tgz
145
153
  ```
146
154
 
147
155
  ## Estado
148
156
 
149
- `0.1.20` mantiene la corrección del desplazamiento interno del texto y ancla las etiquetas a las dimensiones reales de las geometrías redondeadas. Además fija un margen superior absoluto para las etiquetas secundarias de contenedores abiertos, situado dentro del frontal del contenedor y sin depender de sus dimensiones. También corrige los sólidos truncados, normaliza sus dimensiones finales, refuerza la visibilidad de la toolbar con el atributo `toolbar="on"`/`"off"` y `setToolbarVisible()`, desacopla la paleta por defecto de nombres de dominio, añade actualización programática de la paleta con `setPalette`, expone las acciones de navegación para controles externos y mantiene siempre visibles las ayudas de interacción dentro del viewport. Esta versión añade edición en caliente de entidades y relaciones, eventos compuestos de selección y los modos de relación `directed`, `bidirectional` y `broken`; las relaciones rotas se representan con un único tubo rojo y tres anillos oscilantes distribuidos a lo largo del recorrido.
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/demo/index.html CHANGED
@@ -14,12 +14,12 @@
14
14
  liquidcars-atlas { display: block; width: 100%; max-width: 1480px; margin: 0 auto; }
15
15
  code { color: #85e5d3; }
16
16
  </style>
17
- <script type="module" src="../dist/liquidcars-atlas.js?v=0.1.20"></script>
17
+ <script type="module" src="../dist/liquidcars-atlas.js?v=0.1.21"></script>
18
18
  </head>
19
19
  <body>
20
20
  <header>
21
21
  <h1>LiquidCars Atlas</h1>
22
- <p>Prueba de distribución del componente <code>&lt;liquidcars-atlas&gt;</code> · v0.1.20</p>
22
+ <p>Prueba de distribución del componente <code>&lt;liquidcars-atlas&gt;</code> · v0.1.21</p>
23
23
  </header>
24
24
  <main>
25
25
  <liquidcars-atlas id="atlas" height="720" relation-mode="selected" shell-labels="on"></liquidcars-atlas>
@@ -1,4 +1,4 @@
1
- /*! LiquidCars Atlas 0.1.20 | MIT */
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" || !this.selected) return [];
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 tube = new Mesh(new TubeGeometry(new LineCurve3(from2, to2), 10, tubeRadius, 6, false), new MeshBasicMaterial({ color: tubeColor, transparent: true, opacity }));
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,11 +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
- makeTube(start, end, 0.88, brokenColor, 0.055);
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 }));
30163
+ brokenTube.userData.relationIndex = index;
30164
+ this.relationGroup.add(brokenTube);
30129
30165
  const amplitude = Math.min(0.18, Math.max(0.07, delta.length() * 0.018));
30130
30166
  for (let ringIndex = 0; ringIndex < 3; ringIndex++) {
30131
30167
  const position = start.clone().lerp(end, (ringIndex + 1) / 4);
30132
- const ring = new Mesh(new TorusGeometry(0.085, 0.024, 8, 20), new MeshBasicMaterial({ color: brokenColor, transparent: true, opacity: 1 }));
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;
30133
30170
  ring.userData.phase = ringIndex / 3;
30134
30171
  ring.userData.oscillate = true;
30135
30172
  ring.userData.start = position.clone().addScaledVector(direction, -amplitude);
@@ -30141,7 +30178,9 @@ var LiquidCarsAtlas = class extends HTMLElement {
30141
30178
  }
30142
30179
  makeTube(start, end);
30143
30180
  for (let ringIndex = 0; ringIndex < 4; ringIndex++) {
30144
- const ring = new Mesh(new TorusGeometry(0.068, 0.018, 8, 20), new MeshBasicMaterial({ color, transparent: true, opacity: 0.9 }));
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;
30145
30184
  ring.userData.phase = ringIndex / 4;
30146
30185
  ring.userData.direction = visualMode === "bidirectional" && ringIndex % 2 ? -1 : 1;
30147
30186
  ring.userData.start = start.clone();
@@ -30154,6 +30193,16 @@ var LiquidCarsAtlas = class extends HTMLElement {
30154
30193
  _renderPanel() {
30155
30194
  if (!this.modelData) return;
30156
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
+ }
30157
30206
  if (!node) {
30158
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>';
30159
30208
  this._applyTheme();
@@ -30203,13 +30252,38 @@ var LiquidCarsAtlas = class extends HTMLElement {
30203
30252
  parent = parent.parent ? this.nodes.get(parent.parent) : null;
30204
30253
  }
30205
30254
  this.selected = node;
30255
+ this.selectedRelationIndex = null;
30206
30256
  if (node.type === "shell") this.open.add(node.id);
30207
30257
  this.targetFocus.copy(this._worldPosition(node));
30208
30258
  this.targetZoom = node.parent ? 1.35 : 1.1;
30209
30259
  this._renderPanel();
30210
30260
  this._rebuildRelations();
30211
30261
  this.invalidate();
30212
- 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;
30213
30287
  }
30214
30288
  setRelationMode(mode) {
30215
30289
  this.relationMode = ["all", "selected", "none"].includes(mode) ? mode : "selected";
@@ -30228,7 +30302,9 @@ var LiquidCarsAtlas = class extends HTMLElement {
30228
30302
  }
30229
30303
  reset() {
30230
30304
  const previousId = this.selected?.id || null;
30305
+ const previousRelation = this._publicRelation(this.selectedRelationIndex);
30231
30306
  this.selected = null;
30307
+ this.selectedRelationIndex = null;
30232
30308
  this.open.clear();
30233
30309
  this.relationMode = "selected";
30234
30310
  this.setAttribute("relation-mode", "selected");
@@ -30250,7 +30326,8 @@ var LiquidCarsAtlas = class extends HTMLElement {
30250
30326
  this._renderPanel();
30251
30327
  this._rebuildRelations();
30252
30328
  this.invalidate();
30253
- 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;
30254
30331
  }
30255
30332
  resize() {
30256
30333
  if (!this.renderer) return;
@@ -30366,7 +30443,12 @@ var LiquidCarsAtlas = class extends HTMLElement {
30366
30443
  if (!(node.type === "shell" && this.open.has(node.id))) meshes.push(node.mesh);
30367
30444
  if (node.label?.visible) meshes.push(...node.label.children.filter((face) => face.visible));
30368
30445
  }
30369
- return this.raycaster.intersectObjects(meshes, false)[0]?.object.userData.node || null;
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;
30370
30452
  }
30371
30453
  _bindControls() {
30372
30454
  this.shadowRoot.addEventListener("click", (event) => {
@@ -30403,11 +30485,17 @@ var LiquidCarsAtlas = class extends HTMLElement {
30403
30485
  this.drag = null;
30404
30486
  this.canvas.style.cursor = "grab";
30405
30487
  if (drag && !drag.moved) {
30406
- const node = this._pick(event);
30407
- if (node) {
30408
- if (this.selectionMode === "event") this._emit("lc-select", { id: node.id, entity: this._publicEntity(node.id), source: "pointer" });
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" });
30409
30492
  else this.select(node.id, { source: "pointer" });
30410
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
+ }
30411
30499
  }
30412
30500
  this.invalidate();
30413
30501
  });
package/index.html CHANGED
@@ -14,12 +14,12 @@
14
14
  liquidcars-atlas { display: block; width: 100%; max-width: 1480px; margin: 0 auto; }
15
15
  code { color: #85e5d3; }
16
16
  </style>
17
- <script type="module" src="./dist/liquidcars-atlas.js?v=0.1.20"></script>
17
+ <script type="module" src="./dist/liquidcars-atlas.js?v=0.1.21"></script>
18
18
  </head>
19
19
  <body>
20
20
  <header>
21
21
  <h1>LiquidCars Atlas</h1>
22
- <p>Prueba de distribución del componente <code>&lt;liquidcars-atlas&gt;</code> · v0.1.20</p>
22
+ <p>Prueba de distribución del componente <code>&lt;liquidcars-atlas&gt;</code> · v0.1.21</p>
23
23
  </header>
24
24
  <main>
25
25
  <liquidcars-atlas id="atlas" height="720" relation-mode="selected" shell-labels="on"></liquidcars-atlas>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liquidcars/atlas",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "Reusable 3D conceptual atlas Web Component for LiquidCars-style models",
5
5
  "type": "module",
6
6
  "main": "./dist/liquidcars-atlas.js",