feature: remember node positions after refreshing pages

This commit is contained in:
Cindy Chang
2024-07-01 10:39:53 +08:00
parent 69a3f27cb2
commit 24ccdd47ae
5 changed files with 60 additions and 40 deletions

View File

@@ -8,6 +8,8 @@ export const MODAL_ACCT_EDIT = 'MODAL_ACCT_EDIT';
export const MODAL_ACCT_INFO = 'MODAL_ACCT_INFO'; export const MODAL_ACCT_INFO = 'MODAL_ACCT_INFO';
export const MODAL_DELETE = 'MODAL_DELETE'; export const MODAL_DELETE = 'MODAL_DELETE';
export const SAVE_KEY_NAME = 'CYTOSCAPE_NODE_POSTITION';
export const JUST_CREATE_ACCOUNT_HOT_DURATION_MINS = 2; export const JUST_CREATE_ACCOUNT_HOT_DURATION_MINS = 2;
export const knownLayoutChartOption = { export const knownLayoutChartOption = {

View File

@@ -5,6 +5,8 @@ import 'tippy.js/dist/tippy.css';
import Gradient from 'javascript-color-gradient'; // 多個色階產生器 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';
cytoscape.use( dagre ); cytoscape.use( dagre );
@@ -227,19 +229,29 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu
const cytoscapeStore = CytoscapeStore(); const cytoscapeStore = CytoscapeStore();
cy.ready(() => { cy.ready(() => {
cytoscapeStore.nodePositions.forEach(pos => { cytoscapeStore.loadPositionsFromStorage();
const node = cy.getElementById(pos.id); // 判斷localStorage是否儲存過拜訪資訊
if (node) { // 若曾經儲存過拜訪後的座標位置則restore位置來渲染出來
node.position(pos.position); if(localStorage.getItem(SAVE_KEY_NAME) && JSON.parse(localStorage.getItem(SAVE_KEY_NAME))) {
} const allGraphsRemembered = JSON.parse(localStorage.getItem(SAVE_KEY_NAME));
const currentGraphNodesRemembered = allGraphsRemembered[cytoscapeStore.currentGraphId];
currentGraphNodesRemembered.forEach(nodeRemembered => {
const nodeToDecide = cy.getElementById(nodeRemembered.id);
if (nodeToDecide) {
nodeToDecide.position(nodeRemembered.position);
}
});
}
//存下此刻剛進入畫面時當前所有節點的座標位置
const allNodes = cy.nodes();
allNodes.map(nodeFirstlySave => {
cytoscapeStore.saveNodePosition(nodeFirstlySave.id(), nodeFirstlySave.position);
}); });
// 在改變節點位置後,盡可能地記錄節點線條的位置情報 // 在改變節點位置後,盡可能地記錄節點線條的位置情報
cy.on('dragfree', 'node', (event) => { cy.on('dragfree', 'node', (event) => {
const node = event.target; const nodeToSave = event.target;
const position = node.position(); cytoscapeStore.saveNodePosition(nodeToSave.id(), nodeToSave.position());
cytoscapeStore.saveNodePosition(node.id(), position);
cytoscapeStore.savePositionsToStorage();
}); });
}); });

View File

@@ -1,60 +1,51 @@
import { el } from 'date-fns/locale';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
// interface NodePosition { import { SAVE_KEY_NAME } from '@/constants/constants.js';
// id: string; import { printObject } from '@/utils/jsUtils';
// position: { x: number; y: number };
// graphId: string;
// }
export default defineStore('useCytoscapeStore', { export default defineStore('useCytoscapeStore', {
state: () => ({ state: () => ({
nodePositions: [], nodePositions: {},
currentGraphId: "", currentGraphId: "",
}), }),
actions: { actions: {
/** /**
* 儲存或更新單個節點的位置資訊。 * 儲存或更新單個節點的位置資訊。
* @param {string} id * @param {string} id
* @param {object} position {x, y} * @param {object} position {x, y} position有兩個值x與y
* @param {string} graphId
*/ */
saveNodePosition(id, position) { saveNodePosition(nodeId, position) {
const existingNode = this.nodePositions.find(node => node.id === id && node.graphId === this.currentGraphId); // 若是資訊曾經存在這張圖於localStorage中
if (existingNode) { // 如果存在,更新位置資訊 if (localStorage.getItem(SAVE_KEY_NAME) && JSON.parse(localStorage.getItem(SAVE_KEY_NAME))[this.currentGraphId]) {
existingNode.position = position; const nodeToSave = this.nodePositions[this.currentGraphId].find(node => node.id === nodeId);
} else { // 如果不存在,新增一個新的位置資訊 if(nodeToSave) {
this.nodePositions.push({ nodeToSave.position = position;
id, } else {
position, this.nodePositions[this.currentGraphId] = [... this.nodePositions[this.currentGraphId],
graphId: this.currentGraphId, {id: nodeId, position: position}]
}); }
} }
}, this.savePositionsToStorage();
/**
* 根據節點 ID 獲取該節點的位置資訊
* @param {string} id
* @returns
*/
getNodePosition(id) { // 返回該節點的位置資訊,如果不存在則返回 undefined
return this.nodePositions.find(node => node.id === id)?.position;
}, },
/** /**
* 從本地存儲中加載節點位置資訊。 * 從本地存儲中加載節點位置資訊。
*/ */
loadPositionsFromStorage() { loadPositionsFromStorage() {
const storedPositions = localStorage.getItem('cy-node-positions'); if (localStorage.getItem(SAVE_KEY_NAME)) {
if (storedPositions) { this.nodePositions[this.currentGraphId] = JSON.parse(localStorage.getItem(SAVE_KEY_NAME))[this.currentGraphId];
this.nodePositions = JSON.parse(storedPositions);
} }
}, },
/** /**
* 將節點位置資訊儲存到本地存儲中。 * 將節點位置資訊儲存到本地存儲中。
*/ */
savePositionsToStorage() { savePositionsToStorage() {
localStorage.setItem('cy-node-positions', JSON.stringify(this.nodePositions)); localStorage.setItem(SAVE_KEY_NAME, JSON.stringify(this.nodePositions));
}, },
setCurrentGraphId(currentGraphId) { setCurrentGraphId(currentGraphId) {
this.currentGraphId = currentGraphId; this.currentGraphId = currentGraphId;
this.nodePositions[currentGraphId] = [];
}, },
}, },
}); });

15
src/utils/jsUtils.js Normal file
View File

@@ -0,0 +1,15 @@
export const printObject = (obj, indent = 0) => {
const padding = ' '.repeat(indent);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
console.log(`${padding}${key}: {`);
printObject(obj[key], indent + 2);
console.log(`${padding}}`);
} else {
console.log(`${padding}${key}: ${obj[key]}`);
}
}
}
}

View File

@@ -110,7 +110,7 @@ export default {
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
const loginStore = LoginStore(); const loginStore = LoginStore();
if (!getCookie("isLuciaLoggedIn")) { if (!getCookie("isLuciaLoggedIn")) { //這裡不要用pinia的isLoggedIn來檢查因為會有重新整理時撈不到Persisted value的值的bug
if (getCookie('luciaRefreshToken')) { if (getCookie('luciaRefreshToken')) {
await loginStore.refreshToken(); await loginStore.refreshToken();
loginStore.setIsLoggedIn(true); loginStore.setIsLoggedIn(true);