@project-skymap/library 0.0.2 → 0.1.0

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/dist/index.d.cts CHANGED
@@ -39,6 +39,10 @@ type StarMapConfig = {
39
39
  scale: [number, number];
40
40
  }>;
41
41
  };
42
+ focus?: {
43
+ nodeId?: string;
44
+ animate?: boolean;
45
+ };
42
46
  layout?: {
43
47
  mode?: "radial" | "grid" | "force" | "spherical";
44
48
  radius?: number;
package/dist/index.d.ts CHANGED
@@ -39,6 +39,10 @@ type StarMapConfig = {
39
39
  scale: [number, number];
40
40
  }>;
41
41
  };
42
+ focus?: {
43
+ nodeId?: string;
44
+ animate?: boolean;
45
+ };
42
46
  layout?: {
43
47
  mode?: "radial" | "grid" | "force" | "spherical";
44
48
  radius?: number;
package/dist/index.js CHANGED
@@ -332,6 +332,8 @@ function createEngine({
332
332
  renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
333
333
  renderer.setClearColor(0, 1);
334
334
  container.appendChild(renderer.domElement);
335
+ renderer.domElement.style.width = "100%";
336
+ renderer.domElement.style.height = "100%";
335
337
  renderer.domElement.style.touchAction = "none";
336
338
  const scene = new THREE4.Scene();
337
339
  const camera = new THREE4.PerspectiveCamera(90, 1, 0.1, 5e3);
@@ -644,14 +646,104 @@ function createEngine({
644
646
  }
645
647
  resize();
646
648
  }
649
+ function applyFocus(targetId, animate = true) {
650
+ if (!targetId) {
651
+ for (const [id, mesh] of meshById.entries()) {
652
+ mesh.traverse((obj) => {
653
+ if (obj.material) obj.material.opacity = 1;
654
+ });
655
+ mesh.userData.interactive = true;
656
+ }
657
+ for (const line of lineByBookId.values()) {
658
+ line.visible = true;
659
+ line.material.opacity = 0.3;
660
+ }
661
+ return;
662
+ }
663
+ const childrenMap = /* @__PURE__ */ new Map();
664
+ for (const n of nodeById.values()) {
665
+ if (n.parent) {
666
+ const list = childrenMap.get(n.parent) ?? [];
667
+ list.push(n.id);
668
+ childrenMap.set(n.parent, list);
669
+ }
670
+ }
671
+ const activeIds = /* @__PURE__ */ new Set();
672
+ const queue = [targetId];
673
+ activeIds.add(targetId);
674
+ while (queue.length > 0) {
675
+ const curr = queue.pop();
676
+ const kids = childrenMap.get(curr);
677
+ if (kids) {
678
+ for (const k of kids) {
679
+ activeIds.add(k);
680
+ queue.push(k);
681
+ }
682
+ }
683
+ }
684
+ for (const [id, mesh] of meshById.entries()) {
685
+ const isActive = activeIds.has(id);
686
+ const opacity = isActive ? 1 : 0.1;
687
+ mesh.traverse((obj) => {
688
+ if (obj.material) obj.material.opacity = opacity;
689
+ });
690
+ mesh.userData.interactive = isActive;
691
+ }
692
+ for (const [bookId, line] of lineByBookId.entries()) {
693
+ const isActive = activeIds.has(bookId);
694
+ line.material.opacity = isActive ? 0.3 : 0.05;
695
+ }
696
+ if (animate) {
697
+ const targetMesh = meshById.get(targetId);
698
+ if (targetMesh) {
699
+ animateFocusTo(targetMesh);
700
+ } else {
701
+ const sum = new THREE4.Vector3();
702
+ let count = 0;
703
+ for (const id of activeIds) {
704
+ const mesh = meshById.get(id);
705
+ if (mesh) {
706
+ sum.add(mesh.getWorldPosition(new THREE4.Vector3()));
707
+ count++;
708
+ }
709
+ }
710
+ if (count > 0) {
711
+ const centroid = sum.divideScalar(count);
712
+ animateFocusTo(centroid);
713
+ }
714
+ }
715
+ }
716
+ }
717
+ let lastData = void 0;
718
+ let lastAdapter = void 0;
719
+ let lastModel = void 0;
647
720
  function setConfig(cfg) {
721
+ let shouldRebuild = false;
648
722
  let model = cfg.model;
649
- if (!model && cfg.data && cfg.adapter) model = cfg.adapter(cfg.data);
650
- if (!model) {
651
- clearRoot();
652
- return;
723
+ if (!model && cfg.data && cfg.adapter) {
724
+ if (cfg.data !== lastData || cfg.adapter !== lastAdapter) {
725
+ model = cfg.adapter(cfg.data);
726
+ shouldRebuild = true;
727
+ lastData = cfg.data;
728
+ lastAdapter = cfg.adapter;
729
+ lastModel = model;
730
+ } else {
731
+ model = lastModel;
732
+ }
733
+ } else if (model) {
734
+ shouldRebuild = true;
735
+ lastData = void 0;
736
+ lastAdapter = void 0;
737
+ lastModel = model;
738
+ }
739
+ if (shouldRebuild && model) {
740
+ buildFromModel(model, cfg);
741
+ }
742
+ if (cfg.focus?.nodeId) {
743
+ applyFocus(cfg.focus.nodeId, cfg.focus.animate);
744
+ } else {
745
+ applyFocus(void 0, false);
653
746
  }
654
- buildFromModel(model, cfg);
655
747
  }
656
748
  function setHandlers(next) {
657
749
  handlers = next;
@@ -662,7 +754,9 @@ function createEngine({
662
754
  pointer.y = -((ev.clientY - rect.top) / rect.height * 2 - 1);
663
755
  raycaster.setFromCamera(pointer, camera);
664
756
  const hits = raycaster.intersectObjects(root.children, true);
665
- const hit = hits.find((h) => h.object.type === "Mesh" || h.object.type === "Sprite");
757
+ const hit = hits.find(
758
+ (h) => (h.object.type === "Mesh" || h.object.type === "Sprite") && h.object.userData.interactive !== false
759
+ );
666
760
  const id = hit?.object?.userData?.id;
667
761
  return id ? nodeById.get(id) : void 0;
668
762
  }
@@ -766,11 +860,12 @@ function createEngine({
766
860
  function easeInOutCubic(t) {
767
861
  return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
768
862
  }
769
- function animateFocusTo(mesh) {
863
+ function animateFocusTo(target) {
770
864
  cancelFocusAnim();
771
865
  const { azimuth: startAz, polar: startPolar } = getControlsAnglesSafe();
772
866
  const startFov = camera.fov;
773
- const { targetAz, targetPolar } = aimAtWorldPoint(mesh.getWorldPosition(new THREE4.Vector3()));
867
+ const targetPos = target instanceof THREE4.Object3D ? target.getWorldPosition(new THREE4.Vector3()) : target;
868
+ const { targetAz, targetPolar } = aimAtWorldPoint(targetPos);
774
869
  const endFov = THREE4.MathUtils.clamp(env.focusZoomFov, env.minFov, env.maxFov);
775
870
  const start2 = performance.now();
776
871
  const dur = Math.max(120, env.focusDurationMs);