@basic-genomics/hivtrace-viz 1.5.0 → 1.5.2
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/index.html +279 -60
- package/package.json +2 -2
package/dist/embed/index.html
CHANGED
|
@@ -1023,6 +1023,10 @@
|
|
|
1023
1023
|
style="margin-left: 8px;">
|
|
1024
1024
|
<i class="fa fa-play"></i> 播放动画
|
|
1025
1025
|
</button>
|
|
1026
|
+
<!-- 聚焦根按钮 -->
|
|
1027
|
+
<button type="button" class="btn btn-default btn-sm" id="tree_show_root_btn" title="聚焦到根节点">
|
|
1028
|
+
<i class="fa fa-dot-circle-o"></i> 聚焦根
|
|
1029
|
+
</button>
|
|
1026
1030
|
<!-- 统计信息 -->
|
|
1027
1031
|
<div style="flex: 1;"></div>
|
|
1028
1032
|
<div class="hivtrace-tree-stats" style="display: flex; gap: 12px; font-size: 13px; color: #6b7280;">
|
|
@@ -1166,35 +1170,79 @@
|
|
|
1166
1170
|
|
|
1167
1171
|
// 停止任何正在进行的动画,防止状态冲突
|
|
1168
1172
|
this.stopAnimation();
|
|
1173
|
+
this.cy.stop();
|
|
1169
1174
|
|
|
1170
1175
|
this.currentClusterId = clusterId;
|
|
1171
1176
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1177
|
+
// 将 matchingNodes 提升到外部作用域,供聚焦使用
|
|
1178
|
+
var matchingNodes = null;
|
|
1179
|
+
if (clusterId != null) {
|
|
1180
|
+
var strClusterId = String(clusterId);
|
|
1181
|
+
matchingNodes = this.cy.nodes().filter(function (n) {
|
|
1182
|
+
return n.data('cluster_id') != null && String(n.data('cluster_id')) === strClusterId;
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// 计算需要高亮的路径元素(在 batch 外部计算,供聚焦使用)
|
|
1187
|
+
var pathEles = self.cy.collection();
|
|
1188
|
+
if (clusterId != null && matchingNodes && matchingNodes.length > 1) {
|
|
1189
|
+
var mrca = self.findClusterRoot(clusterId);
|
|
1190
|
+
if (mrca) {
|
|
1191
|
+
var mrcaId = mrca.id();
|
|
1192
|
+
pathEles = pathEles.union(mrca);
|
|
1193
|
+
matchingNodes.forEach(function (node) {
|
|
1194
|
+
var preds = node.predecessors();
|
|
1195
|
+
for (var i = 0; i < preds.length; i++) {
|
|
1196
|
+
var ele = preds[i];
|
|
1197
|
+
pathEles = pathEles.union(ele);
|
|
1198
|
+
if (ele.isNode() && ele.id() === mrcaId) break;
|
|
1199
|
+
}
|
|
1178
1200
|
});
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1179
1203
|
|
|
1180
|
-
|
|
1204
|
+
// 批量更新样式(高亮/置灰)
|
|
1205
|
+
this.cy.batch(function () {
|
|
1206
|
+
if (clusterId != null && matchingNodes && matchingNodes.length > 0) {
|
|
1181
1207
|
self.cy.elements().addClass('grayed-out');
|
|
1182
1208
|
matchingNodes.removeClass('grayed-out');
|
|
1183
|
-
|
|
1184
|
-
if (matchingNodes.length > 1) {
|
|
1185
|
-
var dijk = self.cy.elements().dijkstra({ root: matchingNodes[0], directed: false });
|
|
1186
|
-
// 使用集合 union 快速合并路径元素
|
|
1187
|
-
var pathEles = matchingNodes.slice(1).reduce(function (acc, node) {
|
|
1188
|
-
return acc.union(dijk.pathTo(node));
|
|
1189
|
-
}, self.cy.collection());
|
|
1209
|
+
if (pathEles.length > 0) {
|
|
1190
1210
|
pathEles.removeClass('grayed-out');
|
|
1191
1211
|
}
|
|
1192
1212
|
} else {
|
|
1193
1213
|
self.cy.elements().removeClass('grayed-out');
|
|
1194
1214
|
}
|
|
1195
1215
|
});
|
|
1216
|
+
|
|
1217
|
+
// 自动聚焦到对应视图(包含节点和连接边)
|
|
1218
|
+
if (clusterId != null && matchingNodes && matchingNodes.length > 0) {
|
|
1219
|
+
// 合并簇成员节点和路径边,确保完整视图
|
|
1220
|
+
var fitEles = matchingNodes.union(pathEles);
|
|
1221
|
+
this.cy.animate({
|
|
1222
|
+
fit: { eles: fitEles, padding: 50 }
|
|
1223
|
+
}, {
|
|
1224
|
+
duration: 300,
|
|
1225
|
+
easing: 'ease-out',
|
|
1226
|
+
queue: false
|
|
1227
|
+
});
|
|
1228
|
+
} else if (clusterId == null) {
|
|
1229
|
+
// 恢复全局视图
|
|
1230
|
+
this.cy.animate({
|
|
1231
|
+
fit: { eles: this.cy.elements(), padding: 50 }
|
|
1232
|
+
}, {
|
|
1233
|
+
duration: 300,
|
|
1234
|
+
easing: 'ease-out',
|
|
1235
|
+
queue: false
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
TreeViz.prototype.fitView = function () {
|
|
1240
|
+
if (!this.cy) return;
|
|
1241
|
+
this.stopAnimation();
|
|
1242
|
+
this.cy.stop();
|
|
1243
|
+
this.cy.resize();
|
|
1244
|
+
this.cy.fit(undefined, 50);
|
|
1196
1245
|
};
|
|
1197
|
-
TreeViz.prototype.fitView = function () { if (this.cy) { this.cy.resize(); this.cy.fit(undefined, 50); } };
|
|
1198
1246
|
TreeViz.prototype.getAvailableClusters = function () {
|
|
1199
1247
|
if (!this.cy) return [];
|
|
1200
1248
|
var counts = new Map();
|
|
@@ -1230,6 +1278,26 @@
|
|
|
1230
1278
|
}
|
|
1231
1279
|
return null;
|
|
1232
1280
|
};
|
|
1281
|
+
// 聚焦到根节点(使用官方 animate API)
|
|
1282
|
+
TreeViz.prototype.focusOnRoot = function () {
|
|
1283
|
+
if (!this.cy) return null;
|
|
1284
|
+
var root = this.findRoot();
|
|
1285
|
+
if (!root) return null;
|
|
1286
|
+
// 停止渐显动画(setTimeout 定时器)
|
|
1287
|
+
this.stopAnimation();
|
|
1288
|
+
// 停止视图动画(Cytoscape animate)
|
|
1289
|
+
this.cy.stop();
|
|
1290
|
+
// 使用 Cytoscape.js 官方推荐的 animate + fit API
|
|
1291
|
+
// queue: false 确保立即执行,不排队
|
|
1292
|
+
this.cy.animate({
|
|
1293
|
+
fit: { eles: root, padding: 100 }
|
|
1294
|
+
}, {
|
|
1295
|
+
duration: 300,
|
|
1296
|
+
easing: 'ease-out',
|
|
1297
|
+
queue: false
|
|
1298
|
+
});
|
|
1299
|
+
return root.data();
|
|
1300
|
+
};
|
|
1233
1301
|
// 查找簇成员的最近共同祖先(MRCA)
|
|
1234
1302
|
// 使用官方 predecessors() + intersection() API
|
|
1235
1303
|
TreeViz.prototype.findClusterRoot = function (clusterId) {
|
|
@@ -1284,6 +1352,32 @@
|
|
|
1284
1352
|
: this.findRoot();
|
|
1285
1353
|
if (!animRoot) return;
|
|
1286
1354
|
|
|
1355
|
+
// 先停止现有视图动画,防止冲突
|
|
1356
|
+
this.cy.stop();
|
|
1357
|
+
|
|
1358
|
+
// 确保视图能看到完整动画区域
|
|
1359
|
+
if (this.currentClusterId != null) {
|
|
1360
|
+
// 簇视图:聚焦到簇的子树(MRCA 及其所有后代)
|
|
1361
|
+
// 这样能确保看到完整的动画范围
|
|
1362
|
+
var subtreeEles = animRoot.union(animRoot.successors());
|
|
1363
|
+
this.cy.animate({
|
|
1364
|
+
fit: { eles: subtreeEles, padding: 50 }
|
|
1365
|
+
}, {
|
|
1366
|
+
duration: 200,
|
|
1367
|
+
easing: 'ease-out',
|
|
1368
|
+
queue: false
|
|
1369
|
+
});
|
|
1370
|
+
} else {
|
|
1371
|
+
// 全局视图:适应整棵树,确保看到完整动画
|
|
1372
|
+
this.cy.animate({
|
|
1373
|
+
fit: { eles: this.cy.elements(), padding: 50 }
|
|
1374
|
+
}, {
|
|
1375
|
+
duration: 200,
|
|
1376
|
+
easing: 'ease-out',
|
|
1377
|
+
queue: false
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1287
1381
|
// 第一步:全部置灰(使用 batch 确保立即生效)
|
|
1288
1382
|
this.cy.batch(function () {
|
|
1289
1383
|
self.cy.elements().addClass('grayed-out');
|
|
@@ -1481,7 +1575,7 @@
|
|
|
1481
1575
|
}
|
|
1482
1576
|
|
|
1483
1577
|
// 禁用进化树工具栏按钮
|
|
1484
|
-
['tree_fit_btn', 'tree_labels_btn', 'tree_animate_btn', 'tree_export_png', 'tree_export_json',
|
|
1578
|
+
['tree_fit_btn', 'tree_labels_btn', 'tree_animate_btn', 'tree_show_root_btn', 'tree_export_png', 'tree_export_json',
|
|
1485
1579
|
'tree_cluster_prev_btn', 'tree_cluster_next_btn', 'tree_cluster_selector'].forEach(function (id) {
|
|
1486
1580
|
var btn = document.getElementById(id);
|
|
1487
1581
|
if (btn) {
|
|
@@ -1502,7 +1596,7 @@
|
|
|
1502
1596
|
}
|
|
1503
1597
|
}
|
|
1504
1598
|
// 恢复工具栏按钮
|
|
1505
|
-
['tree_fit_btn', 'tree_labels_btn', 'tree_animate_btn', 'tree_export_png', 'tree_export_json',
|
|
1599
|
+
['tree_fit_btn', 'tree_labels_btn', 'tree_animate_btn', 'tree_show_root_btn', 'tree_export_png', 'tree_export_json',
|
|
1506
1600
|
'tree_cluster_prev_btn', 'tree_cluster_next_btn', 'tree_cluster_selector'].forEach(function (id) {
|
|
1507
1601
|
var btn = document.getElementById(id);
|
|
1508
1602
|
if (btn) {
|
|
@@ -1513,6 +1607,52 @@
|
|
|
1513
1607
|
});
|
|
1514
1608
|
}
|
|
1515
1609
|
|
|
1610
|
+
// 隐藏进化树 Tab(当没有进化树数据时)
|
|
1611
|
+
function hideTreeTab() {
|
|
1612
|
+
var treeTab = document.getElementById('tree-tab');
|
|
1613
|
+
if (treeTab) {
|
|
1614
|
+
// 检查当前是否正在查看进化树 Tab
|
|
1615
|
+
var isTreeTabActive = treeTab.classList.contains('active');
|
|
1616
|
+
|
|
1617
|
+
treeTab.style.display = 'none';
|
|
1618
|
+
treeTab.classList.add('disabled');
|
|
1619
|
+
treeTab.classList.remove('active');
|
|
1620
|
+
|
|
1621
|
+
// 清除加载指示器
|
|
1622
|
+
var tabLink = treeTab.querySelector('a');
|
|
1623
|
+
if (tabLink) {
|
|
1624
|
+
tabLink.innerHTML = '进化树';
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
// 如果当前正在查看进化树 Tab,切换到第一个 Tab(分子网络)
|
|
1628
|
+
if (isTreeTabActive) {
|
|
1629
|
+
var firstTab = document.querySelector('.nav-tabs > li:first-child a[data-toggle="tab"]');
|
|
1630
|
+
if (firstTab) {
|
|
1631
|
+
$(firstTab).tab('show');
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
// 清除树容器内容
|
|
1636
|
+
var treeContainer = document.getElementById('tree_container');
|
|
1637
|
+
if (treeContainer) {
|
|
1638
|
+
treeContainer.innerHTML = '';
|
|
1639
|
+
}
|
|
1640
|
+
// 隐藏树 Tab 内容面板
|
|
1641
|
+
var treePane = document.getElementById('tree');
|
|
1642
|
+
if (treePane) {
|
|
1643
|
+
treePane.classList.remove('active');
|
|
1644
|
+
}
|
|
1645
|
+
// 清除全局树数据引用
|
|
1646
|
+
if (window._treeData) {
|
|
1647
|
+
window._treeData = null;
|
|
1648
|
+
}
|
|
1649
|
+
// 清除所有树相关的全局状态
|
|
1650
|
+
window._treeSelectTreeCluster = null;
|
|
1651
|
+
window._treeCurrentClusterIndex = undefined;
|
|
1652
|
+
window._treeExportId = null;
|
|
1653
|
+
tree_viz = null;
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1516
1656
|
// 进化树初始化函数
|
|
1517
1657
|
|
|
1518
1658
|
function initTreeViz(treeData, options) {
|
|
@@ -1606,6 +1746,7 @@
|
|
|
1606
1746
|
// 选择簇
|
|
1607
1747
|
function selectTreeCluster(index) {
|
|
1608
1748
|
currentClusterIndex = index;
|
|
1749
|
+
window._treeCurrentClusterIndex = currentClusterIndex; // 暴露到全局作用域
|
|
1609
1750
|
var label = document.getElementById('tree_cluster_selector_label');
|
|
1610
1751
|
|
|
1611
1752
|
if (index < 0) {
|
|
@@ -1619,6 +1760,11 @@
|
|
|
1619
1760
|
updateTreeNavButtons();
|
|
1620
1761
|
}
|
|
1621
1762
|
|
|
1763
|
+
// 暴露函数到全局作用域供事件处理器使用
|
|
1764
|
+
window._treeSelectTreeCluster = selectTreeCluster;
|
|
1765
|
+
window._treeCurrentClusterIndex = currentClusterIndex;
|
|
1766
|
+
window._treeExportId = options && options.exportId ? options.exportId : null;
|
|
1767
|
+
|
|
1622
1768
|
// 默认高亮簇
|
|
1623
1769
|
if (options && options.treeDefaultClusterId != null) {
|
|
1624
1770
|
var defaultIndex = clusters.findIndex(function (c) {
|
|
@@ -1630,66 +1776,124 @@
|
|
|
1630
1776
|
}
|
|
1631
1777
|
|
|
1632
1778
|
updateTreeNavButtons();
|
|
1779
|
+
}
|
|
1633
1780
|
|
|
1781
|
+
// 进化树工具栏事件初始化(在页面加载时调用一次,使用 null 检查确保安全)
|
|
1782
|
+
function initTreeToolbarEvents() {
|
|
1634
1783
|
// 适应窗口按钮
|
|
1635
|
-
document.getElementById('tree_fit_btn')
|
|
1636
|
-
|
|
1637
|
-
|
|
1784
|
+
var treeFitBtn = document.getElementById('tree_fit_btn');
|
|
1785
|
+
if (treeFitBtn) {
|
|
1786
|
+
treeFitBtn.addEventListener('click', function () {
|
|
1787
|
+
if (tree_viz && tree_viz.cy) {
|
|
1788
|
+
tree_viz.fitView();
|
|
1789
|
+
}
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1638
1792
|
|
|
1639
1793
|
// 标签按钮
|
|
1640
|
-
document.getElementById('tree_labels_btn')
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1794
|
+
var treeLabelsBtn = document.getElementById('tree_labels_btn');
|
|
1795
|
+
if (treeLabelsBtn) {
|
|
1796
|
+
treeLabelsBtn.addEventListener('click', function () {
|
|
1797
|
+
if (tree_viz && tree_viz.cy) {
|
|
1798
|
+
var showing = tree_viz.toggleLabels();
|
|
1799
|
+
var labelsText = document.getElementById('tree_labels_text');
|
|
1800
|
+
if (labelsText) {
|
|
1801
|
+
labelsText.textContent = showing ? '隐藏标签' : '显示标签';
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
// 聚焦根按钮
|
|
1808
|
+
var treeShowRootBtn = document.getElementById('tree_show_root_btn');
|
|
1809
|
+
if (treeShowRootBtn) {
|
|
1810
|
+
treeShowRootBtn.addEventListener('click', function () {
|
|
1811
|
+
if (tree_viz && tree_viz.cy) {
|
|
1812
|
+
tree_viz.focusOnRoot();
|
|
1813
|
+
}
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1644
1816
|
|
|
1645
1817
|
// 上一个簇
|
|
1646
|
-
document.getElementById('tree_cluster_prev_btn')
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1818
|
+
var treePrevBtn = document.getElementById('tree_cluster_prev_btn');
|
|
1819
|
+
if (treePrevBtn) {
|
|
1820
|
+
treePrevBtn.addEventListener('click', function () {
|
|
1821
|
+
if (tree_viz && window._treeCurrentClusterIndex >= 0 && window._treeSelectTreeCluster) {
|
|
1822
|
+
window._treeSelectTreeCluster(window._treeCurrentClusterIndex - 1);
|
|
1823
|
+
}
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1651
1826
|
|
|
1652
1827
|
// 下一个簇
|
|
1653
|
-
document.getElementById('tree_cluster_next_btn')
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1828
|
+
var treeNextBtn = document.getElementById('tree_cluster_next_btn');
|
|
1829
|
+
if (treeNextBtn) {
|
|
1830
|
+
treeNextBtn.addEventListener('click', function () {
|
|
1831
|
+
if (tree_viz && window._treeSelectTreeCluster) {
|
|
1832
|
+
var clusters = tree_viz.getAvailableClusters();
|
|
1833
|
+
if (typeof window._treeCurrentClusterIndex !== 'undefined' &&
|
|
1834
|
+
window._treeCurrentClusterIndex < clusters.length - 1) {
|
|
1835
|
+
window._treeSelectTreeCluster(window._treeCurrentClusterIndex + 1);
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1658
1840
|
|
|
1659
1841
|
// 簇选择器下拉菜单点击
|
|
1660
|
-
document.getElementById('tree_cluster_selector_menu')
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
var
|
|
1670
|
-
if (
|
|
1671
|
-
|
|
1842
|
+
var treeClusterMenu = document.getElementById('tree_cluster_selector_menu');
|
|
1843
|
+
if (treeClusterMenu) {
|
|
1844
|
+
treeClusterMenu.addEventListener('click', function (e) {
|
|
1845
|
+
e.preventDefault();
|
|
1846
|
+
var link = e.target.closest('a[data-value]');
|
|
1847
|
+
if (!link) return;
|
|
1848
|
+
|
|
1849
|
+
if (!window._treeSelectTreeCluster) return;
|
|
1850
|
+
|
|
1851
|
+
var value = link.getAttribute('data-value');
|
|
1852
|
+
if (value === '') {
|
|
1853
|
+
window._treeSelectTreeCluster(-1);
|
|
1854
|
+
} else {
|
|
1855
|
+
var index = parseInt(link.getAttribute('data-index'), 10);
|
|
1856
|
+
if (!isNaN(index)) {
|
|
1857
|
+
window._treeSelectTreeCluster(index);
|
|
1858
|
+
}
|
|
1672
1859
|
}
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1675
1862
|
|
|
1676
1863
|
// 导出 PNG
|
|
1677
|
-
document.getElementById('tree_export_png')
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1864
|
+
var treeExportPng = document.getElementById('tree_export_png');
|
|
1865
|
+
if (treeExportPng) {
|
|
1866
|
+
treeExportPng.addEventListener('click', function (e) {
|
|
1867
|
+
e.preventDefault();
|
|
1868
|
+
if (tree_viz && tree_viz.cy) {
|
|
1869
|
+
var exportId = window._treeExportId || 'tree';
|
|
1870
|
+
tree_viz.exportPNG(exportId + '_tree');
|
|
1871
|
+
}
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1681
1874
|
|
|
1682
1875
|
// 导出 JSON
|
|
1683
|
-
document.getElementById('tree_export_json')
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1876
|
+
var treeExportJson = document.getElementById('tree_export_json');
|
|
1877
|
+
if (treeExportJson) {
|
|
1878
|
+
treeExportJson.addEventListener('click', function (e) {
|
|
1879
|
+
e.preventDefault();
|
|
1880
|
+
if (tree_viz && window._treeData) {
|
|
1881
|
+
var exportId = window._treeExportId || 'tree';
|
|
1882
|
+
tree_viz.exportJSON(window._treeData, exportId + '_tree');
|
|
1883
|
+
}
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1687
1886
|
|
|
1688
1887
|
// 播放动画按钮
|
|
1689
|
-
document.getElementById('tree_animate_btn')
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1888
|
+
var treeAnimateBtn = document.getElementById('tree_animate_btn');
|
|
1889
|
+
if (treeAnimateBtn) {
|
|
1890
|
+
treeAnimateBtn.addEventListener('click', function (e) {
|
|
1891
|
+
e.preventDefault();
|
|
1892
|
+
if (tree_viz && tree_viz.cy) {
|
|
1893
|
+
tree_viz.animateFromRoot({ delay: 100 });
|
|
1894
|
+
}
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1693
1897
|
}
|
|
1694
1898
|
|
|
1695
1899
|
function HandleAppError(err_string) {
|
|
@@ -2493,6 +2697,9 @@
|
|
|
2493
2697
|
// 初始化全屏功能
|
|
2494
2698
|
FullscreenManager.init();
|
|
2495
2699
|
|
|
2700
|
+
// 初始化进化树工具栏事件(只注册一次,使用 null 检查确保安全)
|
|
2701
|
+
initTreeToolbarEvents();
|
|
2702
|
+
|
|
2496
2703
|
// 通知父窗口准备就绪
|
|
2497
2704
|
window.parent.postMessage({ type: 'HIVTRACE_INIT_READY' }, '*');
|
|
2498
2705
|
|
|
@@ -2511,7 +2718,13 @@
|
|
|
2511
2718
|
} else if (data.options.treeData && data.options.treeData.nodes && data.options.treeData.nodes.length > 0) {
|
|
2512
2719
|
// 如果有进化树数据,初始化进化树
|
|
2513
2720
|
initTreeViz(data.options.treeData, data.options);
|
|
2721
|
+
} else {
|
|
2722
|
+
// 没有进化树数据,隐藏进化树 Tab
|
|
2723
|
+
hideTreeTab();
|
|
2514
2724
|
}
|
|
2725
|
+
} else {
|
|
2726
|
+
// 没有 options,隐藏进化树 Tab
|
|
2727
|
+
hideTreeTab();
|
|
2515
2728
|
}
|
|
2516
2729
|
} else if (data.type === 'HIVTRACE_UPDATE_DATA') {
|
|
2517
2730
|
updateNetworkData(data.graphData, data.options);
|
|
@@ -2523,7 +2736,13 @@
|
|
|
2523
2736
|
} else if (data.options.treeData && data.options.treeData.nodes && data.options.treeData.nodes.length > 0) {
|
|
2524
2737
|
// 更新进化树数据
|
|
2525
2738
|
initTreeViz(data.options.treeData, data.options);
|
|
2739
|
+
} else {
|
|
2740
|
+
// 没有进化树数据,隐藏进化树 Tab
|
|
2741
|
+
hideTreeTab();
|
|
2526
2742
|
}
|
|
2743
|
+
} else {
|
|
2744
|
+
// 没有 options,隐藏进化树 Tab
|
|
2745
|
+
hideTreeTab();
|
|
2527
2746
|
}
|
|
2528
2747
|
|
|
2529
2748
|
} else if (data.type === 'HIVTRACE_ERROR') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basic-genomics/hivtrace-viz",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "HIV-TRACE molecular transmission network visualization with React integration",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18"
|
|
@@ -104,4 +104,4 @@
|
|
|
104
104
|
"vite"
|
|
105
105
|
],
|
|
106
106
|
"packageManager": "yarn@1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447"
|
|
107
|
-
}
|
|
107
|
+
}
|