From 24ccdd47ae358f70f3a6624c97fbec68ef39ecf4 Mon Sep 17 00:00:00 2001 From: Cindy Chang Date: Mon, 1 Jul 2024 10:39:53 +0800 Subject: [PATCH] feature: remember node positions after refreshing pages --- src/constants/constants.js | 2 ++ src/module/cytoscapeMap.js | 30 ++++++++++++++------- src/stores/cytoscapeStore.js | 51 +++++++++++++++--------------------- src/utils/jsUtils.js | 15 +++++++++++ src/views/MainContainer.vue | 2 +- 5 files changed, 60 insertions(+), 40 deletions(-) create mode 100644 src/utils/jsUtils.js diff --git a/src/constants/constants.js b/src/constants/constants.js index 98c7b40..87a5231 100644 --- a/src/constants/constants.js +++ b/src/constants/constants.js @@ -8,6 +8,8 @@ export const MODAL_ACCT_EDIT = 'MODAL_ACCT_EDIT'; export const MODAL_ACCT_INFO = 'MODAL_ACCT_INFO'; 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 knownLayoutChartOption = { diff --git a/src/module/cytoscapeMap.js b/src/module/cytoscapeMap.js index a37a84b..6a736de 100644 --- a/src/module/cytoscapeMap.js +++ b/src/module/cytoscapeMap.js @@ -5,6 +5,8 @@ import 'tippy.js/dist/tippy.css'; import Gradient from 'javascript-color-gradient'; // 多個色階產生器 import { getTimeLabel } from '@/module/timeLabel.js'; // 時間格式轉換器 import CytoscapeStore from '@/stores/cytoscapeStore'; +import { SAVE_KEY_NAME } from '@/constants/constants.js'; + cytoscape.use( dagre ); @@ -227,19 +229,29 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu const cytoscapeStore = CytoscapeStore(); cy.ready(() => { - cytoscapeStore.nodePositions.forEach(pos => { - const node = cy.getElementById(pos.id); - if (node) { - node.position(pos.position); - } + cytoscapeStore.loadPositionsFromStorage(); + // 判斷localStorage是否儲存過拜訪資訊 + // 若曾經儲存過拜訪後的座標位置,則restore位置來渲染出來 + 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) => { - const node = event.target; - const position = node.position(); - cytoscapeStore.saveNodePosition(node.id(), position); - cytoscapeStore.savePositionsToStorage(); + const nodeToSave = event.target; + cytoscapeStore.saveNodePosition(nodeToSave.id(), nodeToSave.position()); }); }); diff --git a/src/stores/cytoscapeStore.js b/src/stores/cytoscapeStore.js index 0130660..f3a39a0 100644 --- a/src/stores/cytoscapeStore.js +++ b/src/stores/cytoscapeStore.js @@ -1,60 +1,51 @@ +import { el } from 'date-fns/locale'; import { defineStore } from 'pinia'; -// interface NodePosition { -// id: string; -// position: { x: number; y: number }; -// graphId: string; -// } +import { SAVE_KEY_NAME } from '@/constants/constants.js'; +import { printObject } from '@/utils/jsUtils'; export default defineStore('useCytoscapeStore', { state: () => ({ - nodePositions: [], + nodePositions: {}, currentGraphId: "", }), actions: { /** * 儲存或更新單個節點的位置資訊。 * @param {string} id - * @param {object} position {x, y} - * @param {string} graphId + * @param {object} position {x, y} position有兩個值,x與y */ - saveNodePosition(id, position) { - const existingNode = this.nodePositions.find(node => node.id === id && node.graphId === this.currentGraphId); - if (existingNode) { // 如果存在,更新位置資訊 - existingNode.position = position; - } else { // 如果不存在,新增一個新的位置資訊 - this.nodePositions.push({ - id, - position, - graphId: this.currentGraphId, - }); + saveNodePosition(nodeId, position) { + // 若是資訊曾經存在這張圖於localStorage中 + if (localStorage.getItem(SAVE_KEY_NAME) && JSON.parse(localStorage.getItem(SAVE_KEY_NAME))[this.currentGraphId]) { + const nodeToSave = this.nodePositions[this.currentGraphId].find(node => node.id === nodeId); + if(nodeToSave) { + nodeToSave.position = position; + } else { + this.nodePositions[this.currentGraphId] = [... this.nodePositions[this.currentGraphId], + {id: nodeId, position: position}] + } + } - }, - /** - * 根據節點 ID 獲取該節點的位置資訊 - * @param {string} id - * @returns - */ - getNodePosition(id) { // 返回該節點的位置資訊,如果不存在則返回 undefined - return this.nodePositions.find(node => node.id === id)?.position; + this.savePositionsToStorage(); }, /** * 從本地存儲中加載節點位置資訊。 */ loadPositionsFromStorage() { - const storedPositions = localStorage.getItem('cy-node-positions'); - if (storedPositions) { - this.nodePositions = JSON.parse(storedPositions); + if (localStorage.getItem(SAVE_KEY_NAME)) { + this.nodePositions[this.currentGraphId] = JSON.parse(localStorage.getItem(SAVE_KEY_NAME))[this.currentGraphId]; } }, /** * 將節點位置資訊儲存到本地存儲中。 */ savePositionsToStorage() { - localStorage.setItem('cy-node-positions', JSON.stringify(this.nodePositions)); + localStorage.setItem(SAVE_KEY_NAME, JSON.stringify(this.nodePositions)); }, setCurrentGraphId(currentGraphId) { this.currentGraphId = currentGraphId; + this.nodePositions[currentGraphId] = []; }, }, }); \ No newline at end of file diff --git a/src/utils/jsUtils.js b/src/utils/jsUtils.js new file mode 100644 index 0000000..4a59618 --- /dev/null +++ b/src/utils/jsUtils.js @@ -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]}`); + } + } + } + } \ No newline at end of file diff --git a/src/views/MainContainer.vue b/src/views/MainContainer.vue index 6ed8310..5c1c8cf 100644 --- a/src/views/MainContainer.vue +++ b/src/views/MainContainer.vue @@ -110,7 +110,7 @@ export default { async beforeRouteEnter(to, from, next) { const loginStore = LoginStore(); - if (!getCookie("isLuciaLoggedIn")) { + if (!getCookie("isLuciaLoggedIn")) { //這裡不要用pinia的isLoggedIn來檢查,因為會有重新整理時撈不到Persisted value的值的bug if (getCookie('luciaRefreshToken')) { await loginStore.refreshToken(); loginStore.setIsLoggedIn(true);