docs(canvas): explain pointer editing and capture cleanup
This commit is contained in:
@@ -76,6 +76,7 @@ export function TransformableNode(props: NodeProps<CanvasNode> & { children: Rea
|
||||
const lease = editing.beginTransform?.(id); if (lease === false) return;
|
||||
if (!editing.beginTransform) editing.begin(id);
|
||||
if (!node.selected) editing.select(id);
|
||||
// node 是 flow.getNode 返回的引用,不深克隆;“起点快照”依赖外层不可变更新约定,不能原地修改该节点。
|
||||
gesture.current = { lease: lease && typeof lease === 'object' ? lease : undefined, node, direction, capture: event.currentTarget, pointerId: event.pointerId, start: flow.screenToFlowPosition({ x: event.clientX, y: event.clientY }) };
|
||||
if(!acquirePointerCapture(event.currentTarget,event.pointerId)){cancelGesture();return;}
|
||||
event.preventDefault();event.stopPropagation();
|
||||
@@ -87,6 +88,7 @@ export function TransformableNode(props: NodeProps<CanvasNode> & { children: Rea
|
||||
if (!ownsPointerCapture(gesture.current,event)) return;
|
||||
const current = flow.screenToFlowPosition({ x: event.clientX, y: event.clientY });
|
||||
const { node, start, direction } = gesture.current!;
|
||||
// resizing 模式显式传 Shift 布尔值,未按 Shift 即解锁比例;普通角落传 undefined 沿用图片/图标默认比例规则。
|
||||
const change = direction === "rotate"
|
||||
? { rotation: rotationFromPointer(node, start, current, event.shiftKey) }
|
||||
: resizeFromPointer(node, direction, { x: current.x - start.x, y: current.y - start.y }, resizing ? event.shiftKey : undefined);
|
||||
@@ -100,6 +102,7 @@ export function TransformableNode(props: NodeProps<CanvasNode> & { children: Rea
|
||||
if(event&&!ownsPointerCapture(gesture.current,event))return;
|
||||
const current = gesture.current; if (!current) return;
|
||||
gesture.current = null;
|
||||
// cancel/commit 调用与释放间没有 finally;Provider/lease 抛错时可能跳过 release,需要遵守动作异常契约。
|
||||
if (current.lease) current.lease.cancel(); else if (editing.cancelTransform) editing.cancelTransform(); else editing.transform(current.node.id, current.direction === "rotate" ? { rotation: current.node.data.rotation || 0 } : { position: current.node.position, width: current.node.width, height: current.node.height });
|
||||
releasePointerCapture(current.capture,current.pointerId);
|
||||
}
|
||||
@@ -107,9 +110,11 @@ export function TransformableNode(props: NodeProps<CanvasNode> & { children: Rea
|
||||
function finish(event: PointerEvent<HTMLElement>) {
|
||||
if(!gesture.current)return;event.stopPropagation();
|
||||
if (!ownsPointerCapture(gesture.current,event)) return; const current = gesture.current!; move(event); gesture.current = null;
|
||||
// 当前手势引用已清空;若 commit 抛错,不会自动恢复引用或执行后面的 capture 释放。
|
||||
if (current.lease) current.lease.commit(); else editing.finishTransform?.();
|
||||
releasePointerCapture(current.capture,current.pointerId);
|
||||
}
|
||||
// 模式关闭/取消选中本身不调用 cancelGesture;实际手势结束还依赖 pointerup/cancel、失焦或卸载。
|
||||
// 容器的CSS zoom使用viewScale,宽高同时除以viewScale,保持投影尺寸与内部显示坐标对应。
|
||||
// schema=2给纯文本/纯图片补四向连接点,非分区显示成员徽标;普通尺寸调整用右下角,模式内显示八向手柄。
|
||||
// 八向手柄的尺寸与边框反向抵消zoom和viewScale,使屏幕上大小稳定;方向决定位置及cursor。
|
||||
@@ -139,6 +144,7 @@ export function TransformableNode(props: NodeProps<CanvasNode> & { children: Rea
|
||||
const delta = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] }[event.key]; if (!delta) return;
|
||||
event.preventDefault(); event.stopPropagation(); const node = flow.getNode(id); if (!node) return;
|
||||
const lease = editing.beginTransform?.(id); if (lease === false) return; if (!editing.beginTransform) editing.begin(id); const scale = (data.viewScale || 1) * (event.ctrlKey || event.metaKey ? 10 : 1);
|
||||
// 键盘按键没有 pointer capture,也不经过 move;preview/commit 同步连用,失败清理由租约实现承担。
|
||||
const change = resizeFromPointer(node, direction, { x: delta[0] * scale, y: delta[1] * scale }, event.shiftKey);
|
||||
if (lease && typeof lease === 'object') { lease.preview(change); lease.commit(); } else { editing.transform(id, change); editing.finishTransform?.(); }
|
||||
}} />;
|
||||
|
||||
Reference in New Issue
Block a user