var _constants = require("../../utils/constants"); var mathAbs = _constants.mathAbs; var matrixUtil = require("../../utils/affine_matrix_util"); function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } /** * @class qrenderer.graphic.transform.TransformMgr * * Global transform manager. When user drag the transform control and begin dragging, this manager will handle the events * and transform parameters for the selected element. * * 全局变换管理器。当用户选中元素,开始拖动变换控制器时,此管理器负责处理事件、重新计算选中元素上的各项参数。 */ var TransformMgr = /*#__PURE__*/ function () { function TransformMgr(dispatcher) { _classCallCheck(this, TransformMgr); this.dispatcher = dispatcher; } _createClass(TransformMgr, [{ key: "startListen", value: function startListen() { this.stopListen(); this.dispatcher.on("mousedown", this.mouseDownHandler1, this); return this; } }, { key: "stopListen", value: function stopListen() { this._restoreSelection(); //incase there was a selected element this.selectedEl = null; this.lastHoveredControl = null; this._x = 0; //cache x axis this._y = 0; //cache y axis this._center = [0, 0]; //cache center point of bounding rect this._position; this._scale; this._rotation; this._width; this._height; this._transform; this._cursor = 'default'; //cache cursor type this._elDraggable = false; //cache original draggable flag of element this._hasControls = false; //whether this.el has controls //remove all event listeners this.dispatcher.off("mousedown", this.mouseDownHandler1, this); this.dispatcher.off("mousedown", this.mouseDownHandler2, this); this.dispatcher.off("mousemove", this.mouseMoveHandler1, this); this.dispatcher.off("pagemousemove", this.mouseMoveHandler2, this); this.dispatcher.off("pagemouseup", this.mouseUpHandler, this); return this; } }, { key: "mouseDownHandler1", value: function mouseDownHandler1(e) { var el = e.target; if (el && el.transformable) { //click on an element this._clickElement(el); } else { //no element is clicked this.startListen(); } } }, { key: "_clickElement", value: function _clickElement(el) { this._restoreSelection(); this.selectedEl = el; this._cursor = el.cursor; this._elDraggable = el.draggable; //cache original draggable flag this._hasControls = el.hasTransformControls = true; el.dirty(); //remove mousedown listener first, then start listen to mousemove //and the second mousedown event this.dispatcher.off("mousedown", this.mouseDownHandler1, this); this.dispatcher.on("mousemove", this.mouseMoveHandler1, this); this.dispatcher.on("mousedown", this.mouseDownHandler2, this); } }, { key: "_restoreSelection", value: function _restoreSelection() { if (this.selectedEl) { //restore original draggable flag this.selectedEl.draggable = this._elDraggable; this.selectedEl.hasTransformControls = false; this.selectedEl.dirty(); } } }, { key: "mouseMoveHandler1", value: function mouseMoveHandler1(e) { var _this = this; if (!this.selectedEl) { return; } var qrX = e.event.qrX; var qrY = e.event.qrY; this.lastHoveredControl = null; this.selectedEl.transformControls.forEach(function (control, index) { if (control.isHover(qrX, qrY)) { _this.lastHoveredControl = control; _this.dispatcher.interceptor.setCursor(control.cursor); } }); } }, { key: "mouseDownHandler2", value: function mouseDownHandler2(e) { var target = e.target; if (this.lastHoveredControl) { //click on a transform control this.selectedEl.draggable = false; this._x = e.offsetX; this._y = e.offsetY; this.dispatcher.off("mousemove", this.mouseMoveHandler1, this); //lockdown current clicked control, do not look for hovered control this.dispatcher.on("pagemousemove", this.mouseMoveHandler2, this); this.dispatcher.on("pagemouseup", this.mouseUpHandler, this); } else if (target && target.id && target.id.indexOf("el-") != -1) { //click on an element, FIXME:better way to determine whether the target is an element? this._clickElement(target); } else { //click on anywhere else this._hasControls = false; this.startListen(); } } }, { key: "mouseMoveHandler2", value: function mouseMoveHandler2(e) { var mouseX = e.offsetX; //x position of mouse in global space var mouseY = e.offsetY; //y position of mouse in global space var name = this.lastHoveredControl.name; if (name === 'SPIN') { this.handleRotate(mouseX, mouseY); } else { this.handleScale(mouseX, mouseY); } } }, { key: "handleRotate", value: function handleRotate(mouseX, mouseY) { var bps = this.getTransformedBoundingRect(); var _matrixUtil$minusVect = matrixUtil.minusVector([mouseX, mouseY], this._center); var _matrixUtil$minusVect2 = _slicedToArray(_matrixUtil$minusVect, 2); mouseX = _matrixUtil$minusVect2[0]; mouseY = _matrixUtil$minusVect2[1]; var sinp = matrixUtil.sinx.apply(matrixUtil, [mouseX, mouseY]); var cosp = matrixUtil.cosx.apply(matrixUtil, [mouseX, mouseY]); var radian = Math.asin(Math.abs(sinp)); if (sinp >= 0) { if (cosp < 0) { radian = Math.PI - radian; } if (this._scale[1] > 0) { //flip in Y direction radian = radian + Math.PI; } radian = radian - Math.PI / 2; } else { radian = -radian; if (cosp < 0) { radian = -(Math.PI + radian); } if (this._scale[1] < 0) { //flip in Y direction radian = radian + Math.PI; } radian = radian + Math.PI / 2; } var position = bps[0]; position = matrixUtil.rotateVector(position, -radian); position = matrixUtil.addVector(position, this._center); this.selectedEl.position = position; this.selectedEl.rotation = -radian; this.selectedEl.dirty(); } }, { key: "handleScale", value: function handleScale(mouseX, mouseY) { var bps = this.getTransformedBoundingRect(); var _this$transformMouseP = this.transformMousePoint(mouseX, mouseY), _this$transformMouseP2 = _slicedToArray(_this$transformMouseP, 2), tmx = _this$transformMouseP2[0], tmy = _this$transformMouseP2[1]; var newSx = mathAbs(tmx / (this._width / 2)); var newSy = mathAbs(tmy / (this._height / 2)); var name = this.lastHoveredControl.name; if (name.indexOf("T") != -1) { newSy = tmy >= 0 ? -newSy : newSy; } else if (name.indexOf("B") != -1) { newSy = tmy >= 0 ? newSy : -newSy; } else { newSy = this._scale[1]; } if (name.indexOf("L") != -1) { newSx = tmx >= 0 ? -newSx : newSx; } else if (name.indexOf("R") != -1) { newSx = tmx >= 0 ? newSx : -newSx; } else { newSx = this._scale[0]; } var position = bps[0]; if (name.indexOf("R") != -1) { position[0] = -tmx; } else if (name.indexOf("L") != -1) { position[0] = tmx; } if (name.indexOf("B") != -1) { position[1] = -tmy; } else if (name.indexOf("T") != -1) { position[1] = tmy; } position = matrixUtil.rotateVector(position, this._rotation); position = matrixUtil.addVector(position, this._center); this.selectedEl.position = position; this.selectedEl.scale = [newSx, newSy]; this.selectedEl.dirty(); } }, { key: "mouseUpHandler", value: function mouseUpHandler(e) { this.selectedEl.draggable = this._elDraggable; this.dispatcher.off("mousedown", this.mouseDownHandler1, this); this.dispatcher.off("pagemousemove", this.mouseMoveHandler2, this); this.dispatcher.off("pagemouseup", this.mouseUpHandler, this); this.dispatcher.on("mousemove", this.mouseMoveHandler1, this); this.dispatcher.on("mousedown", this.mouseDownHandler2, this); } /** * @private * @method getTransformedBoundingRect * Get transformed bouding rect of selected element, including four corner points, center point of original bounding rect, * and rotate control point. The coordinates returned by this method are in global space, the coordinate is based on the * center of bounding rect. * * * 获取变换之后的边界矩形坐标,包括:4个角落上的坐标点、中心坐标点、旋转控制器的坐标点。此方法返回的坐标位于全局空间中,计算的 * 坐标原点在边界矩形的中心点上。 */ }, { key: "getTransformedBoundingRect", value: function getTransformedBoundingRect() { this._position = this.selectedEl.position; //current position in global space this._scale = this.selectedEl.scale; //current scale in global space this._width = this.selectedEl.shape.width //original width without transforming || this.selectedEl.style.width; this._height = this.selectedEl.shape.height //original height without transforming || this.selectedEl.style.height; this._rotation = this.selectedEl.rotation; //current rotation in global space this._center = [this._width / 2, this._height / 2]; //original centerpoint in local space var m = matrixUtil.create(); m = matrixUtil.scale(m, this._scale); m = matrixUtil.rotate(m, this._rotation); m = matrixUtil.translate(m, this._position); this._transform = m; this._center = matrixUtil.transformVector(this._center, this._transform); //center point in global space var p0 = [0, 0]; var p1 = [this._width, 0]; var p2 = [this._width, this._height]; var p3 = [0, this._height]; var p4 = [this._width / 2, -50]; // covert coordinate to global space p0 = matrixUtil.transformVector(p0, this._transform); p1 = matrixUtil.transformVector(p1, this._transform); p2 = matrixUtil.transformVector(p2, this._transform); p3 = matrixUtil.transformVector(p3, this._transform); p4 = matrixUtil.transformVector(p4, this._transform); // move origin to this._center point p0 = matrixUtil.minusVector(p0, this._center); p1 = matrixUtil.minusVector(p1, this._center); p2 = matrixUtil.minusVector(p2, this._center); p3 = matrixUtil.minusVector(p3, this._center); p4 = matrixUtil.minusVector(p4, this._center); // rotate with element's rotation p0 = matrixUtil.rotateVector(p0, -this._rotation); p1 = matrixUtil.rotateVector(p1, -this._rotation); p2 = matrixUtil.rotateVector(p2, -this._rotation); p3 = matrixUtil.rotateVector(p3, -this._rotation); p4 = matrixUtil.rotateVector(p4, -this._rotation); return [p0, p1, p2, p3, p4, this._center]; } /** * @private * @method transformMousePoint * Transform the cursor origin to the center point of bounding rect, then rotate the same angel as the element does. * * * 把光标的原点变换到边界矩形的中心点,并与元素保持相同的旋转角。 * * @param {*} x * @param {*} y */ }, { key: "transformMousePoint", value: function transformMousePoint(x, y) { var _matrixUtil$minusVect3 = matrixUtil.minusVector([x, y], this._center); var _matrixUtil$minusVect4 = _slicedToArray(_matrixUtil$minusVect3, 2); x = _matrixUtil$minusVect4[0]; y = _matrixUtil$minusVect4[1]; var _matrixUtil$rotateVec = matrixUtil.rotateVector([x, y], -this._rotation); var _matrixUtil$rotateVec2 = _slicedToArray(_matrixUtil$rotateVec, 2); x = _matrixUtil$rotateVec2[0]; y = _matrixUtil$rotateVec2[1]; //为什么这里的旋转是反向的? return [x, y]; } }]); return TransformMgr; }(); module.exports = TransformMgr;