@lv-x-software-house/x_view 1.2.3-dev.3 → 1.2.3-dev.5
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 +119 -57
- package/dist/index.mjs +119 -57
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2600,7 +2600,54 @@ function createNewCustomProperty(existingProps = []) {
|
|
|
2600
2600
|
isEditing: true
|
|
2601
2601
|
};
|
|
2602
2602
|
}
|
|
2603
|
-
|
|
2603
|
+
var resolveDescriptionReference = (refString, availableNodes = [], availableAncestries = []) => {
|
|
2604
|
+
const match = refString.match(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/);
|
|
2605
|
+
if (!match) return null;
|
|
2606
|
+
const [_, type, itemId, sectionId] = match;
|
|
2607
|
+
let sourceItem = null;
|
|
2608
|
+
if (type === "node") {
|
|
2609
|
+
sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
|
|
2610
|
+
} else {
|
|
2611
|
+
sourceItem = availableAncestries.find((a) => String(a.ancestry_id) === String(itemId));
|
|
2612
|
+
}
|
|
2613
|
+
if (!sourceItem) return null;
|
|
2614
|
+
const sections = parseDescriptionSections(sourceItem.description, sourceItem.description_sections);
|
|
2615
|
+
const targetSection = sections.find((s) => String(s.id) === String(sectionId));
|
|
2616
|
+
if (!targetSection) return null;
|
|
2617
|
+
return {
|
|
2618
|
+
content: targetSection.content,
|
|
2619
|
+
sourceName: sourceItem.name,
|
|
2620
|
+
sourceId: itemId,
|
|
2621
|
+
type
|
|
2622
|
+
};
|
|
2623
|
+
};
|
|
2624
|
+
function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
|
|
2625
|
+
if (!rawText) return "";
|
|
2626
|
+
let text = rawText;
|
|
2627
|
+
const allNodes = parentData ? Object.values(parentData).flatMap((f) => f.nodes || []) : [];
|
|
2628
|
+
const allAncestries = ancestryData || [];
|
|
2629
|
+
text = text.replace(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g, (match, type, itemId, sectionId) => {
|
|
2630
|
+
const resolved = resolveDescriptionReference(match, allNodes, allAncestries);
|
|
2631
|
+
if (resolved && !resolved.error) {
|
|
2632
|
+
return resolved.content;
|
|
2633
|
+
}
|
|
2634
|
+
return "[Refer\xEAncia indispon\xEDvel]";
|
|
2635
|
+
});
|
|
2636
|
+
text = text.replace(/\*\/\s*\d+(?::[a-zA-Z0-9-]+)?\s*\//g, "");
|
|
2637
|
+
text = text.replace(/\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g, (match, nodeId) => {
|
|
2638
|
+
const node = allNodes.find((n) => String(n.id) === String(nodeId));
|
|
2639
|
+
return node ? `@${node.name}` : `@Men\xE7\xE3o`;
|
|
2640
|
+
});
|
|
2641
|
+
text = text.replace(/\[\[MENTION:image:([^|\]]+)\|?([^\]]*)\]\]/g, (match, url, name) => {
|
|
2642
|
+
return name ? `[Imagem: ${name}]` : `[Imagem]`;
|
|
2643
|
+
});
|
|
2644
|
+
text = text.replace(/^#+\s*/gm, "");
|
|
2645
|
+
text = text.replace(/```[\s\S]*?```/g, "[C\xF3digo]");
|
|
2646
|
+
text = text.replace(/-\s\[[xX ]\]\s*/g, "\u2022 ");
|
|
2647
|
+
text = text.replace(/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/g, "$1");
|
|
2648
|
+
return text.trim();
|
|
2649
|
+
}
|
|
2650
|
+
function generateTooltipHtml(data, parentData, ancestryData) {
|
|
2604
2651
|
const ignoredKeys = ["id", "name", "type", "color", "_baseEmissiveIntensity", "description"];
|
|
2605
2652
|
const customKeys = Object.keys(data).filter((k) => !ignoredKeys.includes(k));
|
|
2606
2653
|
const extras = customKeys.length;
|
|
@@ -2616,20 +2663,23 @@ function generateTooltipHtml(data) {
|
|
|
2616
2663
|
<div style="font-weight:600; font-size: 14px; color: #fff;">${typeDisplay}</div>
|
|
2617
2664
|
<div style="margin-bottom: 2px; color: #e2e8f0;">${data.name || ""}</div>`;
|
|
2618
2665
|
if (data.description) {
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2666
|
+
const cleanDesc = formatDescriptionForTooltip(data.description, parentData, ancestryData);
|
|
2667
|
+
if (cleanDesc) {
|
|
2668
|
+
html += `<div style="
|
|
2669
|
+
margin-top: 6px;
|
|
2670
|
+
padding-top: 6px;
|
|
2671
|
+
border-top: 1px solid rgba(255,255,255,0.1);
|
|
2672
|
+
opacity: 0.85;
|
|
2673
|
+
font-size: 13px;
|
|
2674
|
+
display: -webkit-box;
|
|
2675
|
+
-webkit-line-clamp: 4;
|
|
2676
|
+
-webkit-box-orient: vertical;
|
|
2677
|
+
overflow: hidden;
|
|
2678
|
+
text-overflow: ellipsis;
|
|
2679
|
+
word-break: break-word;
|
|
2680
|
+
white-space: normal;
|
|
2681
|
+
">${cleanDesc}</div>`;
|
|
2682
|
+
}
|
|
2633
2683
|
}
|
|
2634
2684
|
if (extras > 0) {
|
|
2635
2685
|
html += `<div style="margin-top:8px; opacity:0.7; font-size:12px; font-style: italic;">
|
|
@@ -2639,28 +2689,7 @@ function generateTooltipHtml(data) {
|
|
|
2639
2689
|
html += `</div>`;
|
|
2640
2690
|
return html;
|
|
2641
2691
|
}
|
|
2642
|
-
|
|
2643
|
-
const match = refString.match(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/);
|
|
2644
|
-
if (!match) return null;
|
|
2645
|
-
const [_, type, itemId, sectionId] = match;
|
|
2646
|
-
let sourceItem = null;
|
|
2647
|
-
if (type === "node") {
|
|
2648
|
-
sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
|
|
2649
|
-
} else {
|
|
2650
|
-
sourceItem = availableAncestries.find((a) => String(a.ancestry_id) === String(itemId));
|
|
2651
|
-
}
|
|
2652
|
-
if (!sourceItem) return null;
|
|
2653
|
-
const sections = parseDescriptionSections(sourceItem.description, sourceItem.description_sections);
|
|
2654
|
-
const targetSection = sections.find((s) => String(s.id) === String(sectionId));
|
|
2655
|
-
if (!targetSection) return null;
|
|
2656
|
-
return {
|
|
2657
|
-
content: targetSection.content,
|
|
2658
|
-
sourceName: sourceItem.name,
|
|
2659
|
-
sourceId: itemId,
|
|
2660
|
-
type
|
|
2661
|
-
};
|
|
2662
|
-
};
|
|
2663
|
-
function generateLinkTooltipHtml(data) {
|
|
2692
|
+
function generateLinkTooltipHtml(data, parentData, ancestryData) {
|
|
2664
2693
|
var _a, _b;
|
|
2665
2694
|
const hasName = (_a = data == null ? void 0 : data.name) == null ? void 0 : _a.trim();
|
|
2666
2695
|
const hasDescription = (_b = data == null ? void 0 : data.description) == null ? void 0 : _b.trim();
|
|
@@ -2672,16 +2701,19 @@ function generateLinkTooltipHtml(data) {
|
|
|
2672
2701
|
html += `<div style="font-weight:600; font-size: 14px; color: #a5f3fc; margin-bottom: 4px;">${data.name}</div>`;
|
|
2673
2702
|
}
|
|
2674
2703
|
if (hasDescription) {
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2704
|
+
const cleanDesc = formatDescriptionForTooltip(data.description, parentData, ancestryData);
|
|
2705
|
+
if (cleanDesc) {
|
|
2706
|
+
html += `<div style="
|
|
2707
|
+
display: -webkit-box;
|
|
2708
|
+
-webkit-line-clamp: 4;
|
|
2709
|
+
-webkit-box-orient: vertical;
|
|
2710
|
+
overflow: hidden;
|
|
2711
|
+
text-overflow: ellipsis;
|
|
2712
|
+
word-break: break-word;
|
|
2713
|
+
white-space: normal;
|
|
2714
|
+
opacity: 0.9;
|
|
2715
|
+
">${cleanDesc}</div>`;
|
|
2716
|
+
}
|
|
2685
2717
|
}
|
|
2686
2718
|
html += `</div>`;
|
|
2687
2719
|
return html;
|
|
@@ -2897,16 +2929,20 @@ function calculateNodePositions(nodes) {
|
|
|
2897
2929
|
}
|
|
2898
2930
|
return positions;
|
|
2899
2931
|
}
|
|
2900
|
-
function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, isSceneBusy }) {
|
|
2932
|
+
function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, isSceneBusy, parentData, ancestryData }) {
|
|
2901
2933
|
if (!tooltipEl || !camera || !mountEl) return;
|
|
2902
2934
|
let content = "";
|
|
2903
2935
|
let positionTarget = null;
|
|
2904
2936
|
let isLink = false;
|
|
2937
|
+
let currentId = "";
|
|
2905
2938
|
if (hoveredNode && !isSceneBusy) {
|
|
2906
|
-
|
|
2939
|
+
currentId = `node_${hoveredNode.userData.id}`;
|
|
2907
2940
|
positionTarget = hoveredNode;
|
|
2941
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
2942
|
+
content = generateTooltipHtml(hoveredNode.userData, parentData, ancestryData);
|
|
2943
|
+
}
|
|
2908
2944
|
} else if (hoveredLink && !isSceneBusy) {
|
|
2909
|
-
|
|
2945
|
+
currentId = `link_${hoveredLink.userData.id}`;
|
|
2910
2946
|
if (hoveredLink.userData.isCurved) {
|
|
2911
2947
|
const positions = hoveredLink.geometry.attributes.position.array;
|
|
2912
2948
|
const midIndex = Math.floor(positions.length / 2 / 3) * 3;
|
|
@@ -2915,12 +2951,23 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
2915
2951
|
positionTarget = new THREE2.Vector3().addVectors(hoveredLink.userData.sourceNode.position, hoveredLink.userData.targetNode.position).multiplyScalar(0.5);
|
|
2916
2952
|
}
|
|
2917
2953
|
isLink = true;
|
|
2954
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
2955
|
+
content = hoveredLink.userData.isAncestryLink ? generateLinkTooltipHtml(hoveredLink.userData.relationship || {}, parentData, ancestryData) : generateLinkTooltipHtml(hoveredLink.userData, parentData, ancestryData);
|
|
2956
|
+
}
|
|
2918
2957
|
}
|
|
2919
|
-
if (
|
|
2920
|
-
tooltipEl.
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2958
|
+
if (positionTarget) {
|
|
2959
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
2960
|
+
tooltipEl.innerHTML = content;
|
|
2961
|
+
tooltipEl.dataset.currentId = currentId;
|
|
2962
|
+
const anchor3D = new THREE2.Vector3();
|
|
2963
|
+
if (isLink) {
|
|
2964
|
+
anchor3D.copy(positionTarget);
|
|
2965
|
+
} else {
|
|
2966
|
+
positionTarget.getWorldPosition(anchor3D);
|
|
2967
|
+
}
|
|
2968
|
+
tooltipEl._fixedAnchor3D = anchor3D;
|
|
2969
|
+
}
|
|
2970
|
+
const screenPosition = tooltipEl._fixedAnchor3D.clone();
|
|
2924
2971
|
screenPosition.project(camera);
|
|
2925
2972
|
const clientWidth = mountEl.clientWidth;
|
|
2926
2973
|
const clientHeight = mountEl.clientHeight;
|
|
@@ -2937,7 +2984,11 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
2937
2984
|
tooltipEl.style.left = `${x}px`;
|
|
2938
2985
|
tooltipEl.style.top = `${y}px`;
|
|
2939
2986
|
} else {
|
|
2940
|
-
tooltipEl.style.display
|
|
2987
|
+
if (tooltipEl.style.display !== "none") {
|
|
2988
|
+
tooltipEl.style.display = "none";
|
|
2989
|
+
tooltipEl.dataset.currentId = "";
|
|
2990
|
+
tooltipEl._fixedAnchor3D = null;
|
|
2991
|
+
}
|
|
2941
2992
|
}
|
|
2942
2993
|
}
|
|
2943
2994
|
var processDescriptionForSave = (text, existingSections = []) => {
|
|
@@ -10907,7 +10958,18 @@ function XViewScene({
|
|
|
10907
10958
|
ghostNode.userData.labelObject.position.copy(ghostNode.position).add(ghostNode.userData.labelOffset);
|
|
10908
10959
|
}
|
|
10909
10960
|
updateSceneHighlights(stateRef.current);
|
|
10910
|
-
updateTooltip({
|
|
10961
|
+
updateTooltip({
|
|
10962
|
+
tooltipEl: tooltipRef.current,
|
|
10963
|
+
hoveredNode: stateRef.current.hoveredNode,
|
|
10964
|
+
hoveredLink: stateRef.current.hoveredLink,
|
|
10965
|
+
camera,
|
|
10966
|
+
mountEl: currentMount,
|
|
10967
|
+
isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive,
|
|
10968
|
+
parentData: parentDataRef.current,
|
|
10969
|
+
// <--- ADICIONADO AQUI
|
|
10970
|
+
ancestryData: ancestryDataRef.current
|
|
10971
|
+
// <--- ADICIONADO AQUI
|
|
10972
|
+
});
|
|
10911
10973
|
(_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
|
|
10912
10974
|
stateRef.current.controls.update();
|
|
10913
10975
|
renderer.autoClear = false;
|
package/dist/index.mjs
CHANGED
|
@@ -2556,7 +2556,54 @@ function createNewCustomProperty(existingProps = []) {
|
|
|
2556
2556
|
isEditing: true
|
|
2557
2557
|
};
|
|
2558
2558
|
}
|
|
2559
|
-
|
|
2559
|
+
var resolveDescriptionReference = (refString, availableNodes = [], availableAncestries = []) => {
|
|
2560
|
+
const match = refString.match(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/);
|
|
2561
|
+
if (!match) return null;
|
|
2562
|
+
const [_, type, itemId, sectionId] = match;
|
|
2563
|
+
let sourceItem = null;
|
|
2564
|
+
if (type === "node") {
|
|
2565
|
+
sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
|
|
2566
|
+
} else {
|
|
2567
|
+
sourceItem = availableAncestries.find((a) => String(a.ancestry_id) === String(itemId));
|
|
2568
|
+
}
|
|
2569
|
+
if (!sourceItem) return null;
|
|
2570
|
+
const sections = parseDescriptionSections(sourceItem.description, sourceItem.description_sections);
|
|
2571
|
+
const targetSection = sections.find((s) => String(s.id) === String(sectionId));
|
|
2572
|
+
if (!targetSection) return null;
|
|
2573
|
+
return {
|
|
2574
|
+
content: targetSection.content,
|
|
2575
|
+
sourceName: sourceItem.name,
|
|
2576
|
+
sourceId: itemId,
|
|
2577
|
+
type
|
|
2578
|
+
};
|
|
2579
|
+
};
|
|
2580
|
+
function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
|
|
2581
|
+
if (!rawText) return "";
|
|
2582
|
+
let text = rawText;
|
|
2583
|
+
const allNodes = parentData ? Object.values(parentData).flatMap((f) => f.nodes || []) : [];
|
|
2584
|
+
const allAncestries = ancestryData || [];
|
|
2585
|
+
text = text.replace(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g, (match, type, itemId, sectionId) => {
|
|
2586
|
+
const resolved = resolveDescriptionReference(match, allNodes, allAncestries);
|
|
2587
|
+
if (resolved && !resolved.error) {
|
|
2588
|
+
return resolved.content;
|
|
2589
|
+
}
|
|
2590
|
+
return "[Refer\xEAncia indispon\xEDvel]";
|
|
2591
|
+
});
|
|
2592
|
+
text = text.replace(/\*\/\s*\d+(?::[a-zA-Z0-9-]+)?\s*\//g, "");
|
|
2593
|
+
text = text.replace(/\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g, (match, nodeId) => {
|
|
2594
|
+
const node = allNodes.find((n) => String(n.id) === String(nodeId));
|
|
2595
|
+
return node ? `@${node.name}` : `@Men\xE7\xE3o`;
|
|
2596
|
+
});
|
|
2597
|
+
text = text.replace(/\[\[MENTION:image:([^|\]]+)\|?([^\]]*)\]\]/g, (match, url, name) => {
|
|
2598
|
+
return name ? `[Imagem: ${name}]` : `[Imagem]`;
|
|
2599
|
+
});
|
|
2600
|
+
text = text.replace(/^#+\s*/gm, "");
|
|
2601
|
+
text = text.replace(/```[\s\S]*?```/g, "[C\xF3digo]");
|
|
2602
|
+
text = text.replace(/-\s\[[xX ]\]\s*/g, "\u2022 ");
|
|
2603
|
+
text = text.replace(/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/g, "$1");
|
|
2604
|
+
return text.trim();
|
|
2605
|
+
}
|
|
2606
|
+
function generateTooltipHtml(data, parentData, ancestryData) {
|
|
2560
2607
|
const ignoredKeys = ["id", "name", "type", "color", "_baseEmissiveIntensity", "description"];
|
|
2561
2608
|
const customKeys = Object.keys(data).filter((k) => !ignoredKeys.includes(k));
|
|
2562
2609
|
const extras = customKeys.length;
|
|
@@ -2572,20 +2619,23 @@ function generateTooltipHtml(data) {
|
|
|
2572
2619
|
<div style="font-weight:600; font-size: 14px; color: #fff;">${typeDisplay}</div>
|
|
2573
2620
|
<div style="margin-bottom: 2px; color: #e2e8f0;">${data.name || ""}</div>`;
|
|
2574
2621
|
if (data.description) {
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2622
|
+
const cleanDesc = formatDescriptionForTooltip(data.description, parentData, ancestryData);
|
|
2623
|
+
if (cleanDesc) {
|
|
2624
|
+
html += `<div style="
|
|
2625
|
+
margin-top: 6px;
|
|
2626
|
+
padding-top: 6px;
|
|
2627
|
+
border-top: 1px solid rgba(255,255,255,0.1);
|
|
2628
|
+
opacity: 0.85;
|
|
2629
|
+
font-size: 13px;
|
|
2630
|
+
display: -webkit-box;
|
|
2631
|
+
-webkit-line-clamp: 4;
|
|
2632
|
+
-webkit-box-orient: vertical;
|
|
2633
|
+
overflow: hidden;
|
|
2634
|
+
text-overflow: ellipsis;
|
|
2635
|
+
word-break: break-word;
|
|
2636
|
+
white-space: normal;
|
|
2637
|
+
">${cleanDesc}</div>`;
|
|
2638
|
+
}
|
|
2589
2639
|
}
|
|
2590
2640
|
if (extras > 0) {
|
|
2591
2641
|
html += `<div style="margin-top:8px; opacity:0.7; font-size:12px; font-style: italic;">
|
|
@@ -2595,28 +2645,7 @@ function generateTooltipHtml(data) {
|
|
|
2595
2645
|
html += `</div>`;
|
|
2596
2646
|
return html;
|
|
2597
2647
|
}
|
|
2598
|
-
|
|
2599
|
-
const match = refString.match(/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/);
|
|
2600
|
-
if (!match) return null;
|
|
2601
|
-
const [_, type, itemId, sectionId] = match;
|
|
2602
|
-
let sourceItem = null;
|
|
2603
|
-
if (type === "node") {
|
|
2604
|
-
sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
|
|
2605
|
-
} else {
|
|
2606
|
-
sourceItem = availableAncestries.find((a) => String(a.ancestry_id) === String(itemId));
|
|
2607
|
-
}
|
|
2608
|
-
if (!sourceItem) return null;
|
|
2609
|
-
const sections = parseDescriptionSections(sourceItem.description, sourceItem.description_sections);
|
|
2610
|
-
const targetSection = sections.find((s) => String(s.id) === String(sectionId));
|
|
2611
|
-
if (!targetSection) return null;
|
|
2612
|
-
return {
|
|
2613
|
-
content: targetSection.content,
|
|
2614
|
-
sourceName: sourceItem.name,
|
|
2615
|
-
sourceId: itemId,
|
|
2616
|
-
type
|
|
2617
|
-
};
|
|
2618
|
-
};
|
|
2619
|
-
function generateLinkTooltipHtml(data) {
|
|
2648
|
+
function generateLinkTooltipHtml(data, parentData, ancestryData) {
|
|
2620
2649
|
var _a, _b;
|
|
2621
2650
|
const hasName = (_a = data == null ? void 0 : data.name) == null ? void 0 : _a.trim();
|
|
2622
2651
|
const hasDescription = (_b = data == null ? void 0 : data.description) == null ? void 0 : _b.trim();
|
|
@@ -2628,16 +2657,19 @@ function generateLinkTooltipHtml(data) {
|
|
|
2628
2657
|
html += `<div style="font-weight:600; font-size: 14px; color: #a5f3fc; margin-bottom: 4px;">${data.name}</div>`;
|
|
2629
2658
|
}
|
|
2630
2659
|
if (hasDescription) {
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2660
|
+
const cleanDesc = formatDescriptionForTooltip(data.description, parentData, ancestryData);
|
|
2661
|
+
if (cleanDesc) {
|
|
2662
|
+
html += `<div style="
|
|
2663
|
+
display: -webkit-box;
|
|
2664
|
+
-webkit-line-clamp: 4;
|
|
2665
|
+
-webkit-box-orient: vertical;
|
|
2666
|
+
overflow: hidden;
|
|
2667
|
+
text-overflow: ellipsis;
|
|
2668
|
+
word-break: break-word;
|
|
2669
|
+
white-space: normal;
|
|
2670
|
+
opacity: 0.9;
|
|
2671
|
+
">${cleanDesc}</div>`;
|
|
2672
|
+
}
|
|
2641
2673
|
}
|
|
2642
2674
|
html += `</div>`;
|
|
2643
2675
|
return html;
|
|
@@ -2853,16 +2885,20 @@ function calculateNodePositions(nodes) {
|
|
|
2853
2885
|
}
|
|
2854
2886
|
return positions;
|
|
2855
2887
|
}
|
|
2856
|
-
function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, isSceneBusy }) {
|
|
2888
|
+
function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, isSceneBusy, parentData, ancestryData }) {
|
|
2857
2889
|
if (!tooltipEl || !camera || !mountEl) return;
|
|
2858
2890
|
let content = "";
|
|
2859
2891
|
let positionTarget = null;
|
|
2860
2892
|
let isLink = false;
|
|
2893
|
+
let currentId = "";
|
|
2861
2894
|
if (hoveredNode && !isSceneBusy) {
|
|
2862
|
-
|
|
2895
|
+
currentId = `node_${hoveredNode.userData.id}`;
|
|
2863
2896
|
positionTarget = hoveredNode;
|
|
2897
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
2898
|
+
content = generateTooltipHtml(hoveredNode.userData, parentData, ancestryData);
|
|
2899
|
+
}
|
|
2864
2900
|
} else if (hoveredLink && !isSceneBusy) {
|
|
2865
|
-
|
|
2901
|
+
currentId = `link_${hoveredLink.userData.id}`;
|
|
2866
2902
|
if (hoveredLink.userData.isCurved) {
|
|
2867
2903
|
const positions = hoveredLink.geometry.attributes.position.array;
|
|
2868
2904
|
const midIndex = Math.floor(positions.length / 2 / 3) * 3;
|
|
@@ -2871,12 +2907,23 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
2871
2907
|
positionTarget = new THREE2.Vector3().addVectors(hoveredLink.userData.sourceNode.position, hoveredLink.userData.targetNode.position).multiplyScalar(0.5);
|
|
2872
2908
|
}
|
|
2873
2909
|
isLink = true;
|
|
2910
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
2911
|
+
content = hoveredLink.userData.isAncestryLink ? generateLinkTooltipHtml(hoveredLink.userData.relationship || {}, parentData, ancestryData) : generateLinkTooltipHtml(hoveredLink.userData, parentData, ancestryData);
|
|
2912
|
+
}
|
|
2874
2913
|
}
|
|
2875
|
-
if (
|
|
2876
|
-
tooltipEl.
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2914
|
+
if (positionTarget) {
|
|
2915
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
2916
|
+
tooltipEl.innerHTML = content;
|
|
2917
|
+
tooltipEl.dataset.currentId = currentId;
|
|
2918
|
+
const anchor3D = new THREE2.Vector3();
|
|
2919
|
+
if (isLink) {
|
|
2920
|
+
anchor3D.copy(positionTarget);
|
|
2921
|
+
} else {
|
|
2922
|
+
positionTarget.getWorldPosition(anchor3D);
|
|
2923
|
+
}
|
|
2924
|
+
tooltipEl._fixedAnchor3D = anchor3D;
|
|
2925
|
+
}
|
|
2926
|
+
const screenPosition = tooltipEl._fixedAnchor3D.clone();
|
|
2880
2927
|
screenPosition.project(camera);
|
|
2881
2928
|
const clientWidth = mountEl.clientWidth;
|
|
2882
2929
|
const clientHeight = mountEl.clientHeight;
|
|
@@ -2893,7 +2940,11 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
2893
2940
|
tooltipEl.style.left = `${x}px`;
|
|
2894
2941
|
tooltipEl.style.top = `${y}px`;
|
|
2895
2942
|
} else {
|
|
2896
|
-
tooltipEl.style.display
|
|
2943
|
+
if (tooltipEl.style.display !== "none") {
|
|
2944
|
+
tooltipEl.style.display = "none";
|
|
2945
|
+
tooltipEl.dataset.currentId = "";
|
|
2946
|
+
tooltipEl._fixedAnchor3D = null;
|
|
2947
|
+
}
|
|
2897
2948
|
}
|
|
2898
2949
|
}
|
|
2899
2950
|
var processDescriptionForSave = (text, existingSections = []) => {
|
|
@@ -10907,7 +10958,18 @@ function XViewScene({
|
|
|
10907
10958
|
ghostNode.userData.labelObject.position.copy(ghostNode.position).add(ghostNode.userData.labelOffset);
|
|
10908
10959
|
}
|
|
10909
10960
|
updateSceneHighlights(stateRef.current);
|
|
10910
|
-
updateTooltip({
|
|
10961
|
+
updateTooltip({
|
|
10962
|
+
tooltipEl: tooltipRef.current,
|
|
10963
|
+
hoveredNode: stateRef.current.hoveredNode,
|
|
10964
|
+
hoveredLink: stateRef.current.hoveredLink,
|
|
10965
|
+
camera,
|
|
10966
|
+
mountEl: currentMount,
|
|
10967
|
+
isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive,
|
|
10968
|
+
parentData: parentDataRef.current,
|
|
10969
|
+
// <--- ADICIONADO AQUI
|
|
10970
|
+
ancestryData: ancestryDataRef.current
|
|
10971
|
+
// <--- ADICIONADO AQUI
|
|
10972
|
+
});
|
|
10911
10973
|
(_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
|
|
10912
10974
|
stateRef.current.controls.update();
|
|
10913
10975
|
renderer.autoClear = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lv-x-software-house/x_view",
|
|
3
|
-
"version": "1.2.3-dev.
|
|
3
|
+
"version": "1.2.3-dev.5",
|
|
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",
|