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;