Storage.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. var util = require("./core/util");
  2. var env = require("./core/env");
  3. var Group = require("./container/Group");
  4. var timsort = require("./core/timsort");
  5. // Use timsort because in most case elements are partially sorted
  6. // https://jsfiddle.net/pissang/jr4x7mdm/8/
  7. function shapeCompareFunc(a, b) {
  8. if (a.zlevel === b.zlevel) {
  9. if (a.z === b.z) {
  10. // if (a.z2 === b.z2) {
  11. // // FIXME Slow has renderidx compare
  12. // // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement
  13. // // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012
  14. // return a.__renderidx - b.__renderidx;
  15. // }
  16. return a.z2 - b.z2;
  17. }
  18. return a.z - b.z;
  19. }
  20. return a.zlevel - b.zlevel;
  21. }
  22. /**
  23. * 内容仓库 (M)
  24. * @alias module:zrender/Storage
  25. * @constructor
  26. */
  27. var Storage = function () {
  28. // jshint ignore:line
  29. this._roots = [];
  30. this._displayList = [];
  31. this._displayListLen = 0;
  32. };
  33. Storage.prototype = {
  34. constructor: Storage,
  35. /**
  36. * @param {Function} cb
  37. *
  38. */
  39. traverse: function (cb, context) {
  40. for (var i = 0; i < this._roots.length; i++) {
  41. this._roots[i].traverse(cb, context);
  42. }
  43. },
  44. /**
  45. * 返回所有图形的绘制队列
  46. * @param {boolean} [update=false] 是否在返回前更新该数组
  47. * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效
  48. *
  49. * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}
  50. * @return {Array.<module:zrender/graphic/Displayable>}
  51. */
  52. getDisplayList: function (update, includeIgnore) {
  53. includeIgnore = includeIgnore || false;
  54. if (update) {
  55. this.updateDisplayList(includeIgnore);
  56. }
  57. return this._displayList;
  58. },
  59. /**
  60. * 更新图形的绘制队列。
  61. * 每次绘制前都会调用,该方法会先深度优先遍历整个树,更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中,
  62. * 最后根据绘制的优先级(zlevel > z > 插入顺序)排序得到绘制队列
  63. * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组
  64. */
  65. updateDisplayList: function (includeIgnore) {
  66. this._displayListLen = 0;
  67. var roots = this._roots;
  68. var displayList = this._displayList;
  69. for (var i = 0, len = roots.length; i < len; i++) {
  70. this._updateAndAddDisplayable(roots[i], null, includeIgnore);
  71. }
  72. displayList.length = this._displayListLen;
  73. env.canvasSupported && timsort(displayList, shapeCompareFunc);
  74. },
  75. _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {
  76. if (el.ignore && !includeIgnore) {
  77. return;
  78. }
  79. el.beforeUpdate();
  80. if (el.__dirty) {
  81. el.update();
  82. }
  83. el.afterUpdate();
  84. var userSetClipPath = el.clipPath;
  85. if (userSetClipPath) {
  86. // FIXME 效率影响
  87. if (clipPaths) {
  88. clipPaths = clipPaths.slice();
  89. } else {
  90. clipPaths = [];
  91. }
  92. var currentClipPath = userSetClipPath;
  93. var parentClipPath = el; // Recursively add clip path
  94. while (currentClipPath) {
  95. // clipPath 的变换是基于使用这个 clipPath 的元素
  96. currentClipPath.parent = parentClipPath;
  97. currentClipPath.updateTransform();
  98. clipPaths.push(currentClipPath);
  99. parentClipPath = currentClipPath;
  100. currentClipPath = currentClipPath.clipPath;
  101. }
  102. }
  103. if (el.isGroup) {
  104. var children = el._children;
  105. for (var i = 0; i < children.length; i++) {
  106. var child = children[i]; // Force to mark as dirty if group is dirty
  107. // FIXME __dirtyPath ?
  108. if (el.__dirty) {
  109. child.__dirty = true;
  110. }
  111. this._updateAndAddDisplayable(child, clipPaths, includeIgnore);
  112. } // Mark group clean here
  113. el.__dirty = false;
  114. } else {
  115. el.__clipPaths = clipPaths;
  116. this._displayList[this._displayListLen++] = el;
  117. }
  118. },
  119. /**
  120. * 添加图形(Shape)或者组(Group)到根节点
  121. * @param {module:zrender/Element} el
  122. */
  123. addRoot: function (el) {
  124. if (el.__storage === this) {
  125. return;
  126. }
  127. if (el instanceof Group) {
  128. el.addChildrenToStorage(this);
  129. }
  130. this.addToStorage(el);
  131. this._roots.push(el);
  132. },
  133. /**
  134. * 删除指定的图形(Shape)或者组(Group)
  135. * @param {string|Array.<string>} [el] 如果为空清空整个Storage
  136. */
  137. delRoot: function (el) {
  138. if (el == null) {
  139. // 不指定el清空
  140. for (var i = 0; i < this._roots.length; i++) {
  141. var root = this._roots[i];
  142. if (root instanceof Group) {
  143. root.delChildrenFromStorage(this);
  144. }
  145. }
  146. this._roots = [];
  147. this._displayList = [];
  148. this._displayListLen = 0;
  149. return;
  150. }
  151. if (el instanceof Array) {
  152. for (var i = 0, l = el.length; i < l; i++) {
  153. this.delRoot(el[i]);
  154. }
  155. return;
  156. }
  157. var idx = util.indexOf(this._roots, el);
  158. if (idx >= 0) {
  159. this.delFromStorage(el);
  160. this._roots.splice(idx, 1);
  161. if (el instanceof Group) {
  162. el.delChildrenFromStorage(this);
  163. }
  164. }
  165. },
  166. addToStorage: function (el) {
  167. if (el) {
  168. el.__storage = this;
  169. el.dirty(false);
  170. }
  171. return this;
  172. },
  173. delFromStorage: function (el) {
  174. if (el) {
  175. el.__storage = null;
  176. }
  177. return this;
  178. },
  179. /**
  180. * 清空并且释放Storage
  181. */
  182. dispose: function () {
  183. this._renderList = this._roots = null;
  184. },
  185. displayableSortFunc: shapeCompareFunc
  186. };
  187. var _default = Storage;
  188. module.exports = _default;