Painter.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. var _config = require("./config");
  2. var devicePixelRatio = _config.devicePixelRatio;
  3. var util = require("./core/util");
  4. var log = require("./core/log");
  5. var BoundingRect = require("./core/BoundingRect");
  6. var timsort = require("./core/timsort");
  7. var Layer = require("./Layer");
  8. var requestAnimationFrame = require("./animation/requestAnimationFrame");
  9. var Image = require("./graphic/Image");
  10. /**
  11. * Default canvas painter
  12. * @module zrender/Painter
  13. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  14. * errorrik (errorrik@gmail.com)
  15. * pissang (https://www.github.com/pissang)
  16. */
  17. // PENDIGN
  18. // Layer exceeds MAX_PROGRESSIVE_LAYER_NUMBER may have some problem when flush directly second time.
  19. //
  20. // Maximum progressive layer. When exceeding this number. All elements will be drawed in the last layer.
  21. var MAX_PROGRESSIVE_LAYER_NUMBER = 5;
  22. function parseInt10(val) {
  23. return parseInt(val, 10);
  24. }
  25. function isLayerValid(layer) {
  26. if (!layer) {
  27. return false;
  28. }
  29. if (layer.__builtin__) {
  30. return true;
  31. }
  32. if (typeof layer.resize !== 'function' || typeof layer.refresh !== 'function') {
  33. return false;
  34. }
  35. return true;
  36. }
  37. function preProcessLayer(layer) {
  38. layer.__unusedCount++;
  39. }
  40. function postProcessLayer(layer) {
  41. if (layer.__unusedCount == 1) {
  42. layer.clear();
  43. }
  44. }
  45. var tmpRect = new BoundingRect(0, 0, 0, 0);
  46. var viewRect = new BoundingRect(0, 0, 0, 0);
  47. function isDisplayableCulled(el, width, height) {
  48. tmpRect.copy(el.getBoundingRect());
  49. if (el.transform) {
  50. tmpRect.applyTransform(el.transform);
  51. }
  52. viewRect.width = width;
  53. viewRect.height = height;
  54. return !tmpRect.intersect(viewRect);
  55. }
  56. function isClipPathChanged(clipPaths, prevClipPaths) {
  57. if (clipPaths == prevClipPaths) {
  58. // Can both be null or undefined
  59. return false;
  60. }
  61. if (!clipPaths || !prevClipPaths || clipPaths.length !== prevClipPaths.length) {
  62. return true;
  63. }
  64. for (var i = 0; i < clipPaths.length; i++) {
  65. if (clipPaths[i] !== prevClipPaths[i]) {
  66. return true;
  67. }
  68. }
  69. }
  70. function doClip(clipPaths, ctx) {
  71. for (var i = 0; i < clipPaths.length; i++) {
  72. var clipPath = clipPaths[i];
  73. clipPath.setTransform(ctx);
  74. ctx.beginPath();
  75. clipPath.buildPath(ctx, clipPath.shape);
  76. ctx.clip(); // Transform back
  77. clipPath.restoreTransform(ctx);
  78. }
  79. }
  80. function createRoot(width, height) {
  81. var domRoot = document.createElement('div'); // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬
  82. domRoot.style.cssText = ['position:relative', 'overflow:hidden', 'width:' + width + 'px', 'height:' + height + 'px', 'padding:0', 'margin:0', 'border-width:0'].join(';') + ';';
  83. return domRoot;
  84. }
  85. /**
  86. * @alias module:zrender/Painter
  87. * @constructor
  88. * @param {HTMLElement} root 绘图容器
  89. * @param {module:zrender/Storage} storage
  90. * @param {Object} opts
  91. */
  92. var Painter = function (root, storage, opts) {
  93. this.type = 'canvas'; // In node environment using node-canvas
  94. var singleCanvas = !root.nodeName // In node ?
  95. || root.nodeName.toUpperCase() === 'CANVAS';
  96. this._opts = opts = util.extend({}, opts || {});
  97. /**
  98. * @type {number}
  99. */
  100. this.dpr = opts.devicePixelRatio || devicePixelRatio;
  101. /**
  102. * @type {boolean}
  103. * @private
  104. */
  105. this._singleCanvas = singleCanvas;
  106. /**
  107. * 绘图容器
  108. * @type {HTMLElement}
  109. */
  110. this.root = root;
  111. var rootStyle = root.style;
  112. if (rootStyle) {
  113. rootStyle['-webkit-tap-highlight-color'] = 'transparent';
  114. rootStyle['-webkit-user-select'] = rootStyle['user-select'] = rootStyle['-webkit-touch-callout'] = 'none';
  115. root.innerHTML = '';
  116. }
  117. /**
  118. * @type {module:zrender/Storage}
  119. */
  120. this.storage = storage;
  121. /**
  122. * @type {Array.<number>}
  123. * @private
  124. */
  125. var zlevelList = this._zlevelList = [];
  126. /**
  127. * @type {Object.<string, module:zrender/Layer>}
  128. * @private
  129. */
  130. var layers = this._layers = {};
  131. /**
  132. * @type {Object.<string, Object>}
  133. * @type {private}
  134. */
  135. this._layerConfig = {};
  136. if (!singleCanvas) {
  137. this._width = this._getSize(0);
  138. this._height = this._getSize(1);
  139. var domRoot = this._domRoot = createRoot(this._width, this._height);
  140. root.appendChild(domRoot);
  141. } else {
  142. if (opts.width != null) {
  143. root.width = opts.width;
  144. }
  145. if (opts.height != null) {
  146. root.height = opts.height;
  147. } // Use canvas width and height directly
  148. var width = root.width;
  149. var height = root.height;
  150. this._width = width;
  151. this._height = height; // Create layer if only one given canvas
  152. // Device pixel ratio is fixed to 1 because given canvas has its specified width and height
  153. var mainLayer = new Layer(root, this, 1);
  154. mainLayer.initContext(); // FIXME Use canvas width and height
  155. // mainLayer.resize(width, height);
  156. layers[0] = mainLayer;
  157. zlevelList.push(0);
  158. this._domRoot = root;
  159. } // Layers for progressive rendering
  160. this._progressiveLayers = [];
  161. /**
  162. * @type {module:zrender/Layer}
  163. * @private
  164. */
  165. this._hoverlayer;
  166. this._hoverElements = [];
  167. };
  168. Painter.prototype = {
  169. constructor: Painter,
  170. getType: function () {
  171. return 'canvas';
  172. },
  173. /**
  174. * If painter use a single canvas
  175. * @return {boolean}
  176. */
  177. isSingleCanvas: function () {
  178. return this._singleCanvas;
  179. },
  180. /**
  181. * @return {HTMLDivElement}
  182. */
  183. getViewportRoot: function () {
  184. return this._domRoot;
  185. },
  186. getViewportRootOffset: function () {
  187. var viewportRoot = this.getViewportRoot();
  188. if (viewportRoot) {
  189. return {
  190. offsetLeft: viewportRoot.offsetLeft || 0,
  191. offsetTop: viewportRoot.offsetTop || 0
  192. };
  193. }
  194. },
  195. /**
  196. * 刷新
  197. * @param {boolean} [paintAll=false] 强制绘制所有displayable
  198. */
  199. refresh: function (paintAll) {
  200. var list = this.storage.getDisplayList(true);
  201. var zlevelList = this._zlevelList;
  202. this._paintList(list, paintAll); // Paint custum layers
  203. for (var i = 0; i < zlevelList.length; i++) {
  204. var z = zlevelList[i];
  205. var layer = this._layers[z];
  206. if (!layer.__builtin__ && layer.refresh) {
  207. layer.refresh();
  208. }
  209. }
  210. this.refreshHover();
  211. if (this._progressiveLayers.length) {
  212. this._startProgessive();
  213. }
  214. return this;
  215. },
  216. addHover: function (el, hoverStyle) {
  217. if (el.__hoverMir) {
  218. return;
  219. }
  220. var elMirror = new el.constructor({
  221. style: el.style,
  222. shape: el.shape
  223. });
  224. elMirror.__from = el;
  225. el.__hoverMir = elMirror;
  226. elMirror.setStyle(hoverStyle);
  227. this._hoverElements.push(elMirror);
  228. },
  229. removeHover: function (el) {
  230. var elMirror = el.__hoverMir;
  231. var hoverElements = this._hoverElements;
  232. var idx = util.indexOf(hoverElements, elMirror);
  233. if (idx >= 0) {
  234. hoverElements.splice(idx, 1);
  235. }
  236. el.__hoverMir = null;
  237. },
  238. clearHover: function (el) {
  239. var hoverElements = this._hoverElements;
  240. for (var i = 0; i < hoverElements.length; i++) {
  241. var from = hoverElements[i].__from;
  242. if (from) {
  243. from.__hoverMir = null;
  244. }
  245. }
  246. hoverElements.length = 0;
  247. },
  248. refreshHover: function () {
  249. var hoverElements = this._hoverElements;
  250. var len = hoverElements.length;
  251. var hoverLayer = this._hoverlayer;
  252. hoverLayer && hoverLayer.clear();
  253. if (!len) {
  254. return;
  255. }
  256. timsort(hoverElements, this.storage.displayableSortFunc); // Use a extream large zlevel
  257. // FIXME?
  258. if (!hoverLayer) {
  259. hoverLayer = this._hoverlayer = this.getLayer(1e5);
  260. }
  261. var scope = {};
  262. hoverLayer.ctx.save();
  263. for (var i = 0; i < len;) {
  264. var el = hoverElements[i];
  265. var originalEl = el.__from; // Original el is removed
  266. // PENDING
  267. if (!(originalEl && originalEl.__zr)) {
  268. hoverElements.splice(i, 1);
  269. originalEl.__hoverMir = null;
  270. len--;
  271. continue;
  272. }
  273. i++; // Use transform
  274. // FIXME style and shape ?
  275. if (!originalEl.invisible) {
  276. el.transform = originalEl.transform;
  277. el.invTransform = originalEl.invTransform;
  278. el.__clipPaths = originalEl.__clipPaths; // el.
  279. this._doPaintEl(el, hoverLayer, true, scope);
  280. }
  281. }
  282. hoverLayer.ctx.restore();
  283. },
  284. _startProgessive: function () {
  285. var self = this;
  286. if (!self._furtherProgressive) {
  287. return;
  288. } // Use a token to stop progress steps triggered by
  289. // previous zr.refresh calling.
  290. var token = self._progressiveToken = +new Date();
  291. self._progress++;
  292. requestAnimationFrame(step);
  293. function step() {
  294. // In case refreshed or disposed
  295. if (token === self._progressiveToken && self.storage) {
  296. self._doPaintList(self.storage.getDisplayList());
  297. if (self._furtherProgressive) {
  298. self._progress++;
  299. requestAnimationFrame(step);
  300. } else {
  301. self._progressiveToken = -1;
  302. }
  303. }
  304. }
  305. },
  306. _clearProgressive: function () {
  307. this._progressiveToken = -1;
  308. this._progress = 0;
  309. util.each(this._progressiveLayers, function (layer) {
  310. layer.__dirty && layer.clear();
  311. });
  312. },
  313. _paintList: function (list, paintAll) {
  314. if (paintAll == null) {
  315. paintAll = false;
  316. }
  317. this._updateLayerStatus(list);
  318. this._clearProgressive();
  319. this.eachBuiltinLayer(preProcessLayer);
  320. this._doPaintList(list, paintAll);
  321. this.eachBuiltinLayer(postProcessLayer);
  322. },
  323. _doPaintList: function (list, paintAll) {
  324. var currentLayer;
  325. var currentZLevel;
  326. var ctx; // var invTransform = [];
  327. var scope;
  328. var progressiveLayerIdx = 0;
  329. var currentProgressiveLayer;
  330. var width = this._width;
  331. var height = this._height;
  332. var layerProgress;
  333. var frame = this._progress;
  334. function flushProgressiveLayer(layer) {
  335. var dpr = ctx.dpr || 1;
  336. ctx.save();
  337. ctx.globalAlpha = 1;
  338. ctx.shadowBlur = 0; // Avoid layer don't clear in next progressive frame
  339. currentLayer.__dirty = true;
  340. ctx.setTransform(1, 0, 0, 1, 0, 0);
  341. ctx.drawImage(layer.dom, 0, 0, width * dpr, height * dpr);
  342. ctx.restore();
  343. }
  344. for (var i = 0, l = list.length; i < l; i++) {
  345. var el = list[i];
  346. var elZLevel = this._singleCanvas ? 0 : el.zlevel;
  347. var elFrame = el.__frame; // Flush at current context
  348. // PENDING
  349. if (elFrame < 0 && currentProgressiveLayer) {
  350. flushProgressiveLayer(currentProgressiveLayer);
  351. currentProgressiveLayer = null;
  352. } // Change draw layer
  353. if (currentZLevel !== elZLevel) {
  354. if (ctx) {
  355. ctx.restore();
  356. } // Reset scope
  357. scope = {}; // Only 0 zlevel if only has one canvas
  358. currentZLevel = elZLevel;
  359. currentLayer = this.getLayer(currentZLevel);
  360. if (!currentLayer.__builtin__) {
  361. log('ZLevel ' + currentZLevel + ' has been used by unkown layer ' + currentLayer.id);
  362. }
  363. ctx = currentLayer.ctx;
  364. ctx.save(); // Reset the count
  365. currentLayer.__unusedCount = 0;
  366. if (currentLayer.__dirty || paintAll) {
  367. currentLayer.clear();
  368. }
  369. }
  370. if (!(currentLayer.__dirty || paintAll)) {
  371. continue;
  372. }
  373. if (elFrame >= 0) {
  374. // Progressive layer changed
  375. if (!currentProgressiveLayer) {
  376. currentProgressiveLayer = this._progressiveLayers[Math.min(progressiveLayerIdx++, MAX_PROGRESSIVE_LAYER_NUMBER - 1)];
  377. currentProgressiveLayer.ctx.save();
  378. currentProgressiveLayer.renderScope = {};
  379. if (currentProgressiveLayer && currentProgressiveLayer.__progress > currentProgressiveLayer.__maxProgress) {
  380. // flushProgressiveLayer(currentProgressiveLayer);
  381. // Quick jump all progressive elements
  382. // All progressive element are not dirty, jump over and flush directly
  383. i = currentProgressiveLayer.__nextIdxNotProg - 1; // currentProgressiveLayer = null;
  384. continue;
  385. }
  386. layerProgress = currentProgressiveLayer.__progress;
  387. if (!currentProgressiveLayer.__dirty) {
  388. // Keep rendering
  389. frame = layerProgress;
  390. }
  391. currentProgressiveLayer.__progress = frame + 1;
  392. }
  393. if (elFrame === frame) {
  394. this._doPaintEl(el, currentProgressiveLayer, true, currentProgressiveLayer.renderScope);
  395. }
  396. } else {
  397. this._doPaintEl(el, currentLayer, paintAll, scope);
  398. }
  399. el.__dirty = false;
  400. }
  401. if (currentProgressiveLayer) {
  402. flushProgressiveLayer(currentProgressiveLayer);
  403. } // Restore the lastLayer ctx
  404. ctx && ctx.restore(); // If still has clipping state
  405. // if (scope.prevElClipPaths) {
  406. // ctx.restore();
  407. // }
  408. this._furtherProgressive = false;
  409. util.each(this._progressiveLayers, function (layer) {
  410. if (layer.__maxProgress >= layer.__progress) {
  411. this._furtherProgressive = true;
  412. }
  413. }, this);
  414. },
  415. _doPaintEl: function (el, currentLayer, forcePaint, scope) {
  416. var ctx = currentLayer.ctx;
  417. var m = el.transform;
  418. if ((currentLayer.__dirty || forcePaint) && // Ignore invisible element
  419. !el.invisible // Ignore transparent element
  420. && el.style.opacity !== 0 // Ignore scale 0 element, in some environment like node-canvas
  421. // Draw a scale 0 element can cause all following draw wrong
  422. // And setTransform with scale 0 will cause set back transform failed.
  423. && !(m && !m[0] && !m[3]) // Ignore culled element
  424. && !(el.culling && isDisplayableCulled(el, this._width, this._height))) {
  425. var clipPaths = el.__clipPaths; // Optimize when clipping on group with several elements
  426. if (scope.prevClipLayer !== currentLayer || isClipPathChanged(clipPaths, scope.prevElClipPaths)) {
  427. // If has previous clipping state, restore from it
  428. if (scope.prevElClipPaths) {
  429. scope.prevClipLayer.ctx.restore();
  430. scope.prevClipLayer = scope.prevElClipPaths = null; // Reset prevEl since context has been restored
  431. scope.prevEl = null;
  432. } // New clipping state
  433. if (clipPaths) {
  434. ctx.save();
  435. doClip(clipPaths, ctx);
  436. scope.prevClipLayer = currentLayer;
  437. scope.prevElClipPaths = clipPaths;
  438. }
  439. }
  440. el.beforeBrush && el.beforeBrush(ctx);
  441. el.brush(ctx, scope.prevEl || null);
  442. scope.prevEl = el;
  443. el.afterBrush && el.afterBrush(ctx);
  444. }
  445. },
  446. /**
  447. * 获取 zlevel 所在层,如果不存在则会创建一个新的层
  448. * @param {number} zlevel
  449. * @return {module:zrender/Layer}
  450. */
  451. getLayer: function (zlevel) {
  452. if (this._singleCanvas) {
  453. return this._layers[0];
  454. }
  455. var layer = this._layers[zlevel];
  456. if (!layer) {
  457. // Create a new layer
  458. layer = new Layer('zr_' + zlevel, this, this.dpr);
  459. layer.__builtin__ = true;
  460. if (this._layerConfig[zlevel]) {
  461. util.merge(layer, this._layerConfig[zlevel], true);
  462. }
  463. this.insertLayer(zlevel, layer); // Context is created after dom inserted to document
  464. // Or excanvas will get 0px clientWidth and clientHeight
  465. layer.initContext();
  466. }
  467. return layer;
  468. },
  469. insertLayer: function (zlevel, layer) {
  470. var layersMap = this._layers;
  471. var zlevelList = this._zlevelList;
  472. var len = zlevelList.length;
  473. var prevLayer = null;
  474. var i = -1;
  475. var domRoot = this._domRoot;
  476. if (layersMap[zlevel]) {
  477. log('ZLevel ' + zlevel + ' has been used already');
  478. return;
  479. } // Check if is a valid layer
  480. if (!isLayerValid(layer)) {
  481. log('Layer of zlevel ' + zlevel + ' is not valid');
  482. return;
  483. }
  484. if (len > 0 && zlevel > zlevelList[0]) {
  485. for (i = 0; i < len - 1; i++) {
  486. if (zlevelList[i] < zlevel && zlevelList[i + 1] > zlevel) {
  487. break;
  488. }
  489. }
  490. prevLayer = layersMap[zlevelList[i]];
  491. }
  492. zlevelList.splice(i + 1, 0, zlevel);
  493. layersMap[zlevel] = layer; // Vitual layer will not directly show on the screen.
  494. // (It can be a WebGL layer and assigned to a ZImage element)
  495. // But it still under management of zrender.
  496. if (!layer.virtual) {
  497. if (prevLayer) {
  498. var prevDom = prevLayer.dom;
  499. if (prevDom.nextSibling) {
  500. domRoot.insertBefore(layer.dom, prevDom.nextSibling);
  501. } else {
  502. domRoot.appendChild(layer.dom);
  503. }
  504. } else {
  505. if (domRoot.firstChild) {
  506. domRoot.insertBefore(layer.dom, domRoot.firstChild);
  507. } else {
  508. domRoot.appendChild(layer.dom);
  509. }
  510. }
  511. }
  512. },
  513. // Iterate each layer
  514. eachLayer: function (cb, context) {
  515. var zlevelList = this._zlevelList;
  516. var z;
  517. var i;
  518. for (i = 0; i < zlevelList.length; i++) {
  519. z = zlevelList[i];
  520. cb.call(context, this._layers[z], z);
  521. }
  522. },
  523. // Iterate each buildin layer
  524. eachBuiltinLayer: function (cb, context) {
  525. var zlevelList = this._zlevelList;
  526. var layer;
  527. var z;
  528. var i;
  529. for (i = 0; i < zlevelList.length; i++) {
  530. z = zlevelList[i];
  531. layer = this._layers[z];
  532. if (layer.__builtin__) {
  533. cb.call(context, layer, z);
  534. }
  535. }
  536. },
  537. // Iterate each other layer except buildin layer
  538. eachOtherLayer: function (cb, context) {
  539. var zlevelList = this._zlevelList;
  540. var layer;
  541. var z;
  542. var i;
  543. for (i = 0; i < zlevelList.length; i++) {
  544. z = zlevelList[i];
  545. layer = this._layers[z];
  546. if (!layer.__builtin__) {
  547. cb.call(context, layer, z);
  548. }
  549. }
  550. },
  551. /**
  552. * 获取所有已创建的层
  553. * @param {Array.<module:zrender/Layer>} [prevLayer]
  554. */
  555. getLayers: function () {
  556. return this._layers;
  557. },
  558. _updateLayerStatus: function (list) {
  559. var layers = this._layers;
  560. var progressiveLayers = this._progressiveLayers;
  561. var elCountsLastFrame = {};
  562. var progressiveElCountsLastFrame = {};
  563. this.eachBuiltinLayer(function (layer, z) {
  564. elCountsLastFrame[z] = layer.elCount;
  565. layer.elCount = 0;
  566. layer.__dirty = false;
  567. });
  568. util.each(progressiveLayers, function (layer, idx) {
  569. progressiveElCountsLastFrame[idx] = layer.elCount;
  570. layer.elCount = 0;
  571. layer.__dirty = false;
  572. });
  573. var progressiveLayerCount = 0;
  574. var currentProgressiveLayer;
  575. var lastProgressiveKey;
  576. var frameCount = 0;
  577. for (var i = 0, l = list.length; i < l; i++) {
  578. var el = list[i];
  579. var zlevel = this._singleCanvas ? 0 : el.zlevel;
  580. var layer = layers[zlevel];
  581. var elProgress = el.progressive;
  582. if (layer) {
  583. layer.elCount++;
  584. layer.__dirty = layer.__dirty || el.__dirty;
  585. } /////// Update progressive
  586. if (elProgress >= 0) {
  587. // Fix wrong progressive sequence problem.
  588. if (lastProgressiveKey !== elProgress) {
  589. lastProgressiveKey = elProgress;
  590. frameCount++;
  591. }
  592. var elFrame = el.__frame = frameCount - 1;
  593. if (!currentProgressiveLayer) {
  594. var idx = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER - 1);
  595. currentProgressiveLayer = progressiveLayers[idx];
  596. if (!currentProgressiveLayer) {
  597. currentProgressiveLayer = progressiveLayers[idx] = new Layer('progressive', this, this.dpr);
  598. currentProgressiveLayer.initContext();
  599. }
  600. currentProgressiveLayer.__maxProgress = 0;
  601. }
  602. currentProgressiveLayer.__dirty = currentProgressiveLayer.__dirty || el.__dirty;
  603. currentProgressiveLayer.elCount++;
  604. currentProgressiveLayer.__maxProgress = Math.max(currentProgressiveLayer.__maxProgress, elFrame);
  605. if (currentProgressiveLayer.__maxProgress >= currentProgressiveLayer.__progress) {
  606. // Should keep rendering this layer because progressive rendering is not finished yet
  607. layer.__dirty = true;
  608. }
  609. } else {
  610. el.__frame = -1;
  611. if (currentProgressiveLayer) {
  612. currentProgressiveLayer.__nextIdxNotProg = i;
  613. progressiveLayerCount++;
  614. currentProgressiveLayer = null;
  615. }
  616. }
  617. }
  618. if (currentProgressiveLayer) {
  619. progressiveLayerCount++;
  620. currentProgressiveLayer.__nextIdxNotProg = i;
  621. } // 层中的元素数量有发生变化
  622. this.eachBuiltinLayer(function (layer, z) {
  623. if (elCountsLastFrame[z] !== layer.elCount) {
  624. layer.__dirty = true;
  625. }
  626. });
  627. progressiveLayers.length = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER);
  628. util.each(progressiveLayers, function (layer, idx) {
  629. if (progressiveElCountsLastFrame[idx] !== layer.elCount) {
  630. el.__dirty = true;
  631. }
  632. if (layer.__dirty) {
  633. layer.__progress = 0;
  634. }
  635. });
  636. },
  637. /**
  638. * 清除hover层外所有内容
  639. */
  640. clear: function () {
  641. this.eachBuiltinLayer(this._clearLayer);
  642. return this;
  643. },
  644. _clearLayer: function (layer) {
  645. layer.clear();
  646. },
  647. /**
  648. * 修改指定zlevel的绘制参数
  649. *
  650. * @param {string} zlevel
  651. * @param {Object} config 配置对象
  652. * @param {string} [config.clearColor=0] 每次清空画布的颜色
  653. * @param {string} [config.motionBlur=false] 是否开启动态模糊
  654. * @param {number} [config.lastFrameAlpha=0.7]
  655. * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显
  656. */
  657. configLayer: function (zlevel, config) {
  658. if (config) {
  659. var layerConfig = this._layerConfig;
  660. if (!layerConfig[zlevel]) {
  661. layerConfig[zlevel] = config;
  662. } else {
  663. util.merge(layerConfig[zlevel], config, true);
  664. }
  665. var layer = this._layers[zlevel];
  666. if (layer) {
  667. util.merge(layer, layerConfig[zlevel], true);
  668. }
  669. }
  670. },
  671. /**
  672. * 删除指定层
  673. * @param {number} zlevel 层所在的zlevel
  674. */
  675. delLayer: function (zlevel) {
  676. var layers = this._layers;
  677. var zlevelList = this._zlevelList;
  678. var layer = layers[zlevel];
  679. if (!layer) {
  680. return;
  681. }
  682. layer.dom.parentNode.removeChild(layer.dom);
  683. delete layers[zlevel];
  684. zlevelList.splice(util.indexOf(zlevelList, zlevel), 1);
  685. },
  686. /**
  687. * 区域大小变化后重绘
  688. */
  689. resize: function (width, height) {
  690. var domRoot = this._domRoot; // FIXME Why ?
  691. domRoot.style.display = 'none'; // Save input w/h
  692. var opts = this._opts;
  693. width != null && (opts.width = width);
  694. height != null && (opts.height = height);
  695. width = this._getSize(0);
  696. height = this._getSize(1);
  697. domRoot.style.display = ''; // 优化没有实际改变的resize
  698. if (this._width != width || height != this._height) {
  699. domRoot.style.width = width + 'px';
  700. domRoot.style.height = height + 'px';
  701. for (var id in this._layers) {
  702. if (this._layers.hasOwnProperty(id)) {
  703. this._layers[id].resize(width, height);
  704. }
  705. }
  706. util.each(this._progressiveLayers, function (layer) {
  707. layer.resize(width, height);
  708. });
  709. this.refresh(true);
  710. }
  711. this._width = width;
  712. this._height = height;
  713. return this;
  714. },
  715. /**
  716. * 清除单独的一个层
  717. * @param {number} zlevel
  718. */
  719. clearLayer: function (zlevel) {
  720. var layer = this._layers[zlevel];
  721. if (layer) {
  722. layer.clear();
  723. }
  724. },
  725. /**
  726. * 释放
  727. */
  728. dispose: function () {
  729. this.root.innerHTML = '';
  730. this.root = this.storage = this._domRoot = this._layers = null;
  731. },
  732. /**
  733. * Get canvas which has all thing rendered
  734. * @param {Object} opts
  735. * @param {string} [opts.backgroundColor]
  736. * @param {number} [opts.pixelRatio]
  737. */
  738. getRenderedCanvas: function (opts) {
  739. opts = opts || {};
  740. if (this._singleCanvas) {
  741. return this._layers[0].dom;
  742. }
  743. var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);
  744. imageLayer.initContext();
  745. imageLayer.clearColor = opts.backgroundColor;
  746. imageLayer.clear();
  747. var displayList = this.storage.getDisplayList(true);
  748. var scope = {};
  749. var zlevel;
  750. var self = this;
  751. function findAndDrawOtherLayer(smaller, larger) {
  752. var zlevelList = self._zlevelList;
  753. if (smaller == null) {
  754. smaller = -Infinity;
  755. }
  756. var intermediateLayer;
  757. for (var i = 0; i < zlevelList.length; i++) {
  758. var z = zlevelList[i];
  759. var layer = self._layers[z];
  760. if (!layer.__builtin__ && z > smaller && z < larger) {
  761. intermediateLayer = layer;
  762. break;
  763. }
  764. }
  765. if (intermediateLayer && intermediateLayer.renderToCanvas) {
  766. imageLayer.ctx.save();
  767. intermediateLayer.renderToCanvas(imageLayer.ctx);
  768. imageLayer.ctx.restore();
  769. }
  770. }
  771. for (var i = 0; i < displayList.length; i++) {
  772. var el = displayList[i];
  773. if (el.zlevel !== zlevel) {
  774. findAndDrawOtherLayer(zlevel, el.zlevel);
  775. zlevel = el.zlevel;
  776. }
  777. this._doPaintEl(el, imageLayer, true, scope);
  778. }
  779. findAndDrawOtherLayer(zlevel, Infinity);
  780. return imageLayer.dom;
  781. },
  782. /**
  783. * 获取绘图区域宽度
  784. */
  785. getWidth: function () {
  786. return this._width;
  787. },
  788. /**
  789. * 获取绘图区域高度
  790. */
  791. getHeight: function () {
  792. return this._height;
  793. },
  794. _getSize: function (whIdx) {
  795. var opts = this._opts;
  796. var wh = ['width', 'height'][whIdx];
  797. var cwh = ['clientWidth', 'clientHeight'][whIdx];
  798. var plt = ['paddingLeft', 'paddingTop'][whIdx];
  799. var prb = ['paddingRight', 'paddingBottom'][whIdx];
  800. if (opts[wh] != null && opts[wh] !== 'auto') {
  801. return parseFloat(opts[wh]);
  802. }
  803. var root = this.root; // IE8 does not support getComputedStyle, but it use VML.
  804. var stl = document.defaultView.getComputedStyle(root);
  805. return (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) - (parseInt10(stl[plt]) || 0) - (parseInt10(stl[prb]) || 0) | 0;
  806. },
  807. pathToImage: function (path, dpr) {
  808. dpr = dpr || this.dpr;
  809. var canvas = document.createElement('canvas');
  810. var ctx = canvas.getContext('2d');
  811. var rect = path.getBoundingRect();
  812. var style = path.style;
  813. var shadowBlurSize = style.shadowBlur;
  814. var shadowOffsetX = style.shadowOffsetX;
  815. var shadowOffsetY = style.shadowOffsetY;
  816. var lineWidth = style.hasStroke() ? style.lineWidth : 0;
  817. var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);
  818. var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);
  819. var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);
  820. var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);
  821. var width = rect.width + leftMargin + rightMargin;
  822. var height = rect.height + topMargin + bottomMargin;
  823. canvas.width = width * dpr;
  824. canvas.height = height * dpr;
  825. ctx.scale(dpr, dpr);
  826. ctx.clearRect(0, 0, width, height);
  827. ctx.dpr = dpr;
  828. var pathTransform = {
  829. position: path.position,
  830. rotation: path.rotation,
  831. scale: path.scale
  832. };
  833. path.position = [leftMargin - rect.x, topMargin - rect.y];
  834. path.rotation = 0;
  835. path.scale = [1, 1];
  836. path.updateTransform();
  837. if (path) {
  838. path.brush(ctx);
  839. }
  840. var ImageShape = Image;
  841. var imgShape = new ImageShape({
  842. style: {
  843. x: 0,
  844. y: 0,
  845. image: canvas
  846. }
  847. });
  848. if (pathTransform.position != null) {
  849. imgShape.position = path.position = pathTransform.position;
  850. }
  851. if (pathTransform.rotation != null) {
  852. imgShape.rotation = path.rotation = pathTransform.rotation;
  853. }
  854. if (pathTransform.scale != null) {
  855. imgShape.scale = path.scale = pathTransform.scale;
  856. }
  857. return imgShape;
  858. }
  859. };
  860. var _default = Painter;
  861. module.exports = _default;