@canvas-harness/react 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +20 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +21 -11
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -131,6 +131,24 @@ type CanvasProps = {
|
|
|
131
131
|
* <Canvas selectionColor="#10b981" />
|
|
132
132
|
*/
|
|
133
133
|
selectionColor?: string;
|
|
134
|
+
/**
|
|
135
|
+
* Cap on the canvas backing-store DPR. Defaults to `1`.
|
|
136
|
+
*
|
|
137
|
+
* At native device-pixel ratio on hi-DPI displays (Mac Retina ≈ 2,
|
|
138
|
+
* Windows 4K @ 175% ≈ 1.75), the canvas backing buffer can hit
|
|
139
|
+
* 20-30 megapixels per frame — the per-frame GPU-upload cost alone
|
|
140
|
+
* eats a sizable slice of the frame budget. Capping DPR at 1 keeps
|
|
141
|
+
* perf consistent across hardware at the cost of slightly softer
|
|
142
|
+
* shape outlines on hi-DPI displays. Text remains crisp regardless
|
|
143
|
+
* (the text bitmap cache handles its own DPR).
|
|
144
|
+
*
|
|
145
|
+
* Bump to `2` (or `window.devicePixelRatio`) when crispness matters
|
|
146
|
+
* more than FPS — e.g. presentation slides, print-export views.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* <Canvas maxDpr={2} /> // pixel-crisp at the cost of FPS on hi-DPI
|
|
150
|
+
*/
|
|
151
|
+
maxDpr?: number;
|
|
134
152
|
/**
|
|
135
153
|
* Render a custom node's React subtree. Called once per
|
|
136
154
|
* library-mounted custom-node id; positioning is handled by the
|
package/dist/index.d.ts
CHANGED
|
@@ -131,6 +131,24 @@ type CanvasProps = {
|
|
|
131
131
|
* <Canvas selectionColor="#10b981" />
|
|
132
132
|
*/
|
|
133
133
|
selectionColor?: string;
|
|
134
|
+
/**
|
|
135
|
+
* Cap on the canvas backing-store DPR. Defaults to `1`.
|
|
136
|
+
*
|
|
137
|
+
* At native device-pixel ratio on hi-DPI displays (Mac Retina ≈ 2,
|
|
138
|
+
* Windows 4K @ 175% ≈ 1.75), the canvas backing buffer can hit
|
|
139
|
+
* 20-30 megapixels per frame — the per-frame GPU-upload cost alone
|
|
140
|
+
* eats a sizable slice of the frame budget. Capping DPR at 1 keeps
|
|
141
|
+
* perf consistent across hardware at the cost of slightly softer
|
|
142
|
+
* shape outlines on hi-DPI displays. Text remains crisp regardless
|
|
143
|
+
* (the text bitmap cache handles its own DPR).
|
|
144
|
+
*
|
|
145
|
+
* Bump to `2` (or `window.devicePixelRatio`) when crispness matters
|
|
146
|
+
* more than FPS — e.g. presentation slides, print-export views.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* <Canvas maxDpr={2} /> // pixel-crisp at the cost of FPS on hi-DPI
|
|
150
|
+
*/
|
|
151
|
+
maxDpr?: number;
|
|
134
152
|
/**
|
|
135
153
|
* Render a custom node's React subtree. Called once per
|
|
136
154
|
* library-mounted custom-node id; positioning is handled by the
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRenderer, DEFAULT_MINIMAP_MAX_NODES, renderMinimapContent, sceneBounds, drawMinimapViewport, worldViewportFromCamera, screenToWorld, hitTestAny, copy, cut, paste, createPalmRejectionState, createDefaultTextareaEditor, minimapScreenToWorld, notePenActive, shouldRejectTouch, notePenInactive, asEdgeId, midpointToCubicControls, projectToNodeBoundary, marqueeNodes, shouldAutoFit, computeAutoFitHeight, hitTestPoint, worldToNodeLocal, edgeLabelBoundsWorld, asNodeId, zoomAtScreenPoint, clampZoom, panByScreen } from '@canvas-harness/core';
|
|
2
|
-
import { createContext, useContext, useSyncExternalStore, useRef,
|
|
2
|
+
import { createContext, useContext, useSyncExternalStore, useRef, useEffect, useState } from 'react';
|
|
3
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
5
|
// src/Canvas.tsx
|
|
@@ -1045,6 +1045,7 @@ function CanvasSurface({
|
|
|
1045
1045
|
arrowDefaults,
|
|
1046
1046
|
background,
|
|
1047
1047
|
selectionColor,
|
|
1048
|
+
maxDpr,
|
|
1048
1049
|
renderCustomNodeView,
|
|
1049
1050
|
children
|
|
1050
1051
|
}) {
|
|
@@ -1062,8 +1063,15 @@ function CanvasSurface({
|
|
|
1062
1063
|
const interactionMode = useInteractionMode();
|
|
1063
1064
|
useArrowTool(wrapRef, store, tool === "arrow", arrowDefaults);
|
|
1064
1065
|
const { mountedIds, setMountedIds } = useOverlayHost();
|
|
1065
|
-
|
|
1066
|
-
|
|
1066
|
+
useEffect(() => {
|
|
1067
|
+
const el = overlayRef.current;
|
|
1068
|
+
if (!el) return;
|
|
1069
|
+
const apply = (c) => {
|
|
1070
|
+
el.style.transform = `translate(${-c.x * c.z}px, ${-c.y * c.z}px) scale(${c.z})`;
|
|
1071
|
+
};
|
|
1072
|
+
apply(store.getCamera());
|
|
1073
|
+
return store.subscribe("camera", apply);
|
|
1074
|
+
}, [store]);
|
|
1067
1075
|
useEffect(() => {
|
|
1068
1076
|
if (!staticRef.current || !interactiveRef.current || w === 0 || h === 0) return;
|
|
1069
1077
|
if (rendererRef.current) {
|
|
@@ -1079,6 +1087,7 @@ function CanvasSurface({
|
|
|
1079
1087
|
height: h,
|
|
1080
1088
|
background,
|
|
1081
1089
|
selectionColor,
|
|
1090
|
+
maxDpr,
|
|
1082
1091
|
onOverlayChange: (ids) => setMountedIds(ids)
|
|
1083
1092
|
});
|
|
1084
1093
|
r.start();
|
|
@@ -1088,7 +1097,7 @@ function CanvasSurface({
|
|
|
1088
1097
|
r.dispose();
|
|
1089
1098
|
rendererRef.current = null;
|
|
1090
1099
|
};
|
|
1091
|
-
}, [store, theme, w, h, onRenderer, setMountedIds]);
|
|
1100
|
+
}, [store, theme, w, h, maxDpr, onRenderer, setMountedIds]);
|
|
1092
1101
|
useEffect(() => {
|
|
1093
1102
|
rendererRef.current?.setBackground(background);
|
|
1094
1103
|
}, [background]);
|
|
@@ -1110,9 +1119,9 @@ function CanvasSurface({
|
|
|
1110
1119
|
if (toolRef.current === "select") {
|
|
1111
1120
|
const rect = el.getBoundingClientRect();
|
|
1112
1121
|
const screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
1113
|
-
const
|
|
1114
|
-
const world = screenToWorld(screen,
|
|
1115
|
-
const hit = hitTestAny(store, world,
|
|
1122
|
+
const camera = store.getCamera();
|
|
1123
|
+
const world = screenToWorld(screen, camera);
|
|
1124
|
+
const hit = hitTestAny(store, world, camera.z);
|
|
1116
1125
|
if (hit && hit.kind === "body" && "nodeId" in hit) {
|
|
1117
1126
|
store.beginEdit(hit.nodeId);
|
|
1118
1127
|
} else if (hit && hit.kind === "body" && "edgeId" in hit) {
|
|
@@ -1150,9 +1159,9 @@ function CanvasSurface({
|
|
|
1150
1159
|
if (e.button !== 0) return;
|
|
1151
1160
|
if (!isShapeTool(toolRef.current)) return;
|
|
1152
1161
|
if (store.getInteractionState().mode === "editing") return;
|
|
1153
|
-
const
|
|
1154
|
-
const world = screenToWorld(screenFromEvent(e),
|
|
1155
|
-
if (hitTestAny(store, world,
|
|
1162
|
+
const camera = store.getCamera();
|
|
1163
|
+
const world = screenToWorld(screenFromEvent(e), camera);
|
|
1164
|
+
if (hitTestAny(store, world, camera.z)) return;
|
|
1156
1165
|
startWorld = world;
|
|
1157
1166
|
startScreen = screenFromEvent(e);
|
|
1158
1167
|
activePointerId = e.pointerId;
|
|
@@ -1259,7 +1268,8 @@ function CanvasSurface({
|
|
|
1259
1268
|
window.addEventListener("keydown", onKey);
|
|
1260
1269
|
return () => window.removeEventListener("keydown", onKey);
|
|
1261
1270
|
}, [store]);
|
|
1262
|
-
const
|
|
1271
|
+
const initialCamera = store.getCamera();
|
|
1272
|
+
const overlayTransform = `translate(${-initialCamera.x * initialCamera.z}px, ${-initialCamera.y * initialCamera.z}px) scale(${initialCamera.z})`;
|
|
1263
1273
|
return /* @__PURE__ */ jsxs(
|
|
1264
1274
|
"div",
|
|
1265
1275
|
{
|