fix vertical path bug by not handling TB case

This commit is contained in:
Cindy Chang
2024-09-02 13:12:12 +08:00
parent 7b7b722efb
commit 35c7ac355e

View File

@@ -6,7 +6,6 @@ import cola from 'cytoscape-cola';
import tippy from 'tippy.js'; import tippy from 'tippy.js';
import 'tippy.js/dist/tippy.css'; import 'tippy.js/dist/tippy.css';
import MapPathStore from '@/stores/mapPathStore'; import MapPathStore from '@/stores/mapPathStore';
import Gradient from 'javascript-color-gradient'; // 多個色階產生器
import { getTimeLabel } from '@/module/timeLabel.js'; // 時間格式轉換器 import { getTimeLabel } from '@/module/timeLabel.js'; // 時間格式轉換器
import CytoscapeStore from '@/stores/cytoscapeStore'; import CytoscapeStore from '@/stores/cytoscapeStore';
import { SAVE_KEY_NAME } from '@/constants/constants.js'; import { SAVE_KEY_NAME } from '@/constants/constants.js';
@@ -15,7 +14,7 @@ const mapPathStore = MapPathStore();
const composeFreqTypeText = (baseText, dataLayerOption, optionValue) => { //sonar-qube const composeFreqTypeText = (baseText, dataLayerOption, optionValue) => { //sonar-qube
let text = baseText; let text = baseText;
const textInt = dataLayerOption === 'rel_freq' ? baseText + optionValue * 100 + "%" : baseText + optionValue; const textInt = dataLayerOption === 'rel_freq' ? baseText + optionValue * 100 + "%" : baseText + optionValue;
const textFloat = dataLayerOption === 'rel_freq'? baseText + (optionValue * 100).toFixed(2) + "%" : baseText + optionValue.toFixed(2); const textFloat = dataLayerOption === 'rel_freq' ? baseText + (optionValue * 100).toFixed(2) + "%" : baseText + optionValue.toFixed(2);
// 判斷是否為整數,若非整數要取小數點後面兩個值。 // 判斷是否為整數,若非整數要取小數點後面兩個值。
text = Math.trunc(optionValue) === optionValue ? textInt : textFloat; text = Math.trunc(optionValue) === optionValue ? textInt : textFloat;
return text; return text;
@@ -60,10 +59,10 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
style: [ style: [
// 點擊 node 後改變的樣式 // 點擊 node 後改變的樣式
{ {
selector:'node:selected', selector: 'node:selected',
style:{ style: {
'border-color':'red', 'border-color': 'red',
'border-width':'3', 'border-width': '3',
}, },
}, },
// node 節點的樣式 // node 節點的樣式
@@ -71,7 +70,7 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
selector: 'node', selector: 'node',
style: { style: {
'label': 'label':
function(node) { // 節點要顯示的文字 function (node) { // 節點要顯示的文字
// node.data(this.dataLayerType+"."+this.dataLayerOption) 為原先陣列 node.data.key.value // node.data(this.dataLayerType+"."+this.dataLayerOption) 為原先陣列 node.data.key.value
let optionValue = node.data(`${dataLayerType}.${dataLayerOption}`); let optionValue = node.data(`${dataLayerType}.${dataLayerOption}`);
let text = ''; let text = '';
@@ -87,13 +86,13 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
// 在 element 中 activity 歸類在 default所以要先判斷 node 是否為 activity 才裝入文字。 // 在 element 中 activity 歸類在 default所以要先判斷 node 是否為 activity 才裝入文字。
// 可使用 parseInt(整數) parseFloat(浮點數) 將字串轉為數字 // 可使用 parseInt(整數) parseFloat(浮點數) 將字串轉為數字
// Relative 要轉為百分比 % // Relative 要轉為百分比 %
if(node.data('type') === 'activity') { if (node.data('type') === 'activity') {
let textDurRel; let textDurRel;
let timeLabelInt; let timeLabelInt;
let timeLabelFloat; let timeLabelFloat;
let textTimeLabel; let textTimeLabel;
switch(dataLayerType) { switch (dataLayerType) {
case 'freq': // Frequency case 'freq': // Frequency
text = composeFreqTypeText(text, dataLayerOption, optionValue); text = composeFreqTypeText(text, dataLayerOption, optionValue);
break; break;
@@ -114,27 +113,27 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
return text; return text;
}, },
'text-opacity':0.7, 'text-opacity': 0.7,
'background-color': 'data(backgroundColor)', 'background-color': 'data(backgroundColor)',
'border-color':'data(bordercolor)', 'border-color': 'data(bordercolor)',
'border-width': 'border-width':
function(node) { function (node) {
return node.data('type') === 'activity' ? '1' : '2'; return node.data('type') === 'activity' ? '1' : '2';
}, },
'background-image': 'data(nodeImageUrl)', 'background-image': 'data(nodeImageUrl)',
'background-opacity': 'data(backgroundOpacity)', // 透明背景 'background-opacity': 'data(backgroundOpacity)', // 透明背景
'border-opacity': 'data(borderOpacity)', // 透明邊框 'border-opacity': 'data(borderOpacity)', // 透明邊框
'shape':'data(shape)', 'shape': 'data(shape)',
'text-wrap': 'wrap', 'text-wrap': 'wrap',
'text-max-width': 'data(width)', // 在 div 內換行 'text-max-width': 'data(width)', // 在 div 內換行
'text-overflow-wrap': 'anywhere', // 在 div 內換行 'text-overflow-wrap': 'anywhere', // 在 div 內換行
'text-margin-x': function(node) { 'text-margin-x': function (node) {
return node.data('type') === 'activity' ? -5 : 0; return node.data('type') === 'activity' ? -5 : 0;
}, },
'text-margin-y': function(node) { 'text-margin-y': function (node) {
return node.data('type') === 'activity' ? 2 : 0; return node.data('type') === 'activity' ? 2 : 0;
}, },
'padding': function(node) { 'padding': function (node) {
return node.data('type') === 'activity' ? 0 : 0; return node.data('type') === 'activity' ? 0 : 0;
}, },
'text-justification': 'left', 'text-justification': 'left',
@@ -145,7 +144,7 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
'color': 'data(textColor)', 'color': 'data(textColor)',
'line-height': '0.7rem', 'line-height': '0.7rem',
'font-size': 'font-size':
function(node) { function (node) {
return node.data('type') === 'activity' ? 14 : 14; return node.data('type') === 'activity' ? 14 : 14;
}, },
}, },
@@ -154,7 +153,7 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
{ {
selector: 'edge', selector: 'edge',
style: { style: {
'content': function(edge) { // 關係線顯示的文字 'content': function (edge) { // 關係線顯示的文字
let optionValue = edge.data(`${dataLayerType}.${dataLayerOption}`); let optionValue = edge.data(`${dataLayerType}.${dataLayerOption}`);
let result = ''; let result = '';
let edgeInt; let edgeInt;
@@ -163,9 +162,9 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
let timeLabelInt; let timeLabelInt;
let timeLabelFloat; let timeLabelFloat;
let edgeTimeLabel; let edgeTimeLabel;
if(optionValue === '') return optionValue; if (optionValue === '') return optionValue;
switch(dataLayerType) { switch (dataLayerType) {
case 'freq': case 'freq':
edgeInt = dataLayerOption === 'rel_freq' ? optionValue * 100 + "%" : optionValue; edgeInt = dataLayerOption === 'rel_freq' ? optionValue * 100 + "%" : optionValue;
edgeFloat = dataLayerOption === 'rel_freq' ? (optionValue * 100).toFixed(2) + "%" : optionValue.toFixed(2); edgeFloat = dataLayerOption === 'rel_freq' ? (optionValue * 100).toFixed(2) + "%" : optionValue.toFixed(2);
@@ -192,12 +191,12 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
'target-arrow-shape': 'triangle', // 指向目標的箭頭形狀: 三角形 'target-arrow-shape': 'triangle', // 指向目標的箭頭形狀: 三角形
'color': 'gray', //#0066cc 'color': 'gray', //#0066cc
//'control-point-step-size':100, // 從點到點的垂直線,指定貝茲取線邊緣間的距離 //'control-point-step-size':100, // 從點到點的垂直線,指定貝茲取線邊緣間的距離
'width':'data(lineWidth)', 'width': 'data(lineWidth)',
'line-style':'data(style)', 'line-style': 'data(style)',
"text-margin-y": "0.7rem", "text-margin-y": "0.7rem",
//"text-rotation": "autorotate", //"text-rotation": "autorotate",
} }
},{ }, {
selector: '.highlight-edge', selector: '.highlight-edge',
style: { style: {
'color': '#0099FF', 'color': '#0099FF',
@@ -206,14 +205,14 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
'overlay-opacity': 0.2, 'overlay-opacity': 0.2,
'overlay-padding': '5px', 'overlay-padding': '5px',
}, },
},{ }, {
selector: '.highlight-node', selector: '.highlight-node',
style: { style: {
'overlay-color': '#0099FF', 'overlay-color': '#0099FF',
'overlay-opacity': 0.01, 'overlay-opacity': 0.01,
'overlay-padding': '5px', 'overlay-padding': '5px',
}, },
},{ }, {
selector: 'edge[source = target]', // 選擇 self-loop 的邊 selector: 'edge[source = target]', // 選擇 self-loop 的邊
style: { style: {
'loop-direction': '0deg', // 控制 loop 的方向 'loop-direction': '0deg', // 控制 loop 的方向
@@ -224,32 +223,27 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
], ],
}); });
// 讓節點不要左右重疊的演算法
cy.layout({
name: 'spread',
minDist: 60, // 設置最小節點間距
}).run();
// 按下線條,線條及線條上數字有光暈效果 // 按下線條,線條及線條上數字有光暈效果
cy.on('tap', 'edge', function(event) { cy.on('tap', 'edge', function (event) {
cy.edges().removeClass('highlight-edge'); cy.edges().removeClass('highlight-edge');
event.target.addClass('highlight-edge'); event.target.addClass('highlight-edge');
}); });
// 按下節點光暈效果與鄰邊光暈效果 // 按下節點光暈效果與鄰邊光暈效果
cy.on('tap, mousedown', 'node', function(event) { cy.on('tap, mousedown', 'node', function (event) {
mapPathStore.onNodeClickHighlightEdges(event.target); mapPathStore.onNodeClickHighlightEdges(event.target);
}); });
// 按下線段光暈效果與兩端點光暈效果 // 按下線段光暈效果與兩端點光暈效果
cy.on('tap, mousedown', 'edge', function(event) { cy.on('tap, mousedown', 'edge', function (event) {
mapPathStore.onEdgeClickHighlightNodes(event.target); mapPathStore.onEdgeClickHighlightNodes(event.target);
}); });
// creat tippy.js // creat tippy.js
let tip; let tip;
cy.on('mouseover', 'node', function(event) { cy.on('mouseover', 'node', function (event) {
const node = event.target; const node = event.target;
let ref = node.popperRef() let ref = node.popperRef()
let dummyDomEle = document.createElement('div'); let dummyDomEle = document.createElement('div');
@@ -258,23 +252,27 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
tip = new tippy(dummyDomEle, { // tippy props: tip = new tippy(dummyDomEle, { // tippy props:
getReferenceClientRect: ref.getBoundingClientRect, getReferenceClientRect: ref.getBoundingClientRect,
trigger: 'manual', trigger: 'manual',
content:content content: content
}); });
if(node.data("label").length > 10) tip.show(); if (node.data("label").length > 10) tip.show();
}); });
cy.on('mouseout', 'node', function(event) { cy.on('mouseout', 'node', function (event) {
tip.hide(); tip.hide();
}); });
// here we remember and recall positions
const cytoscapeStore = CytoscapeStore(); const cytoscapeStore = CytoscapeStore();
cy.ready(() => { cy.ready(() => {
if (rank === 'TB') {
return; // early return; only handle 'LR' (horizontal) case
}
cytoscapeStore.loadPositionsFromStorage(); cytoscapeStore.loadPositionsFromStorage();
// 判斷localStorage是否儲存過拜訪資訊 // 判斷localStorage是否儲存過拜訪資訊
// 若曾經儲存過拜訪後的座標位置則restore位置來渲染出來 // 若曾經儲存過拜訪後的座標位置則restore位置來渲染出來
if(localStorage.getItem(SAVE_KEY_NAME) && JSON.parse(localStorage.getItem(SAVE_KEY_NAME))) { if (localStorage.getItem(SAVE_KEY_NAME) && JSON.parse(localStorage.getItem(SAVE_KEY_NAME))) {
const allGraphsRemembered = JSON.parse(localStorage.getItem(SAVE_KEY_NAME)); const allGraphsRemembered = JSON.parse(localStorage.getItem(SAVE_KEY_NAME));
const currentGraphNodesRemembered = allGraphsRemembered[cytoscapeStore.currentGraphId]; // 可能是undefined const currentGraphNodesRemembered = allGraphsRemembered[cytoscapeStore.currentGraphId]; // 可能是undefined
if(currentGraphNodesRemembered) { if (currentGraphNodesRemembered) {
currentGraphNodesRemembered.forEach(nodeRemembered => { currentGraphNodesRemembered.forEach(nodeRemembered => {
const nodeToDecide = cy.getElementById(nodeRemembered.id); const nodeToDecide = cy.getElementById(nodeRemembered.id);
if (nodeToDecide) { if (nodeToDecide) {