114 lines
2.8 KiB
TypeScript
114 lines
2.8 KiB
TypeScript
import { create } from "zustand";
|
|
import type { GraphData, GraphNode, GraphLink } from "../types";
|
|
|
|
interface GraphState {
|
|
data: GraphData;
|
|
highlightNodes: Set<string>;
|
|
highlightLinks: Set<GraphLink>;
|
|
isLinkMode: boolean;
|
|
selectedNode: GraphNode | null;
|
|
|
|
// Действия с данными
|
|
setData: (data: GraphData) => void;
|
|
addNode: (node: GraphNode) => void;
|
|
removeNode: (nodeId: string) => void;
|
|
addLink: (link: GraphLink) => void;
|
|
removeLink: (link: GraphLink) => void;
|
|
|
|
// Подсветка
|
|
setHighlight: (nodeIds: Set<string>, links: Set<GraphLink>) => void;
|
|
|
|
// Режим связи
|
|
toggleLinkMode: () => void;
|
|
setSelectedNode: (node: GraphNode | null) => void;
|
|
createLink: (sourceId: string, targetId: string) => void;
|
|
|
|
// Экспорт
|
|
exportData: () => void;
|
|
}
|
|
|
|
export const useGraphStore = create<GraphState>((set, get) => ({
|
|
data: { nodes: [], links: [] },
|
|
highlightNodes: new Set(),
|
|
highlightLinks: new Set(),
|
|
isLinkMode: false,
|
|
selectedNode: null,
|
|
|
|
setData: (data) => set({ data }),
|
|
|
|
addNode: (node) => {
|
|
set((state) => ({
|
|
data: {
|
|
...state.data,
|
|
nodes: [...state.data.nodes, node],
|
|
},
|
|
}));
|
|
},
|
|
|
|
removeNode: (nodeId) => {
|
|
set((state) => ({
|
|
data: {
|
|
nodes: state.data.nodes.filter((n) => n.id !== nodeId),
|
|
links: state.data.links.filter(
|
|
(l) => l.source !== nodeId && l.target !== nodeId,
|
|
),
|
|
},
|
|
}));
|
|
},
|
|
|
|
addLink: (link) => {
|
|
set((state) => ({
|
|
data: {
|
|
...state.data,
|
|
links: [...state.data.links, link],
|
|
},
|
|
}));
|
|
},
|
|
|
|
removeLink: (linkToRemove) => {
|
|
set((state) => ({
|
|
data: {
|
|
...state.data,
|
|
links: state.data.links.filter((l) => l !== linkToRemove),
|
|
},
|
|
}));
|
|
},
|
|
|
|
setHighlight: (nodeIds, links) =>
|
|
set({ highlightNodes: nodeIds, highlightLinks: links }),
|
|
|
|
toggleLinkMode: () =>
|
|
set((state) => ({
|
|
isLinkMode: !state.isLinkMode,
|
|
selectedNode: null,
|
|
})),
|
|
|
|
setSelectedNode: (node) => set({ selectedNode: node }),
|
|
|
|
createLink: (sourceId, targetId) => {
|
|
const { data, addLink } = get();
|
|
|
|
const linkExists = data.links.some(
|
|
(link) =>
|
|
(link.source === sourceId && link.target === targetId) ||
|
|
(link.source === targetId && link.target === sourceId),
|
|
);
|
|
|
|
if (!linkExists) {
|
|
addLink({ source: sourceId, target: targetId, type: "custom" });
|
|
}
|
|
},
|
|
|
|
exportData: () => {
|
|
const { data } = get();
|
|
const dataStr = JSON.stringify(data, null, 2);
|
|
const blob = new Blob([dataStr], { type: "application/json" });
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement("a");
|
|
link.href = url;
|
|
link.download = "graph-data.json";
|
|
link.click();
|
|
URL.revokeObjectURL(url);
|
|
},
|
|
}));
|