| /** |
| * Group是一个容器,可以插入子节点,Group的变换也会被应用到子节点上 |
| * @module zrender/graphic/Group |
| * @example |
| * var Group = require('zrender/container/Group'); |
| * var Circle = require('zrender/graphic/shape/Circle'); |
| * var g = new Group(); |
| * g.position[0] = 100; |
| * g.position[1] = 100; |
| * g.add(new Circle({ |
| * style: { |
| * x: 100, |
| * y: 100, |
| * r: 20, |
| * } |
| * })); |
| * zr.add(g); |
| */ |
| import * as zrUtil from '../core/util'; |
| import Element from '../Element'; |
| import BoundingRect from '../core/BoundingRect'; |
| /** |
| * @alias module:zrender/graphic/Group |
| * @constructor |
| * @extends module:zrender/mixin/Transformable |
| * @extends module:zrender/mixin/Eventful |
| */ |
| |
| var Group = function (opts) { |
| opts = opts || {}; |
| Element.call(this, opts); |
| |
| for (var key in opts) { |
| if (opts.hasOwnProperty(key)) { |
| this[key] = opts[key]; |
| } |
| } |
| |
| this._children = []; |
| this.__storage = null; |
| this.__dirty = true; |
| }; |
| |
| Group.prototype = { |
| constructor: Group, |
| isGroup: true, |
| |
| /** |
| * @type {string} |
| */ |
| type: 'group', |
| |
| /** |
| * 所有子孙元素是否响应鼠标事件 |
| * @name module:/zrender/container/Group#silent |
| * @type {boolean} |
| * @default false |
| */ |
| silent: false, |
| |
| /** |
| * @return {Array.<module:zrender/Element>} |
| */ |
| children: function () { |
| return this._children.slice(); |
| }, |
| |
| /** |
| * 获取指定 index 的儿子节点 |
| * @param {number} idx |
| * @return {module:zrender/Element} |
| */ |
| childAt: function (idx) { |
| return this._children[idx]; |
| }, |
| |
| /** |
| * 获取指定名字的儿子节点 |
| * @param {string} name |
| * @return {module:zrender/Element} |
| */ |
| childOfName: function (name) { |
| var children = this._children; |
| |
| for (var i = 0; i < children.length; i++) { |
| if (children[i].name === name) { |
| return children[i]; |
| } |
| } |
| }, |
| |
| /** |
| * @return {number} |
| */ |
| childCount: function () { |
| return this._children.length; |
| }, |
| |
| /** |
| * 添加子节点到最后 |
| * @param {module:zrender/Element} child |
| */ |
| add: function (child) { |
| if (child && child !== this && child.parent !== this) { |
| this._children.push(child); |
| |
| this._doAdd(child); |
| } |
| |
| return this; |
| }, |
| |
| /** |
| * 添加子节点在 nextSibling 之前 |
| * @param {module:zrender/Element} child |
| * @param {module:zrender/Element} nextSibling |
| */ |
| addBefore: function (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; |
| }, |
| _doAdd: function (child) { |
| if (child.parent) { |
| child.parent.remove(child); |
| } |
| |
| child.parent = this; |
| var storage = this.__storage; |
| var zr = this.__zr; |
| |
| if (storage && storage !== child.__storage) { |
| storage.addToStorage(child); |
| |
| if (child instanceof Group) { |
| child.addChildrenToStorage(storage); |
| } |
| } |
| |
| zr && zr.refresh(); |
| }, |
| |
| /** |
| * 移除子节点 |
| * @param {module:zrender/Element} child |
| */ |
| remove: function (child) { |
| var zr = this.__zr; |
| var storage = this.__storage; |
| var children = this._children; |
| var idx = zrUtil.indexOf(children, child); |
| |
| if (idx < 0) { |
| return this; |
| } |
| |
| children.splice(idx, 1); |
| child.parent = null; |
| |
| if (storage) { |
| storage.delFromStorage(child); |
| |
| if (child instanceof Group) { |
| child.delChildrenFromStorage(storage); |
| } |
| } |
| |
| zr && zr.refresh(); |
| return this; |
| }, |
| |
| /** |
| * 移除所有子节点 |
| */ |
| removeAll: function () { |
| var children = this._children; |
| var storage = this.__storage; |
| var child; |
| var i; |
| |
| for (i = 0; i < children.length; i++) { |
| child = children[i]; |
| |
| if (storage) { |
| storage.delFromStorage(child); |
| |
| if (child instanceof Group) { |
| child.delChildrenFromStorage(storage); |
| } |
| } |
| |
| child.parent = null; |
| } |
| |
| children.length = 0; |
| return this; |
| }, |
| |
| /** |
| * 遍历所有子节点 |
| * @param {Function} cb |
| * @param {} context |
| */ |
| eachChild: function (cb, context) { |
| var children = this._children; |
| |
| for (var i = 0; i < children.length; i++) { |
| var child = children[i]; |
| cb.call(context, child, i); |
| } |
| |
| return this; |
| }, |
| |
| /** |
| * 深度优先遍历所有子孙节点 |
| * @param {Function} cb |
| * @param {} context |
| */ |
| traverse: function (cb, context) { |
| for (var i = 0; i < this._children.length; i++) { |
| var child = this._children[i]; |
| cb.call(context, child); |
| |
| if (child.type === 'group') { |
| child.traverse(cb, context); |
| } |
| } |
| |
| return this; |
| }, |
| addChildrenToStorage: function (storage) { |
| for (var i = 0; i < this._children.length; i++) { |
| var child = this._children[i]; |
| storage.addToStorage(child); |
| |
| if (child instanceof Group) { |
| child.addChildrenToStorage(storage); |
| } |
| } |
| }, |
| delChildrenFromStorage: function (storage) { |
| for (var i = 0; i < this._children.length; i++) { |
| var child = this._children[i]; |
| storage.delFromStorage(child); |
| |
| if (child instanceof Group) { |
| child.delChildrenFromStorage(storage); |
| } |
| } |
| }, |
| dirty: function () { |
| this.__dirty = true; |
| this.__zr && this.__zr.refresh(); |
| return this; |
| }, |
| |
| /** |
| * @return {module:zrender/core/BoundingRect} |
| */ |
| getBoundingRect: function (includeChildren) { |
| // TODO Caching |
| var rect = null; |
| var tmpRect = new BoundingRect(0, 0, 0, 0); |
| var children = includeChildren || this._children; |
| var tmpMat = []; |
| |
| for (var i = 0; i < children.length; i++) { |
| var child = children[i]; |
| |
| if (child.ignore || child.invisible) { |
| continue; |
| } |
| |
| var childRect = child.getBoundingRect(); |
| var transform = child.getLocalTransform(tmpMat); // 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; |
| } |
| }; |
| zrUtil.inherits(Group, Element); |
| export default Group; |