@lv-x-software-house/x_view 1.3.9 → 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.
- package/dist/index.js +240 -4
- package/dist/index.mjs +240 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6232,7 +6232,8 @@ function XViewSidebar({
|
|
|
6232
6232
|
options: [
|
|
6233
6233
|
{ value: "Star", label: "Star" },
|
|
6234
6234
|
{ value: "Circle", label: "Circle" },
|
|
6235
|
-
{ value: "Column", label: "Column" }
|
|
6235
|
+
{ value: "Column", label: "Column" },
|
|
6236
|
+
{ value: "Network", label: "Network" }
|
|
6236
6237
|
],
|
|
6237
6238
|
placeholder: "Selecione um Formato"
|
|
6238
6239
|
}
|
|
@@ -20807,13 +20808,22 @@ function XViewScene({
|
|
|
20807
20808
|
);
|
|
20808
20809
|
const handleActivateReshapeLens = (0, import_react38.useCallback)(
|
|
20809
20810
|
({ type, columns, centerNodeId }) => {
|
|
20810
|
-
const {
|
|
20811
|
+
const {
|
|
20812
|
+
nodeObjects,
|
|
20813
|
+
allLinks = [],
|
|
20814
|
+
ancestryLinks = [],
|
|
20815
|
+
tweenGroup,
|
|
20816
|
+
camera,
|
|
20817
|
+
controls
|
|
20818
|
+
} = stateRef.current;
|
|
20811
20819
|
if (!nodeObjects || !tweenGroup || !camera || !controls) return;
|
|
20812
20820
|
const activeNodeIds = Object.keys(nodeObjects);
|
|
20813
20821
|
if (activeNodeIds.length === 0) return;
|
|
20814
20822
|
let sumX = 0;
|
|
20815
20823
|
let sumY = 0;
|
|
20824
|
+
let sumZ = 0;
|
|
20816
20825
|
let nodeCount = 0;
|
|
20826
|
+
let networkMaxRadius = 150;
|
|
20817
20827
|
activeNodeIds.forEach((id) => {
|
|
20818
20828
|
const mesh = nodeObjects[id];
|
|
20819
20829
|
if (mesh && mesh.material) {
|
|
@@ -20916,23 +20926,249 @@ function XViewScene({
|
|
|
20916
20926
|
sumY += targetY;
|
|
20917
20927
|
nodeCount++;
|
|
20918
20928
|
});
|
|
20929
|
+
} else if (type === "Network") {
|
|
20930
|
+
const N = activeNodeIds.length;
|
|
20931
|
+
const activeSet = new Set(activeNodeIds.map(String));
|
|
20932
|
+
const edges = [];
|
|
20933
|
+
const degreeMap = new Map(activeNodeIds.map((id) => [String(id), 0]));
|
|
20934
|
+
const adjMap = new Map(activeNodeIds.map((id) => [String(id), []]));
|
|
20935
|
+
const seenPairs = /* @__PURE__ */ new Set();
|
|
20936
|
+
[...allLinks, ...ancestryLinks].forEach((line) => {
|
|
20937
|
+
var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2;
|
|
20938
|
+
const u = String(
|
|
20939
|
+
((_c2 = (_b2 = (_a2 = line.userData) == null ? void 0 : _a2.sourceNode) == null ? void 0 : _b2.userData) == null ? void 0 : _c2.id) ?? ((_d2 = line.userData) == null ? void 0 : _d2.source) ?? ""
|
|
20940
|
+
);
|
|
20941
|
+
const v = String(
|
|
20942
|
+
((_g2 = (_f2 = (_e2 = line.userData) == null ? void 0 : _e2.targetNode) == null ? void 0 : _f2.userData) == null ? void 0 : _g2.id) ?? ((_h2 = line.userData) == null ? void 0 : _h2.target) ?? ""
|
|
20943
|
+
);
|
|
20944
|
+
if (u && v && u !== v && activeSet.has(u) && activeSet.has(v)) {
|
|
20945
|
+
const pairKey = u < v ? `${u}_${v}` : `${v}_${u}`;
|
|
20946
|
+
if (!seenPairs.has(pairKey)) {
|
|
20947
|
+
seenPairs.add(pairKey);
|
|
20948
|
+
edges.push([u, v]);
|
|
20949
|
+
degreeMap.set(u, (degreeMap.get(u) || 0) + 1);
|
|
20950
|
+
degreeMap.set(v, (degreeMap.get(v) || 0) + 1);
|
|
20951
|
+
adjMap.get(u).push(v);
|
|
20952
|
+
adjMap.get(v).push(u);
|
|
20953
|
+
}
|
|
20954
|
+
}
|
|
20955
|
+
});
|
|
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
|
|
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
|
+
}
|
|
20979
|
+
const posMap = /* @__PURE__ */ new Map();
|
|
20980
|
+
const anchorMap = /* @__PURE__ */ new Map();
|
|
20981
|
+
const velMap = /* @__PURE__ */ new Map();
|
|
20982
|
+
const goldenAngle = Math.PI * (3 - Math.sqrt(5));
|
|
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
|
+
}
|
|
21018
|
+
});
|
|
21019
|
+
const iterations = 130;
|
|
21020
|
+
const minNodeDist = 56;
|
|
21021
|
+
const minHubDist = 140;
|
|
21022
|
+
const idealEdgeDist = 72;
|
|
21023
|
+
const repulsionRadius = 150;
|
|
21024
|
+
for (let iter = 0; iter < iterations; iter++) {
|
|
21025
|
+
const cooling = 1 - iter / iterations * 0.78;
|
|
21026
|
+
for (let i = 0; i < N; i++) {
|
|
21027
|
+
const idA = interleavedIds[i];
|
|
21028
|
+
const pA = posMap.get(idA);
|
|
21029
|
+
const vA = velMap.get(idA);
|
|
21030
|
+
const degA = degreeMap.get(idA) || 0;
|
|
21031
|
+
for (let j = i + 1; j < N; j++) {
|
|
21032
|
+
const idB = interleavedIds[j];
|
|
21033
|
+
const pB = posMap.get(idB);
|
|
21034
|
+
const vB = velMap.get(idB);
|
|
21035
|
+
const degB = degreeMap.get(idB) || 0;
|
|
21036
|
+
const dx = pA.x - pB.x;
|
|
21037
|
+
const dy = pA.y - pB.y;
|
|
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;
|
|
21046
|
+
const fx = dx * force;
|
|
21047
|
+
const fy = dy * force;
|
|
21048
|
+
const fz = dz * force;
|
|
21049
|
+
vA.x += fx;
|
|
21050
|
+
vA.y += fy;
|
|
21051
|
+
vA.z += fz;
|
|
21052
|
+
vB.x -= fx;
|
|
21053
|
+
vB.y -= fy;
|
|
21054
|
+
vB.z -= fz;
|
|
21055
|
+
}
|
|
21056
|
+
}
|
|
21057
|
+
}
|
|
21058
|
+
for (let e = 0; e < edges.length; e++) {
|
|
21059
|
+
const [u, v] = edges[e];
|
|
21060
|
+
const pU = posMap.get(u);
|
|
21061
|
+
const pV = posMap.get(v);
|
|
21062
|
+
const vU = velMap.get(u);
|
|
21063
|
+
const vV = velMap.get(v);
|
|
21064
|
+
const degU = degreeMap.get(u) || 1;
|
|
21065
|
+
const degV = degreeMap.get(v) || 1;
|
|
21066
|
+
const dx = pV.x - pU.x;
|
|
21067
|
+
const dy = pV.y - pU.y;
|
|
21068
|
+
const dz = pV.z - pU.z;
|
|
21069
|
+
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
21070
|
+
const delta = dist - idealEdgeDist;
|
|
21071
|
+
const degreeDamping = 1 / Math.sqrt(degU + degV);
|
|
21072
|
+
const springStrength = 0.08 * degreeDamping;
|
|
21073
|
+
const fx = dx / dist * delta * springStrength;
|
|
21074
|
+
const fy = dy / dist * delta * springStrength;
|
|
21075
|
+
const fz = dz / dist * delta * springStrength;
|
|
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;
|
|
21084
|
+
}
|
|
21085
|
+
for (let i = 0; i < N; i++) {
|
|
21086
|
+
const id = interleavedIds[i];
|
|
21087
|
+
const p = posMap.get(id);
|
|
21088
|
+
const v = velMap.get(id);
|
|
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;
|
|
21096
|
+
}
|
|
21097
|
+
const maxStep = 10 * cooling;
|
|
21098
|
+
const speed = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z) || 1;
|
|
21099
|
+
const scale = speed > maxStep ? maxStep / speed : cooling;
|
|
21100
|
+
p.x += v.x * scale;
|
|
21101
|
+
p.y += v.y * scale;
|
|
21102
|
+
p.z += v.z * scale;
|
|
21103
|
+
v.x *= 0.4;
|
|
21104
|
+
v.y *= 0.4;
|
|
21105
|
+
v.z *= 0.4;
|
|
21106
|
+
}
|
|
21107
|
+
}
|
|
21108
|
+
activeNodeIds.forEach((id) => {
|
|
21109
|
+
const mesh = nodeObjects[id];
|
|
21110
|
+
const target = posMap.get(String(id)) || { x: 0, y: 0, z: 0 };
|
|
21111
|
+
const posTween = new import_tween2.Tween(mesh.position).to({ x: target.x, y: target.y, z: target.z }, 1500).easing(import_tween2.Easing.Cubic.InOut);
|
|
21112
|
+
tweenGroup.add(posTween);
|
|
21113
|
+
posTween.start();
|
|
21114
|
+
if (mesh.userData.labelObject) {
|
|
21115
|
+
const labelTarget = new THREE3.Vector3(
|
|
21116
|
+
target.x,
|
|
21117
|
+
target.y,
|
|
21118
|
+
target.z
|
|
21119
|
+
).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
|
|
21120
|
+
const lblTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(import_tween2.Easing.Cubic.InOut);
|
|
21121
|
+
tweenGroup.add(lblTween);
|
|
21122
|
+
lblTween.start();
|
|
21123
|
+
}
|
|
21124
|
+
sumX += target.x;
|
|
21125
|
+
sumY += target.y;
|
|
21126
|
+
sumZ += target.z;
|
|
21127
|
+
nodeCount++;
|
|
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
|
+
}
|
|
20919
21143
|
}
|
|
20920
21144
|
if (nodeCount > 0) {
|
|
20921
21145
|
const centerX = sumX / nodeCount;
|
|
20922
21146
|
const centerY = sumY / nodeCount;
|
|
20923
|
-
const
|
|
21147
|
+
const centerZ = type === "Network" ? sumZ / nodeCount : 0;
|
|
21148
|
+
const targetFocus = new THREE3.Vector3(centerX, centerY, centerZ);
|
|
20924
21149
|
const targetTween = new import_tween2.Tween(controls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(import_tween2.Easing.Cubic.InOut);
|
|
20925
21150
|
tweenGroup.add(targetTween);
|
|
20926
21151
|
targetTween.start();
|
|
20927
21152
|
let zoomZ = 140;
|
|
21153
|
+
let camOffsetY = 0;
|
|
20928
21154
|
if (type === "Column") {
|
|
20929
21155
|
const numRows = Math.ceil(nodeCount / (columns || 4));
|
|
20930
21156
|
zoomZ = Math.max(140, numRows * 50);
|
|
20931
21157
|
} else if (type === "Circle" || type === "Star") {
|
|
20932
21158
|
const radius = Math.max(80, nodeCount * 8);
|
|
20933
21159
|
zoomZ = radius * 2.5;
|
|
21160
|
+
} else if (type === "Network") {
|
|
21161
|
+
zoomZ = targetFocus.z + Math.max(220, networkMaxRadius * 1.85);
|
|
21162
|
+
camOffsetY = networkMaxRadius * 0.12;
|
|
20934
21163
|
}
|
|
20935
|
-
const camTween = new import_tween2.Tween(camera.position).to(
|
|
21164
|
+
const camTween = new import_tween2.Tween(camera.position).to(
|
|
21165
|
+
{
|
|
21166
|
+
x: targetFocus.x,
|
|
21167
|
+
y: targetFocus.y + camOffsetY,
|
|
21168
|
+
z: zoomZ
|
|
21169
|
+
},
|
|
21170
|
+
1500
|
|
21171
|
+
).easing(import_tween2.Easing.Cubic.InOut);
|
|
20936
21172
|
tweenGroup.add(camTween);
|
|
20937
21173
|
camTween.start();
|
|
20938
21174
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -6193,7 +6193,8 @@ function XViewSidebar({
|
|
|
6193
6193
|
options: [
|
|
6194
6194
|
{ value: "Star", label: "Star" },
|
|
6195
6195
|
{ value: "Circle", label: "Circle" },
|
|
6196
|
-
{ value: "Column", label: "Column" }
|
|
6196
|
+
{ value: "Column", label: "Column" },
|
|
6197
|
+
{ value: "Network", label: "Network" }
|
|
6197
6198
|
],
|
|
6198
6199
|
placeholder: "Selecione um Formato"
|
|
6199
6200
|
}
|
|
@@ -20909,13 +20910,22 @@ function XViewScene({
|
|
|
20909
20910
|
);
|
|
20910
20911
|
const handleActivateReshapeLens = useCallback8(
|
|
20911
20912
|
({ type, columns, centerNodeId }) => {
|
|
20912
|
-
const {
|
|
20913
|
+
const {
|
|
20914
|
+
nodeObjects,
|
|
20915
|
+
allLinks = [],
|
|
20916
|
+
ancestryLinks = [],
|
|
20917
|
+
tweenGroup,
|
|
20918
|
+
camera,
|
|
20919
|
+
controls
|
|
20920
|
+
} = stateRef.current;
|
|
20913
20921
|
if (!nodeObjects || !tweenGroup || !camera || !controls) return;
|
|
20914
20922
|
const activeNodeIds = Object.keys(nodeObjects);
|
|
20915
20923
|
if (activeNodeIds.length === 0) return;
|
|
20916
20924
|
let sumX = 0;
|
|
20917
20925
|
let sumY = 0;
|
|
20926
|
+
let sumZ = 0;
|
|
20918
20927
|
let nodeCount = 0;
|
|
20928
|
+
let networkMaxRadius = 150;
|
|
20919
20929
|
activeNodeIds.forEach((id) => {
|
|
20920
20930
|
const mesh = nodeObjects[id];
|
|
20921
20931
|
if (mesh && mesh.material) {
|
|
@@ -21018,23 +21028,249 @@ function XViewScene({
|
|
|
21018
21028
|
sumY += targetY;
|
|
21019
21029
|
nodeCount++;
|
|
21020
21030
|
});
|
|
21031
|
+
} else if (type === "Network") {
|
|
21032
|
+
const N = activeNodeIds.length;
|
|
21033
|
+
const activeSet = new Set(activeNodeIds.map(String));
|
|
21034
|
+
const edges = [];
|
|
21035
|
+
const degreeMap = new Map(activeNodeIds.map((id) => [String(id), 0]));
|
|
21036
|
+
const adjMap = new Map(activeNodeIds.map((id) => [String(id), []]));
|
|
21037
|
+
const seenPairs = /* @__PURE__ */ new Set();
|
|
21038
|
+
[...allLinks, ...ancestryLinks].forEach((line) => {
|
|
21039
|
+
var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2;
|
|
21040
|
+
const u = String(
|
|
21041
|
+
((_c2 = (_b2 = (_a2 = line.userData) == null ? void 0 : _a2.sourceNode) == null ? void 0 : _b2.userData) == null ? void 0 : _c2.id) ?? ((_d2 = line.userData) == null ? void 0 : _d2.source) ?? ""
|
|
21042
|
+
);
|
|
21043
|
+
const v = String(
|
|
21044
|
+
((_g2 = (_f2 = (_e2 = line.userData) == null ? void 0 : _e2.targetNode) == null ? void 0 : _f2.userData) == null ? void 0 : _g2.id) ?? ((_h2 = line.userData) == null ? void 0 : _h2.target) ?? ""
|
|
21045
|
+
);
|
|
21046
|
+
if (u && v && u !== v && activeSet.has(u) && activeSet.has(v)) {
|
|
21047
|
+
const pairKey = u < v ? `${u}_${v}` : `${v}_${u}`;
|
|
21048
|
+
if (!seenPairs.has(pairKey)) {
|
|
21049
|
+
seenPairs.add(pairKey);
|
|
21050
|
+
edges.push([u, v]);
|
|
21051
|
+
degreeMap.set(u, (degreeMap.get(u) || 0) + 1);
|
|
21052
|
+
degreeMap.set(v, (degreeMap.get(v) || 0) + 1);
|
|
21053
|
+
adjMap.get(u).push(v);
|
|
21054
|
+
adjMap.get(v).push(u);
|
|
21055
|
+
}
|
|
21056
|
+
}
|
|
21057
|
+
});
|
|
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
|
|
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
|
+
}
|
|
21081
|
+
const posMap = /* @__PURE__ */ new Map();
|
|
21082
|
+
const anchorMap = /* @__PURE__ */ new Map();
|
|
21083
|
+
const velMap = /* @__PURE__ */ new Map();
|
|
21084
|
+
const goldenAngle = Math.PI * (3 - Math.sqrt(5));
|
|
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
|
+
}
|
|
21120
|
+
});
|
|
21121
|
+
const iterations = 130;
|
|
21122
|
+
const minNodeDist = 56;
|
|
21123
|
+
const minHubDist = 140;
|
|
21124
|
+
const idealEdgeDist = 72;
|
|
21125
|
+
const repulsionRadius = 150;
|
|
21126
|
+
for (let iter = 0; iter < iterations; iter++) {
|
|
21127
|
+
const cooling = 1 - iter / iterations * 0.78;
|
|
21128
|
+
for (let i = 0; i < N; i++) {
|
|
21129
|
+
const idA = interleavedIds[i];
|
|
21130
|
+
const pA = posMap.get(idA);
|
|
21131
|
+
const vA = velMap.get(idA);
|
|
21132
|
+
const degA = degreeMap.get(idA) || 0;
|
|
21133
|
+
for (let j = i + 1; j < N; j++) {
|
|
21134
|
+
const idB = interleavedIds[j];
|
|
21135
|
+
const pB = posMap.get(idB);
|
|
21136
|
+
const vB = velMap.get(idB);
|
|
21137
|
+
const degB = degreeMap.get(idB) || 0;
|
|
21138
|
+
const dx = pA.x - pB.x;
|
|
21139
|
+
const dy = pA.y - pB.y;
|
|
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;
|
|
21148
|
+
const fx = dx * force;
|
|
21149
|
+
const fy = dy * force;
|
|
21150
|
+
const fz = dz * force;
|
|
21151
|
+
vA.x += fx;
|
|
21152
|
+
vA.y += fy;
|
|
21153
|
+
vA.z += fz;
|
|
21154
|
+
vB.x -= fx;
|
|
21155
|
+
vB.y -= fy;
|
|
21156
|
+
vB.z -= fz;
|
|
21157
|
+
}
|
|
21158
|
+
}
|
|
21159
|
+
}
|
|
21160
|
+
for (let e = 0; e < edges.length; e++) {
|
|
21161
|
+
const [u, v] = edges[e];
|
|
21162
|
+
const pU = posMap.get(u);
|
|
21163
|
+
const pV = posMap.get(v);
|
|
21164
|
+
const vU = velMap.get(u);
|
|
21165
|
+
const vV = velMap.get(v);
|
|
21166
|
+
const degU = degreeMap.get(u) || 1;
|
|
21167
|
+
const degV = degreeMap.get(v) || 1;
|
|
21168
|
+
const dx = pV.x - pU.x;
|
|
21169
|
+
const dy = pV.y - pU.y;
|
|
21170
|
+
const dz = pV.z - pU.z;
|
|
21171
|
+
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
21172
|
+
const delta = dist - idealEdgeDist;
|
|
21173
|
+
const degreeDamping = 1 / Math.sqrt(degU + degV);
|
|
21174
|
+
const springStrength = 0.08 * degreeDamping;
|
|
21175
|
+
const fx = dx / dist * delta * springStrength;
|
|
21176
|
+
const fy = dy / dist * delta * springStrength;
|
|
21177
|
+
const fz = dz / dist * delta * springStrength;
|
|
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;
|
|
21186
|
+
}
|
|
21187
|
+
for (let i = 0; i < N; i++) {
|
|
21188
|
+
const id = interleavedIds[i];
|
|
21189
|
+
const p = posMap.get(id);
|
|
21190
|
+
const v = velMap.get(id);
|
|
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;
|
|
21198
|
+
}
|
|
21199
|
+
const maxStep = 10 * cooling;
|
|
21200
|
+
const speed = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z) || 1;
|
|
21201
|
+
const scale = speed > maxStep ? maxStep / speed : cooling;
|
|
21202
|
+
p.x += v.x * scale;
|
|
21203
|
+
p.y += v.y * scale;
|
|
21204
|
+
p.z += v.z * scale;
|
|
21205
|
+
v.x *= 0.4;
|
|
21206
|
+
v.y *= 0.4;
|
|
21207
|
+
v.z *= 0.4;
|
|
21208
|
+
}
|
|
21209
|
+
}
|
|
21210
|
+
activeNodeIds.forEach((id) => {
|
|
21211
|
+
const mesh = nodeObjects[id];
|
|
21212
|
+
const target = posMap.get(String(id)) || { x: 0, y: 0, z: 0 };
|
|
21213
|
+
const posTween = new Tween2(mesh.position).to({ x: target.x, y: target.y, z: target.z }, 1500).easing(Easing2.Cubic.InOut);
|
|
21214
|
+
tweenGroup.add(posTween);
|
|
21215
|
+
posTween.start();
|
|
21216
|
+
if (mesh.userData.labelObject) {
|
|
21217
|
+
const labelTarget = new THREE3.Vector3(
|
|
21218
|
+
target.x,
|
|
21219
|
+
target.y,
|
|
21220
|
+
target.z
|
|
21221
|
+
).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
|
|
21222
|
+
const lblTween = new Tween2(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(Easing2.Cubic.InOut);
|
|
21223
|
+
tweenGroup.add(lblTween);
|
|
21224
|
+
lblTween.start();
|
|
21225
|
+
}
|
|
21226
|
+
sumX += target.x;
|
|
21227
|
+
sumY += target.y;
|
|
21228
|
+
sumZ += target.z;
|
|
21229
|
+
nodeCount++;
|
|
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
|
+
}
|
|
21021
21245
|
}
|
|
21022
21246
|
if (nodeCount > 0) {
|
|
21023
21247
|
const centerX = sumX / nodeCount;
|
|
21024
21248
|
const centerY = sumY / nodeCount;
|
|
21025
|
-
const
|
|
21249
|
+
const centerZ = type === "Network" ? sumZ / nodeCount : 0;
|
|
21250
|
+
const targetFocus = new THREE3.Vector3(centerX, centerY, centerZ);
|
|
21026
21251
|
const targetTween = new Tween2(controls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(Easing2.Cubic.InOut);
|
|
21027
21252
|
tweenGroup.add(targetTween);
|
|
21028
21253
|
targetTween.start();
|
|
21029
21254
|
let zoomZ = 140;
|
|
21255
|
+
let camOffsetY = 0;
|
|
21030
21256
|
if (type === "Column") {
|
|
21031
21257
|
const numRows = Math.ceil(nodeCount / (columns || 4));
|
|
21032
21258
|
zoomZ = Math.max(140, numRows * 50);
|
|
21033
21259
|
} else if (type === "Circle" || type === "Star") {
|
|
21034
21260
|
const radius = Math.max(80, nodeCount * 8);
|
|
21035
21261
|
zoomZ = radius * 2.5;
|
|
21262
|
+
} else if (type === "Network") {
|
|
21263
|
+
zoomZ = targetFocus.z + Math.max(220, networkMaxRadius * 1.85);
|
|
21264
|
+
camOffsetY = networkMaxRadius * 0.12;
|
|
21036
21265
|
}
|
|
21037
|
-
const camTween = new Tween2(camera.position).to(
|
|
21266
|
+
const camTween = new Tween2(camera.position).to(
|
|
21267
|
+
{
|
|
21268
|
+
x: targetFocus.x,
|
|
21269
|
+
y: targetFocus.y + camOffsetY,
|
|
21270
|
+
z: zoomZ
|
|
21271
|
+
},
|
|
21272
|
+
1500
|
|
21273
|
+
).easing(Easing2.Cubic.InOut);
|
|
21038
21274
|
tweenGroup.add(camTween);
|
|
21039
21275
|
camTween.start();
|
|
21040
21276
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lv-x-software-house/x_view",
|
|
3
|
-
"version": "1.
|
|
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",
|