fix: 背景默认锁定;补 ShapeMenu 的 close 绑定
背景铺满整个画板,不锁的话画布上就没有「空白处」了:想框选、想点空白取消选中, 实际都会抓住背景整个拖走(实测一次误拖就把底图挪出画板)。但也不能做成永久 不可选——用户对背景的核心需求正是「调整/缩放/裁剪一下」。锁定是可见且可撤销的: 图层面板那一行的锁图标点一下就解开,解开后拖拽缩放和普通图层完全一样。 走 layerLocked 而不是直接写 selectable:false,因为锁定态由 applyLocked 统一管, 自己写 selectable 会被 object:added 触发的 registerLayer 翻回去。 TopBar 没把 Dropdown 的 close 传给 ShapeMenu,选完形状下拉不收。 顺带删掉 useEditor.addRect:形状改成拖拽创建之后没有调用方了。
This commit is contained in:
@@ -168,8 +168,8 @@ async function scrollToExport() {
|
|||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #panel>
|
<template #panel="{ close }">
|
||||||
<ShapeMenu />
|
<ShapeMenu :close="close" />
|
||||||
</template>
|
</template>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,20 @@ import { capImageSize } from "./imageLimits";
|
|||||||
* 关键实现约束(都是踩出来的,别再踩):
|
* 关键实现约束(都是踩出来的,别再踩):
|
||||||
* - `current()` 每次现找,不要缓存引用——`loadFromJSON` 之后画布上是新对象,
|
* - `current()` 每次现找,不要缓存引用——`loadFromJSON` 之后画布上是新对象,
|
||||||
* 缓存的引用会指向一个已经不在画布上的旧对象。
|
* 缓存的引用会指向一个已经不在画布上的旧对象。
|
||||||
* - **背景和普通图层一样可以点选、拖动、缩放。** 一开始做成了不可点选(防止点空白
|
* - **背景默认锁定(`layerLocked = true`)。**
|
||||||
* 处误选),但用户对背景的核心需求就是「调整 / 缩放 / 裁剪一下」,不可点选就没法
|
*
|
||||||
* 在画布上取景。要取消选中点画板外面的灰底就行——画布是无限工作区,画板外一大片
|
* 它铺满整个画板,不锁的话画布上就没有「空白处」了:想框选、想点空白取消选中,
|
||||||
* 都是空的。(顺带省掉一个坑:`selectable:false` 会被图层面板的解锁按钮
|
* 实际都会抓住背景把它整个拖走(2026-09-05 实测,一次误拖就把底图挪出画板)。
|
||||||
* `applyLocked(obj,false)` 翻回 true,得靠「最后再设」这种顺序技巧才压得住。)
|
*
|
||||||
|
* 但也不能做成永久不可选——用户对背景的核心需求正是「调整 / 缩放 / 裁剪一下」。
|
||||||
|
* 锁定是**可见且可撤销**的:图层面板那一行的锁图标点一下就能解开,解开后拖拽
|
||||||
|
* 缩放和普通图层完全一样。
|
||||||
|
*
|
||||||
|
* 走 `layerLocked` 而不是直接写 `selectable: false`,是因为锁定态由
|
||||||
|
* `applyLocked()` 统一管(selectable / evented / lockMovement… 一整套),
|
||||||
|
* 而 `registerLayer()` 每次都会照 `layerLocked` 重设一遍。自己写 `selectable`
|
||||||
|
* 会被 `object:added` 触发的那次 `registerLayer` 翻回去,只能靠「最后再设」
|
||||||
|
* 这类顺序技巧压住,脆。
|
||||||
* - 铺满用 `width * scaleX` 而不是 `getScaledWidth()`:后者会把默认 strokeWidth
|
* - 铺满用 `width * scaleX` 而不是 `getScaledWidth()`:后者会把默认 strokeWidth
|
||||||
* 也算进去(见 common 的 Fabric 陷阱 3)。
|
* 也算进去(见 common 的 Fabric 陷阱 3)。
|
||||||
*/
|
*/
|
||||||
@@ -107,6 +116,8 @@ export function useBackground() {
|
|||||||
const capped = capImageSize(img.getElement() as HTMLImageElement);
|
const capped = capImageSize(img.getElement() as HTMLImageElement);
|
||||||
if (capped !== img.getElement()) img.setElement(capped);
|
if (capped !== img.getElement()) img.setElement(capped);
|
||||||
img.isBackground = true;
|
img.isBackground = true;
|
||||||
|
// 默认锁定,理由见文件头。registerLayer 会照这个标志跑一遍 applyLocked。
|
||||||
|
img.layerLocked = true;
|
||||||
fitToCanvas(img);
|
fitToCanvas(img);
|
||||||
registerLayer(img);
|
registerLayer(img);
|
||||||
c.add(img);
|
c.add(img);
|
||||||
@@ -132,6 +143,7 @@ export function useBackground() {
|
|||||||
fill: color,
|
fill: color,
|
||||||
});
|
});
|
||||||
rect.isBackground = true;
|
rect.isBackground = true;
|
||||||
|
rect.layerLocked = true;
|
||||||
registerLayer(rect);
|
registerLayer(rect);
|
||||||
c.add(rect);
|
c.add(rect);
|
||||||
c.sendObjectToBack(rect);
|
c.sendObjectToBack(rect);
|
||||||
|
|||||||
@@ -328,31 +328,6 @@ function addText(text = "标题"): Textbox {
|
|||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 加一个矩形。圆角走 rx/ry,右栏的「圆角」改的就是它。 */
|
|
||||||
function addRect(at?: { x: number; y: number }): Rect {
|
|
||||||
const c = canvas.value;
|
|
||||||
if (!c) throw new Error("画布还没挂载");
|
|
||||||
const w = Math.round(size.value.width * 0.3);
|
|
||||||
const h = Math.round(size.value.height * 0.25);
|
|
||||||
const rect = new Rect({
|
|
||||||
left: at?.x ?? size.value.width / 2,
|
|
||||||
top: at?.y ?? size.value.height / 2,
|
|
||||||
originX: "center",
|
|
||||||
originY: "center",
|
|
||||||
width: w,
|
|
||||||
height: h,
|
|
||||||
fill: "#6ea8fe",
|
|
||||||
rx: 0,
|
|
||||||
ry: 0,
|
|
||||||
});
|
|
||||||
registerLayer(rect);
|
|
||||||
c.add(rect);
|
|
||||||
c.setActiveObject(rect);
|
|
||||||
c.requestRenderAll();
|
|
||||||
bumpRevision();
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCanvas(): Canvas {
|
function getCanvas(): Canvas {
|
||||||
const c = canvas.value;
|
const c = canvas.value;
|
||||||
if (!c) throw new Error("画布还没挂载");
|
if (!c) throw new Error("画布还没挂载");
|
||||||
@@ -380,7 +355,6 @@ export function useEditor() {
|
|||||||
setSize,
|
setSize,
|
||||||
addImage,
|
addImage,
|
||||||
addText,
|
addText,
|
||||||
addRect,
|
|
||||||
getCanvas,
|
getCanvas,
|
||||||
selectedObjects,
|
selectedObjects,
|
||||||
bumpRevision,
|
bumpRevision,
|
||||||
|
|||||||
Reference in New Issue
Block a user