@liquidcars/atlas 0.1.10 → 0.1.11
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 +5 -2
- package/dist/liquidcars-atlas.js +64 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,6 +56,7 @@ atlas.setTheme({
|
|
|
56
56
|
lighting: { ambient: 1.8, directional: 3.0 },
|
|
57
57
|
ui: { breadcrumbs: true, panel: true, toolbar: true, hint: false }
|
|
58
58
|
});
|
|
59
|
+
atlas.setPalette({ channels: '#58b6ec', offers: '#48c8b0', connection: '#f4edba' });
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
El mismo bloque `theme` puede formar parte del JSON del modelo. Los estilos
|
|
@@ -75,7 +76,9 @@ Eventos disponibles: `lc-ready`, `lc-error`, `lc-select`, `lc-relation-mode` y `
|
|
|
75
76
|
- `s` son dimensiones absolutas locales `[x, y, z]`.
|
|
76
77
|
- `relations` acepta objetos `{from, to, label}` o la forma corta `[from, to, label]`.
|
|
77
78
|
|
|
78
|
-
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`.
|
|
79
|
+
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.
|
|
80
|
+
|
|
81
|
+
La paleta puede cambiarse después de cargar el modelo mediante `atlas.setPalette({ nombre: color })` o asignando `atlas.palette = { ... }`. El cambio actualiza las piezas, aristas y relaciones sin reconstruir el modelo.
|
|
79
82
|
|
|
80
83
|
## Distribución
|
|
81
84
|
|
|
@@ -95,4 +98,4 @@ npm install ./liquidcars-atlas-0.1.10.tgz
|
|
|
95
98
|
|
|
96
99
|
## Estado
|
|
97
100
|
|
|
98
|
-
`0.1.
|
|
101
|
+
`0.1.11` 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. Esta versión corrige los sólidos truncados, normaliza sus dimensiones finales, refuerza la visibilidad de la toolbar y añade actualización programática de la paleta con `setPalette`.
|
package/dist/liquidcars-atlas.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! LiquidCars Atlas 0.1.
|
|
1
|
+
/*! LiquidCars Atlas 0.1.11 | MIT */
|
|
2
2
|
|
|
3
3
|
// src/three.core.js
|
|
4
4
|
var REVISION = "180";
|
|
@@ -29029,7 +29029,7 @@ function normalizeTheme(value) {
|
|
|
29029
29029
|
}
|
|
29030
29030
|
var CSS = [
|
|
29031
29031
|
":host{display:block;position:relative;height:var(--lc-height,680px);min-height:420px;color:var(--lc-panel-title,#e9f0f5);font:14px Inter,system-ui,-apple-system,sans-serif;background:var(--lc-bg,#0a111a);border:1px solid #294252;border-radius:12px;overflow:hidden;contain:content}",
|
|
29032
|
-
"*{box-sizing:border-box}.atlas{display:grid;grid-template-columns:minmax(0,1fr) 300px;height:100%}.atlas[data-panel=hidden]{grid-template-columns:1fr}.viewport{position:relative;min-width:0;background:radial-gradient(ellipse at 50% 45%,var(--lc-bg-glow,#1c2b39),var(--lc-bg-fade,#0a111a) 82%)}canvas{display:block;width:100%;height:100%;cursor:grab;touch-action:none}.toolbar{position:absolute;z-index:
|
|
29032
|
+
"*{box-sizing:border-box}.atlas{display:grid;grid-template-columns:minmax(0,1fr) 300px;height:100%}.atlas[data-panel=hidden]{grid-template-columns:1fr}.viewport{position:relative;min-width:0;background:radial-gradient(ellipse at 50% 45%,var(--lc-bg-glow,#1c2b39),var(--lc-bg-fade,#0a111a) 82%)}canvas{display:block;width:100%;height:100%;cursor:grab;touch-action:none}.toolbar{position:absolute;z-index:10;bottom:16px;left:50%;transform:translateX(-50%);display:flex;gap:3px;padding:6px;background:var(--lc-toolbar-bg,#15232fe8);border:1px solid var(--lc-toolbar-border,#3a5062);border-radius:8px;white-space:nowrap}.toolbar[data-hidden=true],.toolbar[hidden],.panel[data-hidden=true],.panel[hidden],.crumbs[data-hidden=true],.crumbs[hidden],.hint[data-hidden=true],.hint[hidden]{display:none!important}.toolbar button{height:30px;padding:0 9px;border:0;border-radius:5px;background:none;color:var(--lc-toolbar-text,#dbe7ec);cursor:pointer}.toolbar button:hover,.toolbar button.active{background:var(--lc-toolbar-active,#1f3d4b);color:var(--lc-toolbar-active-text,#c5f2e9)}.toolbar i{display:block;width:1px;margin:2px 3px;background:#38515f}.hint{position:absolute;bottom:5px;left:0;right:0;text-align:center;font-size:11px;color:var(--lc-hint,#8da6b8);pointer-events:none}.panel{overflow:auto;padding:24px 20px;background:var(--lc-panel-bg,linear-gradient(140deg,#182633,#0e1925 65%));border-left:1px solid var(--lc-panel-border,#2a3a48)}.panel h2{font-size:26px;line-height:1.12;font-weight:470;margin:12px 0;color:var(--lc-panel-title,#e9f0f5)}.panel h3{font-size:11px;letter-spacing:1.4px;color:#91aabd;margin:24px 0 10px}.panel p{font-size:14px;line-height:1.55;color:var(--lc-panel-text,#b5c6d2)}.panel .eyebrow{font-size:11px;letter-spacing:1.7px;color:#6ad7c0}.panel .sub{font-size:13px;color:#8fa8bd;margin-bottom:16px}.panel button{display:block;width:100%;padding:10px 0;text-align:left;background:none;border:0;border-bottom:1px solid var(--lc-panel-border,#2a3a48);color:#d9e7eb;cursor:pointer}.panel button:hover{color:#6ad7c0}.panel .relation{padding:10px 0;border-bottom:1px solid var(--lc-panel-border,#2a3a48)}.panel .relation strong{display:block;font-weight:550}.panel .relation small{display:block;color:#86a6b9;font-size:12px;margin-top:4px}.panel .back{color:#9db7c8;font-size:13px}.panel .crumbs{display:flex;flex-wrap:wrap;gap:5px;align-items:center;margin:0 0 12px}.panel .crumbs button{display:inline;width:auto;padding:3px 7px;border:0;border-radius:4px;background:var(--lc-crumb-bg,#142733);color:var(--lc-crumb-text,#91b6c7);font-size:12px}.panel .crumbs button.current{background:var(--lc-crumb-active,#1c4a4d);color:var(--lc-crumb-active-text,#c5f2e9)}.panel .note{border-top:1px solid var(--lc-panel-border,#2a3a48);padding-top:16px;margin-top:22px;font-size:12px;color:#7692a6}.error{position:absolute;inset:20%;padding:18px;background:#172b3b;border:1px solid #7896a9;line-height:1.5;z-index:4}@media(max-width:900px){.toolbar{gap:0}.toolbar button{padding:0 6px;font-size:12px}}@media(max-width:760px){:host{height:680px}.atlas{grid-template-columns:1fr;grid-template-rows:minmax(420px,1fr) auto}.panel{max-height:250px;border-left:0;border-top:1px solid var(--lc-panel-border,#2a3a48);padding:18px}.toolbar{bottom:10px}.hint{display:none}}"
|
|
29033
29033
|
].join("");
|
|
29034
29034
|
var TEMPLATE = '<div class="atlas"><section class="viewport"><canvas tabindex="0" aria-label="Modelo 3D interactivo"></canvas><div class="toolbar"><button data-action="minus" aria-label="Alejar">\u2212</button><button data-action="plus" aria-label="Acercar">+</button><i></i><button data-action="fit">\u2316 Encuadrar</button><button data-action="front">\u25B1 Frontal</button><button data-action="labels" class="active" aria-pressed="true">\u25A7 Etiquetas</button><i></i><button data-action="relations-all" aria-pressed="false">Todas</button><button data-action="relations-selected" class="active" aria-pressed="true">Selecci\xF3n</button><button data-action="relations-none" aria-pressed="false">Ocultar</button></div><div class="hint">Arrastra para girar \xB7 rueda para zoom \xB7 clic para seleccionar</div></section><aside class="panel" aria-live="polite"></aside></div>';
|
|
29035
29035
|
function escapeHtml(value) {
|
|
@@ -29117,11 +29117,15 @@ function makeGeometry(kind, radius = 0, segments = 4, size = [1, 1, 1]) {
|
|
|
29117
29117
|
case "frustum-cone":
|
|
29118
29118
|
case "truncated-cone":
|
|
29119
29119
|
return r ? roundedFrustum(0.28, 0.5, r, s) : new CylinderGeometry(0.28, 0.5, 1, 32);
|
|
29120
|
+
// A frustum is a solid with two finite parallel faces. ConeGeometry
|
|
29121
|
+
// leaves the narrow face collapsed to an apex, which made both truncated
|
|
29122
|
+
// pyramid variants look like ordinary pyramids. CylinderGeometry with
|
|
29123
|
+
// three/four radial segments gives us a real triangular/square frustum.
|
|
29120
29124
|
case "frustum-pyramid":
|
|
29121
29125
|
case "truncated-pyramid":
|
|
29122
|
-
return
|
|
29126
|
+
return new CylinderGeometry(0.28, 0.5, 1, 4);
|
|
29123
29127
|
case "frustum-triangle":
|
|
29124
|
-
return
|
|
29128
|
+
return new CylinderGeometry(0.28, 0.5, 1, 3);
|
|
29125
29129
|
case "prism":
|
|
29126
29130
|
return r ? roundedPrism(6, r, s) : new CylinderGeometry(0.5, 0.5, 1, 6);
|
|
29127
29131
|
case "pyramid-square":
|
|
@@ -29140,6 +29144,15 @@ function makeGeometry(kind, radius = 0, segments = 4, size = [1, 1, 1]) {
|
|
|
29140
29144
|
return r ? roundedBox(r, s, size) : new BoxGeometry(1, 1, 1);
|
|
29141
29145
|
}
|
|
29142
29146
|
}
|
|
29147
|
+
function normalizeGeometry(geometry) {
|
|
29148
|
+
geometry.computeBoundingBox();
|
|
29149
|
+
const bounds = geometry.boundingBox;
|
|
29150
|
+
const size = bounds?.getSize(new Vector3());
|
|
29151
|
+
if (!size || !size.x || !size.y || !size.z) return geometry;
|
|
29152
|
+
geometry.scale(1 / size.x, 1 / size.y, 1 / size.z);
|
|
29153
|
+
geometry.computeBoundingBox();
|
|
29154
|
+
return geometry;
|
|
29155
|
+
}
|
|
29143
29156
|
function makeLabel(text, color, dimensions, type = "") {
|
|
29144
29157
|
const bitmap = document.createElement("canvas");
|
|
29145
29158
|
const context = bitmap.getContext("2d");
|
|
@@ -29280,6 +29293,24 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29280
29293
|
set model(value) {
|
|
29281
29294
|
this.load(value);
|
|
29282
29295
|
}
|
|
29296
|
+
get palette() {
|
|
29297
|
+
return this.modelData?.palette || { ...DEFAULT_PALETTE };
|
|
29298
|
+
}
|
|
29299
|
+
set palette(value) {
|
|
29300
|
+
this.setPalette(value);
|
|
29301
|
+
}
|
|
29302
|
+
setPalette(value = {}) {
|
|
29303
|
+
if (!value || typeof value !== "object") return this;
|
|
29304
|
+
if (!this.modelData) {
|
|
29305
|
+
this._pendingPalette = { ...this._pendingPalette || {}, ...value };
|
|
29306
|
+
return this;
|
|
29307
|
+
}
|
|
29308
|
+
this.modelData.palette = { ...this.modelData.palette, ...value };
|
|
29309
|
+
this._recolorNodes();
|
|
29310
|
+
this._rebuildRelations();
|
|
29311
|
+
this.invalidate();
|
|
29312
|
+
return this;
|
|
29313
|
+
}
|
|
29283
29314
|
get styles() {
|
|
29284
29315
|
return this.theme;
|
|
29285
29316
|
}
|
|
@@ -29325,11 +29356,24 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29325
29356
|
const panel = this.shadowRoot.querySelector(".panel");
|
|
29326
29357
|
const hint = this.shadowRoot.querySelector(".hint");
|
|
29327
29358
|
if (atlas) atlas.dataset.panel = theme.ui.panel === false ? "hidden" : "visible";
|
|
29328
|
-
|
|
29329
|
-
|
|
29330
|
-
|
|
29359
|
+
const toolbarVisible = theme.ui.toolbar !== false;
|
|
29360
|
+
const panelVisible = theme.ui.panel !== false;
|
|
29361
|
+
const hintVisible = theme.ui.hint !== false;
|
|
29362
|
+
if (toolbar) {
|
|
29363
|
+
toolbar.dataset.hidden = String(!toolbarVisible);
|
|
29364
|
+
toolbar.hidden = !toolbarVisible;
|
|
29365
|
+
}
|
|
29366
|
+
if (panel) {
|
|
29367
|
+
panel.dataset.hidden = String(!panelVisible);
|
|
29368
|
+
panel.hidden = !panelVisible;
|
|
29369
|
+
}
|
|
29370
|
+
if (hint) {
|
|
29371
|
+
hint.dataset.hidden = String(!hintVisible);
|
|
29372
|
+
hint.hidden = !hintVisible;
|
|
29373
|
+
}
|
|
29331
29374
|
this.shadowRoot.querySelectorAll(".crumbs").forEach((crumbs) => {
|
|
29332
29375
|
crumbs.dataset.hidden = String(theme.ui.breadcrumbs === false);
|
|
29376
|
+
crumbs.hidden = theme.ui.breadcrumbs === false;
|
|
29333
29377
|
});
|
|
29334
29378
|
}
|
|
29335
29379
|
async _loadInitial() {
|
|
@@ -29348,6 +29392,10 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29348
29392
|
try {
|
|
29349
29393
|
const data = typeof source === "string" ? await fetch(source).then((response) => response.json()) : source;
|
|
29350
29394
|
this.modelData = normalizeModel(data);
|
|
29395
|
+
if (this._pendingPalette) {
|
|
29396
|
+
this.modelData.palette = { ...this.modelData.palette, ...this._pendingPalette };
|
|
29397
|
+
this._pendingPalette = null;
|
|
29398
|
+
}
|
|
29351
29399
|
this.theme = this.modelData.theme;
|
|
29352
29400
|
this._applyTheme();
|
|
29353
29401
|
this._build();
|
|
@@ -29405,6 +29453,14 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29405
29453
|
this.nodes.clear();
|
|
29406
29454
|
this.relationGroup.clear();
|
|
29407
29455
|
}
|
|
29456
|
+
_recolorNodes() {
|
|
29457
|
+
if (!this.modelData) return;
|
|
29458
|
+
for (const node of this.nodes.values()) {
|
|
29459
|
+
const color = this.modelData.palette[node.c] || node.c || this.modelData.palette.component;
|
|
29460
|
+
if (node.material) node.material.color.set(color);
|
|
29461
|
+
if (node.edge?.material) node.edge.material.color.set(color);
|
|
29462
|
+
}
|
|
29463
|
+
}
|
|
29408
29464
|
_build() {
|
|
29409
29465
|
if (!this._ensureRenderer()) return;
|
|
29410
29466
|
this._clearObjects();
|
|
@@ -29416,6 +29472,7 @@ var LiquidCarsAtlas = class extends HTMLElement {
|
|
|
29416
29472
|
const geometryKind = entity.geometry || "box";
|
|
29417
29473
|
const baked = geometryKind === "box" && Number(entity.radius) > 0;
|
|
29418
29474
|
const geometry = makeGeometry(geometryKind, entity.radius, entity.segments, entity.s);
|
|
29475
|
+
if (!baked) normalizeGeometry(geometry);
|
|
29419
29476
|
const color = this.modelData.palette[entity.c] || entity.c || this.modelData.palette.component;
|
|
29420
29477
|
node.material = new MeshStandardMaterial({ color, roughness: 0.72, metalness: 0.06, transparent: true, opacity: entity.type === "shell" ? 0.96 : 1 });
|
|
29421
29478
|
node.mesh = new Mesh(geometry, node.material);
|