Skip to content

Commit 111f6b4

Browse files
add initial canvas positioning by its' content bounding
1 parent 118779d commit 111f6b4

4 files changed

Lines changed: 90 additions & 5 deletions

File tree

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import {
1414
OnPointerMoveHandler,
1515
OnPointerDownHandler,
1616
} from "../canvas-event-target";
17-
import { transform_by_zoom_delta, get_hovering_target } from "../math";
17+
import {
18+
transform_by_zoom_delta,
19+
get_hovering_target,
20+
centerOf,
21+
} from "../math";
1822
import { utils } from "@design-sdk/core";
1923
import { LazyFrame } from "@code-editor/canvas/lazy-frame";
2024
import { HudCustomRenderers, HudSurface } from "./hud-surface";
@@ -73,9 +77,14 @@ export function Canvas({
7377
CanvasState & {
7478
config?: CanvsPreferences;
7579
}) {
76-
const [zoom, setZoom] = useState(INITIAL_SCALE);
80+
const { center: _inicial_xy, scale: _initial_scale } = useMemo(
81+
() => centerOf(null, ...nodes),
82+
[nodes]
83+
);
84+
85+
const [zoom, setZoom] = useState(_initial_scale);
7786
const [isZooming, setIsZooming] = useState(false);
78-
const [xy, setXY] = useState<[number, number]>(INITIAL_XY);
87+
const [xy, setXY] = useState<[number, number]>(_inicial_xy);
7988
const [isPanning, setIsPanning] = useState(false);
8089

8190
const node = (id) => designq.find_node_by_id_under_inpage_nodes(id, nodes);
@@ -89,7 +98,6 @@ export function Canvas({
8998

9099
useEffect(() => {
91100
setHoveringLayer(wshighlight);
92-
// console.log("wshighlight", wshighlight, highlightedLayer);
93101
}, [highlightedLayer]);
94102

95103
const onPointerMove: OnPointerMoveHandler = (state) => {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
type Rect = {
2+
x: number;
3+
y: number;
4+
width: number;
5+
height: number;
6+
rotation: number;
7+
};
8+
9+
type Box = [number, number, number, number];
10+
11+
/**
12+
* get center of a list of rectangles and the scale factor to fit them all.
13+
*
14+
* the rectangle contains x, y, w, h and rotation as r.
15+
*
16+
* the output is a bounding box x1, y1, x2, y2 and scale.
17+
*/
18+
export function centerOf(
19+
bound: Box,
20+
...rects: Rect[]
21+
): {
22+
box: Box;
23+
center: [number, number];
24+
scale: number;
25+
} {
26+
if (!rects || rects.length === 0) {
27+
return {
28+
box: [0, 0, 0, 0],
29+
center: [0, 0],
30+
scale: 1,
31+
};
32+
}
33+
34+
let x1 = Infinity;
35+
let y1 = Infinity;
36+
let x2 = -Infinity;
37+
let y2 = -Infinity;
38+
39+
for (const rect of rects) {
40+
const { x, y, width: w, height: h, rotation: r } = rect;
41+
const [cx, cy] = rotate(x + w / 2, y + h / 2, r);
42+
x1 = Math.min(x1, cx - w / 2);
43+
y1 = Math.min(y1, cy - h / 2);
44+
x2 = Math.max(x2, cx + w / 2);
45+
y2 = Math.max(y2, cy + h / 2);
46+
}
47+
const ww = x2 - x1;
48+
const hh = y2 - y1;
49+
const box: Box = [x1, y1, x2, y2];
50+
51+
return {
52+
box: box,
53+
center: [(x1 + x2) / 2, (y1 + y2) / 2],
54+
scale: scaleToFit(bound, box),
55+
};
56+
}
57+
58+
function rotate(x: number, y: number, r: number): [number, number] {
59+
const cos = Math.cos(r);
60+
const sin = Math.sin(r);
61+
return [x * cos - y * sin, x * sin + y * cos];
62+
}
63+
64+
function scaleToFit(a: Box, b: Box): number {
65+
if (!a || !b) {
66+
return 1;
67+
}
68+
const [ax1, ay1, ax2, ay2] = a;
69+
const [bx1, by1, bx2, by2] = b;
70+
const aw = ax2 - ax1;
71+
const ah = ay2 - ay1;
72+
const bw = bx2 - bx1;
73+
const bh = by2 - by1;
74+
const scale = Math.min(bw / aw, bh / ah);
75+
return scale;
76+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from "./gesture-transform";
22
export * from "./hovering-target";
3+
export * from "./center-of";

editor/scaffolds/canvas/canvas.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function VisualContentArea({ fileid }: { fileid: string }) {
2222
? state.design.pages
2323
.find((p) => p.id == selectedPage)
2424
.children.filter(Boolean)
25-
: null;
25+
: [];
2626

2727
const isEmptyPage = thisPageNodes?.length === 0;
2828

0 commit comments

Comments
 (0)