Skip to content

Commit a79b14b

Browse files
add save/load canvas states - selections & transform
1 parent ed2144d commit a79b14b

8 files changed

Lines changed: 57 additions & 14 deletions

File tree

editor-packages/editor-canvas/canvas-event-target/canvas-event-target.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ export function CanvasEventTarget({
137137
onMoveStart: onPointerMoveStart,
138138
onMoveEnd: onPointerMoveEnd,
139139
},
140-
{ target: interactionEventTargetRef }
140+
{
141+
target: interactionEventTargetRef,
142+
eventOptions: {
143+
passive: false,
144+
},
145+
}
141146
);
142147

143148
return (

editor-packages/editor-canvas/canvas/canvas.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useEffect, useRef, useState, useMemo } from "react";
22
import { ReflectSceneNode } from "@design-sdk/figma-node";
3-
import styled from "@emotion/styled";
3+
import { CanvasStateStore } from "../stores";
44
import {
55
CanvasEventTarget,
66
OnPanningHandler,
@@ -22,6 +22,7 @@ const LAYER_HOVER_HIT_MARGIN = 3.5;
2222
const MIN_ZOOM = 0.02;
2323

2424
interface CanvasState {
25+
pageid: string;
2526
filekey: string;
2627
nodes: ReflectSceneNode[];
2728
highlightedLayer?: string;
@@ -56,11 +57,9 @@ export function Canvas({
5657
onSelectNode,
5758
onClearSelection,
5859
filekey,
60+
pageid,
5961
nodes,
60-
initialTransform = {
61-
xy: INITIAL_XY,
62-
scale: INITIAL_SCALE,
63-
},
62+
initialTransform,
6463
highlightedLayer,
6564
selectedNodes,
6665
readonly = true,
@@ -73,11 +72,23 @@ export function Canvas({
7372
CanvasState & {
7473
config?: CanvsPreferences;
7574
}) {
75+
const _canvas_state_store = new CanvasStateStore(filekey, pageid);
76+
77+
initialTransform = initialTransform ??
78+
_canvas_state_store.getLastTransform() ?? {
79+
scale: INITIAL_SCALE,
80+
xy: INITIAL_XY,
81+
};
82+
7683
const [zoom, setZoom] = useState(initialTransform.scale);
7784
const [isZooming, setIsZooming] = useState(false);
7885
const [offset, setOffset] = useState<[number, number]>(initialTransform.xy);
7986
const nonscaled_offset: XY = [offset[0] / zoom, offset[1] / zoom]; // offset;
8087
const [isPanning, setIsPanning] = useState(false);
88+
const cvtransform: CanvasTransform = {
89+
scale: zoom,
90+
xy: offset,
91+
};
8192

8293
const node = (id) => designq.find_node_by_id_under_inpage_nodes(id, nodes);
8394

@@ -173,13 +184,15 @@ export function Canvas({
173184
setIsPanning(true);
174185
}}
175186
onPanningEnd={() => {
187+
_canvas_state_store.saveLastTransform(cvtransform);
176188
setIsPanning(false);
177189
}}
178190
onZooming={onZooming}
179191
onZoomingStart={() => {
180192
setIsZooming(true);
181193
}}
182194
onZoomingEnd={() => {
195+
_canvas_state_store.saveLastTransform(cvtransform);
183196
setIsZooming(false);
184197
}}
185198
onPointerMove={onPointerMove}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { CanvasStateStore } from "./page-state-store";

editor-packages/editor-canvas/stores/page-state-store.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,22 @@ import type { CanvasTransform } from "../types";
77
*
88
* (uses session storage)
99
*/
10-
export class PageStateStore {
10+
export class CanvasStateStore {
1111
constructor(readonly filekey: string, readonly pageid: string) {}
1212

13-
saveLastSelection(nodeid: string) {
13+
saveLastSelection(...nodes: string[]) {
1414
sessionStorage.setItem(
1515
`canvas-page-state-store/${this.filekey}/${this.pageid}/last-selection`,
16-
nodeid
16+
nodes ? JSON.stringify(nodes) : null
1717
);
1818
}
1919

20-
getLastSelection(): string | null {
21-
return sessionStorage.getItem(
20+
getLastSelection(): string[] | null {
21+
const pl = sessionStorage.getItem(
2222
`canvas-page-state-store/${this.filekey}/${this.pageid}/last-selection`
2323
);
24+
if (!pl) return null;
25+
return JSON.parse(pl);
2426
}
2527

2628
saveLastTransform(transform: CanvasTransform) {

editor/core/reducers/editor-reducer.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import produce from "immer";
22
import { Action, SelectNodeAction, SelectPageAction } from "core/actions";
33
import { EditorState } from "core/states";
44
import { useRouter } from "next/router";
5+
import { CanvasStateStore } from "@code-editor/canvas/stores";
56

67
export function editorReducer(state: EditorState, action: Action): EditorState {
78
const router = useRouter();
9+
const filekey = state.design.key;
810

911
// TODO: handle actions here.
1012
switch (action.type) {
@@ -18,7 +20,14 @@ export function editorReducer(state: EditorState, action: Action): EditorState {
1820
router.push(router);
1921

2022
return produce(state, (draft) => {
21-
draft.selectedNodes = [node].filter(Boolean);
23+
const _canvas_state_store = new CanvasStateStore(
24+
filekey,
25+
state.selectedPage
26+
);
27+
28+
const new_selections = [node].filter(Boolean);
29+
_canvas_state_store.saveLastSelection(...new_selections);
30+
draft.selectedNodes = new_selections;
2231
});
2332
}
2433
case "select-page": {
@@ -32,8 +41,16 @@ export function editorReducer(state: EditorState, action: Action): EditorState {
3241
router.push(router);
3342

3443
return produce(state, (draft) => {
44+
const _canvas_state_store = new CanvasStateStore(filekey, page);
45+
46+
const last_known_selections_of_this_page =
47+
_canvas_state_store.getLastSelection() ?? [];
48+
console.log(
49+
"last_known_selections_of_this_page",
50+
last_known_selections_of_this_page
51+
);
3552
draft.selectedPage = page;
36-
draft.selectedNodes = [];
53+
draft.selectedNodes = last_known_selections_of_this_page;
3754
});
3855
}
3956
default:

editor/pages/_development/editor-canvas/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export default function EditorCanvasDevPage() {
1111
>
1212
<Canvas
1313
filekey="unknown"
14+
pageid="1"
1415
selectedNodes={[]}
1516
nodes={[]}
1617
renderItem={function (node): React.ReactNode {

editor/scaffolds/canvas/canvas.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export function VisualContentArea({ fileid }: { fileid: string }) {
5151
<Canvas
5252
key={selectedPage}
5353
filekey={state.design.key}
54+
pageid={selectedPage}
5455
selectedNodes={selectedNodes.filter(Boolean)}
5556
highlightedLayer={highlightedLayer}
5657
onSelectNode={(node) => {

editor/scaffolds/editor/editor.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ export function Editor({
6464
3 +
6565
0.2;
6666

67+
// this key is used for force re-rendering canvas after the whole file is fetched.
68+
const _refreshkey = loading || !_initially_loaded ? "1" : "0";
69+
6770
return (
6871
<>
6972
{(loading || !_initially_loaded) && (
@@ -75,7 +78,7 @@ export function Editor({
7578
>
7679
<WorkspaceContentPanelGridLayout>
7780
<WorkspaceContentPanel flex={6}>
78-
<Canvas fileid={state?.design?.key} />
81+
<Canvas key={_refreshkey} fileid={state?.design?.key} />
7982
</WorkspaceContentPanel>
8083
<WorkspaceContentPanel
8184
hidden={state.selectedNodes.length === 0}

0 commit comments

Comments
 (0)