Storage.js 5.9 KB

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