Storage.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /**
  2. * Storage内容仓库模块
  3. * @module zrender/Storage
  4. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  5. * @author errorrik (errorrik@gmail.com)
  6. * @author pissang (https://github.com/pissang/)
  7. */
  8. import * as util from './core/util';
  9. import env from './core/env';
  10. import Group from './container/Group';
  11. // Use timsort because in most case elements are partially sorted
  12. // https://jsfiddle.net/pissang/jr4x7mdm/8/
  13. import timsort from './core/timsort';
  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 () { // jshint ignore:line
  35. this._roots = [];
  36. this._displayList = [];
  37. this._displayListLen = 0;
  38. };
  39. Storage.prototype = {
  40. constructor: Storage,
  41. /**
  42. * @param {Function} cb
  43. *
  44. */
  45. traverse: function (cb, context) {
  46. for (var i = 0; i < this._roots.length; i++) {
  47. this._roots[i].traverse(cb, context);
  48. }
  49. },
  50. /**
  51. * 返回所有图形的绘制队列
  52. * @param {boolean} [update=false] 是否在返回前更新该数组
  53. * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效
  54. *
  55. * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}
  56. * @return {Array.<module:zrender/graphic/Displayable>}
  57. */
  58. getDisplayList: function (update, includeIgnore) {
  59. includeIgnore = includeIgnore || false;
  60. if (update) {
  61. this.updateDisplayList(includeIgnore);
  62. }
  63. return this._displayList;
  64. },
  65. /**
  66. * 更新图形的绘制队列。
  67. * 每次绘制前都会调用,该方法会先深度优先遍历整个树,更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中,
  68. * 最后根据绘制的优先级(zlevel > z > 插入顺序)排序得到绘制队列
  69. * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组
  70. */
  71. updateDisplayList: function (includeIgnore) {
  72. this._displayListLen = 0;
  73. var roots = this._roots;
  74. var displayList = this._displayList;
  75. for (var i = 0, len = roots.length; i < len; i++) {
  76. this._updateAndAddDisplayable(roots[i], null, includeIgnore);
  77. }
  78. displayList.length = this._displayListLen;
  79. // 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. }
  100. else {
  101. clipPaths = [];
  102. }
  103. var currentClipPath = userSetClipPath;
  104. var parentClipPath = el;
  105. // Recursively add clip path
  106. while (currentClipPath) {
  107. // clipPath 的变换是基于使用这个 clipPath 的元素
  108. currentClipPath.parent = parentClipPath;
  109. currentClipPath.updateTransform();
  110. clipPaths.push(currentClipPath);
  111. parentClipPath = currentClipPath;
  112. currentClipPath = currentClipPath.clipPath;
  113. }
  114. }
  115. if (el.isGroup) {
  116. var children = el._children;
  117. for (var i = 0; i < children.length; i++) {
  118. var child = children[i];
  119. // Force to mark as dirty if group is dirty
  120. // FIXME __dirtyPath ?
  121. if (el.__dirty) {
  122. child.__dirty = true;
  123. }
  124. this._updateAndAddDisplayable(child, clipPaths, includeIgnore);
  125. }
  126. // Mark group clean here
  127. el.__dirty = false;
  128. }
  129. else {
  130. el.__clipPaths = clipPaths;
  131. this._displayList[this._displayListLen++] = el;
  132. }
  133. },
  134. /**
  135. * 添加图形(Shape)或者组(Group)到根节点
  136. * @param {module:zrender/Element} el
  137. */
  138. addRoot: function (el) {
  139. if (el.__storage === this) {
  140. return;
  141. }
  142. if (el instanceof Group) {
  143. el.addChildrenToStorage(this);
  144. }
  145. this.addToStorage(el);
  146. this._roots.push(el);
  147. },
  148. /**
  149. * 删除指定的图形(Shape)或者组(Group)
  150. * @param {string|Array.<string>} [el] 如果为空清空整个Storage
  151. */
  152. delRoot: function (el) {
  153. if (el == null) {
  154. // 不指定el清空
  155. for (var i = 0; i < this._roots.length; i++) {
  156. var root = this._roots[i];
  157. if (root instanceof Group) {
  158. root.delChildrenFromStorage(this);
  159. }
  160. }
  161. this._roots = [];
  162. this._displayList = [];
  163. this._displayListLen = 0;
  164. return;
  165. }
  166. if (el instanceof Array) {
  167. for (var i = 0, l = el.length; i < l; i++) {
  168. this.delRoot(el[i]);
  169. }
  170. return;
  171. }
  172. var idx = util.indexOf(this._roots, el);
  173. if (idx >= 0) {
  174. this.delFromStorage(el);
  175. this._roots.splice(idx, 1);
  176. if (el instanceof Group) {
  177. el.delChildrenFromStorage(this);
  178. }
  179. }
  180. },
  181. addToStorage: function (el) {
  182. el.__storage = this;
  183. el.dirty(false);
  184. return this;
  185. },
  186. delFromStorage: function (el) {
  187. if (el) {
  188. el.__storage = null;
  189. }
  190. return this;
  191. },
  192. /**
  193. * 清空并且释放Storage
  194. */
  195. dispose: function () {
  196. this._renderList =
  197. this._roots = null;
  198. },
  199. displayableSortFunc: shapeCompareFunc
  200. };
  201. export default Storage;