mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
refactor: moving connector label to connector view (#11738)
### Changed Moved connector label moving logic from `default-tool` to connector view. #### Other infrastructure changes: - Gfx element view now can handles drag events - Added `context.preventDefault()` support to bypass built-in interactions in extension - Handle the pointer events in element view will bypass the built-in interactions automatically > The built-in interactions include element dragging, click selection, drag-to-scale operations, etc.
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
import type { ConnectorElementModel } from '@blocksuite/affine-model';
|
||||
import {
|
||||
type ConnectorElementModel,
|
||||
LocalShapeElementModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { Bound, serializeXYWH, Vec } from '@blocksuite/global/gfx';
|
||||
import type { PointerEventState } from '@blocksuite/std';
|
||||
import {
|
||||
type DragEndContext,
|
||||
type DragMoveContext,
|
||||
type DragStartContext,
|
||||
generateKeyBetween,
|
||||
GfxElementModelView,
|
||||
} from '@blocksuite/std/gfx';
|
||||
|
||||
@@ -30,11 +36,17 @@ export class ConnectorElementView extends GfxElementModelView<ConnectorElementMo
|
||||
override onCreated(): void {
|
||||
super.onCreated();
|
||||
|
||||
this._initDblClickToEdit();
|
||||
this._initLabelMoving();
|
||||
}
|
||||
|
||||
private _initDblClickToEdit(): void {
|
||||
this.on('dblclick', evt => {
|
||||
private _initLabelMoving(): void {
|
||||
let curLabelElement: LocalShapeElementModel | null = null;
|
||||
|
||||
if (this.model.isLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enterLabelEditor = (evt: PointerEventState) => {
|
||||
const edgeless = this.std.view.getBlock(this.std.store.root!.id);
|
||||
|
||||
if (edgeless && !this.model.isLocked()) {
|
||||
@@ -44,6 +56,121 @@ export class ConnectorElementView extends GfxElementModelView<ConnectorElementMo
|
||||
this.gfx.viewport.toModelCoord(evt.x, evt.y)
|
||||
);
|
||||
}
|
||||
};
|
||||
const getCurrentPosition = (evt: PointerEventState) => {
|
||||
const [x, y] = this.gfx.viewport.toModelCoord(evt.x, evt.y);
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
clientX: evt.raw.clientX,
|
||||
clientY: evt.raw.clientY,
|
||||
};
|
||||
};
|
||||
const watchEvent = (labelModel: LocalShapeElementModel) => {
|
||||
const view = this.gfx.view.get(labelModel) as GfxElementModelView;
|
||||
const connectorModel = this.model;
|
||||
|
||||
let labelBound: Bound | null = null;
|
||||
let startPoint = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
clientX: 0,
|
||||
clientY: 0,
|
||||
};
|
||||
let lastPoint = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
clientX: 0,
|
||||
clientY: 0,
|
||||
};
|
||||
|
||||
view.on('dblclick', evt => {
|
||||
enterLabelEditor(evt);
|
||||
});
|
||||
view.on('dragstart', evt => {
|
||||
startPoint = getCurrentPosition(evt);
|
||||
labelBound = Bound.deserialize(labelModel.xywh);
|
||||
|
||||
connectorModel.stash('labelXYWH');
|
||||
connectorModel.stash('labelOffset');
|
||||
});
|
||||
|
||||
view.on('dragmove', evt => {
|
||||
if (!labelBound) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastPoint = getCurrentPosition(evt);
|
||||
const newBound = labelBound.clone();
|
||||
const delta = [lastPoint.x - startPoint.x, lastPoint.y - startPoint.y];
|
||||
const center = connectorModel.getNearestPoint(
|
||||
Vec.add(newBound.center, delta)
|
||||
);
|
||||
const distance = connectorModel.getOffsetDistanceByPoint(center);
|
||||
newBound.center = center;
|
||||
|
||||
connectorModel.labelXYWH = newBound.toXYWH();
|
||||
connectorModel.labelOffset = {
|
||||
distance,
|
||||
};
|
||||
});
|
||||
|
||||
view.on('dragend', () => {
|
||||
if (labelBound) {
|
||||
labelBound = null;
|
||||
connectorModel.pop('labelXYWH');
|
||||
connectorModel.pop('labelOffset');
|
||||
}
|
||||
});
|
||||
};
|
||||
const updateLabelElement = () => {
|
||||
if (!this.model.labelXYWH || !this.model.text) {
|
||||
// Clean up existing label element if conditions are no longer met
|
||||
if (curLabelElement) {
|
||||
this.surface.deleteLocalElement(curLabelElement);
|
||||
curLabelElement = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const labelElement =
|
||||
curLabelElement || new LocalShapeElementModel(this.surface);
|
||||
labelElement.xywh = serializeXYWH(...this.model.labelXYWH);
|
||||
labelElement.index = generateKeyBetween(this.model.index, null);
|
||||
|
||||
if (!curLabelElement) {
|
||||
curLabelElement = labelElement;
|
||||
|
||||
labelElement.fillColor = 'transparent';
|
||||
labelElement.strokeColor = 'transparent';
|
||||
labelElement.strokeWidth = 0;
|
||||
|
||||
this.surface.addLocalElement(labelElement);
|
||||
this.disposable.add(() => {
|
||||
this.surface.deleteLocalElement(labelElement);
|
||||
});
|
||||
watchEvent(labelElement);
|
||||
}
|
||||
};
|
||||
|
||||
this.disposable.add(
|
||||
this.model.propsUpdated.subscribe(payload => {
|
||||
if (
|
||||
payload.key === 'labelXYWH' ||
|
||||
payload.key === 'text' ||
|
||||
payload.key === 'index'
|
||||
) {
|
||||
updateLabelElement();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
updateLabelElement();
|
||||
|
||||
this.on('dblclick', evt => {
|
||||
if (!curLabelElement) {
|
||||
enterLabelEditor(evt);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ShapeElementModel } from '@blocksuite/affine-model';
|
||||
import { ShapeElementModel } from '@blocksuite/affine-model';
|
||||
import { GfxElementModelView } from '@blocksuite/std/gfx';
|
||||
|
||||
import { mountShapeTextEditor } from './text/edgeless-shape-text-editor';
|
||||
@@ -16,7 +16,11 @@ export class ShapeElementView extends GfxElementModelView<ShapeElementModel> {
|
||||
this.on('dblclick', () => {
|
||||
const edgeless = this.std.view.getBlock(this.std.store.root!.id);
|
||||
|
||||
if (edgeless && !this.model.isLocked()) {
|
||||
if (
|
||||
edgeless &&
|
||||
!this.model.isLocked() &&
|
||||
this.model instanceof ShapeElementModel
|
||||
) {
|
||||
mountShapeTextEditor(this.model, edgeless);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user