UI④:元素盘点击落子真能落 —— 原型里这条路是坏的
事件流实测:click → drag.init → create.start → create.move → **create.rejected**。 create.move 要有 hover 目标才算 canExecute,而 click 到达时鼠标早已抬起, 拖拽在同一个调用栈里就被拒 —— 工具提示写着「点击后点画布落子」,一颗子也落不下。 点击这条路改为直接 modeling.createShape 到空位(撞车往下让、一列满换列); 拖拽那条路不动。实测:落子 32→33、追加自动连线 33→34、撤销回退干净。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -441,36 +441,92 @@ export const PALETTE_SPECS: Array<{ key: string; label: string; className: strin
|
||||
];
|
||||
|
||||
class FlowPalette {
|
||||
static $inject = ["palette", "create", "elementFactory", "elementRegistry", "flowEditorConfig"];
|
||||
static $inject = ["palette", "create", "elementFactory", "elementRegistry", "flowEditorConfig", "modeling", "canvas"];
|
||||
|
||||
private _create: Any;
|
||||
private _elementFactory: Any;
|
||||
private _elementRegistry: Any;
|
||||
private _config: Any;
|
||||
private _modeling: Any;
|
||||
private _canvas: Any;
|
||||
|
||||
constructor(palette: Any, create: Any, elementFactory: Any, elementRegistry: Any, flowEditorConfig: Any) {
|
||||
constructor(
|
||||
palette: Any,
|
||||
create: Any,
|
||||
elementFactory: Any,
|
||||
elementRegistry: Any,
|
||||
flowEditorConfig: Any,
|
||||
modeling: Any,
|
||||
canvas: Any,
|
||||
) {
|
||||
this._create = create;
|
||||
this._elementFactory = elementFactory;
|
||||
this._elementRegistry = elementRegistry;
|
||||
this._config = flowEditorConfig;
|
||||
this._modeling = modeling;
|
||||
this._canvas = canvas;
|
||||
palette.registerProvider(this);
|
||||
}
|
||||
|
||||
/** 造一枚待落的新节点(id 现取,避开已用与保留号) */
|
||||
private _mint(spec: NewNodeSpec): Any {
|
||||
const bo = specNode(spec);
|
||||
bo.id = mintNodeId(spec.kind, usedIds(this._elementRegistry), this._config.reserved);
|
||||
const size = MANUAL_SIZES[spec.kind];
|
||||
return this._elementFactory.createShape({ width: size.w, height: size.h, businessObject: bo });
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击落子的落点:视口中心起,撞车就往下让一格,直到空位。
|
||||
*
|
||||
* 为什么不复用拖拽那条路:`create.start` 靠鼠标**移动**取 hover 目标才算 `canExecute`,
|
||||
* 而 click 事件到达时鼠标早已抬起 —— 拖拽在同一个调用栈里就以 `create.rejected` 收场,
|
||||
* 一颗子也落不下(实测)。所以点击这条路直接建,不走拖拽。
|
||||
*/
|
||||
private _freeSpot(shape: Any): { x: number; y: number } {
|
||||
const viewbox = this._canvas.viewbox();
|
||||
let x = snap(viewbox.x + viewbox.width / 2);
|
||||
let y = snap(viewbox.y + Math.min(viewbox.height / 2, 200));
|
||||
const hits = (px: number, py: number) =>
|
||||
this._elementRegistry
|
||||
.getAll()
|
||||
.some(
|
||||
(el: Any) =>
|
||||
!el.waypoints &&
|
||||
el.parent &&
|
||||
!el.labelTarget &&
|
||||
Math.abs(el.x + el.width / 2 - px) < (el.width + shape.width) / 2 + 20 &&
|
||||
Math.abs(el.y + el.height / 2 - py) < (el.height + shape.height) / 2 + 20,
|
||||
);
|
||||
let guard = 0;
|
||||
while (hits(x, y) && guard < 40) {
|
||||
y = snap(y + 70);
|
||||
guard += 1;
|
||||
// 一列排满就换到右边一列重来,别无限往下掉出视野
|
||||
if (guard % 8 === 0) {
|
||||
x = snap(x + 160);
|
||||
y = snap(viewbox.y + Math.min(viewbox.height / 2, 200));
|
||||
}
|
||||
}
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
getPaletteEntries(): Record<string, Any> {
|
||||
const entries: Record<string, Any> = {};
|
||||
for (const item of PALETTE_SPECS) {
|
||||
const action = (event: Any) => {
|
||||
const bo = specNode(item.spec);
|
||||
bo.id = mintNodeId(item.spec.kind, usedIds(this._elementRegistry), this._config.reserved);
|
||||
const size = MANUAL_SIZES[item.spec.kind];
|
||||
const shape = this._elementFactory.createShape({ width: size.w, height: size.h, businessObject: bo });
|
||||
this._create.start(event, shape);
|
||||
};
|
||||
entries[item.key] = {
|
||||
group: "flow",
|
||||
className: item.className,
|
||||
title: `${item.label} — 拖到画布或点击后点画布落子`,
|
||||
action: { dragstart: action, click: action },
|
||||
title: `${item.label} — 拖到画布,或直接点击(落在空位上,再拖到想要的地方)`,
|
||||
action: {
|
||||
// 拖:鼠标一路带着走,落点由手定
|
||||
dragstart: (event: Any) => this._create.start(event, this._mint(item.spec)),
|
||||
// 点:当场落在空位上 —— 见 `_freeSpot` 注释,点击走不通拖拽那条路
|
||||
click: () => {
|
||||
const shape = this._mint(item.spec);
|
||||
this._modeling.createShape(shape, this._freeSpot(shape), this._canvas.getRootElement());
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
return entries;
|
||||
|
||||
Reference in New Issue
Block a user