Skip to content

Commit a9ddc4c

Browse files
committed
improve viewport zooming
1 parent fc37454 commit a9ddc4c

2 files changed

Lines changed: 8 additions & 35 deletions

File tree

packages/learningmap/src/EditorCanvas.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export const EditorCanvas = memo(({ defaultLanguage = "en" }: EditorCanvasProps)
9595
({ nodes: selectedNodes }) => {
9696
// Only select nodes, not edges (as per requirement #6)
9797
setSelectedNodeIds(selectedNodes.map(n => n.id));
98-
98+
9999
// Close the node panel if no nodes are selected and it's currently open
100100
if (selectedNodes.length === 0) {
101101
setDrawerOpen(false);
@@ -150,6 +150,7 @@ export const EditorCanvas = memo(({ defaultLanguage = "en" }: EditorCanvasProps)
150150
onPaneClick={handlePaneClick}
151151
nodeTypes={nodeTypes}
152152
selectionOnDrag={false}
153+
minZoom={0.2}
153154
edgeTypes={edgeTypes}
154155
proOptions={{ hideAttribution: true }}
155156
defaultEdgeOptions={defaultEdgeOptions}

packages/learningmap/src/LearningMap.tsx

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import { Controls, Edge, Node, Panel, ReactFlow, ReactFlowProvider, useReactFlow } from "@xyflow/react";
1+
import { Controls, Node, Panel, ReactFlow, ReactFlowProvider, useReactFlow } from "@xyflow/react";
22
import { ImageNode } from "./nodes/ImageNode";
33
import { TaskNode } from "./nodes/TaskNode";
44
import { TextNode } from "./nodes/TextNode";
55
import { TopicNode } from "./nodes/TopicNode";
6-
import { NodeData, RoadmapData, RoadmapState, Settings } from "./types";
6+
import { NodeData, RoadmapData, RoadmapState } from "./types";
77
import { useCallback, useEffect } from "react";
88
import { parseRoadmapData } from "./helper";
99
import { Drawer } from "./Drawer";
1010
import { ProgressTracker } from "./ProgressTracker";
11-
import { getTranslations } from "./translations";
1211
import { useViewerStore } from "./viewerStore";
1312

1413
const nodeTypes = {
@@ -65,45 +64,20 @@ export function LearningMap({
6564
const setDrawerOpen = useViewerStore(state => state.setDrawerOpen);
6665
const loadRoadmapData = useViewerStore(state => state.loadRoadmapData);
6766
const getRoadmapState = useViewerStore(state => state.getRoadmapState);
68-
const updateNodesStates = useViewerStore(state => state.updateNodesStates);
6967
const updateNodeState = useViewerStore(state => state.updateNodeState);
70-
68+
7169
const { fitView, getViewport } = useReactFlow();
7270

7371
// Use language from settings if available, otherwise use prop
7472
const effectiveLanguage = settings?.language || language;
75-
const t = getTranslations(effectiveLanguage);
7673

7774
const { completed, mastered, total } = countCompletedNodes(nodes);
7875

7976
const parsedRoadmap = parseRoadmapData(roadmapData);
8077

81-
// Calculate translateExtent to ensure at least one node is always visible
82-
const calculateTranslateExtent = useCallback(() => {
83-
if (nodes.length === 0) return [[-Infinity, -Infinity], [Infinity, Infinity]] as [[number, number], [number, number]];
84-
85-
const padding = 200; // Add padding so nodes aren't at the very edge
86-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
87-
88-
nodes.forEach(node => {
89-
if (node.position) {
90-
// Estimate node size (approximate, could be refined)
91-
const nodeWidth = node.width || 200;
92-
const nodeHeight = node.height || 100;
93-
94-
minX = Math.min(minX, node.position.x - padding);
95-
minY = Math.min(minY, node.position.y - padding);
96-
maxX = Math.max(maxX, node.position.x + nodeWidth + padding);
97-
maxY = Math.max(maxY, node.position.y + nodeHeight + padding);
98-
}
99-
});
100-
101-
return [[minX, minY], [maxX, maxY]] as [[number, number], [number, number]];
102-
}, [nodes]);
103-
10478
useEffect(() => {
10579
loadRoadmapData(parsedRoadmap, initialState);
106-
80+
10781
// Only use fitView if there's no saved state
10882
if (!initialState) {
10983
// Use setTimeout to ensure nodes are rendered before fitView
@@ -141,7 +115,7 @@ export function LearningMap({
141115
useEffect(() => {
142116
const viewport = getViewport();
143117
const minimalState = getRoadmapState(viewport);
144-
118+
145119
if (onChange) {
146120
onChange(minimalState);
147121
} else {
@@ -168,8 +142,6 @@ export function LearningMap({
168142
zoom: initialState?.zoom || settings?.viewport?.zoom || 1,
169143
};
170144

171-
const translateExtent = calculateTranslateExtent();
172-
173145
return (
174146
<div
175147
className="editor-canvas"
@@ -193,9 +165,9 @@ export function LearningMap({
193165
edges={edges}
194166
onNodeClick={onNodeClick}
195167
onNodesChange={onNodesChange}
168+
minZoom={0.2}
196169
nodeTypes={nodeTypes}
197170
defaultViewport={defaultViewport}
198-
translateExtent={translateExtent}
199171
proOptions={{ hideAttribution: true }}
200172
defaultEdgeOptions={defaultEdgeOptions}
201173
nodesDraggable={false}

0 commit comments

Comments
 (0)