@basic-genomics/hivtrace-viz 1.1.8 → 1.1.10
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/embed/hivtrace.js +1 -1
- package/dist/embed/hivtrace.js.map +1 -1
- package/dist/embed/index.html +124 -219
- package/dist/hivtrace.js +1 -1
- package/dist/hivtrace.js.map +1 -1
- package/package.json +2 -2
package/dist/embed/index.html
CHANGED
|
@@ -149,9 +149,11 @@
|
|
|
149
149
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
.hivtrace-fullscreen-btn button:hover
|
|
152
|
+
.hivtrace-fullscreen-btn button:hover,
|
|
153
|
+
.hivtrace-fullscreen-btn button:focus {
|
|
153
154
|
background: #f4f4f5;
|
|
154
155
|
color: #18181b;
|
|
156
|
+
text-decoration: none;
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
/* 状态栏 badge 和 label 样式优化 */
|
|
@@ -285,54 +287,6 @@
|
|
|
285
287
|
padding: 4px 12px;
|
|
286
288
|
}
|
|
287
289
|
|
|
288
|
-
/* 簇选择器样式 */
|
|
289
|
-
.hivtrace-cluster-selector {
|
|
290
|
-
display: inline-flex;
|
|
291
|
-
align-items: stretch;
|
|
292
|
-
border: 1px solid #ccc;
|
|
293
|
-
border-radius: 4px;
|
|
294
|
-
background: #fff;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
.hivtrace-cluster-selector-label {
|
|
298
|
-
display: flex;
|
|
299
|
-
align-items: center;
|
|
300
|
-
justify-content: center;
|
|
301
|
-
padding: 6px 12px;
|
|
302
|
-
font-size: 13px;
|
|
303
|
-
color: #555;
|
|
304
|
-
background: #f5f5f5;
|
|
305
|
-
border-right: 1px solid #ccc;
|
|
306
|
-
white-space: nowrap;
|
|
307
|
-
min-width: 60px;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
.hivtrace-cluster-selector .input-group-btn {
|
|
311
|
-
display: flex;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
.hivtrace-cluster-selector-btn {
|
|
315
|
-
border: none !important;
|
|
316
|
-
border-radius: 0 !important;
|
|
317
|
-
box-shadow: none !important;
|
|
318
|
-
min-width: 100px;
|
|
319
|
-
text-align: left;
|
|
320
|
-
display: flex;
|
|
321
|
-
align-items: center;
|
|
322
|
-
justify-content: space-between;
|
|
323
|
-
padding: 6px 12px;
|
|
324
|
-
font-size: 13px;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
.hivtrace-cluster-selector-btn:hover,
|
|
328
|
-
.hivtrace-cluster-selector-btn:focus {
|
|
329
|
-
background: #f9f9f9;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
.hivtrace-cluster-selector-btn .caret {
|
|
333
|
-
margin-left: 8px;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
290
|
/* ========================================
|
|
337
291
|
属性标签页 - 新布局
|
|
338
292
|
顶部横向 pills + 下方左图右表
|
|
@@ -408,7 +362,8 @@
|
|
|
408
362
|
}
|
|
409
363
|
|
|
410
364
|
/* 下方:图表和表格上下排列(默认/小屏幕) */
|
|
411
|
-
.hivtrace-attributes-content
|
|
365
|
+
.hivtrace-attributes-content,
|
|
366
|
+
.hivtrace-stats-content {
|
|
412
367
|
flex: 1;
|
|
413
368
|
display: flex;
|
|
414
369
|
flex-direction: column;
|
|
@@ -419,20 +374,24 @@
|
|
|
419
374
|
|
|
420
375
|
/* 大屏幕(> 996px):左右布局 */
|
|
421
376
|
@media (min-width: 997px) {
|
|
422
|
-
|
|
377
|
+
|
|
378
|
+
.hivtrace-attributes-content,
|
|
379
|
+
.hivtrace-stats-content {
|
|
423
380
|
flex-direction: row;
|
|
424
381
|
}
|
|
425
382
|
}
|
|
426
383
|
|
|
427
|
-
/*
|
|
428
|
-
.hivtrace-viz-panel
|
|
429
|
-
|
|
384
|
+
/* 可视化面板和统计面板 */
|
|
385
|
+
.hivtrace-viz-panel,
|
|
386
|
+
.hivtrace-stats-panel {
|
|
387
|
+
flex: 1;
|
|
430
388
|
display: flex;
|
|
431
389
|
flex-direction: column;
|
|
432
390
|
background: #f9fafb;
|
|
433
391
|
border: 1px solid #e5e7eb;
|
|
434
392
|
border-radius: 8px;
|
|
435
393
|
padding: 12px;
|
|
394
|
+
min-width: 0;
|
|
436
395
|
}
|
|
437
396
|
|
|
438
397
|
/* 大屏幕(> 996px):图表固定宽度 500px */
|
|
@@ -441,6 +400,11 @@
|
|
|
441
400
|
width: 500px;
|
|
442
401
|
flex-shrink: 0;
|
|
443
402
|
}
|
|
403
|
+
|
|
404
|
+
.hivtrace-stats-panel {
|
|
405
|
+
flex: 1;
|
|
406
|
+
min-width: 300px;
|
|
407
|
+
}
|
|
444
408
|
}
|
|
445
409
|
|
|
446
410
|
.hivtrace-panel-toolbar {
|
|
@@ -641,9 +605,6 @@
|
|
|
641
605
|
<li class="active" id="main-tab">
|
|
642
606
|
<a id="trace-default-tab" href="#trace-results" data-toggle="tab">网络</a>
|
|
643
607
|
</li>
|
|
644
|
-
<li class="disabled" id="graph-tab">
|
|
645
|
-
<a href="#trace-graph" data-toggle="tab">统计</a>
|
|
646
|
-
</li>
|
|
647
608
|
<li class="disabled" id="clusters-tab">
|
|
648
609
|
<a href="#trace-clusters" data-toggle="tab">簇</a>
|
|
649
610
|
</li>
|
|
@@ -651,7 +612,7 @@
|
|
|
651
612
|
<a href="#trace-nodes" data-toggle="tab">节点</a>
|
|
652
613
|
</li>
|
|
653
614
|
<li class="disabled" id="attributes-tab">
|
|
654
|
-
<a href="#trace-attributes" data-toggle="tab"
|
|
615
|
+
<a href="#trace-attributes" data-toggle="tab">统计</a>
|
|
655
616
|
</li>
|
|
656
617
|
</ul>
|
|
657
618
|
|
|
@@ -823,39 +784,6 @@
|
|
|
823
784
|
</div>
|
|
824
785
|
</div>
|
|
825
786
|
|
|
826
|
-
<div id="trace-graph" class="tab-pane">
|
|
827
|
-
<div class="hivtrace-stats-container">
|
|
828
|
-
<!-- 顶部:Cluster 选择器工具栏 -->
|
|
829
|
-
<div class="hivtrace-stats-header">
|
|
830
|
-
<div class="hivtrace-cluster-selector">
|
|
831
|
-
<span class="hivtrace-cluster-selector-label">选择簇</span>
|
|
832
|
-
<div class="input-group-btn">
|
|
833
|
-
<button type="button" class="btn btn-default dropdown-toggle hivtrace-cluster-selector-btn"
|
|
834
|
-
data-toggle="dropdown" id="stats_cluster_selector_btn">
|
|
835
|
-
<span id="stats_cluster_selector_label">总览</span> <span class="caret"></span>
|
|
836
|
-
</button>
|
|
837
|
-
<ul class="dropdown-menu" role="menu" id="stats_cluster_selector_menu">
|
|
838
|
-
<li><a href="#" data-value="">总览</a></li>
|
|
839
|
-
</ul>
|
|
840
|
-
</div>
|
|
841
|
-
</div>
|
|
842
|
-
</div>
|
|
843
|
-
|
|
844
|
-
<!-- 下方:统计表格和直方图 -->
|
|
845
|
-
<div class="hivtrace-stats-content">
|
|
846
|
-
<div class="hivtrace-stats-panel">
|
|
847
|
-
<p class="lead" id="stats_title">网络统计</p>
|
|
848
|
-
<table class="table table-striped table-condensed table-responsive" id="graph_summary_table"></table>
|
|
849
|
-
</div>
|
|
850
|
-
<div class="hivtrace-stats-panel">
|
|
851
|
-
<p id="histogram_label" class="lead"></p>
|
|
852
|
-
<div id="histogram_tag"></div>
|
|
853
|
-
</div>
|
|
854
|
-
</div>
|
|
855
|
-
</div>
|
|
856
|
-
</div>
|
|
857
|
-
|
|
858
|
-
|
|
859
787
|
|
|
860
788
|
|
|
861
789
|
|
|
@@ -886,16 +814,17 @@
|
|
|
886
814
|
|
|
887
815
|
<div id="trace-attributes" class="tab-pane">
|
|
888
816
|
<div class="hivtrace-attributes-container">
|
|
889
|
-
<!-- 顶部:簇选择器 +
|
|
817
|
+
<!-- 顶部:簇选择器 + 属性选择器 -->
|
|
890
818
|
<div class="hivtrace-attributes-header">
|
|
891
819
|
<!-- 簇选择器 -->
|
|
892
820
|
<div style="margin-bottom: 12px;">
|
|
893
|
-
<div class="
|
|
894
|
-
<span class="
|
|
821
|
+
<div class="input-group input-group-sm" style="max-width: 280px;">
|
|
822
|
+
<span class="input-group-addon" style="min-width: 60px; text-align: center;">选择簇</span>
|
|
895
823
|
<div class="input-group-btn">
|
|
896
|
-
<button type="button" class="btn btn-default dropdown-toggle
|
|
897
|
-
|
|
898
|
-
<span id="attrs_cluster_selector_label">总览</span> <span class="caret"
|
|
824
|
+
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
|
|
825
|
+
id="attrs_cluster_selector_btn" style="min-width: 140px; text-align: left;">
|
|
826
|
+
<span id="attrs_cluster_selector_label">总览</span> <span class="caret"
|
|
827
|
+
style="float: right; margin-top: 8px;"></span>
|
|
899
828
|
</button>
|
|
900
829
|
<ul class="dropdown-menu" role="menu" id="attrs_cluster_selector_menu">
|
|
901
830
|
<li><a href="#" data-value="">总览</a></li>
|
|
@@ -907,8 +836,21 @@
|
|
|
907
836
|
<div class="hivtrace-pill-row" data-hivtrace-ui-role="attributes_cat"></div>
|
|
908
837
|
</div>
|
|
909
838
|
|
|
910
|
-
<!--
|
|
911
|
-
<div class="hivtrace-
|
|
839
|
+
<!-- 统计内容区域(选中 None 时显示) -->
|
|
840
|
+
<div class="hivtrace-stats-content" id="attrs_stats_content">
|
|
841
|
+
<div class="hivtrace-stats-panel">
|
|
842
|
+
<p class="lead" id="attrs_stats_title">网络统计</p>
|
|
843
|
+
<table class="table table-striped table-condensed table-responsive" id="graph_summary_table">
|
|
844
|
+
</table>
|
|
845
|
+
</div>
|
|
846
|
+
<div class="hivtrace-stats-panel">
|
|
847
|
+
<p id="histogram_label" class="lead"></p>
|
|
848
|
+
<div id="histogram_tag"></div>
|
|
849
|
+
</div>
|
|
850
|
+
</div>
|
|
851
|
+
|
|
852
|
+
<!-- 属性可视化内容(选中属性时显示) -->
|
|
853
|
+
<div class="hivtrace-attributes-content" style="display: none;">
|
|
912
854
|
<!-- 左侧:可视化区域(弦图/散点图) -->
|
|
913
855
|
<div class="hivtrace-viz-panel" data-hivtrace-ui-role="aux_svg_holder_enclosed" style="display: none">
|
|
914
856
|
<div class="hivtrace-panel-toolbar">
|
|
@@ -947,7 +889,6 @@
|
|
|
947
889
|
<img class="hidden" id="hyphy-chart-image" />
|
|
948
890
|
<canvas class="hidden" id="hyphy-chart-canvas"></canvas>
|
|
949
891
|
|
|
950
|
-
</div> <!-- 关闭内容容器 -->
|
|
951
892
|
</div> <!-- 关闭 #hivtrace-main -->
|
|
952
893
|
|
|
953
894
|
<script src="./hivtrace.js"></script>
|
|
@@ -982,9 +923,8 @@
|
|
|
982
923
|
var attributes = null;
|
|
983
924
|
|
|
984
925
|
// 从传入的options中获取配置
|
|
926
|
+
var enableClusterTracking = options && options.enableClusterTracking === true;
|
|
985
927
|
var expandClusters = options && Array.isArray(options.expand) ? options.expand : [];
|
|
986
|
-
// 获取自定义上下文菜单项配置
|
|
987
|
-
var customContextMenuItems = options && Array.isArray(options.customContextMenuItems) ? options.customContextMenuItems : [];
|
|
988
928
|
|
|
989
929
|
// 获取基因距离阈值并动态更新簇标签
|
|
990
930
|
var threshold = options && typeof options.threshold === 'number' ? options.threshold : 0.015;
|
|
@@ -1018,61 +958,6 @@
|
|
|
1018
958
|
}
|
|
1019
959
|
);
|
|
1020
960
|
|
|
1021
|
-
// 将自定义上下文菜单项赋值给 user_graph 实例
|
|
1022
|
-
if (customContextMenuItems.length > 0) {
|
|
1023
|
-
user_graph.customContextMenuItems = customContextMenuItems;
|
|
1024
|
-
// 设置点击回调,通过 postMessage 通知宿主应用
|
|
1025
|
-
user_graph.onCustomMenuItemClick = function (itemId, clusterInfo) {
|
|
1026
|
-
// 提取节点的关键信息(避免循环引用和不可序列化的对象)
|
|
1027
|
-
var extractNodeInfo = function (node) {
|
|
1028
|
-
if (!node) return null;
|
|
1029
|
-
return {
|
|
1030
|
-
id: node.id,
|
|
1031
|
-
// 基本属性
|
|
1032
|
-
degree: node.degree,
|
|
1033
|
-
// 节点属性(如果存在)
|
|
1034
|
-
attributes: node.patient_attributes || node.attributes || undefined,
|
|
1035
|
-
// 位置信息
|
|
1036
|
-
x: typeof node.x === 'number' ? node.x : undefined,
|
|
1037
|
-
y: typeof node.y === 'number' ? node.y : undefined,
|
|
1038
|
-
// 状态信息
|
|
1039
|
-
is_hidden: Boolean(node.is_hidden),
|
|
1040
|
-
match_filter: Boolean(node.match_filter),
|
|
1041
|
-
// 子簇信息(如果存在)
|
|
1042
|
-
subcluster_id: node.subcluster_id,
|
|
1043
|
-
subcluster_label: node.subcluster_label,
|
|
1044
|
-
};
|
|
1045
|
-
};
|
|
1046
|
-
|
|
1047
|
-
var essentialClusterData = {
|
|
1048
|
-
cluster_id: clusterInfo?.cluster_id ?? clusterInfo?.id ?? undefined,
|
|
1049
|
-
node_count: clusterInfo?.node_count ?? (Array.isArray(clusterInfo?.nodes) ? clusterInfo.nodes.length : 0),
|
|
1050
|
-
cluster_size: typeof clusterInfo?.cluster_size === 'number' ? clusterInfo.cluster_size : undefined,
|
|
1051
|
-
position: {
|
|
1052
|
-
x: typeof clusterInfo?.x === 'number' ? clusterInfo.x : undefined,
|
|
1053
|
-
y: typeof clusterInfo?.y === 'number' ? clusterInfo.y : undefined
|
|
1054
|
-
},
|
|
1055
|
-
state: {
|
|
1056
|
-
expanded: Boolean(clusterInfo?.expanded),
|
|
1057
|
-
fixed: Boolean(clusterInfo?.fixed)
|
|
1058
|
-
},
|
|
1059
|
-
// 节点 ID 列表(向后兼容)
|
|
1060
|
-
node_ids: Array.isArray(clusterInfo?.nodes)
|
|
1061
|
-
? clusterInfo.nodes.map(function (node) { return node?.id }).filter(Boolean)
|
|
1062
|
-
: [],
|
|
1063
|
-
// 完整节点信息(用于扩展)
|
|
1064
|
-
nodes: Array.isArray(clusterInfo?.nodes)
|
|
1065
|
-
? clusterInfo.nodes.map(extractNodeInfo).filter(Boolean)
|
|
1066
|
-
: []
|
|
1067
|
-
};
|
|
1068
|
-
window.parent.postMessage({
|
|
1069
|
-
type: 'CUSTOM_MENU_CLICK',
|
|
1070
|
-
itemId: itemId,
|
|
1071
|
-
clusterInfo: essentialClusterData
|
|
1072
|
-
}, '*');
|
|
1073
|
-
};
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
961
|
if (user_graph.is_empty()) {
|
|
1077
962
|
HandleAppError(
|
|
1078
963
|
"This network contains no clusters and cannot be displayed"
|
|
@@ -1081,10 +966,10 @@
|
|
|
1081
966
|
hivtrace.histogramDistances(graph, histogram_tag, histogram_label);
|
|
1082
967
|
hivtrace.graphSummary(user_graph, graph_summary_tag);
|
|
1083
968
|
|
|
1084
|
-
// 初始化 cluster 选择器 (
|
|
969
|
+
// 初始化 cluster 选择器 (统计 Tab)
|
|
1085
970
|
(function initClusterSelector() {
|
|
1086
|
-
var menu = document.getElementById('
|
|
1087
|
-
var label = document.getElementById('
|
|
971
|
+
var menu = document.getElementById('attrs_cluster_selector_menu');
|
|
972
|
+
var label = document.getElementById('attrs_cluster_selector_label');
|
|
1088
973
|
if (!menu || !label) return;
|
|
1089
974
|
|
|
1090
975
|
// 获取所有 cluster 并按 ID 排序
|
|
@@ -1104,20 +989,26 @@
|
|
|
1104
989
|
menu.appendChild(li);
|
|
1105
990
|
});
|
|
1106
991
|
|
|
992
|
+
// 设置属性页的簇过滤状态
|
|
993
|
+
user_graph.attributes_selected_cluster = null;
|
|
994
|
+
|
|
1107
995
|
// 监听 dropdown 菜单项点击
|
|
1108
996
|
menu.addEventListener('click', function (e) {
|
|
1109
997
|
if (e.target.tagName === 'A') {
|
|
1110
998
|
e.preventDefault();
|
|
1111
999
|
var selectedClusterId = e.target.getAttribute('data-value');
|
|
1112
1000
|
var selectedText = e.target.textContent;
|
|
1113
|
-
var statsTitle = document.getElementById('
|
|
1001
|
+
var statsTitle = document.getElementById('attrs_stats_title');
|
|
1114
1002
|
|
|
1115
1003
|
// 更新按钮文本
|
|
1116
1004
|
label.textContent = selectedText;
|
|
1117
1005
|
|
|
1006
|
+
// 设置属性页的簇过滤
|
|
1007
|
+
user_graph.attributes_selected_cluster = selectedClusterId || null;
|
|
1008
|
+
|
|
1118
1009
|
if (!selectedClusterId) {
|
|
1119
1010
|
// 显示全网统计
|
|
1120
|
-
statsTitle.textContent = '网络统计';
|
|
1011
|
+
if (statsTitle) statsTitle.textContent = '网络统计';
|
|
1121
1012
|
hivtrace.graphSummary(user_graph, graph_summary_tag);
|
|
1122
1013
|
hivtrace.histogramDistances(graph, histogram_tag, histogram_label);
|
|
1123
1014
|
} else {
|
|
@@ -1127,10 +1018,19 @@
|
|
|
1127
1018
|
});
|
|
1128
1019
|
|
|
1129
1020
|
if (cluster) {
|
|
1130
|
-
statsTitle.textContent = '簇 ' + selectedClusterId + ' 统计';
|
|
1021
|
+
if (statsTitle) statsTitle.textContent = '簇 ' + selectedClusterId + ' 统计';
|
|
1131
1022
|
updateClusterStatistics(cluster);
|
|
1132
1023
|
}
|
|
1133
1024
|
}
|
|
1025
|
+
|
|
1026
|
+
// 重新触发当前选中的属性(如果有)
|
|
1027
|
+
if (user_graph.colorizer && user_graph.colorizer['category_id']) {
|
|
1028
|
+
if (user_graph.colorizer['continuous']) {
|
|
1029
|
+
user_graph.handle_attribute_continuous(user_graph.colorizer['category_id']);
|
|
1030
|
+
} else {
|
|
1031
|
+
user_graph.handle_attribute_categorical(user_graph.colorizer['category_id'], false);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1134
1034
|
}
|
|
1135
1035
|
});
|
|
1136
1036
|
|
|
@@ -1241,64 +1141,75 @@
|
|
|
1241
1141
|
}
|
|
1242
1142
|
})();
|
|
1243
1143
|
|
|
1244
|
-
// 初始化属性标签页的 cluster 选择器
|
|
1245
|
-
(function initAttrsClusterSelector() {
|
|
1246
|
-
var menu = document.getElementById('attrs_cluster_selector_menu');
|
|
1247
|
-
var label = document.getElementById('attrs_cluster_selector_label');
|
|
1248
|
-
if (!menu || !label) return;
|
|
1249
|
-
|
|
1250
|
-
// 获取所有 cluster 并按 ID 排序
|
|
1251
|
-
var clusters = user_graph.clusters || [];
|
|
1252
|
-
clusters = clusters.slice().sort(function (a, b) {
|
|
1253
|
-
return a.cluster_id - b.cluster_id;
|
|
1254
|
-
});
|
|
1255
|
-
|
|
1256
|
-
// 填充 cluster 选项到 dropdown menu
|
|
1257
|
-
clusters.forEach(function (cluster) {
|
|
1258
|
-
var li = document.createElement('li');
|
|
1259
|
-
var a = document.createElement('a');
|
|
1260
|
-
a.href = '#';
|
|
1261
|
-
a.setAttribute('data-value', cluster.cluster_id);
|
|
1262
|
-
a.textContent = '簇 ' + cluster.cluster_id + ' (' + cluster.children.length + ' 节点)';
|
|
1263
|
-
li.appendChild(a);
|
|
1264
|
-
menu.appendChild(li);
|
|
1265
|
-
});
|
|
1266
|
-
|
|
1267
|
-
// 监听 dropdown 菜单项点击
|
|
1268
|
-
menu.addEventListener('click', function (e) {
|
|
1269
|
-
if (e.target.tagName === 'A') {
|
|
1270
|
-
e.preventDefault();
|
|
1271
|
-
var selectedClusterId = e.target.getAttribute('data-value');
|
|
1272
|
-
var selectedText = e.target.textContent;
|
|
1273
1144
|
|
|
1274
|
-
// 更新按钮文本
|
|
1275
|
-
label.textContent = selectedText;
|
|
1276
1145
|
|
|
1277
|
-
// 设置属性页的簇过滤
|
|
1278
|
-
user_graph.attributes_selected_cluster = selectedClusterId || null;
|
|
1279
1146
|
|
|
1280
|
-
// 更新属性 pill 上的数字(显示簇内唯一值数量)
|
|
1281
|
-
user_graph.updateAttributePillCounts(selectedClusterId || null);
|
|
1282
1147
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1148
|
+
// 可配置的追踪簇回调功能 - 基于传入参数决定是否启用
|
|
1149
|
+
if (enableClusterTracking) {
|
|
1150
|
+
user_graph.onTrackCluster = function (clusterInfo, allData) {
|
|
1151
|
+
try {
|
|
1152
|
+
// 直接提取需要的数据,避免复杂的数据清理
|
|
1153
|
+
const essentialClusterData = {
|
|
1154
|
+
cluster_id: clusterInfo?.cluster_id ?? clusterInfo?.id ?? undefined,
|
|
1155
|
+
node_count: clusterInfo?.node_count ?? (Array.isArray(clusterInfo?.nodes) ? clusterInfo.nodes.length : 0),
|
|
1156
|
+
cluster_size: typeof clusterInfo?.cluster_size === 'number' ? clusterInfo.cluster_size : undefined,
|
|
1157
|
+
position: {
|
|
1158
|
+
x: typeof clusterInfo?.x === 'number' ? clusterInfo.x : undefined,
|
|
1159
|
+
y: typeof clusterInfo?.y === 'number' ? clusterInfo.y : undefined
|
|
1160
|
+
},
|
|
1161
|
+
state: {
|
|
1162
|
+
expanded: Boolean(clusterInfo?.expanded),
|
|
1163
|
+
fixed: Boolean(clusterInfo?.fixed)
|
|
1164
|
+
},
|
|
1165
|
+
// 只提取节点ID列表,避免传递复杂对象
|
|
1166
|
+
node_ids: Array.isArray(clusterInfo?.nodes)
|
|
1167
|
+
? clusterInfo.nodes.slice(0, 20).map(node => node?.id).filter(Boolean)
|
|
1168
|
+
: []
|
|
1169
|
+
};
|
|
1170
|
+
|
|
1171
|
+
// 提取网络统计信息
|
|
1172
|
+
const networkStats = {
|
|
1173
|
+
total_nodes: allData?.network_info?.node_count ?? user_graph?.nodes?.length ?? 0,
|
|
1174
|
+
total_edges: allData?.network_info?.edge_count ?? user_graph?.edges?.length ?? 0,
|
|
1175
|
+
total_clusters: allData?.network_info?.cluster_count ?? 0
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
// 发送轻量级、精确的数据
|
|
1179
|
+
window.parent.postMessage({
|
|
1180
|
+
type: 'TRACK_CLUSTER',
|
|
1181
|
+
clusterInfo: essentialClusterData,
|
|
1182
|
+
allData: { network_info: networkStats }
|
|
1183
|
+
}, '*');
|
|
1184
|
+
|
|
1185
|
+
} catch (error) {
|
|
1186
|
+
console.warn('簇追踪回调处理失败:', error.message);
|
|
1187
|
+
|
|
1188
|
+
// 最小化降级数据
|
|
1189
|
+
window.parent.postMessage({
|
|
1190
|
+
type: 'TRACK_CLUSTER',
|
|
1191
|
+
clusterInfo: {
|
|
1192
|
+
cluster_id: 'fallback',
|
|
1193
|
+
node_count: 0,
|
|
1194
|
+
cluster_size: undefined,
|
|
1195
|
+
position: { x: undefined, y: undefined },
|
|
1196
|
+
state: { expanded: false, fixed: false },
|
|
1197
|
+
node_ids: []
|
|
1198
|
+
},
|
|
1199
|
+
allData: {
|
|
1200
|
+
network_info: {
|
|
1201
|
+
total_nodes: 0,
|
|
1202
|
+
total_edges: 0,
|
|
1203
|
+
total_clusters: 0
|
|
1204
|
+
}
|
|
1291
1205
|
}
|
|
1292
|
-
}
|
|
1206
|
+
}, '*');
|
|
1293
1207
|
}
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1298
1210
|
|
|
1299
1211
|
[
|
|
1300
1212
|
"#main-tab",
|
|
1301
|
-
"#graph-tab",
|
|
1302
1213
|
"#clusters-tab",
|
|
1303
1214
|
"#subclusters-tab",
|
|
1304
1215
|
"#nodes-tab",
|
|
@@ -1411,17 +1322,11 @@
|
|
|
1411
1322
|
overlay.innerHTML = `
|
|
1412
1323
|
<i class="fa fa-exclamation-triangle hivtrace-error-icon"></i>
|
|
1413
1324
|
<div class="hivtrace-error-message">${message}</div>
|
|
1414
|
-
<button class="hivtrace-retry-btn" onclick="
|
|
1325
|
+
<button class="hivtrace-retry-btn" onclick="location.reload()">重试</button>
|
|
1415
1326
|
`;
|
|
1416
1327
|
window.parent.postMessage({ type: 'ERROR', message: message }, '*');
|
|
1417
1328
|
}
|
|
1418
1329
|
|
|
1419
|
-
// 请求宿主应用重试
|
|
1420
|
-
function requestRetry() {
|
|
1421
|
-
window.parent.postMessage({ type: 'HIVTRACE_RETRY' }, '*');
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
1330
|
|
|
1426
1331
|
function in_progress() {
|
|
1427
1332
|
return $(".progress").length > 0;
|