@lv-x-software-house/x_view 1.4.0 → 1.4.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.
Files changed (3) hide show
  1. package/dist/index.js +118 -60
  2. package/dist/index.mjs +118 -60
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20823,6 +20823,7 @@ function XViewScene({
20823
20823
  let sumY = 0;
20824
20824
  let sumZ = 0;
20825
20825
  let nodeCount = 0;
20826
+ let networkMaxRadius = 150;
20826
20827
  activeNodeIds.forEach((id) => {
20827
20828
  const mesh = nodeObjects[id];
20828
20829
  if (mesh && mesh.material) {
@@ -20930,6 +20931,7 @@ function XViewScene({
20930
20931
  const activeSet = new Set(activeNodeIds.map(String));
20931
20932
  const edges = [];
20932
20933
  const degreeMap = new Map(activeNodeIds.map((id) => [String(id), 0]));
20934
+ const adjMap = new Map(activeNodeIds.map((id) => [String(id), []]));
20933
20935
  const seenPairs = /* @__PURE__ */ new Set();
20934
20936
  [...allLinks, ...ancestryLinks].forEach((line) => {
20935
20937
  var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2;
@@ -20946,55 +20948,104 @@ function XViewScene({
20946
20948
  edges.push([u, v]);
20947
20949
  degreeMap.set(u, (degreeMap.get(u) || 0) + 1);
20948
20950
  degreeMap.set(v, (degreeMap.get(v) || 0) + 1);
20951
+ adjMap.get(u).push(v);
20952
+ adjMap.get(v).push(u);
20949
20953
  }
20950
20954
  }
20951
20955
  });
20952
- const baseSpread = Math.max(45, Math.sqrt(N) * 19);
20953
- const boundX = baseSpread * 1.75;
20954
- const boundY = baseSpread * 1;
20955
- const boundZ = Math.min(85, Math.max(25, baseSpread * 0.45));
20956
- const sortedIds = [...activeNodeIds].sort(
20957
- (a, b) => (degreeMap.get(String(b)) || 0) - (degreeMap.get(String(a)) || 0)
20956
+ const hubCount = Array.from(degreeMap.values()).filter(
20957
+ (d) => d >= 3
20958
+ ).length;
20959
+ const volumeRadius = Math.max(
20960
+ 130,
20961
+ Math.cbrt(N) * 58 + Math.sqrt(N) * 24 + hubCount * 8
20958
20962
  );
20963
+ const radiusX = volumeRadius * 1.45;
20964
+ const radiusY = volumeRadius * 1.15;
20965
+ const radiusZ = volumeRadius * 1.15;
20966
+ const connectedIds = activeNodeIds.map(String).filter((id) => (degreeMap.get(id) || 0) > 0).sort((a, b) => (degreeMap.get(b) || 0) - (degreeMap.get(a) || 0));
20967
+ const isolatedIds = activeNodeIds.map(String).filter((id) => (degreeMap.get(id) || 0) === 0);
20968
+ const interleavedIds = [];
20969
+ let cIdx = 0;
20970
+ let iIdx = 0;
20971
+ for (let k = 0; k < N; k++) {
20972
+ const takeConnected = cIdx < connectedIds.length && (iIdx >= isolatedIds.length || cIdx / Math.max(1, connectedIds.length) <= iIdx / Math.max(1, isolatedIds.length));
20973
+ if (takeConnected) {
20974
+ interleavedIds.push(connectedIds[cIdx++]);
20975
+ } else if (iIdx < isolatedIds.length) {
20976
+ interleavedIds.push(isolatedIds[iIdx++]);
20977
+ }
20978
+ }
20959
20979
  const posMap = /* @__PURE__ */ new Map();
20980
+ const anchorMap = /* @__PURE__ */ new Map();
20960
20981
  const velMap = /* @__PURE__ */ new Map();
20961
20982
  const goldenAngle = Math.PI * (3 - Math.sqrt(5));
20962
- sortedIds.forEach((id, idx) => {
20963
- const t = N > 1 ? idx / (N - 1) : 0.5;
20964
- const r = Math.sqrt(0.12 + 0.88 * t);
20965
- const theta = idx * goldenAngle * 7;
20966
- const zLayer = Math.sin(idx * 2.39996) * boundZ * (0.4 + 0.6 * r);
20967
- posMap.set(String(id), {
20968
- x: Math.cos(theta) * r * boundX,
20969
- y: Math.sin(theta) * r * boundY,
20970
- z: zLayer
20971
- });
20972
- velMap.set(String(id), { x: 0, y: 0, z: 0 });
20983
+ interleavedIds.forEach((id, idx) => {
20984
+ const t = (idx + 0.5) / Math.max(1, N);
20985
+ const yDir = 1 - 2 * t;
20986
+ const radiusAtY = Math.sqrt(Math.max(0, 1 - yDir * yDir));
20987
+ const theta = idx * goldenAngle;
20988
+ const xDir = Math.cos(theta) * radiusAtY;
20989
+ const zDir = Math.sin(theta) * radiusAtY;
20990
+ const shell = 0.3 + 0.7 * Math.cbrt(idx * 7 % Math.max(1, N) / Math.max(1, N));
20991
+ const px = xDir * shell * radiusX;
20992
+ const py = yDir * shell * radiusY;
20993
+ const pz = zDir * shell * radiusZ;
20994
+ posMap.set(id, { x: px, y: py, z: pz });
20995
+ anchorMap.set(id, { x: px, y: py, z: pz });
20996
+ velMap.set(id, { x: 0, y: 0, z: 0 });
20997
+ });
20998
+ connectedIds.forEach((id, idx) => {
20999
+ const deg = degreeMap.get(id) || 0;
21000
+ if (deg <= 2) {
21001
+ const neighbors = adjMap.get(id) || [];
21002
+ const hubNeighbor = neighbors.reduce(
21003
+ (best, curr) => (degreeMap.get(curr) || 0) > (degreeMap.get(best) || 0) ? curr : best,
21004
+ neighbors[0]
21005
+ );
21006
+ const hubPos = posMap.get(hubNeighbor);
21007
+ const myPos = posMap.get(id);
21008
+ if (hubPos && myPos && hubNeighbor !== id) {
21009
+ const phi = idx * goldenAngle * 3;
21010
+ const costheta = Math.cos(idx * 1.732);
21011
+ const sintheta = Math.sqrt(Math.max(0, 1 - costheta * costheta));
21012
+ const orbitDist = 62 + idx % 3 * 16;
21013
+ myPos.x = hubPos.x + sintheta * Math.cos(phi) * orbitDist;
21014
+ myPos.y = hubPos.y + sintheta * Math.sin(phi) * orbitDist;
21015
+ myPos.z = hubPos.z + costheta * orbitDist;
21016
+ }
21017
+ }
20973
21018
  });
20974
- const iterations = 120;
20975
- const minNodeDist = 24;
20976
- const idealEdgeDist = 28;
20977
- const repulsionRadius = 65;
21019
+ const iterations = 130;
21020
+ const minNodeDist = 56;
21021
+ const minHubDist = 140;
21022
+ const idealEdgeDist = 72;
21023
+ const repulsionRadius = 150;
20978
21024
  for (let iter = 0; iter < iterations; iter++) {
20979
- const cooling = 1 - iter / iterations * 0.75;
21025
+ const cooling = 1 - iter / iterations * 0.78;
20980
21026
  for (let i = 0; i < N; i++) {
20981
- const idA = String(sortedIds[i]);
21027
+ const idA = interleavedIds[i];
20982
21028
  const pA = posMap.get(idA);
20983
21029
  const vA = velMap.get(idA);
21030
+ const degA = degreeMap.get(idA) || 0;
20984
21031
  for (let j = i + 1; j < N; j++) {
20985
- const idB = String(sortedIds[j]);
21032
+ const idB = interleavedIds[j];
20986
21033
  const pB = posMap.get(idB);
20987
21034
  const vB = velMap.get(idB);
21035
+ const degB = degreeMap.get(idB) || 0;
20988
21036
  const dx = pA.x - pB.x;
20989
21037
  const dy = pA.y - pB.y;
20990
- const dz = (pA.z - pB.z) * 0.6;
20991
- const distSq = dx * dx + dy * dy + dz * dz + 0.1;
20992
- const dist = Math.sqrt(distSq);
20993
- if (dist < repulsionRadius) {
20994
- const force = dist < minNodeDist ? (minNodeDist - dist) / dist * 1.8 : (repulsionRadius - dist) / repulsionRadius * 0.35 / dist;
21038
+ const dz = pA.z - pB.z;
21039
+ const dist = Math.sqrt(dx * dx + dy * dy + dz * dz + 0.1);
21040
+ const bothHubs = degA >= 3 && degB >= 3;
21041
+ const oneHub = degA >= 3 || degB >= 3;
21042
+ const effectiveMinDist = bothHubs ? minHubDist : oneHub ? minNodeDist * 1.35 : minNodeDist;
21043
+ const effectiveRepRadius = bothHubs ? repulsionRadius * 1.6 : repulsionRadius;
21044
+ if (dist < effectiveRepRadius) {
21045
+ const force = dist < effectiveMinDist ? (effectiveMinDist - dist) / dist * 2.4 : (effectiveRepRadius - dist) / effectiveRepRadius * 0.65 / dist;
20995
21046
  const fx = dx * force;
20996
21047
  const fy = dy * force;
20997
- const fz = (pA.z - pB.z) * force * 0.5;
21048
+ const fz = dz * force;
20998
21049
  vA.x += fx;
20999
21050
  vA.y += fy;
21000
21051
  vA.z += fz;
@@ -21010,42 +21061,40 @@ function XViewScene({
21010
21061
  const pV = posMap.get(v);
21011
21062
  const vU = velMap.get(u);
21012
21063
  const vV = velMap.get(v);
21064
+ const degU = degreeMap.get(u) || 1;
21065
+ const degV = degreeMap.get(v) || 1;
21013
21066
  const dx = pV.x - pU.x;
21014
21067
  const dy = pV.y - pU.y;
21015
21068
  const dz = pV.z - pU.z;
21016
21069
  const dist = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
21017
21070
  const delta = dist - idealEdgeDist;
21018
- const springStrength = 0.085;
21071
+ const degreeDamping = 1 / Math.sqrt(degU + degV);
21072
+ const springStrength = 0.08 * degreeDamping;
21019
21073
  const fx = dx / dist * delta * springStrength;
21020
21074
  const fy = dy / dist * delta * springStrength;
21021
21075
  const fz = dz / dist * delta * springStrength;
21022
- vU.x += fx;
21023
- vU.y += fy;
21024
- vU.z += fz;
21025
- vV.x -= fx;
21026
- vV.y -= fy;
21027
- vV.z -= fz;
21076
+ const weightU = degV / (degU + degV);
21077
+ const weightV = degU / (degU + degV);
21078
+ vU.x += fx * weightU * 1.7;
21079
+ vU.y += fy * weightU * 1.7;
21080
+ vU.z += fz * weightU * 1.7;
21081
+ vV.x -= fx * weightV * 1.7;
21082
+ vV.y -= fy * weightV * 1.7;
21083
+ vV.z -= fz * weightV * 1.7;
21028
21084
  }
21029
21085
  for (let i = 0; i < N; i++) {
21030
- const id = String(sortedIds[i]);
21086
+ const id = interleavedIds[i];
21031
21087
  const p = posMap.get(id);
21032
21088
  const v = velMap.get(id);
21033
- const nx = p.x / boundX;
21034
- const ny = p.y / boundY;
21035
- const nz = p.z / boundZ;
21036
- const radialNorm = Math.sqrt(nx * nx + ny * ny);
21037
- if (radialNorm > 0.95) {
21038
- const pull = (radialNorm - 0.95) * 2.2;
21039
- v.x -= nx * pull * 8;
21040
- v.y -= ny * pull * 8;
21041
- } else if (radialNorm < 0.2 && N > 12 && (degreeMap.get(id) || 0) === 0) {
21042
- v.x += (nx || 0.1) * 1.5;
21043
- v.y += (ny || 0.1) * 1.5;
21044
- }
21045
- if (Math.abs(nz) > 0.95) {
21046
- v.z -= nz * (Math.abs(nz) - 0.95) * 10;
21089
+ const anchor = anchorMap.get(id);
21090
+ const deg = degreeMap.get(id) || 0;
21091
+ if (deg === 0 || deg >= 3) {
21092
+ const anchorPull = deg === 0 ? 0.055 : 0.035;
21093
+ v.x += (anchor.x - p.x) * anchorPull;
21094
+ v.y += (anchor.y - p.y) * anchorPull;
21095
+ v.z += (anchor.z - p.z) * anchorPull;
21047
21096
  }
21048
- const maxStep = 6 * cooling;
21097
+ const maxStep = 10 * cooling;
21049
21098
  const speed = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z) || 1;
21050
21099
  const scale = speed > maxStep ? maxStep / speed : cooling;
21051
21100
  p.x += v.x * scale;
@@ -21077,6 +21126,20 @@ function XViewScene({
21077
21126
  sumZ += target.z;
21078
21127
  nodeCount++;
21079
21128
  });
21129
+ if (nodeCount > 0) {
21130
+ const cx = sumX / nodeCount;
21131
+ const cy = sumY / nodeCount;
21132
+ const cz = sumZ / nodeCount;
21133
+ let maxDist = 120;
21134
+ activeNodeIds.forEach((id) => {
21135
+ const p = posMap.get(String(id));
21136
+ if (p) {
21137
+ const d = Math.hypot(p.x - cx, p.y - cy, p.z - cz);
21138
+ if (d > maxDist) maxDist = d;
21139
+ }
21140
+ });
21141
+ networkMaxRadius = maxDist;
21142
+ }
21080
21143
  }
21081
21144
  if (nodeCount > 0) {
21082
21145
  const centerX = sumX / nodeCount;
@@ -21095,13 +21158,8 @@ function XViewScene({
21095
21158
  const radius = Math.max(80, nodeCount * 8);
21096
21159
  zoomZ = radius * 2.5;
21097
21160
  } else if (type === "Network") {
21098
- const baseSpread = Math.max(45, Math.sqrt(nodeCount) * 19);
21099
- const immersionFactor = Math.max(
21100
- 0.52,
21101
- 1.15 - Math.min(nodeCount, 120) * 52e-4
21102
- );
21103
- zoomZ = targetFocus.z + Math.max(55, baseSpread * immersionFactor);
21104
- camOffsetY = -baseSpread * 0.08;
21161
+ zoomZ = targetFocus.z + Math.max(220, networkMaxRadius * 1.85);
21162
+ camOffsetY = networkMaxRadius * 0.12;
21105
21163
  }
21106
21164
  const camTween = new import_tween2.Tween(camera.position).to(
21107
21165
  {
package/dist/index.mjs CHANGED
@@ -20925,6 +20925,7 @@ function XViewScene({
20925
20925
  let sumY = 0;
20926
20926
  let sumZ = 0;
20927
20927
  let nodeCount = 0;
20928
+ let networkMaxRadius = 150;
20928
20929
  activeNodeIds.forEach((id) => {
20929
20930
  const mesh = nodeObjects[id];
20930
20931
  if (mesh && mesh.material) {
@@ -21032,6 +21033,7 @@ function XViewScene({
21032
21033
  const activeSet = new Set(activeNodeIds.map(String));
21033
21034
  const edges = [];
21034
21035
  const degreeMap = new Map(activeNodeIds.map((id) => [String(id), 0]));
21036
+ const adjMap = new Map(activeNodeIds.map((id) => [String(id), []]));
21035
21037
  const seenPairs = /* @__PURE__ */ new Set();
21036
21038
  [...allLinks, ...ancestryLinks].forEach((line) => {
21037
21039
  var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2;
@@ -21048,55 +21050,104 @@ function XViewScene({
21048
21050
  edges.push([u, v]);
21049
21051
  degreeMap.set(u, (degreeMap.get(u) || 0) + 1);
21050
21052
  degreeMap.set(v, (degreeMap.get(v) || 0) + 1);
21053
+ adjMap.get(u).push(v);
21054
+ adjMap.get(v).push(u);
21051
21055
  }
21052
21056
  }
21053
21057
  });
21054
- const baseSpread = Math.max(45, Math.sqrt(N) * 19);
21055
- const boundX = baseSpread * 1.75;
21056
- const boundY = baseSpread * 1;
21057
- const boundZ = Math.min(85, Math.max(25, baseSpread * 0.45));
21058
- const sortedIds = [...activeNodeIds].sort(
21059
- (a, b) => (degreeMap.get(String(b)) || 0) - (degreeMap.get(String(a)) || 0)
21058
+ const hubCount = Array.from(degreeMap.values()).filter(
21059
+ (d) => d >= 3
21060
+ ).length;
21061
+ const volumeRadius = Math.max(
21062
+ 130,
21063
+ Math.cbrt(N) * 58 + Math.sqrt(N) * 24 + hubCount * 8
21060
21064
  );
21065
+ const radiusX = volumeRadius * 1.45;
21066
+ const radiusY = volumeRadius * 1.15;
21067
+ const radiusZ = volumeRadius * 1.15;
21068
+ const connectedIds = activeNodeIds.map(String).filter((id) => (degreeMap.get(id) || 0) > 0).sort((a, b) => (degreeMap.get(b) || 0) - (degreeMap.get(a) || 0));
21069
+ const isolatedIds = activeNodeIds.map(String).filter((id) => (degreeMap.get(id) || 0) === 0);
21070
+ const interleavedIds = [];
21071
+ let cIdx = 0;
21072
+ let iIdx = 0;
21073
+ for (let k = 0; k < N; k++) {
21074
+ const takeConnected = cIdx < connectedIds.length && (iIdx >= isolatedIds.length || cIdx / Math.max(1, connectedIds.length) <= iIdx / Math.max(1, isolatedIds.length));
21075
+ if (takeConnected) {
21076
+ interleavedIds.push(connectedIds[cIdx++]);
21077
+ } else if (iIdx < isolatedIds.length) {
21078
+ interleavedIds.push(isolatedIds[iIdx++]);
21079
+ }
21080
+ }
21061
21081
  const posMap = /* @__PURE__ */ new Map();
21082
+ const anchorMap = /* @__PURE__ */ new Map();
21062
21083
  const velMap = /* @__PURE__ */ new Map();
21063
21084
  const goldenAngle = Math.PI * (3 - Math.sqrt(5));
21064
- sortedIds.forEach((id, idx) => {
21065
- const t = N > 1 ? idx / (N - 1) : 0.5;
21066
- const r = Math.sqrt(0.12 + 0.88 * t);
21067
- const theta = idx * goldenAngle * 7;
21068
- const zLayer = Math.sin(idx * 2.39996) * boundZ * (0.4 + 0.6 * r);
21069
- posMap.set(String(id), {
21070
- x: Math.cos(theta) * r * boundX,
21071
- y: Math.sin(theta) * r * boundY,
21072
- z: zLayer
21073
- });
21074
- velMap.set(String(id), { x: 0, y: 0, z: 0 });
21085
+ interleavedIds.forEach((id, idx) => {
21086
+ const t = (idx + 0.5) / Math.max(1, N);
21087
+ const yDir = 1 - 2 * t;
21088
+ const radiusAtY = Math.sqrt(Math.max(0, 1 - yDir * yDir));
21089
+ const theta = idx * goldenAngle;
21090
+ const xDir = Math.cos(theta) * radiusAtY;
21091
+ const zDir = Math.sin(theta) * radiusAtY;
21092
+ const shell = 0.3 + 0.7 * Math.cbrt(idx * 7 % Math.max(1, N) / Math.max(1, N));
21093
+ const px = xDir * shell * radiusX;
21094
+ const py = yDir * shell * radiusY;
21095
+ const pz = zDir * shell * radiusZ;
21096
+ posMap.set(id, { x: px, y: py, z: pz });
21097
+ anchorMap.set(id, { x: px, y: py, z: pz });
21098
+ velMap.set(id, { x: 0, y: 0, z: 0 });
21099
+ });
21100
+ connectedIds.forEach((id, idx) => {
21101
+ const deg = degreeMap.get(id) || 0;
21102
+ if (deg <= 2) {
21103
+ const neighbors = adjMap.get(id) || [];
21104
+ const hubNeighbor = neighbors.reduce(
21105
+ (best, curr) => (degreeMap.get(curr) || 0) > (degreeMap.get(best) || 0) ? curr : best,
21106
+ neighbors[0]
21107
+ );
21108
+ const hubPos = posMap.get(hubNeighbor);
21109
+ const myPos = posMap.get(id);
21110
+ if (hubPos && myPos && hubNeighbor !== id) {
21111
+ const phi = idx * goldenAngle * 3;
21112
+ const costheta = Math.cos(idx * 1.732);
21113
+ const sintheta = Math.sqrt(Math.max(0, 1 - costheta * costheta));
21114
+ const orbitDist = 62 + idx % 3 * 16;
21115
+ myPos.x = hubPos.x + sintheta * Math.cos(phi) * orbitDist;
21116
+ myPos.y = hubPos.y + sintheta * Math.sin(phi) * orbitDist;
21117
+ myPos.z = hubPos.z + costheta * orbitDist;
21118
+ }
21119
+ }
21075
21120
  });
21076
- const iterations = 120;
21077
- const minNodeDist = 24;
21078
- const idealEdgeDist = 28;
21079
- const repulsionRadius = 65;
21121
+ const iterations = 130;
21122
+ const minNodeDist = 56;
21123
+ const minHubDist = 140;
21124
+ const idealEdgeDist = 72;
21125
+ const repulsionRadius = 150;
21080
21126
  for (let iter = 0; iter < iterations; iter++) {
21081
- const cooling = 1 - iter / iterations * 0.75;
21127
+ const cooling = 1 - iter / iterations * 0.78;
21082
21128
  for (let i = 0; i < N; i++) {
21083
- const idA = String(sortedIds[i]);
21129
+ const idA = interleavedIds[i];
21084
21130
  const pA = posMap.get(idA);
21085
21131
  const vA = velMap.get(idA);
21132
+ const degA = degreeMap.get(idA) || 0;
21086
21133
  for (let j = i + 1; j < N; j++) {
21087
- const idB = String(sortedIds[j]);
21134
+ const idB = interleavedIds[j];
21088
21135
  const pB = posMap.get(idB);
21089
21136
  const vB = velMap.get(idB);
21137
+ const degB = degreeMap.get(idB) || 0;
21090
21138
  const dx = pA.x - pB.x;
21091
21139
  const dy = pA.y - pB.y;
21092
- const dz = (pA.z - pB.z) * 0.6;
21093
- const distSq = dx * dx + dy * dy + dz * dz + 0.1;
21094
- const dist = Math.sqrt(distSq);
21095
- if (dist < repulsionRadius) {
21096
- const force = dist < minNodeDist ? (minNodeDist - dist) / dist * 1.8 : (repulsionRadius - dist) / repulsionRadius * 0.35 / dist;
21140
+ const dz = pA.z - pB.z;
21141
+ const dist = Math.sqrt(dx * dx + dy * dy + dz * dz + 0.1);
21142
+ const bothHubs = degA >= 3 && degB >= 3;
21143
+ const oneHub = degA >= 3 || degB >= 3;
21144
+ const effectiveMinDist = bothHubs ? minHubDist : oneHub ? minNodeDist * 1.35 : minNodeDist;
21145
+ const effectiveRepRadius = bothHubs ? repulsionRadius * 1.6 : repulsionRadius;
21146
+ if (dist < effectiveRepRadius) {
21147
+ const force = dist < effectiveMinDist ? (effectiveMinDist - dist) / dist * 2.4 : (effectiveRepRadius - dist) / effectiveRepRadius * 0.65 / dist;
21097
21148
  const fx = dx * force;
21098
21149
  const fy = dy * force;
21099
- const fz = (pA.z - pB.z) * force * 0.5;
21150
+ const fz = dz * force;
21100
21151
  vA.x += fx;
21101
21152
  vA.y += fy;
21102
21153
  vA.z += fz;
@@ -21112,42 +21163,40 @@ function XViewScene({
21112
21163
  const pV = posMap.get(v);
21113
21164
  const vU = velMap.get(u);
21114
21165
  const vV = velMap.get(v);
21166
+ const degU = degreeMap.get(u) || 1;
21167
+ const degV = degreeMap.get(v) || 1;
21115
21168
  const dx = pV.x - pU.x;
21116
21169
  const dy = pV.y - pU.y;
21117
21170
  const dz = pV.z - pU.z;
21118
21171
  const dist = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
21119
21172
  const delta = dist - idealEdgeDist;
21120
- const springStrength = 0.085;
21173
+ const degreeDamping = 1 / Math.sqrt(degU + degV);
21174
+ const springStrength = 0.08 * degreeDamping;
21121
21175
  const fx = dx / dist * delta * springStrength;
21122
21176
  const fy = dy / dist * delta * springStrength;
21123
21177
  const fz = dz / dist * delta * springStrength;
21124
- vU.x += fx;
21125
- vU.y += fy;
21126
- vU.z += fz;
21127
- vV.x -= fx;
21128
- vV.y -= fy;
21129
- vV.z -= fz;
21178
+ const weightU = degV / (degU + degV);
21179
+ const weightV = degU / (degU + degV);
21180
+ vU.x += fx * weightU * 1.7;
21181
+ vU.y += fy * weightU * 1.7;
21182
+ vU.z += fz * weightU * 1.7;
21183
+ vV.x -= fx * weightV * 1.7;
21184
+ vV.y -= fy * weightV * 1.7;
21185
+ vV.z -= fz * weightV * 1.7;
21130
21186
  }
21131
21187
  for (let i = 0; i < N; i++) {
21132
- const id = String(sortedIds[i]);
21188
+ const id = interleavedIds[i];
21133
21189
  const p = posMap.get(id);
21134
21190
  const v = velMap.get(id);
21135
- const nx = p.x / boundX;
21136
- const ny = p.y / boundY;
21137
- const nz = p.z / boundZ;
21138
- const radialNorm = Math.sqrt(nx * nx + ny * ny);
21139
- if (radialNorm > 0.95) {
21140
- const pull = (radialNorm - 0.95) * 2.2;
21141
- v.x -= nx * pull * 8;
21142
- v.y -= ny * pull * 8;
21143
- } else if (radialNorm < 0.2 && N > 12 && (degreeMap.get(id) || 0) === 0) {
21144
- v.x += (nx || 0.1) * 1.5;
21145
- v.y += (ny || 0.1) * 1.5;
21146
- }
21147
- if (Math.abs(nz) > 0.95) {
21148
- v.z -= nz * (Math.abs(nz) - 0.95) * 10;
21191
+ const anchor = anchorMap.get(id);
21192
+ const deg = degreeMap.get(id) || 0;
21193
+ if (deg === 0 || deg >= 3) {
21194
+ const anchorPull = deg === 0 ? 0.055 : 0.035;
21195
+ v.x += (anchor.x - p.x) * anchorPull;
21196
+ v.y += (anchor.y - p.y) * anchorPull;
21197
+ v.z += (anchor.z - p.z) * anchorPull;
21149
21198
  }
21150
- const maxStep = 6 * cooling;
21199
+ const maxStep = 10 * cooling;
21151
21200
  const speed = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z) || 1;
21152
21201
  const scale = speed > maxStep ? maxStep / speed : cooling;
21153
21202
  p.x += v.x * scale;
@@ -21179,6 +21228,20 @@ function XViewScene({
21179
21228
  sumZ += target.z;
21180
21229
  nodeCount++;
21181
21230
  });
21231
+ if (nodeCount > 0) {
21232
+ const cx = sumX / nodeCount;
21233
+ const cy = sumY / nodeCount;
21234
+ const cz = sumZ / nodeCount;
21235
+ let maxDist = 120;
21236
+ activeNodeIds.forEach((id) => {
21237
+ const p = posMap.get(String(id));
21238
+ if (p) {
21239
+ const d = Math.hypot(p.x - cx, p.y - cy, p.z - cz);
21240
+ if (d > maxDist) maxDist = d;
21241
+ }
21242
+ });
21243
+ networkMaxRadius = maxDist;
21244
+ }
21182
21245
  }
21183
21246
  if (nodeCount > 0) {
21184
21247
  const centerX = sumX / nodeCount;
@@ -21197,13 +21260,8 @@ function XViewScene({
21197
21260
  const radius = Math.max(80, nodeCount * 8);
21198
21261
  zoomZ = radius * 2.5;
21199
21262
  } else if (type === "Network") {
21200
- const baseSpread = Math.max(45, Math.sqrt(nodeCount) * 19);
21201
- const immersionFactor = Math.max(
21202
- 0.52,
21203
- 1.15 - Math.min(nodeCount, 120) * 52e-4
21204
- );
21205
- zoomZ = targetFocus.z + Math.max(55, baseSpread * immersionFactor);
21206
- camOffsetY = -baseSpread * 0.08;
21263
+ zoomZ = targetFocus.z + Math.max(220, networkMaxRadius * 1.85);
21264
+ camOffsetY = networkMaxRadius * 0.12;
21207
21265
  }
21208
21266
  const camTween = new Tween2(camera.position).to(
21209
21267
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "Pacote privado contendo os componentes e lógica de renderização 3D do X View.",
5
5
  "author": "iv.x - Engenharia de Software - ivxsoftwarehouse@gmail.com",
6
6
  "license": "UNLICENSED",