@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering.
410 lines • 16.9 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.PathDrawer = void 0;
var util_1 = require("../../util");
var geometry_1 = require("../../geometry");
var view_1 = require("../../view");
// need: <meta http-equiv="x-ua-compatible" content="IE=Edge" />
var PathDrawer = /** @class */ (function (_super) {
__extends(PathDrawer, _super);
function PathDrawer(options) {
var _this = _super.call(this) || this;
_this.MOVEMENT_DETECTION_THRESHOLD = 150;
_this.options = util_1.ObjectExt.merge({}, PathDrawer.defaultOptions, options);
_this.action = 'awaiting-input';
_this.render();
_this.startListening();
return _this;
}
Object.defineProperty(PathDrawer.prototype, "vel", {
get: function () {
return util_1.Vector.create(this.container);
},
enumerable: false,
configurable: true
});
PathDrawer.prototype.render = function () {
var options = this.options;
this.container = util_1.Dom.createSvgElement('g');
util_1.Dom.addClass(this.container, this.prefixClassName('path-drawer'));
this.pathTemplate = util_1.Dom.createSvgElement('path');
util_1.Dom.attr(this.pathTemplate, options.pathAttributes);
this.startPointElement = util_1.Vector.create(options.startPointMarkup).addClass('start-point').node;
this.controlElement = util_1.Dom.createSvgElement('path');
util_1.Dom.addClass(this.controlElement, 'control-path');
util_1.Vector.create('rect', {
x: 0,
y: 0,
width: '100%',
height: '100%',
fill: 'transparent',
stroke: 'none',
}).appendTo(this.container);
this.options.target.appendChild(this.container);
return this;
};
PathDrawer.prototype.onRemove = function () {
this.remove(this.pathElement);
this.clear();
this.stopListening();
};
PathDrawer.prototype.startListening = function () {
this.delegateEvents({
mousedown: 'onMouseDown',
touchstart: 'onMouseDown',
dblclick: 'onDoubleClick',
contextmenu: 'onContextMenu',
'mousedown .start-point': 'onStartPointMouseDown',
'touchstart .start-point': 'onStartPointMouseDown',
});
};
PathDrawer.prototype.stopListening = function () {
this.undelegateEvents();
};
PathDrawer.prototype.clear = function () {
var path = this.pathElement;
if (path && path.pathSegList.numberOfItems <= 1) {
this.remove(path);
}
this.startPointElement.remove();
this.controlElement.remove();
this.undelegateDocumentEvents();
this.action = 'awaiting-input';
this.emit('clear');
};
PathDrawer.prototype.createPath = function (x, y) {
this.pathElement = this.pathTemplate.cloneNode(true);
this.addMoveSegment(x, y);
util_1.Dom.translate(this.startPointElement, x, y, {
absolute: true,
});
this.vel.before(this.pathElement);
this.vel.append(this.startPointElement);
this.emit('path:create', { path: this.pathElement });
};
PathDrawer.prototype.closePath = function () {
var path = this.pathElement;
var first = this.getPathSeg(path, 0);
var last = this.getPathSeg(path, -1);
if (last.pathSegType === SVGPathSeg.PATHSEG_LINETO_ABS) {
path.pathSegList.replaceItem(path.createSVGPathSegClosePath(), path.pathSegList.numberOfItems - 1);
}
else {
last.x = first.x;
last.y = first.y;
path.pathSegList.appendItem(path.createSVGPathSegClosePath());
}
this.finishPath('path:close');
};
PathDrawer.prototype.finishPath = function (name) {
var path = this.pathElement;
if (path && 0 < this.numberOfVisibleSegments()) {
this.emit('path:finish', { path: path });
this.trigger(name, { path: path });
}
else {
this.emit('path:abort', { path: path });
}
this.clear();
};
PathDrawer.prototype.numberOfVisibleSegments = function () {
var path = this.pathElement;
var remaining = path.pathSegList.numberOfItems;
remaining = remaining - 1;
var last = this.getPathSeg(path, -1);
if (last.pathSegType === SVGPathSeg.PATHSEG_CLOSEPATH) {
remaining = remaining - 1;
}
return remaining;
};
PathDrawer.prototype.addMoveSegment = function (x, y) {
var path = this.pathElement;
var seg = path.createSVGPathSegMovetoAbs(x, y);
path.pathSegList.appendItem(seg);
this.emit('path:segment:add', { path: path });
this.emit('path:move-segment:add', { path: path });
};
PathDrawer.prototype.addLineSegment = function (x, y) {
var path = this.pathElement;
var seg = path.createSVGPathSegLinetoAbs(x, y);
path.pathSegList.appendItem(seg);
this.emit('path:segment:add', { path: path });
this.emit('path:line-segment:add', { path: path });
};
PathDrawer.prototype.addCurveSegment = function (x, y, x1, y1, x2, y2) {
var path = this.pathElement;
var seg = path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2 || x, y2 || y);
path.pathSegList.appendItem(seg);
this.emit('path:segment:add', { path: path });
this.emit('path:curve-segment:add', { path: path });
};
PathDrawer.prototype.adjustLastSegment = function (x, y, x1, y1, x2, y2) {
var path = this.pathElement;
var snapRadius = this.options.snapRadius;
if (snapRadius && x != null && y != null) {
var snaped = this.snapLastSegmentCoordinates(x, y, snapRadius);
x = snaped.x; // tslint:disable-line
y = snaped.y; // tslint:disable-line
}
var seg = this.getPathSeg(path, -1);
if (x != null) {
seg.x = x;
}
if (y != null) {
seg.y = y;
}
if (x1 != null) {
seg.x1 = x1;
}
if (y1 != null) {
seg.y1 = y1;
}
if (x2 != null) {
seg.x2 = x2;
}
if (y2 != null) {
seg.y2 = y2;
}
this.emit('path:edit', { path: path });
this.emit('path:last-segment:adjust', { path: path });
};
PathDrawer.prototype.snapLastSegmentCoordinates = function (x, y, snapRadius) {
var path = this.pathElement;
var xSnaped = false;
var ySnaped = false;
var targetX = x;
var targetY = y;
for (var i = path.pathSegList.numberOfItems - 2; 0 <= i && (!xSnaped || !ySnaped); i -= 1) {
var seg = this.getPathSeg(path, i);
if (!xSnaped && Math.abs(seg.x - x) < snapRadius) {
targetX = seg.x;
xSnaped = true;
}
if (!ySnaped && Math.abs(seg.y - y) < snapRadius) {
targetY = seg.y;
ySnaped = true;
}
}
return new geometry_1.Point(targetX, targetY);
};
PathDrawer.prototype.removeLastSegment = function () {
var path = this.pathElement;
path.pathSegList.removeItem(path.pathSegList.numberOfItems - 1);
this.emit('path:edit', { path: path });
this.emit('path:last-segment:remove', { path: path });
};
PathDrawer.prototype.findControlPoint = function (x, y) {
var path = this.pathElement;
var seg = this.getPathSeg(path, -1);
return new geometry_1.Point(x, y).reflection(seg);
};
PathDrawer.prototype.replaceLastSegmentWithCurve = function () {
var path = this.pathElement;
var last = this.getPathSeg(path, -1);
var prev = this.getPathSeg(path, -2);
var seg = path.createSVGPathSegCurvetoCubicAbs(last.x, last.y, prev.x, prev.y, last.x, last.y);
path.pathSegList.replaceItem(seg, path.pathSegList.numberOfItems - 1);
this.emit('path:edit', { path: path });
this.emit('path:last-segment:replace-with-curve', { path: path });
};
PathDrawer.prototype.adjustControlPath = function (x1, y1, x2, y2) {
var controlPathElement = this.controlElement;
controlPathElement.pathSegList.initialize(controlPathElement.createSVGPathSegMovetoAbs(x1, y1));
controlPathElement.pathSegList.appendItem(controlPathElement.createSVGPathSegLinetoAbs(x2, y2));
this.vel.append(controlPathElement);
var path = this.pathElement;
this.emit('path:interact', { path: path });
this.emit('path:control:adjust', { path: path });
};
PathDrawer.prototype.removeControlPath = function () {
var path = this.pathElement;
var svgControl = this.controlElement;
svgControl.pathSegList.clear();
this.vel.append(svgControl);
this.emit('path:interact', { path: path });
this.emit('path:control:remove', { path: path });
};
PathDrawer.prototype.getPathSeg = function (path, index) {
var i = index < 0 ? path.pathSegList.numberOfItems + index : index;
return path.pathSegList.getItem(i);
};
PathDrawer.prototype.onMouseDown = function (evt) {
var e = this.normalizeEvent(evt);
e.stopPropagation();
if (this.isLeftMouseDown(e) &&
this.isSamePositionEvent(e) &&
this.container.parentNode) {
var local = this.vel.toLocalPoint(e.clientX, e.clientY);
switch (this.action) {
case 'awaiting-input':
this.createPath(local.x, local.y);
this.action = 'path-created';
this.delegateDocumentEvents(PathDrawer.documentEvents);
break;
case 'adjusting-line-end':
this.action = 'awaiting-line-end';
break;
case 'adjusting-curve-end':
this.action = 'awaiting-curve-control-2';
}
this.timeStamp = e.timeStamp;
}
};
PathDrawer.prototype.onMouseMove = function (evt) {
var e = this.normalizeEvent(evt);
e.stopPropagation();
if ('awaiting-input' !== this.action) {
var local = this.vel.toLocalPoint(e.clientX, e.clientY);
var timeStamp = this.timeStamp;
if (timeStamp) {
if (e.timeStamp - timeStamp < this.MOVEMENT_DETECTION_THRESHOLD) {
switch (this.action) {
case 'path-created': {
var translate = util_1.Dom.translate(this.startPointElement);
this.adjustControlPath(translate.tx, translate.ty, local.x, local.y);
break;
}
case 'awaiting-line-end':
case 'adjusting-curve-control-1': {
this.adjustLastSegment(local.x, local.y);
break;
}
case 'awaiting-curve-control-2': {
this.adjustLastSegment(local.x, local.y, null, null, local.x, local.y);
}
}
}
else {
switch (this.action) {
case 'path-created':
this.action = 'adjusting-curve-control-1';
break;
case 'awaiting-line-end':
this.replaceLastSegmentWithCurve();
this.action = 'adjusting-curve-control-2';
break;
case 'awaiting-curve-control-2':
this.action = 'adjusting-curve-control-2';
break;
case 'adjusting-curve-control-1': {
var translate = util_1.Dom.translate(this.startPointElement);
this.adjustControlPath(translate.tx, translate.ty, local.x, local.y);
break;
}
case 'adjusting-curve-control-2': {
var controlPoint = this.findControlPoint(local.x, local.y);
this.adjustLastSegment(null, null, null, null, controlPoint.x, controlPoint.y);
this.adjustControlPath(controlPoint.x, controlPoint.y, local.x, local.y);
}
}
}
}
else {
switch (this.action) {
case 'adjusting-line-end':
this.adjustLastSegment(local.x, local.y);
break;
case 'adjusting-curve-end':
this.adjustLastSegment(local.x, local.y, null, null, local.x, local.y);
}
}
}
};
PathDrawer.prototype.onPointerUp = function (evt) {
this.timeStamp = null;
var e = this.normalizeEvent(evt);
e.stopPropagation();
if (this.isLeftMouseDown(e) && this.isSamePositionEvent(e)) {
var local = this.vel.toLocalPoint(e.clientX, e.clientY);
switch (this.action) {
case 'path-created':
case 'awaiting-line-end':
this.addLineSegment(local.x, local.y);
this.action = 'adjusting-line-end';
break;
case 'awaiting-curve-control-2':
this.removeControlPath();
this.addLineSegment(local.x, local.y);
this.action = 'adjusting-line-end';
break;
case 'adjusting-curve-control-1':
case 'adjusting-curve-control-2':
this.addCurveSegment(local.x, local.y, local.x, local.y);
this.action = 'adjusting-curve-end';
}
}
};
PathDrawer.prototype.onStartPointMouseDown = function (evt) {
var e = this.normalizeEvent(evt);
e.stopPropagation();
if (this.isLeftMouseDown(e) && this.isSamePositionEvent(e)) {
this.closePath();
}
};
PathDrawer.prototype.onDoubleClick = function (evt) {
var e = this.normalizeEvent(evt);
e.preventDefault();
e.stopPropagation();
if (this.isLeftMouseDown(e)) {
if (this.pathElement && 0 < this.numberOfVisibleSegments()) {
this.removeLastSegment();
this.finishPath('path:stop');
}
}
};
PathDrawer.prototype.onContextMenu = function (evt) {
var e = this.normalizeEvent(evt);
e.preventDefault();
e.stopPropagation();
if (this.isSamePositionEvent(e)) {
if (this.pathElement && 0 < this.numberOfVisibleSegments()) {
this.removeLastSegment();
this.finishPath('path:stop');
}
}
};
PathDrawer.prototype.isLeftMouseDown = function (e) {
return (e.which || 0) <= 1;
};
PathDrawer.prototype.isSamePositionEvent = function (e) {
var originalEvent = e.originalEvent;
return originalEvent == null || originalEvent.detail <= 1;
};
return PathDrawer;
}(view_1.View));
exports.PathDrawer = PathDrawer;
(function (PathDrawer) {
PathDrawer.defaultOptions = {
pathAttributes: {
class: null,
fill: '#ffffff',
stroke: '#000000',
'stroke-width': 1,
'pointer-events': 'none',
},
startPointMarkup: '<circle r="5"/>',
snapRadius: 0,
};
PathDrawer.documentEvents = {
mousemove: 'onMouseMove',
touchmove: 'onMouseMove',
mouseup: 'onMouseUp',
touchend: 'onMouseUp',
touchcancel: 'onMouseUp',
};
})(PathDrawer = exports.PathDrawer || (exports.PathDrawer = {}));
exports.PathDrawer = PathDrawer;
//# sourceMappingURL=drawer.js.map