refactor: redesign element transform manager interface (#11679)
### Change - Rename `ElementTransformManager` -> `InteractivityManager` - Now you can `event.on` and `action.onXXX` method to extend interactivity behaviour. The old approach of overriding methods directly is deprecated.
This commit is contained in:
@@ -5,12 +5,9 @@ import {
|
||||
} from '@blocksuite/affine-model';
|
||||
import {
|
||||
type DragExtensionInitializeContext,
|
||||
type ExtensionDragEndContext,
|
||||
type ExtensionDragMoveContext,
|
||||
type ExtensionDragStartContext,
|
||||
getTopElements,
|
||||
GfxExtensionIdentifier,
|
||||
TransformExtension,
|
||||
InteractivityExtension,
|
||||
} from '@blocksuite/std/gfx';
|
||||
|
||||
import {
|
||||
@@ -19,7 +16,7 @@ import {
|
||||
isFrameBlock,
|
||||
} from './frame-manager';
|
||||
|
||||
export class FrameHighlightManager extends TransformExtension {
|
||||
export class FrameHighlightManager extends InteractivityExtension {
|
||||
static override key = 'frame-highlight-manager';
|
||||
|
||||
get frameMgr() {
|
||||
@@ -32,57 +29,54 @@ export class FrameHighlightManager extends TransformExtension {
|
||||
return this.std.getOptional(OverlayIdentifier('frame')) as FrameOverlay;
|
||||
}
|
||||
|
||||
override onDragInitialize(_: DragExtensionInitializeContext): {
|
||||
onDragStart?: (context: ExtensionDragStartContext) => void;
|
||||
onDragMove?: (context: ExtensionDragMoveContext) => void;
|
||||
onDragEnd?: (context: ExtensionDragEndContext) => void;
|
||||
clear?: () => void;
|
||||
} {
|
||||
if (!this.frameMgr || !this.frameHighlightOverlay) {
|
||||
return {};
|
||||
}
|
||||
override mounted() {
|
||||
this.action.onDragInitialize((_: DragExtensionInitializeContext) => {
|
||||
if (!this.frameMgr || !this.frameHighlightOverlay) {
|
||||
return {};
|
||||
}
|
||||
|
||||
let hoveredFrame: FrameBlockModel | null = null;
|
||||
const { frameMgr, frameHighlightOverlay } = this;
|
||||
let draggedFrames: FrameBlockModel[] = [];
|
||||
let hoveredFrame: FrameBlockModel | null = null;
|
||||
const { frameMgr, frameHighlightOverlay } = this;
|
||||
let draggedFrames: FrameBlockModel[] = [];
|
||||
|
||||
return {
|
||||
onDragStart(context) {
|
||||
draggedFrames = context.elements
|
||||
.map(elem => elem.model)
|
||||
.filter(model => isFrameBlock(model));
|
||||
},
|
||||
onDragMove(context) {
|
||||
const { dragLastPos } = context;
|
||||
return {
|
||||
onDragStart(context) {
|
||||
draggedFrames = context.elements
|
||||
.map(elem => elem.model)
|
||||
.filter(model => isFrameBlock(model));
|
||||
},
|
||||
onDragMove(context) {
|
||||
const { dragLastPos } = context;
|
||||
|
||||
hoveredFrame = frameMgr.getFrameFromPoint(
|
||||
[dragLastPos.x, dragLastPos.y],
|
||||
draggedFrames
|
||||
);
|
||||
hoveredFrame = frameMgr.getFrameFromPoint(
|
||||
[dragLastPos.x, dragLastPos.y],
|
||||
draggedFrames
|
||||
);
|
||||
|
||||
if (hoveredFrame && !hoveredFrame.isLocked()) {
|
||||
frameHighlightOverlay.highlight(hoveredFrame);
|
||||
} else {
|
||||
frameHighlightOverlay.clear();
|
||||
}
|
||||
},
|
||||
onDragEnd(context) {
|
||||
const topElements = getTopElements(
|
||||
context.elements.map(elem =>
|
||||
elem.model.group instanceof MindmapElementModel
|
||||
? elem.model.group
|
||||
: elem.model
|
||||
)
|
||||
);
|
||||
|
||||
if (hoveredFrame) {
|
||||
frameMgr.addElementsToFrame(hoveredFrame, topElements);
|
||||
} else {
|
||||
topElements.forEach(elem => frameMgr.removeFromParentFrame(elem));
|
||||
}
|
||||
|
||||
if (hoveredFrame && !hoveredFrame.isLocked()) {
|
||||
frameHighlightOverlay.highlight(hoveredFrame);
|
||||
} else {
|
||||
frameHighlightOverlay.clear();
|
||||
}
|
||||
},
|
||||
onDragEnd(context) {
|
||||
const topElements = getTopElements(
|
||||
context.elements.map(elem =>
|
||||
elem.model.group instanceof MindmapElementModel
|
||||
? elem.model.group
|
||||
: elem.model
|
||||
)
|
||||
);
|
||||
|
||||
if (hoveredFrame) {
|
||||
frameMgr.addElementsToFrame(hoveredFrame, topElements);
|
||||
} else {
|
||||
topElements.forEach(elem => frameMgr.removeFromParentFrame(elem));
|
||||
}
|
||||
|
||||
frameHighlightOverlay.clear();
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,16 +21,16 @@ import { NoteTool } from '@blocksuite/affine-gfx-note';
|
||||
import { ShapeTool } from '@blocksuite/affine-gfx-shape';
|
||||
import { TemplateTool } from '@blocksuite/affine-gfx-template';
|
||||
import { TextTool } from '@blocksuite/affine-gfx-text';
|
||||
import { ElementTransformManager } from '@blocksuite/std/gfx';
|
||||
import { InteractivityManager } from '@blocksuite/std/gfx';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import { EdgelessElementToolbarExtension } from './configs/toolbar';
|
||||
import { EdgelessRootBlockSpec } from './edgeless-root-spec.js';
|
||||
import { DblClickAddEdgelessText } from './element-transform/dblclick-add-edgeless-text.js';
|
||||
import { SnapExtension } from './element-transform/snap-manager.js';
|
||||
import { DefaultTool } from './gfx-tool/default-tool.js';
|
||||
import { EmptyTool } from './gfx-tool/empty-tool.js';
|
||||
import { PanTool } from './gfx-tool/pan-tool.js';
|
||||
import { DblClickAddEdgelessText } from './interact-extensions/dblclick-add-edgeless-text.js';
|
||||
import { SnapExtension } from './interact-extensions/snap-manager.js';
|
||||
import { EditPropsMiddlewareBuilder } from './middlewares/base.js';
|
||||
import { SnapOverlay } from './utils/snap-manager.js';
|
||||
|
||||
@@ -51,7 +51,7 @@ export const EdgelessToolExtension: ExtensionType[] = [
|
||||
];
|
||||
|
||||
export const EdgelessEditExtensions: ExtensionType[] = [
|
||||
ElementTransformManager,
|
||||
InteractivityManager,
|
||||
ConnectorFilter,
|
||||
SnapExtension,
|
||||
MindMapDragExtension,
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import {
|
||||
addText,
|
||||
insertEdgelessTextCommand,
|
||||
} from '@blocksuite/affine-gfx-text';
|
||||
import {
|
||||
FeatureFlagService,
|
||||
TelemetryProvider,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import type { PointerEventState } from '@blocksuite/std';
|
||||
import { TransformExtension } from '@blocksuite/std/gfx';
|
||||
|
||||
export class DblClickAddEdgelessText extends TransformExtension {
|
||||
static override key = 'dbl-click-add-edgeless-text';
|
||||
|
||||
override dblClick(e: PointerEventState): void {
|
||||
const textFlag = this.std.store
|
||||
.get(FeatureFlagService)
|
||||
.getFlag('enable_edgeless_text');
|
||||
const picked = this.gfx.getElementByPoint(
|
||||
...this.gfx.viewport.toModelCoord(e.x, e.y)
|
||||
);
|
||||
|
||||
if (picked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (textFlag) {
|
||||
const [x, y] = this.gfx.viewport.toModelCoord(e.x, e.y);
|
||||
this.std.command.exec(insertEdgelessTextCommand, { x, y });
|
||||
} else {
|
||||
const edgelessView = this.std.view.getBlock(
|
||||
this.std.store.root?.id || ''
|
||||
);
|
||||
|
||||
if (edgelessView) {
|
||||
addText(edgelessView, e);
|
||||
}
|
||||
}
|
||||
|
||||
this.std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
||||
control: 'canvas:dbclick',
|
||||
page: 'whiteboard editor',
|
||||
module: 'toolbar',
|
||||
segment: 'toolbar',
|
||||
type: 'text',
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import { OverlayIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import { MindmapElementModel } from '@blocksuite/affine-model';
|
||||
import type { Bound } from '@blocksuite/global/gfx';
|
||||
import {
|
||||
type DragExtensionInitializeContext,
|
||||
type ExtensionDragMoveContext,
|
||||
type GfxModel,
|
||||
TransformExtension,
|
||||
} from '@blocksuite/std/gfx';
|
||||
|
||||
import type { SnapOverlay } from '../utils/snap-manager';
|
||||
|
||||
export class SnapExtension extends TransformExtension {
|
||||
static override key = 'snap-manager';
|
||||
|
||||
get snapOverlay() {
|
||||
return this.std.getOptional(
|
||||
OverlayIdentifier('snap-manager')
|
||||
) as SnapOverlay;
|
||||
}
|
||||
|
||||
override onDragInitialize(initContext: DragExtensionInitializeContext) {
|
||||
const snapOverlay = this.snapOverlay;
|
||||
|
||||
if (!snapOverlay) {
|
||||
return {};
|
||||
}
|
||||
|
||||
let alignBound: Bound;
|
||||
|
||||
return {
|
||||
onDragStart() {
|
||||
alignBound = snapOverlay.setMovingElements(
|
||||
initContext.elements,
|
||||
initContext.elements.reduce((pre, elem) => {
|
||||
if (elem.group instanceof MindmapElementModel) {
|
||||
pre.push(elem.group);
|
||||
}
|
||||
|
||||
return pre;
|
||||
}, [] as GfxModel[])
|
||||
);
|
||||
},
|
||||
onDragMove(context: ExtensionDragMoveContext) {
|
||||
if (
|
||||
context.elements.length === 0 ||
|
||||
alignBound.w === 0 ||
|
||||
alignBound.h === 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentBound = alignBound.moveDelta(context.dx, context.dy);
|
||||
const alignRst = snapOverlay.align(currentBound);
|
||||
|
||||
context.dx = alignRst.dx + context.dx;
|
||||
context.dy = alignRst.dy + context.dy;
|
||||
},
|
||||
onDragEnd() {
|
||||
snapOverlay.clear();
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,9 @@ import {
|
||||
BaseTool,
|
||||
getTopElements,
|
||||
type GfxModel,
|
||||
InteractivityIdentifier,
|
||||
isGfxGroupCompatibleModel,
|
||||
type PointTestOptions,
|
||||
TransformManagerIdentifier,
|
||||
} from '@blocksuite/std/gfx';
|
||||
import { effect } from '@preact/signals-core';
|
||||
|
||||
@@ -196,8 +196,8 @@ export class DefaultTool extends BaseTool {
|
||||
return this.gfx.selection;
|
||||
}
|
||||
|
||||
get elementTransformMgr() {
|
||||
return this.std.getOptional(TransformManagerIdentifier);
|
||||
get interactivity() {
|
||||
return this.std.getOptional(InteractivityIdentifier);
|
||||
}
|
||||
|
||||
private get frameOverlay() {
|
||||
@@ -380,9 +380,9 @@ export class DefaultTool extends BaseTool {
|
||||
}
|
||||
|
||||
if (this.dragType === DefaultModeDragType.ContentMoving) {
|
||||
if (this.elementTransformMgr) {
|
||||
if (this.interactivity) {
|
||||
this.doc.captureSync();
|
||||
this.elementTransformMgr.initializeDrag({
|
||||
this.interactivity.initializeDrag({
|
||||
movingElements: this._toBeMoved,
|
||||
event: event.raw,
|
||||
onDragEnd: () => {
|
||||
@@ -397,12 +397,12 @@ export class DefaultTool extends BaseTool {
|
||||
override click(e: PointerEventState) {
|
||||
if (this.doc.readonly) return;
|
||||
|
||||
if (!this.elementTransformMgr?.dispatchOnSelected(e)) {
|
||||
if (!this.interactivity?.dispatchOnSelected(e)) {
|
||||
this.edgelessSelectionManager.clear();
|
||||
resetNativeSelection(null);
|
||||
}
|
||||
|
||||
this.elementTransformMgr?.dispatch('click', e);
|
||||
this.interactivity?.dispatch('click', e);
|
||||
}
|
||||
|
||||
override deactivate() {
|
||||
@@ -424,7 +424,7 @@ export class DefaultTool extends BaseTool {
|
||||
return;
|
||||
}
|
||||
|
||||
this.elementTransformMgr?.dispatch('dblclick', e);
|
||||
this.interactivity?.dispatch('dblclick', e);
|
||||
}
|
||||
|
||||
override dragEnd() {
|
||||
@@ -523,7 +523,7 @@ export class DefaultTool extends BaseTool {
|
||||
}
|
||||
|
||||
override pointerDown(e: PointerEventState): void {
|
||||
this.elementTransformMgr?.dispatch('pointerdown', e);
|
||||
this.interactivity?.dispatch('pointerdown', e);
|
||||
}
|
||||
|
||||
override pointerMove(e: PointerEventState) {
|
||||
@@ -542,11 +542,11 @@ export class DefaultTool extends BaseTool {
|
||||
this.frameOverlay.clear();
|
||||
}
|
||||
|
||||
this.elementTransformMgr?.dispatch('pointermove', e);
|
||||
this.interactivity?.dispatch('pointermove', e);
|
||||
}
|
||||
|
||||
override pointerUp(e: PointerEventState) {
|
||||
this.elementTransformMgr?.dispatch('pointerup', e);
|
||||
this.interactivity?.dispatch('pointerup', e);
|
||||
}
|
||||
|
||||
override tripleClick() {}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
addText,
|
||||
insertEdgelessTextCommand,
|
||||
} from '@blocksuite/affine-gfx-text';
|
||||
import {
|
||||
FeatureFlagService,
|
||||
TelemetryProvider,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import type { PointerEventState } from '@blocksuite/std';
|
||||
import { InteractivityExtension } from '@blocksuite/std/gfx';
|
||||
|
||||
export class DblClickAddEdgelessText extends InteractivityExtension {
|
||||
static override key = 'dbl-click-add-edgeless-text';
|
||||
|
||||
override mounted() {
|
||||
this.event.on('dblclick', (e: PointerEventState) => {
|
||||
const textFlag = this.std.store
|
||||
.get(FeatureFlagService)
|
||||
.getFlag('enable_edgeless_text');
|
||||
const picked = this.gfx.getElementByPoint(
|
||||
...this.gfx.viewport.toModelCoord(e.x, e.y)
|
||||
);
|
||||
|
||||
if (picked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (textFlag) {
|
||||
const [x, y] = this.gfx.viewport.toModelCoord(e.x, e.y);
|
||||
this.std.command.exec(insertEdgelessTextCommand, { x, y });
|
||||
} else {
|
||||
const edgelessView = this.std.view.getBlock(
|
||||
this.std.store.root?.id || ''
|
||||
);
|
||||
|
||||
if (edgelessView) {
|
||||
addText(edgelessView, e);
|
||||
}
|
||||
}
|
||||
|
||||
this.std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
||||
control: 'canvas:dbclick',
|
||||
page: 'whiteboard editor',
|
||||
module: 'toolbar',
|
||||
segment: 'toolbar',
|
||||
type: 'text',
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { OverlayIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import { MindmapElementModel } from '@blocksuite/affine-model';
|
||||
import type { Bound } from '@blocksuite/global/gfx';
|
||||
import {
|
||||
type DragExtensionInitializeContext,
|
||||
type ExtensionDragMoveContext,
|
||||
type GfxModel,
|
||||
InteractivityExtension,
|
||||
} from '@blocksuite/std/gfx';
|
||||
|
||||
import type { SnapOverlay } from '../utils/snap-manager';
|
||||
|
||||
export class SnapExtension extends InteractivityExtension {
|
||||
static override key = 'snap-manager';
|
||||
|
||||
get snapOverlay() {
|
||||
return this.std.getOptional(
|
||||
OverlayIdentifier('snap-manager')
|
||||
) as SnapOverlay;
|
||||
}
|
||||
|
||||
override mounted(): void {
|
||||
this.action.onDragInitialize(
|
||||
(initContext: DragExtensionInitializeContext) => {
|
||||
const snapOverlay = this.snapOverlay;
|
||||
|
||||
if (!snapOverlay) {
|
||||
return {};
|
||||
}
|
||||
|
||||
let alignBound: Bound;
|
||||
|
||||
return {
|
||||
onDragStart() {
|
||||
alignBound = snapOverlay.setMovingElements(
|
||||
initContext.elements,
|
||||
initContext.elements.reduce((pre, elem) => {
|
||||
if (elem.group instanceof MindmapElementModel) {
|
||||
pre.push(elem.group);
|
||||
}
|
||||
|
||||
return pre;
|
||||
}, [] as GfxModel[])
|
||||
);
|
||||
},
|
||||
onDragMove(context: ExtensionDragMoveContext) {
|
||||
if (
|
||||
context.elements.length === 0 ||
|
||||
alignBound.w === 0 ||
|
||||
alignBound.h === 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentBound = alignBound.moveDelta(context.dx, context.dy);
|
||||
const alignRst = snapOverlay.align(currentBound);
|
||||
|
||||
context.dx = alignRst.dx + context.dx;
|
||||
context.dy = alignRst.dy + context.dy;
|
||||
},
|
||||
onDragEnd() {
|
||||
snapOverlay.clear();
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,42 @@
|
||||
import { ConnectorElementModel } from '@blocksuite/affine-model';
|
||||
import {
|
||||
type DragExtensionInitializeContext,
|
||||
TransformExtension,
|
||||
InteractivityExtension,
|
||||
} from '@blocksuite/std/gfx';
|
||||
|
||||
export class ConnectorFilter extends TransformExtension {
|
||||
export class ConnectorFilter extends InteractivityExtension {
|
||||
static override key = 'connector-filter';
|
||||
override onDragInitialize(context: DragExtensionInitializeContext) {
|
||||
let hasConnectorFlag = false;
|
||||
|
||||
const elementSet = new Set(context.elements.map(elem => elem.id));
|
||||
const elements = context.elements.filter(elem => {
|
||||
if (elem instanceof ConnectorElementModel) {
|
||||
const sourceElemNotFound =
|
||||
elem.source.id && !elementSet.has(elem.source.id);
|
||||
const targetElemNotFound =
|
||||
elem.target.id && !elementSet.has(elem.target.id);
|
||||
override mounted() {
|
||||
this.action.onDragInitialize((context: DragExtensionInitializeContext) => {
|
||||
let hasConnectorFlag = false;
|
||||
|
||||
// If either source or target element is not found, then remove the connector
|
||||
if (sourceElemNotFound || targetElemNotFound) {
|
||||
return false;
|
||||
const elementSet = new Set(context.elements.map(elem => elem.id));
|
||||
const elements = context.elements.filter(elem => {
|
||||
if (elem instanceof ConnectorElementModel) {
|
||||
const sourceElemNotFound =
|
||||
elem.source.id && !elementSet.has(elem.source.id);
|
||||
const targetElemNotFound =
|
||||
elem.target.id && !elementSet.has(elem.target.id);
|
||||
|
||||
// If either source or target element is not found, then remove the connector
|
||||
if (sourceElemNotFound || targetElemNotFound) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hasConnectorFlag = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
hasConnectorFlag = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (hasConnectorFlag) {
|
||||
// connector needs to be updated first
|
||||
elements.sort((a, _) => (a instanceof ConnectorElementModel ? -1 : 1));
|
||||
}
|
||||
|
||||
return true;
|
||||
return {};
|
||||
});
|
||||
|
||||
if (hasConnectorFlag) {
|
||||
// connector needs to be updated first
|
||||
elements.sort((a, _) => (a instanceof ConnectorElementModel ? -1 : 1));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export * from './adapter';
|
||||
export * from './element-renderer';
|
||||
export * from './element-transform';
|
||||
export * from './indicator-overlay';
|
||||
export * from './interactivity';
|
||||
export * from './toolbar/config';
|
||||
export * from './toolbar/senior-tool';
|
||||
export * from './utils';
|
||||
|
||||
@@ -16,8 +16,8 @@ import {
|
||||
type ExtensionDragStartContext,
|
||||
type GfxModel,
|
||||
type GfxPrimitiveElementModel,
|
||||
InteractivityExtension,
|
||||
isGfxGroupCompatibleModel,
|
||||
TransformExtension,
|
||||
} from '@blocksuite/std/gfx';
|
||||
|
||||
import type { MindMapIndicatorOverlay } from '../indicator-overlay';
|
||||
@@ -43,7 +43,7 @@ type DragMindMapCtx = {
|
||||
originalMindMapBound: Bound;
|
||||
};
|
||||
|
||||
export class MindMapDragExtension extends TransformExtension {
|
||||
export class MindMapDragExtension extends InteractivityExtension {
|
||||
static override key = 'mind-map-drag';
|
||||
/**
|
||||
* The response area of the mind map is calculated in real time.
|
||||
@@ -376,78 +376,80 @@ export class MindMapDragExtension extends TransformExtension {
|
||||
};
|
||||
}
|
||||
|
||||
override onDragInitialize(context: DragExtensionInitializeContext) {
|
||||
if (isSingleMindMapNode(context.elements)) {
|
||||
const mindmap = context.elements[0].group as MindmapElementModel;
|
||||
const mindmapNode = mindmap.getNode(context.elements[0].id)!;
|
||||
const mindmapBound = mindmap.elementBound;
|
||||
const isRoot = mindmapNode === mindmap.tree;
|
||||
override mounted() {
|
||||
this.action.onDragInitialize((context: DragExtensionInitializeContext) => {
|
||||
if (isSingleMindMapNode(context.elements)) {
|
||||
const mindmap = context.elements[0].group as MindmapElementModel;
|
||||
const mindmapNode = mindmap.getNode(context.elements[0].id)!;
|
||||
const mindmapBound = mindmap.elementBound;
|
||||
const isRoot = mindmapNode === mindmap.tree;
|
||||
|
||||
mindmapBound.x -= NODE_HORIZONTAL_SPACING;
|
||||
mindmapBound.y -= NODE_VERTICAL_SPACING * 2;
|
||||
mindmapBound.w += NODE_HORIZONTAL_SPACING * 2;
|
||||
mindmapBound.h += NODE_VERTICAL_SPACING * 4;
|
||||
mindmapBound.x -= NODE_HORIZONTAL_SPACING;
|
||||
mindmapBound.y -= NODE_VERTICAL_SPACING * 2;
|
||||
mindmapBound.w += NODE_HORIZONTAL_SPACING * 2;
|
||||
mindmapBound.h += NODE_VERTICAL_SPACING * 4;
|
||||
|
||||
this._calcDragResponseArea(mindmap);
|
||||
this._calcDragResponseArea(mindmap);
|
||||
|
||||
const clearDragStatus = isRoot
|
||||
? mindmap.stashTree(mindmapNode)
|
||||
: this._setupDragNodeImage(mindmapNode, context.dragStartPos);
|
||||
const clearOpacity = this._updateNodeOpacity(mindmap, mindmapNode);
|
||||
const clearDragStatus = isRoot
|
||||
? mindmap.stashTree(mindmapNode)
|
||||
: this._setupDragNodeImage(mindmapNode, context.dragStartPos);
|
||||
const clearOpacity = this._updateNodeOpacity(mindmap, mindmapNode);
|
||||
|
||||
if (!isRoot) {
|
||||
context.elements.splice(0, 1);
|
||||
if (!isRoot) {
|
||||
context.elements.splice(0, 1);
|
||||
}
|
||||
|
||||
const mindMapDragCtx: DragMindMapCtx = {
|
||||
mindmap,
|
||||
node: mindmapNode,
|
||||
isRoot,
|
||||
originalMindMapBound: mindmapBound,
|
||||
};
|
||||
|
||||
return {
|
||||
...this._createManipulationHandlers(mindMapDragCtx),
|
||||
clear() {
|
||||
clearOpacity();
|
||||
clearDragStatus?.();
|
||||
if (!isRoot) {
|
||||
context.elements.push(mindmapNode.element);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const mindMapDragCtx: DragMindMapCtx = {
|
||||
mindmap,
|
||||
node: mindmapNode,
|
||||
isRoot,
|
||||
originalMindMapBound: mindmapBound,
|
||||
};
|
||||
const mindmapNodes = new Set<GfxModel>();
|
||||
const mindmaps = new Set<MindmapElementModel>();
|
||||
|
||||
return {
|
||||
...this._createManipulationHandlers(mindMapDragCtx),
|
||||
clear() {
|
||||
clearOpacity();
|
||||
clearDragStatus?.();
|
||||
if (!isRoot) {
|
||||
context.elements.push(mindmapNode.element);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
context.elements.forEach(el => {
|
||||
if (isMindmapNode(el)) {
|
||||
const mindmap =
|
||||
el.group instanceof MindmapElementModel
|
||||
? el.group
|
||||
: (el as MindmapElementModel);
|
||||
|
||||
const mindmapNodes = new Set<GfxModel>();
|
||||
const mindmaps = new Set<MindmapElementModel>();
|
||||
mindmaps.add(mindmap);
|
||||
mindmap.childElements.forEach(child => mindmapNodes.add(child));
|
||||
} else if (isGfxGroupCompatibleModel(el)) {
|
||||
el.descendantElements.forEach(desc => {
|
||||
if (desc.group instanceof MindmapElementModel) {
|
||||
mindmaps.add(desc.group);
|
||||
desc.group.childElements.forEach(_el => mindmapNodes.add(_el));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
context.elements.forEach(el => {
|
||||
if (isMindmapNode(el)) {
|
||||
const mindmap =
|
||||
el.group instanceof MindmapElementModel
|
||||
? el.group
|
||||
: (el as MindmapElementModel);
|
||||
|
||||
mindmaps.add(mindmap);
|
||||
mindmap.childElements.forEach(child => mindmapNodes.add(child));
|
||||
} else if (isGfxGroupCompatibleModel(el)) {
|
||||
el.descendantElements.forEach(desc => {
|
||||
if (desc.group instanceof MindmapElementModel) {
|
||||
mindmaps.add(desc.group);
|
||||
desc.group.childElements.forEach(_el => mindmapNodes.add(_el));
|
||||
}
|
||||
if (mindmapNodes.size > 1) {
|
||||
mindmapNodes.forEach(node => context.elements.push(node));
|
||||
return this._createTranslationHandlers({
|
||||
mindmaps,
|
||||
nodes: mindmapNodes,
|
||||
});
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
if (mindmapNodes.size > 1) {
|
||||
mindmapNodes.forEach(node => context.elements.push(node));
|
||||
return this._createTranslationHandlers({
|
||||
mindmaps,
|
||||
nodes: mindmapNodes,
|
||||
});
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user