@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering
389 lines • 14.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Dnd = exports.DndDefaults = void 0;
const tslib_1 = require("tslib");
const dom_align_1 = require("dom-align");
const common_1 = require("../../common");
const constants_1 = require("../../constants");
const geometry_1 = require("../../geometry");
const graph_1 = require("../../graph");
const view_1 = require("../../view");
const raw_1 = require("./style/raw");
exports.DndDefaults = {
// animation: false,
getDragNode: (sourceNode) => sourceNode.clone(),
getDropNode: (draggingNode) => draggingNode.clone(),
};
class Dnd extends view_1.View {
get targetScroller() {
const target = this.options.target;
const scroller = target.getPlugin('scroller');
return scroller;
}
get targetGraph() {
return this.options.target;
}
get targetModel() {
return this.targetGraph.model;
}
get snapline() {
const target = this.options.target;
const snapline = target.getPlugin('snapline');
return snapline;
}
constructor(options) {
super();
this.name = 'dnd';
this.options = Object.assign(Object.assign({}, exports.DndDefaults), options);
this.init();
}
init() {
common_1.CssLoader.ensure(this.name, raw_1.content);
this.container = document.createElement('div');
common_1.Dom.addClass(this.container, this.prefixClassName('widget-dnd'));
this.draggingGraph = new graph_1.Graph(Object.assign(Object.assign({}, this.options.delegateGraphOptions), { container: document.createElement('div'), width: 1, height: 1, async: false }));
common_1.Dom.append(this.container, this.draggingGraph.container);
}
start(node, evt) {
var _a;
const e = evt;
e.preventDefault();
this.targetModel.startBatch('dnd');
common_1.Dom.addClass(this.container, 'dragging');
common_1.Dom.appendTo(this.container, this.options.draggingContainer || document.body);
this.sourceNode = node;
this.prepareDragging(node, e.clientX, e.clientY);
const local = this.updateNodePosition(e.clientX, e.clientY);
if (this.isSnaplineEnabled()) {
this.snapline.captureCursorOffset({
e,
node,
cell: node,
view: this.draggingView,
x: local.x,
y: local.y,
});
(_a = this.draggingNode) === null || _a === void 0 ? void 0 : _a.on('change:position', this.snap, this);
}
this.delegateDocumentEvents(constants_1.DocumentEvents, e.data);
}
isSnaplineEnabled() {
var _a;
return (_a = this.snapline) === null || _a === void 0 ? void 0 : _a.isEnabled();
}
prepareDragging(sourceNode, clientX, clientY) {
const draggingGraph = this.draggingGraph;
const draggingModel = draggingGraph.model;
const draggingNode = this.options.getDragNode(sourceNode, {
sourceNode,
draggingGraph,
targetGraph: this.targetGraph,
});
draggingNode.position(0, 0);
let padding = 5;
if (this.isSnaplineEnabled()) {
padding += this.snapline.options.tolerance || 0;
}
if (this.isSnaplineEnabled() || this.options.scaled) {
const scale = this.targetGraph.transform.getScale();
draggingGraph.scale(scale.sx, scale.sy);
padding *= Math.max(scale.sx, scale.sy);
}
else {
draggingGraph.scale(1, 1);
}
this.clearDragging();
// if (this.options.animation) {
// this.$container.stop(true, true)
// }
draggingModel.resetCells([draggingNode]);
const delegateView = draggingGraph.findViewByCell(draggingNode);
delegateView.undelegateEvents();
delegateView.cell.off('changed');
draggingGraph.fitToContent({
padding,
allowNewOrigin: 'any',
useCellGeometry: false,
});
const bbox = delegateView.getBBox();
this.geometryBBox = delegateView.getBBox({ useCellGeometry: true });
this.delta = this.geometryBBox.getTopLeft().diff(bbox.getTopLeft());
this.draggingNode = draggingNode;
this.draggingView = delegateView;
this.draggingBBox = draggingNode.getBBox();
this.padding = padding;
this.updateGraphPosition(clientX, clientY);
}
updateGraphPosition(clientX, clientY) {
const delta = this.delta;
const nodeBBox = this.geometryBBox;
const padding = this.padding || 5;
const offset = {
left: clientX - delta.x - nodeBBox.width / 2 - padding,
top: clientY - delta.y - nodeBBox.height / 2 - padding,
};
if (this.draggingGraph) {
(0, dom_align_1.alignPoint)(this.container, {
clientX: offset.left,
clientY: offset.top,
}, {
points: ['tl'],
});
}
}
updateNodePosition(x, y) {
const local = this.targetGraph.clientToLocal(x, y);
const bbox = this.draggingBBox;
if (bbox) {
local.x -= bbox.width / 2;
local.y -= bbox.height / 2;
this.draggingNode.position(local.x, local.y);
}
return local;
}
snap({ cell, current, options, }) {
const node = cell;
if (options.snapped) {
const bbox = this.draggingBBox;
node.position(bbox.x + options.tx, bbox.y + options.ty, { silent: true });
this.draggingView.translate();
node.position(current.x, current.y, { silent: true });
this.snapOffset = {
x: options.tx,
y: options.ty,
};
}
else {
this.snapOffset = null;
}
}
onMouseMove(evt) {
this.onDragging(evt);
}
onMouseUp(evt) {
this.onDragEnd(evt);
}
onDragging(evt) {
const draggingView = this.draggingView;
if (draggingView) {
evt.preventDefault();
const e = this.normalizeEvent(evt);
const clientX = e.clientX;
const clientY = e.clientY;
this.updateGraphPosition(clientX, clientY);
const local = this.updateNodePosition(clientX, clientY);
const embeddingMode = this.targetGraph.options.embedding.enabled;
const isValidArea = (embeddingMode || this.isSnaplineEnabled()) &&
this.isInsideValidArea({
x: clientX,
y: clientY,
});
if (embeddingMode) {
draggingView.setEventData(e, {
graph: this.targetGraph,
candidateEmbedView: this.candidateEmbedView,
});
const data = draggingView.getEventData(e);
if (isValidArea) {
draggingView.processEmbedding(e, data);
}
else {
draggingView.clearEmbedding(data);
}
this.candidateEmbedView = data.candidateEmbedView;
}
// update snapline
if (this.isSnaplineEnabled()) {
if (isValidArea) {
this.snapline.snapOnMoving({
e,
view: draggingView,
x: local.x,
y: local.y,
});
}
else {
this.snapline.hide();
}
}
}
}
onDragEnd(evt) {
const draggingNode = this.draggingNode;
if (draggingNode) {
const e = this.normalizeEvent(evt);
const draggingView = this.draggingView;
const draggingBBox = this.draggingBBox;
const snapOffset = this.snapOffset;
let x = draggingBBox.x;
let y = draggingBBox.y;
if (snapOffset) {
x += snapOffset.x;
y += snapOffset.y;
}
draggingNode.position(x, y, { silent: true });
const ret = this.drop(draggingNode, { x: e.clientX, y: e.clientY });
const callback = (node) => {
if (node) {
this.onDropped(draggingNode);
if (this.targetGraph.options.embedding.enabled && draggingView) {
draggingView.setEventData(e, {
cell: node,
graph: this.targetGraph,
candidateEmbedView: this.candidateEmbedView,
});
draggingView.finalizeEmbedding(e, draggingView.getEventData(e));
}
}
else {
this.onDropInvalid();
}
this.candidateEmbedView = null;
this.targetModel.stopBatch('dnd');
};
if (common_1.FunctionExt.isAsync(ret)) {
// stop dragging
this.undelegateDocumentEvents();
ret.then(callback); // eslint-disable-line
}
else {
callback(ret);
}
}
}
clearDragging() {
if (this.draggingNode) {
this.sourceNode = null;
this.draggingNode.remove();
this.draggingNode = null;
this.draggingView = null;
this.delta = null;
this.padding = null;
this.snapOffset = null;
this.undelegateDocumentEvents();
}
}
onDropped(draggingNode) {
if (this.draggingNode === draggingNode) {
this.clearDragging();
common_1.Dom.removeClass(this.container, 'dragging');
common_1.Dom.remove(this.container);
}
}
onDropInvalid() {
const draggingNode = this.draggingNode;
if (draggingNode) {
this.onDropped(draggingNode);
// todo
// const anim = this.options.animation
// if (anim) {
// const duration = (typeof anim === 'object' && anim.duration) || 150
// const easing = (typeof anim === 'object' && anim.easing) || 'swing'
// this.draggingView = null
// this.$container.animate(this.originOffset!, duration, easing, () =>
// this.onDropped(draggingNode),
// )
// } else {
// this.onDropped(draggingNode)
// }
}
}
isInsideValidArea(p) {
let targetRect;
let dndRect = null;
const targetGraph = this.targetGraph;
const targetScroller = this.targetScroller;
if (this.options.dndContainer) {
dndRect = this.getDropArea(this.options.dndContainer);
}
const isInsideDndRect = dndRect === null || dndRect === void 0 ? void 0 : dndRect.containsPoint(p);
if (targetScroller) {
if (targetScroller.options.autoResize) {
targetRect = this.getDropArea(targetScroller.container);
}
else {
const outter = this.getDropArea(targetScroller.container);
targetRect = this.getDropArea(targetGraph.container).intersectsWithRect(outter);
}
}
else {
targetRect = this.getDropArea(targetGraph.container);
}
return !isInsideDndRect && targetRect && targetRect.containsPoint(p);
}
getDropArea(elem) {
const offset = common_1.Dom.offset(elem);
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
const scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
return geometry_1.Rectangle.create({
x: offset.left +
parseInt(common_1.Dom.css(elem, 'border-left-width'), 10) -
scrollLeft,
y: offset.top +
parseInt(common_1.Dom.css(elem, 'border-top-width'), 10) -
scrollTop,
width: elem.clientWidth,
height: elem.clientHeight,
});
}
drop(draggingNode, pos) {
if (this.isInsideValidArea(pos)) {
const targetGraph = this.targetGraph;
const targetModel = targetGraph.model;
const local = targetGraph.clientToLocal(pos);
const sourceNode = this.sourceNode;
const droppingNode = this.options.getDropNode(draggingNode, {
sourceNode,
draggingNode,
targetGraph: this.targetGraph,
draggingGraph: this.draggingGraph,
});
const bbox = droppingNode.getBBox();
local.x += bbox.x - bbox.width / 2;
local.y += bbox.y - bbox.height / 2;
const gridSize = this.snapOffset ? 1 : targetGraph.getGridSize();
droppingNode.position((0, geometry_1.snapToGrid)(local.x, gridSize), (0, geometry_1.snapToGrid)(local.y, gridSize));
droppingNode.removeZIndex();
const validateNode = this.options.validateNode;
const ret = validateNode
? validateNode(droppingNode, {
sourceNode,
draggingNode,
droppingNode,
targetGraph,
draggingGraph: this.draggingGraph,
})
: true;
if (typeof ret === 'boolean') {
if (ret) {
targetModel.addCell(droppingNode, { stencil: this.cid });
return droppingNode;
}
return null;
}
return common_1.FunctionExt.toDeferredBoolean(ret).then((valid) => {
if (valid) {
targetModel.addCell(droppingNode, { stencil: this.cid });
return droppingNode;
}
return null;
});
}
return null;
}
onRemove() {
if (this.draggingGraph) {
this.draggingGraph.view.remove();
this.draggingGraph.dispose();
}
}
dispose() {
this.remove();
common_1.CssLoader.clean(this.name);
}
}
exports.Dnd = Dnd;
tslib_1.__decorate([
(0, common_1.disposable)()
], Dnd.prototype, "dispose", null);
//# sourceMappingURL=index.js.map