var dataUtil = require("../utils/data_structure_util"); var Element = require("./Element"); var Rect = require("./shape/Rect"); function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 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; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } /** * @class qrenderer.graphic.Group * * - Group can have child nodes, not the other Element types. * - The transformations applied to Group will apply to its children too. * * - Group 可以插入子节点,其它类型不能。 * - Group 上的变换也会被应用到子节点上。 */ var Group = /*#__PURE__*/ function (_Rect) { _inherits(Group, _Rect); /** * @method constructor Group */ function Group() { var _this; var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, Group); _this = _possibleConstructorReturn(this, _getPrototypeOf(Group).call(this, dataUtil.merge({ style: { fill: '#ccc' } }, options, true))); /** * @property {String} type */ _this.type = 'group'; /** * @property {String} resizeStrategy * - free: The group will not resitrict child nodes' positions, all child nodes are free to move. * - resize: The group will auto resize according to the position of child nodes. * - restrict: The group will restrict the position of child nodes, no child nodes can move outside group area. * * * - free: Group 不会限制子节点的位置,所有子节点都可以自由移动。 * - resize: Group 会自动调整自己的尺寸来适配子节点的位置。 * - restrict: Group 会限制子节点的位置,子节点只能在 group 内部移动,不能超出 group 的范围。 */ _this.resizeStrategy = 'resize'; // free, resize, restrict /** * @property children */ _this.children = []; /** * @private * @property __storage */ _this.__storage = null; return _this; } /** * @method buildPath * 绘制元素路径 * @param {Object} ctx * @param {String} shape */ _createClass(Group, [{ key: "buildPath", value: function buildPath(ctx, shape) { Rect.prototype.buildPath.call(this, ctx, shape); } /** * @method add * 添加子节点到最后 * @param {Element} child */ }, { key: "add", value: function add(child) { if (child && child !== this && child.parent !== this) { this._doAdd(child); } return this; } /** * @method addBefore * 添加子节点在 nextSibling 之前 * @param {Element} child * @param {Element} nextSibling */ }, { key: "addBefore", value: function addBefore(child, nextSibling) { if (child && child !== this && child.parent !== this && nextSibling && nextSibling.parent === this) { var children = this.children; var idx = children.indexOf(nextSibling); if (idx >= 0) { children.splice(idx, 0, child); this._doAdd(child); } } return this; } /** * @private * @method _doAdd * @param {*} child */ }, { key: "_doAdd", value: function _doAdd(child) { child.parent && child.parent.remove(child); child.parent = this; this.children.push(child); this.__qr && (child.__qr = this.__qr); this.__storage && this.__storage.addToStorage(child); //listen to moving and resizing evnets. child.beforeMove = this.beforeChildMove; child.on("moving", this.childEventHandler, this); child.on("resizing", this.childEventHandler, this); } }, { key: "childEventHandler", value: function childEventHandler(child) { if (this.resizeStrategy === 'free') { return; } else if (this.resizeStrategy === 'resize') { this.resizeGroup(child); } } //执行上下文是子元素对象 }, { key: "beforeChildMove", value: function beforeChildMove(dx, dy, event) { var group = this.parent; if (group.resizeStrategy === 'free') { return true; } var groupOriginalRect = group.originalBoundingRect; var groupRect = group.getOuterBoundingRect(); var childRect = this.getOuterBoundingRect(); if (this.position[0] < 0) { this.position[0] = 0; return false; } if (this.position[1] < 0) { this.position[1] = 0; return false; } if (group.resizeStrategy === 'restrict') { var tempWidth = childRect.x2 - groupRect.x1; if (tempWidth > groupOriginalRect.width) { this.position[0] = groupOriginalRect.width - childRect.width; return false; } var tempHeight = childRect.y2 - groupRect.y1; if (tempHeight > groupOriginalRect.height) { this.position[1] = groupOriginalRect.height - childRect.height; return false; } } return true; } }, { key: "resizeGroup", value: function resizeGroup(child) { var groupOriginalRect = this.originalBoundingRect; var groupRect = this.getOuterBoundingRect(); var childRect = child.getOuterBoundingRect(); var newWidth = groupOriginalRect.width; var newHeight = groupOriginalRect.height; if (child.position[0] >= 0) { var temp = childRect.x2 - groupRect.x1; if (temp > groupOriginalRect.width) { newWidth = temp; } } if (child.position[1] >= 0) { var _temp = childRect.y2 - groupRect.y1; if (_temp > groupOriginalRect.height) { newHeight = _temp; } } this.shape.width = newWidth; this.shape.height = newHeight; this.dirty(); this.trigger("resizing", this); } /** * @method remove * 移除子节点 * @param {Element} child */ }, { key: "remove", value: function remove(child) { child.beforeMove = null; child.off("moving", this.childEventHandler, this); child.off("resizing", this.childEventHandler, this); var idx = dataUtil.indexOf(this.children, child); if (idx >= 0) { this.children.splice(idx, 1); this.__storage && this.__storage.delFromStorage(child); } return this; } /** * @method removeAll * 移除所有子节点 */ }, { key: "removeAll", value: function removeAll() { var storage = this.__storage; this.children.forEach(function (child, index) { storage && storage.delFromStorage(child); child.parent = null; }); this.children.length = 0; return this; } /** * @method eachChild * 遍历所有子节点 * @param {Function} cb * @param {Object} context */ }, { key: "eachChild", value: function eachChild(cb, context) { this.children.forEach(function (child, index) { cb.call(context, child); }); return this; } /** * @method traverse * 深度优先遍历所有子孙节点 * @param {Function} cb * @param {Object} context */ }, { key: "traverse", value: function traverse(cb, context) { this.children.forEach(function (child, index) { cb.call(context, child); if (child.type === 'group') { child.traverse(cb, context); } }); return this; } /** * @method addToStorage * Override addToStorage method of super class. * @param {qrenderer.core.Storage} storage */ }, { key: "addToStorageHandler", value: function addToStorageHandler(storage) { var _this2 = this; //首先把子元素添加到 storage this.children.forEach(function (child, index) { child.parent = _this2; child.__qr = _this2.__qr; storage.addToStorage(child); }); //然后在调用父层的处理函数添加自身 Element.prototype.addToStorageHandler.call(this, storage); } /** * @method delFromStorageHandler * Override delFromStorageHandler method of super class. * @param {qrenderer.core.Storage} storage */ }, { key: "delFromStorageHandler", value: function delFromStorageHandler(storage) { //首先把子元素从 storage 中删除 this.children.forEach(function (child, index) { child.parent = null; storage.delFromStorage(child); }); //然后在调用父层的处理函数删除自身 Element.prototype.delFromStorageHandler.call(this, storage); } }, { key: "toJSONObject", value: function toJSONObject() { var result = Element.prototype.toJSONObject.call(this); result.linkable = this.linkable; result.children = []; this.children.forEach(function (child, index) { result.children.push(child.toJSONObject()); }); return result; } // /**FIXME:refactor this method // * @method getBoundingRect // * @return {BoundingRect} // */ // getBoundingRect(includeChildren) { // // TODO Caching // let rect = null; // let tmpRect = new BoundingRect(0, 0, 0, 0); // let children = includeChildren || this.children; // for (let i = 0; i < children.length; i++) { // let child = children[i]; // if (child.ignore || child.invisible) { // continue; // } // let childRect = child.getBoundingRect(); // let transform = child.getLocalTransform(); // // TODO: // // The boundingRect cacluated by transforming original // // rect may be bigger than the actual bundingRect when rotation // // is used. (Consider a circle rotated aginst its center, where // // the actual boundingRect should be the same as that not be // // rotated.) But we can not find better approach to calculate // // actual boundingRect yet, considering performance. // if (transform) { // tmpRect.copy(childRect); // tmpRect.applyTransform(transform); // rect = rect || tmpRect.clone(); // rect.union(tmpRect); // }else { // rect = rect || childRect.clone(); // rect.union(childRect); // } // } // return rect || tmpRect; // } }]); return Group; }(Rect); var _default = Group; module.exports = _default;