diff --git a/apps/web/src/components/DiagramEditorPane.test.mjs b/apps/web/src/components/DiagramEditorPane.test.mjs
index 2a465fef..b035c7cf 100644
--- a/apps/web/src/components/DiagramEditorPane.test.mjs
+++ b/apps/web/src/components/DiagramEditorPane.test.mjs
@@ -204,7 +204,10 @@ describe("diagram editor canvas surface", () => {
expect(source).toContain("diagramNodeBounds(graph)");
expect(source).toContain("flowchartFitsReadableViewport(bounds, size, padding, minScale, policy.maxScale)");
expect(source).toContain("readDiagramContent(graph, document)");
+ expect(source).toContain("readDiagramContent(graphRef.current, document)");
expect(source).toContain("diagramReaderFocusNode(document)");
+ expect(source).toContain("zoomDiagram(graph, 1, true)");
+ expect(source).not.toContain('document.kind === "flowchart" ? 1 : minScale');
expect(source).toContain("scroller.positionPoint({ x: box.x + box.width / 2, y: box.y }, \"50%\", 48)");
expect(source).toContain('policy.anchor === "leftmost"');
expect(source).toContain("scroller.positionPoint({ x: origin.x, y: origin.y }, 40, 48)");
@@ -212,7 +215,7 @@ describe("diagram editor canvas surface", () => {
expect(source).toContain("scroller.zoomToRect(bounds, options)");
expect(source).toContain("getDiagramLayoutViewport(document.kind)");
expect(source).toContain("fitDiagramContent(graph, document, containerRef.current);");
- expect(source).toContain("fitDiagramContent(graph, document, containerRef.current, 40, layout.viewport, { readable: true })");
+ expect(source).toContain("fitDiagramContent(graph, document, containerRef.current, 40, layout.viewport)");
});
test("labels auto layout directly instead of relying on an ambiguous icon", () => {
@@ -226,14 +229,14 @@ describe("diagram editor canvas surface", () => {
expect(toolbarSource).not.toContain("onFit");
expect(toolbarSource).not.toContain('t("diagram.fit")');
expect(source).not.toContain("onFit={() =>");
- expect(source).toContain("fitDiagramContent(graph, document, containerRef.current, 40, layout.viewport, { readable: true });");
+ expect(source).toContain("fitDiagramContent(graph, document, containerRef.current, 40, layout.viewport);");
});
test("lets the zoom percent be typed instead of only resetting to 100%", () => {
expect(toolbarSource).toContain("onZoomTo");
expect(toolbarSource).toContain("parseDiagramZoomPercent");
expect(toolbarSource).toContain('t("diagram.zoomPercent")');
- expect(toolbarSource).toContain('t("diagram.zoomPercentHint")');
+ expect(toolbarSource).not.toContain('t("diagram.zoomPercentHint")');
expect(toolbarSource).toContain("onPointerDown={(event) => event.stopPropagation()}");
expect(toolbarSource).not.toContain("onResetZoom");
expect(source).toContain("onZoomTo={(percent) =>");
diff --git a/apps/web/src/components/DiagramEditorPane.tsx b/apps/web/src/components/DiagramEditorPane.tsx
index ce7c7de0..d16f3c34 100644
--- a/apps/web/src/components/DiagramEditorPane.tsx
+++ b/apps/web/src/components/DiagramEditorPane.tsx
@@ -1153,11 +1153,10 @@ const diagramViewportSize = (graph: Graph, container: HTMLElement | null) => {
const readDiagramContent = (graph: Graph, document: DiagramDocument) => {
const policy = getDiagramLayoutViewport(document.kind);
- const minScale = policy.minScale ?? 1;
const focus = diagramReaderFocusNode(document);
const cell = focus ? graph.getCellById(focus.id) : null;
ensureDiagramPaperContainsNodes(graph);
- zoomDiagram(graph, document.kind === "flowchart" ? 1 : minScale, true);
+ zoomDiagram(graph, 1, true);
ensureDiagramPaperContainsNodes(graph);
if (!cell?.isNode()) {
centerDiagramContent(graph);
@@ -1188,19 +1187,16 @@ const fitDiagramContent = (
container: HTMLElement | null,
padding = 32,
viewport?: DiagramLayoutViewport,
- options: { readable?: boolean } = {},
) => {
const policy = viewport ?? getDiagramLayoutViewport(document.kind);
const bounds = diagramNodeBounds(graph);
if (!bounds) return;
ensureDiagramPaperContainsNodes(graph);
- if (options.readable) {
- const size = diagramViewportSize(graph, container);
- const minScale = policy.minScale ?? 1;
- if (size && !flowchartFitsReadableViewport(bounds, size, padding, minScale, policy.maxScale)) {
- readDiagramContent(graph, document);
- return;
- }
+ const size = diagramViewportSize(graph, container);
+ const minScale = policy.minScale ?? 1;
+ if (size && !flowchartFitsReadableViewport(bounds, size, padding, minScale, policy.maxScale)) {
+ readDiagramContent(graph, document);
+ return;
}
// Fit every node, including mind-map branches left of the root. Zooming to a
// visible subset or to edge paths lets Scroller shrink the paper and clip.
@@ -1695,7 +1691,7 @@ export const DiagramEditorPane = ({
if (graphRef.current !== graph) return false;
if (!diagramCanvasIsReady(canvasSurfaceRef.current)) return false;
ensureDiagramPaperContainsNodes(graph);
- fitDiagramContent(graph, document, containerRef.current, 32, undefined, { readable: true });
+ fitDiagramContent(graph, document, containerRef.current, 32);
return true;
};
settleLoadedViewport();
@@ -2467,7 +2463,7 @@ export const DiagramEditorPane = ({
if (document.kind === "mind-map") applyMindMapHierarchy(graph, themeRef.current, appearanceRef.current, structureRef.current);
graph.stopBatch("layout");
ensureDiagramPaperContainsNodes(graph);
- fitDiagramContent(graph, document, containerRef.current, 40, layout.viewport, { readable: true });
+ fitDiagramContent(graph, document, containerRef.current, 40, layout.viewport);
if (changed) {
setDirty(savedSnapshotRef.current !== diagramEditorSnapshot(
titleRef.current,
diff --git a/apps/web/src/components/DiagramToolbar.tsx b/apps/web/src/components/DiagramToolbar.tsx
index 6588d87f..1aa58734 100644
--- a/apps/web/src/components/DiagramToolbar.tsx
+++ b/apps/web/src/components/DiagramToolbar.tsx
@@ -220,38 +220,33 @@ const DiagramZoomPercentField = ({
};
return (
-
-
-
-
- {t("diagram.zoomPercentHint")}
-
+
);
};
diff --git a/apps/web/src/lib/diagram-layout.test.mjs b/apps/web/src/lib/diagram-layout.test.mjs
index 46158667..ed42d81e 100644
--- a/apps/web/src/lib/diagram-layout.test.mjs
+++ b/apps/web/src/lib/diagram-layout.test.mjs
@@ -314,23 +314,17 @@ describe("diagram auto layout", () => {
expect(Math.hypot(loopCenter.x - b3Center.x, loopCenter.y - b3Center.y)).toBeLessThan(420);
});
- test("keeps flowchart viewports at reading size instead of shrinking the whole stack", () => {
+ test("caps auto-layout zoom at 100% and refuses to shrink below reading size", () => {
expect(getDiagramLayoutViewport("flowchart")).toEqual({
anchor: "center",
maxScale: 1,
minScale: DIAGRAM_READABLE_MIN_SCALE,
});
- });
-
- test("keeps mind-map viewports at reading size instead of shrinking the whole tree", () => {
expect(getDiagramLayoutViewport("mind-map")).toEqual({
anchor: "root",
maxScale: 1,
minScale: DIAGRAM_READABLE_MIN_SCALE,
});
- });
-
- test("keeps architecture viewports at reading size instead of shrinking the whole graph", () => {
expect(getDiagramLayoutViewport("architecture")).toEqual({
anchor: "leftmost",
maxScale: 1,
diff --git a/packages/shared/src/diagram-flowchart-style.test.mjs b/packages/shared/src/diagram-flowchart-style.test.mjs
index 7e124d0a..79aa4e68 100644
--- a/packages/shared/src/diagram-flowchart-style.test.mjs
+++ b/packages/shared/src/diagram-flowchart-style.test.mjs
@@ -2,7 +2,6 @@ import { describe, expect, test } from "bun:test";
import { flowchartNodePresentation } from "./diagram-node-presentation.ts";
import {
DIAGRAM_READABLE_MIN_SCALE,
- FLOWCHART_READABLE_MIN_SCALE,
FLOWCHART_SELECTABLE_THEMES,
FLOWCHART_SURFACES,
FLOWCHART_THEME_GROUPS,
@@ -115,13 +114,17 @@ describe("flowchart edge geometry", () => {
describe("flowchart readable viewport", () => {
const viewport = { width: 960, height: 720 };
- test("keeps compact flows inside the canvas", () => {
+ test("keeps compact flows inside the canvas at full size", () => {
expect(flowchartFitsReadableViewport({ width: 180, height: 280 }, viewport)).toBe(true);
+ expect(flowchartFitsReadableViewport({ width: 176, height: 240 }, viewport)).toBe(true);
+ expect(flowchartFitsReadableViewport({ width: 460, height: 220 }, viewport)).toBe(true);
+ expect(flowchartFitsReadableViewport({ width: 738, height: 330 }, viewport)).toBe(true);
});
- test("refuses to shrink a tall flow below reading size", () => {
+ test("refuses to shrink a tall map into a postage stamp", () => {
expect(flowchartFitsReadableViewport({ width: 220, height: 1680 }, viewport)).toBe(false);
- expect(FLOWCHART_READABLE_MIN_SCALE).toBe(DIAGRAM_READABLE_MIN_SCALE);
expect(DIAGRAM_READABLE_MIN_SCALE).toBe(0.85);
});
});
+
+
diff --git a/packages/shared/src/diagram-flowchart-style.ts b/packages/shared/src/diagram-flowchart-style.ts
index 524bd5f4..295eea0a 100644
--- a/packages/shared/src/diagram-flowchart-style.ts
+++ b/packages/shared/src/diagram-flowchart-style.ts
@@ -41,16 +41,15 @@ export const flowchartEdgeIsStraight = (source: FlowchartBox, target: FlowchartB
export const FLOWCHART_LAYOUT_SPACING = { rank: 56, node: 36 };
-// Auto layout and opening stay at reading size. Shrinking the whole graph into
-// the viewport makes large notes unreadable; show the start and let the canvas scroll.
+// Auto-fit may shrink the whole graph down to this scale. Below it, keep 100%
+// and start from the origin — never compress a large note into a postage stamp.
export const DIAGRAM_READABLE_MIN_SCALE = 0.85;
-export const FLOWCHART_READABLE_MIN_SCALE = DIAGRAM_READABLE_MIN_SCALE;
export const flowchartFitsReadableViewport = (
bounds: { width: number; height: number },
viewport: { width: number; height: number },
padding = 32,
- minScale = FLOWCHART_READABLE_MIN_SCALE,
+ minScale = DIAGRAM_READABLE_MIN_SCALE,
maxScale = 1,
) => {
const availableWidth = Math.max(viewport.width - padding * 2, 1);
diff --git a/packages/shared/src/diagram-layout.ts b/packages/shared/src/diagram-layout.ts
index efab1732..3b1d0947 100644
--- a/packages/shared/src/diagram-layout.ts
+++ b/packages/shared/src/diagram-layout.ts
@@ -5,7 +5,6 @@ export {
DIAGRAM_READABLE_MIN_SCALE,
FLOWCHART_EDGE_ROUTER,
FLOWCHART_LAYOUT_SPACING,
- FLOWCHART_READABLE_MIN_SCALE,
flowchartEdgeIsStraight,
flowchartEdgePorts,
flowchartFitsReadableViewport,
diff --git a/packages/shared/src/i18n/en-US.ts b/packages/shared/src/i18n/en-US.ts
index d26704d3..5cb865fa 100644
--- a/packages/shared/src/i18n/en-US.ts
+++ b/packages/shared/src/i18n/en-US.ts
@@ -355,7 +355,6 @@ export const enUS = {
zoomIn: "Zoom in",
zoomOut: "Zoom out",
zoomPercent: "Zoom percent",
- zoomPercentHint: "Type 30%–250%, press Enter",
listCounts: "{{nodes}} nodes · {{edges}} links",
resetZoom: "Reset to 100% and center",
readFlow: "Read from start",
diff --git a/packages/shared/src/i18n/zh-CN.ts b/packages/shared/src/i18n/zh-CN.ts
index 11be2523..07c28404 100644
--- a/packages/shared/src/i18n/zh-CN.ts
+++ b/packages/shared/src/i18n/zh-CN.ts
@@ -355,7 +355,6 @@ export const zhCN = {
zoomIn: "放大",
zoomOut: "缩小",
zoomPercent: "缩放百分比",
- zoomPercentHint: "输入 30%–250%,回车确认",
listCounts: "{{nodes}} 节点 · {{edges}} 连线",
resetZoom: "恢复 100% 并居中",
readFlow: "从起点阅读",