diff --git a/src/module/cytoscapeMap.js b/src/module/cytoscapeMap.js index 2b6567e..a37a84b 100644 --- a/src/module/cytoscapeMap.js +++ b/src/module/cytoscapeMap.js @@ -4,6 +4,7 @@ import tippy from 'tippy.js'; import 'tippy.js/dist/tippy.css'; import Gradient from 'javascript-color-gradient'; // 多個色階產生器 import { getTimeLabel } from '@/module/timeLabel.js'; // 時間格式轉換器 +import CytoscapeStore from '@/stores/cytoscapeStore'; cytoscape.use( dagre ); @@ -19,6 +20,7 @@ cytoscape.use( dagre ); * @param {string} dataLayerOption DataLayer's options * @param {string} curve Curve's type * @param {string} graphId cytoscape's container + * @return {cytoscape.Core} cy */ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, curveStyle, rank, graphId) { // create color Gradient @@ -217,8 +219,29 @@ export default function cytoscapeMap(mapData, dataLayerType, dataLayerOption, cu content:content }); if(node.data("label").length > 10) tip.show(); - }) + }); cy.on('mouseout', 'node', function(event) { tip.hide(); - }) + }); + + const cytoscapeStore = CytoscapeStore(); + + cy.ready(() => { + cytoscapeStore.nodePositions.forEach(pos => { + const node = cy.getElementById(pos.id); + if (node) { + node.position(pos.position); + } + }); + + // 在改變節點位置後,盡可能地記錄節點線條的位置情報 + cy.on('dragfree', 'node', (event) => { + const node = event.target; + const position = node.position(); + cytoscapeStore.saveNodePosition(node.id(), position); + cytoscapeStore.savePositionsToStorage(); + }); + }); + + return cy; } diff --git a/src/router/index.js b/src/router/index.js index deed596..1e3b92d 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -2,9 +2,9 @@ import { createRouter, createWebHistory, } from "vue-router"; import AuthContainer from '@/views/AuthContainer.vue'; import MainContainer from '@/views/MainContainer.vue'; import Login from '@/views/Login/Login.vue'; -import Files from '@/views/Files/index.vue'; +import Files from '@/views/Files/Files.vue'; import Upload from '@/views/Upload/index.vue'; -import Map from '@/views/Discover/Map/index.vue'; +import Map from '@/views/Discover/Map/Map.vue'; import Conformance from '@/views/Discover/Conformance/index.vue'; import Performance from '@/views/Discover/Performance/index.vue'; import CompareDashboard from '@/views/Compare/Dashboard/index.vue'; diff --git a/src/stores/cytoscapeStore.js b/src/stores/cytoscapeStore.js new file mode 100644 index 0000000..0130660 --- /dev/null +++ b/src/stores/cytoscapeStore.js @@ -0,0 +1,60 @@ +import { defineStore } from 'pinia'; + +// interface NodePosition { +// id: string; +// position: { x: number; y: number }; +// graphId: string; +// } + +export default defineStore('useCytoscapeStore', { + state: () => ({ + nodePositions: [], + currentGraphId: "", + }), + actions: { + /** + * 儲存或更新單個節點的位置資訊。 + * @param {string} id + * @param {object} position {x, y} + * @param {string} graphId + */ + 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, + }); + } + }, + /** + * 根據節點 ID 獲取該節點的位置資訊 + * @param {string} id + * @returns + */ + getNodePosition(id) { // 返回該節點的位置資訊,如果不存在則返回 undefined + return this.nodePositions.find(node => node.id === id)?.position; + }, + /** + * 從本地存儲中加載節點位置資訊。 + */ + loadPositionsFromStorage() { + const storedPositions = localStorage.getItem('cy-node-positions'); + if (storedPositions) { + this.nodePositions = JSON.parse(storedPositions); + } + }, + /** + * 將節點位置資訊儲存到本地存儲中。 + */ + savePositionsToStorage() { + localStorage.setItem('cy-node-positions', JSON.stringify(this.nodePositions)); + }, + setCurrentGraphId(currentGraphId) { + this.currentGraphId = currentGraphId; + }, + }, +}); \ No newline at end of file diff --git a/src/stores/login.js b/src/stores/login.js index a60f201..721182f 100644 --- a/src/stores/login.js +++ b/src/stores/login.js @@ -2,6 +2,7 @@ import { defineStore } from "pinia"; import axios from 'axios'; import apiError from '@/module/apiError.js'; import { deleteCookie, setCookie, getCookie } from "../utils/cookieUtil"; +import LoginStore from "@/stores/login.js"; export default defineStore('loginStore', { // data, methods, computed @@ -60,7 +61,6 @@ export default defineStore('loginStore', { * Refresh Token */ async refreshToken() { - console.log('TODO:TODO:', this.auth); const api = '/api/oauth/token'; this.auth.grant_type = 'refresh_token'; @@ -123,6 +123,9 @@ export default defineStore('loginStore', { }, setRememberedReturnToUrl(returnToUrl){ this.rememberedReturnToUrl = returnToUrl - } - } + }, + setIsLoggedIn(boolean) { + this.isLoggedIn = boolean; + }, + }, }); diff --git a/src/views/Discover/Map/index.vue b/src/views/Discover/Map/Map.vue similarity index 94% rename from src/views/Discover/Map/index.vue rename to src/views/Discover/Map/Map.vue index 8646055..cc744a4 100644 --- a/src/views/Discover/Map/index.vue +++ b/src/views/Discover/Map/Map.vue @@ -53,12 +53,14 @@