| var _config = require("./config"); | 
|   | 
| var devicePixelRatio = _config.devicePixelRatio; | 
|   | 
| var util = require("./core/util"); | 
|   | 
| var logError = require("./core/log"); | 
|   | 
| var BoundingRect = require("./core/BoundingRect"); | 
|   | 
| var timsort = require("./core/timsort"); | 
|   | 
| var Layer = require("./Layer"); | 
|   | 
| var requestAnimationFrame = require("./animation/requestAnimationFrame"); | 
|   | 
| var Image = require("./graphic/Image"); | 
|   | 
| var env = require("./core/env"); | 
|   | 
| var HOVER_LAYER_ZLEVEL = 1e5; | 
| var CANVAS_ZLEVEL = 314159; | 
| var EL_AFTER_INCREMENTAL_INC = 0.01; | 
| var INCREMENTAL_INC = 0.001; | 
|   | 
| function parseInt10(val) { | 
|   return parseInt(val, 10); | 
| } | 
|   | 
| function isLayerValid(layer) { | 
|   if (!layer) { | 
|     return false; | 
|   } | 
|   | 
|   if (layer.__builtin__) { | 
|     return true; | 
|   } | 
|   | 
|   if (typeof layer.resize !== 'function' || typeof layer.refresh !== 'function') { | 
|     return false; | 
|   } | 
|   | 
|   return true; | 
| } | 
|   | 
| var tmpRect = new BoundingRect(0, 0, 0, 0); | 
| var viewRect = new BoundingRect(0, 0, 0, 0); | 
|   | 
| function isDisplayableCulled(el, width, height) { | 
|   tmpRect.copy(el.getBoundingRect()); | 
|   | 
|   if (el.transform) { | 
|     tmpRect.applyTransform(el.transform); | 
|   } | 
|   | 
|   viewRect.width = width; | 
|   viewRect.height = height; | 
|   return !tmpRect.intersect(viewRect); | 
| } | 
|   | 
| function isClipPathChanged(clipPaths, prevClipPaths) { | 
|   // displayable.__clipPaths can only be `null`/`undefined` or an non-empty array. | 
|   if (clipPaths === prevClipPaths) { | 
|     return false; | 
|   } | 
|   | 
|   if (!clipPaths || !prevClipPaths || clipPaths.length !== prevClipPaths.length) { | 
|     return true; | 
|   } | 
|   | 
|   for (var i = 0; i < clipPaths.length; i++) { | 
|     if (clipPaths[i] !== prevClipPaths[i]) { | 
|       return true; | 
|     } | 
|   } | 
|   | 
|   return false; | 
| } | 
|   | 
| function doClip(clipPaths, ctx) { | 
|   for (var i = 0; i < clipPaths.length; i++) { | 
|     var clipPath = clipPaths[i]; | 
|     clipPath.setTransform(ctx); | 
|     ctx.beginPath(); | 
|     clipPath.buildPath(ctx, clipPath.shape); | 
|     ctx.clip(); // Transform back | 
|   | 
|     clipPath.restoreTransform(ctx); | 
|   } | 
| } | 
|   | 
| function createRoot(width, height) { | 
|   var domRoot = document.createElement('div'); // domRoot.onselectstart = returnFalse; // Avoid page selected | 
|   | 
|   domRoot.style.cssText = ['position:relative', // IOS13 safari probably has a compositing bug (z order of the canvas and the consequent | 
|   // dom does not act as expected) when some of the parent dom has | 
|   // `-webkit-overflow-scrolling: touch;` and the webpage is longer than one screen and | 
|   // the canvas is not at the top part of the page. | 
|   // Check `https://bugs.webkit.org/show_bug.cgi?id=203681` for more details. We remove | 
|   // this `overflow:hidden` to avoid the bug. | 
|   // 'overflow:hidden', | 
|   'width:' + width + 'px', 'height:' + height + 'px', 'padding:0', 'margin:0', 'border-width:0'].join(';') + ';'; | 
|   return domRoot; | 
| } | 
| /** | 
|  * @alias module:zrender/Painter | 
|  * @constructor | 
|  * @param {HTMLElement} root 绘图容器 | 
|  * @param {module:zrender/Storage} storage | 
|  * @param {Object} opts | 
|  */ | 
|   | 
|   | 
| var Painter = function (root, storage, opts) { | 
|   this.type = 'canvas'; // In node environment using node-canvas | 
|   | 
|   var singleCanvas = !root.nodeName // In node ? | 
|   || root.nodeName.toUpperCase() === 'CANVAS'; | 
|   this._opts = opts = util.extend({}, opts || {}); | 
|   /** | 
|    * @type {number} | 
|    */ | 
|   | 
|   this.dpr = opts.devicePixelRatio || devicePixelRatio; | 
|   /** | 
|    * @type {boolean} | 
|    * @private | 
|    */ | 
|   | 
|   this._singleCanvas = singleCanvas; | 
|   /** | 
|    * 绘图容器 | 
|    * @type {HTMLElement} | 
|    */ | 
|   | 
|   this.root = root; | 
|   var rootStyle = root.style; | 
|   | 
|   if (rootStyle) { | 
|     rootStyle['-webkit-tap-highlight-color'] = 'transparent'; | 
|     rootStyle['-webkit-user-select'] = rootStyle['user-select'] = rootStyle['-webkit-touch-callout'] = 'none'; | 
|     root.innerHTML = ''; | 
|   } | 
|   /** | 
|    * @type {module:zrender/Storage} | 
|    */ | 
|   | 
|   | 
|   this.storage = storage; | 
|   /** | 
|    * @type {Array.<number>} | 
|    * @private | 
|    */ | 
|   | 
|   var zlevelList = this._zlevelList = []; | 
|   /** | 
|    * @type {Object.<string, module:zrender/Layer>} | 
|    * @private | 
|    */ | 
|   | 
|   var layers = this._layers = {}; | 
|   /** | 
|    * @type {Object.<string, Object>} | 
|    * @private | 
|    */ | 
|   | 
|   this._layerConfig = {}; | 
|   /** | 
|    * zrender will do compositing when root is a canvas and have multiple zlevels. | 
|    */ | 
|   | 
|   this._needsManuallyCompositing = false; | 
|   | 
|   if (!singleCanvas) { | 
|     this._width = this._getSize(0); | 
|     this._height = this._getSize(1); | 
|     var domRoot = this._domRoot = createRoot(this._width, this._height); | 
|     root.appendChild(domRoot); | 
|   } else { | 
|     var width = root.width; | 
|     var height = root.height; | 
|   | 
|     if (opts.width != null) { | 
|       width = opts.width; | 
|     } | 
|   | 
|     if (opts.height != null) { | 
|       height = opts.height; | 
|     } | 
|   | 
|     this.dpr = opts.devicePixelRatio || 1; // Use canvas width and height directly | 
|   | 
|     root.width = width * this.dpr; | 
|     root.height = height * this.dpr; | 
|     this._width = width; | 
|     this._height = height; // Create layer if only one given canvas | 
|     // Device can be specified to create a high dpi image. | 
|   | 
|     var mainLayer = new Layer(root, this, this.dpr); | 
|     mainLayer.__builtin__ = true; | 
|     mainLayer.initContext(); // FIXME Use canvas width and height | 
|     // mainLayer.resize(width, height); | 
|   | 
|     layers[CANVAS_ZLEVEL] = mainLayer; | 
|     mainLayer.zlevel = CANVAS_ZLEVEL; // Not use common zlevel. | 
|   | 
|     zlevelList.push(CANVAS_ZLEVEL); | 
|     this._domRoot = root; | 
|   } | 
|   /** | 
|    * @type {module:zrender/Layer} | 
|    * @private | 
|    */ | 
|   | 
|   | 
|   this._hoverlayer = null; | 
|   this._hoverElements = []; | 
| }; | 
|   | 
| Painter.prototype = { | 
|   constructor: Painter, | 
|   getType: function () { | 
|     return 'canvas'; | 
|   }, | 
|   | 
|   /** | 
|    * If painter use a single canvas | 
|    * @return {boolean} | 
|    */ | 
|   isSingleCanvas: function () { | 
|     return this._singleCanvas; | 
|   }, | 
|   | 
|   /** | 
|    * @return {HTMLDivElement} | 
|    */ | 
|   getViewportRoot: function () { | 
|     return this._domRoot; | 
|   }, | 
|   getViewportRootOffset: function () { | 
|     var viewportRoot = this.getViewportRoot(); | 
|   | 
|     if (viewportRoot) { | 
|       return { | 
|         offsetLeft: viewportRoot.offsetLeft || 0, | 
|         offsetTop: viewportRoot.offsetTop || 0 | 
|       }; | 
|     } | 
|   }, | 
|   | 
|   /** | 
|    * 刷新 | 
|    * @param {boolean} [paintAll=false] 强制绘制所有displayable | 
|    */ | 
|   refresh: function (paintAll) { | 
|     var list = this.storage.getDisplayList(true); | 
|     var zlevelList = this._zlevelList; | 
|     this._redrawId = Math.random(); | 
|   | 
|     this._paintList(list, paintAll, this._redrawId); // Paint custum layers | 
|   | 
|   | 
|     for (var i = 0; i < zlevelList.length; i++) { | 
|       var z = zlevelList[i]; | 
|       var layer = this._layers[z]; | 
|   | 
|       if (!layer.__builtin__ && layer.refresh) { | 
|         var clearColor = i === 0 ? this._backgroundColor : null; | 
|         layer.refresh(clearColor); | 
|       } | 
|     } | 
|   | 
|     this.refreshHover(); | 
|     return this; | 
|   }, | 
|   addHover: function (el, hoverStyle) { | 
|     if (el.__hoverMir) { | 
|       return; | 
|     } | 
|   | 
|     var elMirror = new el.constructor({ | 
|       style: el.style, | 
|       shape: el.shape, | 
|       z: el.z, | 
|       z2: el.z2, | 
|       silent: el.silent | 
|     }); | 
|     elMirror.__from = el; | 
|     el.__hoverMir = elMirror; | 
|     hoverStyle && elMirror.setStyle(hoverStyle); | 
|   | 
|     this._hoverElements.push(elMirror); | 
|   | 
|     return elMirror; | 
|   }, | 
|   removeHover: function (el) { | 
|     var elMirror = el.__hoverMir; | 
|     var hoverElements = this._hoverElements; | 
|     var idx = util.indexOf(hoverElements, elMirror); | 
|   | 
|     if (idx >= 0) { | 
|       hoverElements.splice(idx, 1); | 
|     } | 
|   | 
|     el.__hoverMir = null; | 
|   }, | 
|   clearHover: function (el) { | 
|     var hoverElements = this._hoverElements; | 
|   | 
|     for (var i = 0; i < hoverElements.length; i++) { | 
|       var from = hoverElements[i].__from; | 
|   | 
|       if (from) { | 
|         from.__hoverMir = null; | 
|       } | 
|     } | 
|   | 
|     hoverElements.length = 0; | 
|   }, | 
|   refreshHover: function () { | 
|     var hoverElements = this._hoverElements; | 
|     var len = hoverElements.length; | 
|     var hoverLayer = this._hoverlayer; | 
|     hoverLayer && hoverLayer.clear(); | 
|   | 
|     if (!len) { | 
|       return; | 
|     } | 
|   | 
|     timsort(hoverElements, this.storage.displayableSortFunc); // Use a extream large zlevel | 
|     // FIXME? | 
|   | 
|     if (!hoverLayer) { | 
|       hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL); | 
|     } | 
|   | 
|     var scope = {}; | 
|     hoverLayer.ctx.save(); | 
|   | 
|     for (var i = 0; i < len;) { | 
|       var el = hoverElements[i]; | 
|       var originalEl = el.__from; // Original el is removed | 
|       // PENDING | 
|   | 
|       if (!(originalEl && originalEl.__zr)) { | 
|         hoverElements.splice(i, 1); | 
|         originalEl.__hoverMir = null; | 
|         len--; | 
|         continue; | 
|       } | 
|   | 
|       i++; // Use transform | 
|       // FIXME style and shape ? | 
|   | 
|       if (!originalEl.invisible) { | 
|         el.transform = originalEl.transform; | 
|         el.invTransform = originalEl.invTransform; | 
|         el.__clipPaths = originalEl.__clipPaths; // el. | 
|   | 
|         this._doPaintEl(el, hoverLayer, true, scope); | 
|       } | 
|     } | 
|   | 
|     hoverLayer.ctx.restore(); | 
|   }, | 
|   getHoverLayer: function () { | 
|     return this.getLayer(HOVER_LAYER_ZLEVEL); | 
|   }, | 
|   _paintList: function (list, paintAll, redrawId) { | 
|     if (this._redrawId !== redrawId) { | 
|       return; | 
|     } | 
|   | 
|     paintAll = paintAll || false; | 
|   | 
|     this._updateLayerStatus(list); | 
|   | 
|     var finished = this._doPaintList(list, paintAll); | 
|   | 
|     if (this._needsManuallyCompositing) { | 
|       this._compositeManually(); | 
|     } | 
|   | 
|     if (!finished) { | 
|       var self = this; | 
|       requestAnimationFrame(function () { | 
|         self._paintList(list, paintAll, redrawId); | 
|       }); | 
|     } | 
|   }, | 
|   _compositeManually: function () { | 
|     var ctx = this.getLayer(CANVAS_ZLEVEL).ctx; | 
|     var width = this._domRoot.width; | 
|     var height = this._domRoot.height; | 
|     ctx.clearRect(0, 0, width, height); // PENDING, If only builtin layer? | 
|   | 
|     this.eachBuiltinLayer(function (layer) { | 
|       if (layer.virtual) { | 
|         ctx.drawImage(layer.dom, 0, 0, width, height); | 
|       } | 
|     }); | 
|   }, | 
|   _doPaintList: function (list, paintAll) { | 
|     var layerList = []; | 
|   | 
|     for (var zi = 0; zi < this._zlevelList.length; zi++) { | 
|       var zlevel = this._zlevelList[zi]; | 
|       var layer = this._layers[zlevel]; | 
|   | 
|       if (layer.__builtin__ && layer !== this._hoverlayer && (layer.__dirty || paintAll)) { | 
|         layerList.push(layer); | 
|       } | 
|     } | 
|   | 
|     var finished = true; | 
|   | 
|     for (var k = 0; k < layerList.length; k++) { | 
|       var layer = layerList[k]; | 
|       var ctx = layer.ctx; | 
|       var scope = {}; | 
|       ctx.save(); | 
|       var start = paintAll ? layer.__startIndex : layer.__drawIndex; | 
|       var useTimer = !paintAll && layer.incremental && Date.now; | 
|       var startTime = useTimer && Date.now(); | 
|       var clearColor = layer.zlevel === this._zlevelList[0] ? this._backgroundColor : null; // All elements in this layer are cleared. | 
|   | 
|       if (layer.__startIndex === layer.__endIndex) { | 
|         layer.clear(false, clearColor); | 
|       } else if (start === layer.__startIndex) { | 
|         var firstEl = list[start]; | 
|   | 
|         if (!firstEl.incremental || !firstEl.notClear || paintAll) { | 
|           layer.clear(false, clearColor); | 
|         } | 
|       } | 
|   | 
|       if (start === -1) { | 
|         console.error('For some unknown reason. drawIndex is -1'); | 
|         start = layer.__startIndex; | 
|       } | 
|   | 
|       for (var i = start; i < layer.__endIndex; i++) { | 
|         var el = list[i]; | 
|   | 
|         this._doPaintEl(el, layer, paintAll, scope); | 
|   | 
|         el.__dirty = el.__dirtyText = false; | 
|   | 
|         if (useTimer) { | 
|           // Date.now can be executed in 13,025,305 ops/second. | 
|           var dTime = Date.now() - startTime; // Give 15 millisecond to draw. | 
|           // The rest elements will be drawn in the next frame. | 
|   | 
|           if (dTime > 15) { | 
|             break; | 
|           } | 
|         } | 
|       } | 
|   | 
|       layer.__drawIndex = i; | 
|   | 
|       if (layer.__drawIndex < layer.__endIndex) { | 
|         finished = false; | 
|       } | 
|   | 
|       if (scope.prevElClipPaths) { | 
|         // Needs restore the state. If last drawn element is in the clipping area. | 
|         ctx.restore(); | 
|       } | 
|   | 
|       ctx.restore(); | 
|     } | 
|   | 
|     if (env.wxa) { | 
|       // Flush for weixin application | 
|       util.each(this._layers, function (layer) { | 
|         if (layer && layer.ctx && layer.ctx.draw) { | 
|           layer.ctx.draw(); | 
|         } | 
|       }); | 
|     } | 
|   | 
|     return finished; | 
|   }, | 
|   _doPaintEl: function (el, currentLayer, forcePaint, scope) { | 
|     var ctx = currentLayer.ctx; | 
|     var m = el.transform; | 
|   | 
|     if ((currentLayer.__dirty || forcePaint) && // Ignore invisible element | 
|     !el.invisible // Ignore transparent element | 
|     && el.style.opacity !== 0 // Ignore scale 0 element, in some environment like node-canvas | 
|     // Draw a scale 0 element can cause all following draw wrong | 
|     // And setTransform with scale 0 will cause set back transform failed. | 
|     && !(m && !m[0] && !m[3]) // Ignore culled element | 
|     && !(el.culling && isDisplayableCulled(el, this._width, this._height))) { | 
|       var clipPaths = el.__clipPaths; | 
|       var prevElClipPaths = scope.prevElClipPaths; // Optimize when clipping on group with several elements | 
|   | 
|       if (!prevElClipPaths || isClipPathChanged(clipPaths, prevElClipPaths)) { | 
|         // If has previous clipping state, restore from it | 
|         if (prevElClipPaths) { | 
|           ctx.restore(); | 
|           scope.prevElClipPaths = null; // Reset prevEl since context has been restored | 
|   | 
|           scope.prevEl = null; | 
|         } // New clipping state | 
|   | 
|   | 
|         if (clipPaths) { | 
|           ctx.save(); | 
|           doClip(clipPaths, ctx); | 
|           scope.prevElClipPaths = clipPaths; | 
|         } | 
|       } | 
|   | 
|       el.beforeBrush && el.beforeBrush(ctx); | 
|       el.brush(ctx, scope.prevEl || null); | 
|       scope.prevEl = el; | 
|       el.afterBrush && el.afterBrush(ctx); | 
|     } | 
|   }, | 
|   | 
|   /** | 
|    * 获取 zlevel 所在层,如果不存在则会创建一个新的层 | 
|    * @param {number} zlevel | 
|    * @param {boolean} virtual Virtual layer will not be inserted into dom. | 
|    * @return {module:zrender/Layer} | 
|    */ | 
|   getLayer: function (zlevel, virtual) { | 
|     if (this._singleCanvas && !this._needsManuallyCompositing) { | 
|       zlevel = CANVAS_ZLEVEL; | 
|     } | 
|   | 
|     var layer = this._layers[zlevel]; | 
|   | 
|     if (!layer) { | 
|       // Create a new layer | 
|       layer = new Layer('zr_' + zlevel, this, this.dpr); | 
|       layer.zlevel = zlevel; | 
|       layer.__builtin__ = true; | 
|   | 
|       if (this._layerConfig[zlevel]) { | 
|         util.merge(layer, this._layerConfig[zlevel], true); | 
|       } | 
|   | 
|       if (virtual) { | 
|         layer.virtual = virtual; | 
|       } | 
|   | 
|       this.insertLayer(zlevel, layer); // Context is created after dom inserted to document | 
|       // Or excanvas will get 0px clientWidth and clientHeight | 
|   | 
|       layer.initContext(); | 
|     } | 
|   | 
|     return layer; | 
|   }, | 
|   insertLayer: function (zlevel, layer) { | 
|     var layersMap = this._layers; | 
|     var zlevelList = this._zlevelList; | 
|     var len = zlevelList.length; | 
|     var prevLayer = null; | 
|     var i = -1; | 
|     var domRoot = this._domRoot; | 
|   | 
|     if (layersMap[zlevel]) { | 
|       logError('ZLevel ' + zlevel + ' has been used already'); | 
|       return; | 
|     } // Check if is a valid layer | 
|   | 
|   | 
|     if (!isLayerValid(layer)) { | 
|       logError('Layer of zlevel ' + zlevel + ' is not valid'); | 
|       return; | 
|     } | 
|   | 
|     if (len > 0 && zlevel > zlevelList[0]) { | 
|       for (i = 0; i < len - 1; i++) { | 
|         if (zlevelList[i] < zlevel && zlevelList[i + 1] > zlevel) { | 
|           break; | 
|         } | 
|       } | 
|   | 
|       prevLayer = layersMap[zlevelList[i]]; | 
|     } | 
|   | 
|     zlevelList.splice(i + 1, 0, zlevel); | 
|     layersMap[zlevel] = layer; // Vitual layer will not directly show on the screen. | 
|     // (It can be a WebGL layer and assigned to a ZImage element) | 
|     // But it still under management of zrender. | 
|   | 
|     if (!layer.virtual) { | 
|       if (prevLayer) { | 
|         var prevDom = prevLayer.dom; | 
|   | 
|         if (prevDom.nextSibling) { | 
|           domRoot.insertBefore(layer.dom, prevDom.nextSibling); | 
|         } else { | 
|           domRoot.appendChild(layer.dom); | 
|         } | 
|       } else { | 
|         if (domRoot.firstChild) { | 
|           domRoot.insertBefore(layer.dom, domRoot.firstChild); | 
|         } else { | 
|           domRoot.appendChild(layer.dom); | 
|         } | 
|       } | 
|     } | 
|   }, | 
|   // Iterate each layer | 
|   eachLayer: function (cb, context) { | 
|     var zlevelList = this._zlevelList; | 
|     var z; | 
|     var i; | 
|   | 
|     for (i = 0; i < zlevelList.length; i++) { | 
|       z = zlevelList[i]; | 
|       cb.call(context, this._layers[z], z); | 
|     } | 
|   }, | 
|   // Iterate each buildin layer | 
|   eachBuiltinLayer: function (cb, context) { | 
|     var zlevelList = this._zlevelList; | 
|     var layer; | 
|     var z; | 
|     var i; | 
|   | 
|     for (i = 0; i < zlevelList.length; i++) { | 
|       z = zlevelList[i]; | 
|       layer = this._layers[z]; | 
|   | 
|       if (layer.__builtin__) { | 
|         cb.call(context, layer, z); | 
|       } | 
|     } | 
|   }, | 
|   // Iterate each other layer except buildin layer | 
|   eachOtherLayer: function (cb, context) { | 
|     var zlevelList = this._zlevelList; | 
|     var layer; | 
|     var z; | 
|     var i; | 
|   | 
|     for (i = 0; i < zlevelList.length; i++) { | 
|       z = zlevelList[i]; | 
|       layer = this._layers[z]; | 
|   | 
|       if (!layer.__builtin__) { | 
|         cb.call(context, layer, z); | 
|       } | 
|     } | 
|   }, | 
|   | 
|   /** | 
|    * 获取所有已创建的层 | 
|    * @param {Array.<module:zrender/Layer>} [prevLayer] | 
|    */ | 
|   getLayers: function () { | 
|     return this._layers; | 
|   }, | 
|   _updateLayerStatus: function (list) { | 
|     this.eachBuiltinLayer(function (layer, z) { | 
|       layer.__dirty = layer.__used = false; | 
|     }); | 
|   | 
|     function updatePrevLayer(idx) { | 
|       if (prevLayer) { | 
|         if (prevLayer.__endIndex !== idx) { | 
|           prevLayer.__dirty = true; | 
|         } | 
|   | 
|         prevLayer.__endIndex = idx; | 
|       } | 
|     } | 
|   | 
|     if (this._singleCanvas) { | 
|       for (var i = 1; i < list.length; i++) { | 
|         var el = list[i]; | 
|   | 
|         if (el.zlevel !== list[i - 1].zlevel || el.incremental) { | 
|           this._needsManuallyCompositing = true; | 
|           break; | 
|         } | 
|       } | 
|     } | 
|   | 
|     var prevLayer = null; | 
|     var incrementalLayerCount = 0; | 
|   | 
|     for (var i = 0; i < list.length; i++) { | 
|       var el = list[i]; | 
|       var zlevel = el.zlevel; | 
|       var layer; // PENDING If change one incremental element style ? | 
|       // TODO Where there are non-incremental elements between incremental elements. | 
|   | 
|       if (el.incremental) { | 
|         layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing); | 
|         layer.incremental = true; | 
|         incrementalLayerCount = 1; | 
|       } else { | 
|         layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing); | 
|       } | 
|   | 
|       if (!layer.__builtin__) { | 
|         logError('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id); | 
|       } | 
|   | 
|       if (layer !== prevLayer) { | 
|         layer.__used = true; | 
|   | 
|         if (layer.__startIndex !== i) { | 
|           layer.__dirty = true; | 
|         } | 
|   | 
|         layer.__startIndex = i; | 
|   | 
|         if (!layer.incremental) { | 
|           layer.__drawIndex = i; | 
|         } else { | 
|           // Mark layer draw index needs to update. | 
|           layer.__drawIndex = -1; | 
|         } | 
|   | 
|         updatePrevLayer(i); | 
|         prevLayer = layer; | 
|       } | 
|   | 
|       if (el.__dirty) { | 
|         layer.__dirty = true; | 
|   | 
|         if (layer.incremental && layer.__drawIndex < 0) { | 
|           // Start draw from the first dirty element. | 
|           layer.__drawIndex = i; | 
|         } | 
|       } | 
|     } | 
|   | 
|     updatePrevLayer(i); | 
|     this.eachBuiltinLayer(function (layer, z) { | 
|       // Used in last frame but not in this frame. Needs clear | 
|       if (!layer.__used && layer.getElementCount() > 0) { | 
|         layer.__dirty = true; | 
|         layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0; | 
|       } // For incremental layer. In case start index changed and no elements are dirty. | 
|   | 
|   | 
|       if (layer.__dirty && layer.__drawIndex < 0) { | 
|         layer.__drawIndex = layer.__startIndex; | 
|       } | 
|     }); | 
|   }, | 
|   | 
|   /** | 
|    * 清除hover层外所有内容 | 
|    */ | 
|   clear: function () { | 
|     this.eachBuiltinLayer(this._clearLayer); | 
|     return this; | 
|   }, | 
|   _clearLayer: function (layer) { | 
|     layer.clear(); | 
|   }, | 
|   setBackgroundColor: function (backgroundColor) { | 
|     this._backgroundColor = backgroundColor; | 
|   }, | 
|   | 
|   /** | 
|    * 修改指定zlevel的绘制参数 | 
|    * | 
|    * @param {string} zlevel | 
|    * @param {Object} config 配置对象 | 
|    * @param {string} [config.clearColor=0] 每次清空画布的颜色 | 
|    * @param {string} [config.motionBlur=false] 是否开启动态模糊 | 
|    * @param {number} [config.lastFrameAlpha=0.7] | 
|    *                 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显 | 
|    */ | 
|   configLayer: function (zlevel, config) { | 
|     if (config) { | 
|       var layerConfig = this._layerConfig; | 
|   | 
|       if (!layerConfig[zlevel]) { | 
|         layerConfig[zlevel] = config; | 
|       } else { | 
|         util.merge(layerConfig[zlevel], config, true); | 
|       } | 
|   | 
|       for (var i = 0; i < this._zlevelList.length; i++) { | 
|         var _zlevel = this._zlevelList[i]; | 
|   | 
|         if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) { | 
|           var layer = this._layers[_zlevel]; | 
|           util.merge(layer, layerConfig[zlevel], true); | 
|         } | 
|       } | 
|     } | 
|   }, | 
|   | 
|   /** | 
|    * 删除指定层 | 
|    * @param {number} zlevel 层所在的zlevel | 
|    */ | 
|   delLayer: function (zlevel) { | 
|     var layers = this._layers; | 
|     var zlevelList = this._zlevelList; | 
|     var layer = layers[zlevel]; | 
|   | 
|     if (!layer) { | 
|       return; | 
|     } | 
|   | 
|     layer.dom.parentNode.removeChild(layer.dom); | 
|     delete layers[zlevel]; | 
|     zlevelList.splice(util.indexOf(zlevelList, zlevel), 1); | 
|   }, | 
|   | 
|   /** | 
|    * 区域大小变化后重绘 | 
|    */ | 
|   resize: function (width, height) { | 
|     if (!this._domRoot.style) { | 
|       // Maybe in node or worker | 
|       if (width == null || height == null) { | 
|         return; | 
|       } | 
|   | 
|       this._width = width; | 
|       this._height = height; | 
|       this.getLayer(CANVAS_ZLEVEL).resize(width, height); | 
|     } else { | 
|       var domRoot = this._domRoot; // FIXME Why ? | 
|   | 
|       domRoot.style.display = 'none'; // Save input w/h | 
|   | 
|       var opts = this._opts; | 
|       width != null && (opts.width = width); | 
|       height != null && (opts.height = height); | 
|       width = this._getSize(0); | 
|       height = this._getSize(1); | 
|       domRoot.style.display = ''; // 优化没有实际改变的resize | 
|   | 
|       if (this._width !== width || height !== this._height) { | 
|         domRoot.style.width = width + 'px'; | 
|         domRoot.style.height = height + 'px'; | 
|   | 
|         for (var id in this._layers) { | 
|           if (this._layers.hasOwnProperty(id)) { | 
|             this._layers[id].resize(width, height); | 
|           } | 
|         } | 
|   | 
|         util.each(this._progressiveLayers, function (layer) { | 
|           layer.resize(width, height); | 
|         }); | 
|         this.refresh(true); | 
|       } | 
|   | 
|       this._width = width; | 
|       this._height = height; | 
|     } | 
|   | 
|     return this; | 
|   }, | 
|   | 
|   /** | 
|    * 清除单独的一个层 | 
|    * @param {number} zlevel | 
|    */ | 
|   clearLayer: function (zlevel) { | 
|     var layer = this._layers[zlevel]; | 
|   | 
|     if (layer) { | 
|       layer.clear(); | 
|     } | 
|   }, | 
|   | 
|   /** | 
|    * 释放 | 
|    */ | 
|   dispose: function () { | 
|     this.root.innerHTML = ''; | 
|     this.root = this.storage = this._domRoot = this._layers = null; | 
|   }, | 
|   | 
|   /** | 
|    * Get canvas which has all thing rendered | 
|    * @param {Object} opts | 
|    * @param {string} [opts.backgroundColor] | 
|    * @param {number} [opts.pixelRatio] | 
|    */ | 
|   getRenderedCanvas: function (opts) { | 
|     opts = opts || {}; | 
|   | 
|     if (this._singleCanvas && !this._compositeManually) { | 
|       return this._layers[CANVAS_ZLEVEL].dom; | 
|     } | 
|   | 
|     var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr); | 
|     imageLayer.initContext(); | 
|     imageLayer.clear(false, opts.backgroundColor || this._backgroundColor); | 
|   | 
|     if (opts.pixelRatio <= this.dpr) { | 
|       this.refresh(); | 
|       var width = imageLayer.dom.width; | 
|       var height = imageLayer.dom.height; | 
|       var ctx = imageLayer.ctx; | 
|       this.eachLayer(function (layer) { | 
|         if (layer.__builtin__) { | 
|           ctx.drawImage(layer.dom, 0, 0, width, height); | 
|         } else if (layer.renderToCanvas) { | 
|           imageLayer.ctx.save(); | 
|           layer.renderToCanvas(imageLayer.ctx); | 
|           imageLayer.ctx.restore(); | 
|         } | 
|       }); | 
|     } else { | 
|       // PENDING, echarts-gl and incremental rendering. | 
|       var scope = {}; | 
|       var displayList = this.storage.getDisplayList(true); | 
|   | 
|       for (var i = 0; i < displayList.length; i++) { | 
|         var el = displayList[i]; | 
|   | 
|         this._doPaintEl(el, imageLayer, true, scope); | 
|       } | 
|     } | 
|   | 
|     return imageLayer.dom; | 
|   }, | 
|   | 
|   /** | 
|    * 获取绘图区域宽度 | 
|    */ | 
|   getWidth: function () { | 
|     return this._width; | 
|   }, | 
|   | 
|   /** | 
|    * 获取绘图区域高度 | 
|    */ | 
|   getHeight: function () { | 
|     return this._height; | 
|   }, | 
|   _getSize: function (whIdx) { | 
|     var opts = this._opts; | 
|     var wh = ['width', 'height'][whIdx]; | 
|     var cwh = ['clientWidth', 'clientHeight'][whIdx]; | 
|     var plt = ['paddingLeft', 'paddingTop'][whIdx]; | 
|     var prb = ['paddingRight', 'paddingBottom'][whIdx]; | 
|   | 
|     if (opts[wh] != null && opts[wh] !== 'auto') { | 
|       return parseFloat(opts[wh]); | 
|     } | 
|   | 
|     var root = this.root; // IE8 does not support getComputedStyle, but it use VML. | 
|   | 
|     var stl = document.defaultView.getComputedStyle(root); | 
|     return (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) - (parseInt10(stl[plt]) || 0) - (parseInt10(stl[prb]) || 0) | 0; | 
|   }, | 
|   pathToImage: function (path, dpr) { | 
|     dpr = dpr || this.dpr; | 
|     var canvas = document.createElement('canvas'); | 
|     var ctx = canvas.getContext('2d'); | 
|     var rect = path.getBoundingRect(); | 
|     var style = path.style; | 
|     var shadowBlurSize = style.shadowBlur * dpr; | 
|     var shadowOffsetX = style.shadowOffsetX * dpr; | 
|     var shadowOffsetY = style.shadowOffsetY * dpr; | 
|     var lineWidth = style.hasStroke() ? style.lineWidth : 0; | 
|     var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize); | 
|     var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize); | 
|     var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize); | 
|     var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize); | 
|     var width = rect.width + leftMargin + rightMargin; | 
|     var height = rect.height + topMargin + bottomMargin; | 
|     canvas.width = width * dpr; | 
|     canvas.height = height * dpr; | 
|     ctx.scale(dpr, dpr); | 
|     ctx.clearRect(0, 0, width, height); | 
|     ctx.dpr = dpr; | 
|     var pathTransform = { | 
|       position: path.position, | 
|       rotation: path.rotation, | 
|       scale: path.scale | 
|     }; | 
|     path.position = [leftMargin - rect.x, topMargin - rect.y]; | 
|     path.rotation = 0; | 
|     path.scale = [1, 1]; | 
|     path.updateTransform(); | 
|   | 
|     if (path) { | 
|       path.brush(ctx); | 
|     } | 
|   | 
|     var ImageShape = Image; | 
|     var imgShape = new ImageShape({ | 
|       style: { | 
|         x: 0, | 
|         y: 0, | 
|         image: canvas | 
|       } | 
|     }); | 
|   | 
|     if (pathTransform.position != null) { | 
|       imgShape.position = path.position = pathTransform.position; | 
|     } | 
|   | 
|     if (pathTransform.rotation != null) { | 
|       imgShape.rotation = path.rotation = pathTransform.rotation; | 
|     } | 
|   | 
|     if (pathTransform.scale != null) { | 
|       imgShape.scale = path.scale = pathTransform.scale; | 
|     } | 
|   | 
|     return imgShape; | 
|   } | 
| }; | 
| var _default = Painter; | 
| module.exports = _default; |