UNPKG

@mapgis/webclient-es6-mapboxgl

Version:

1,114 lines (964 loc) 34.3 kB
import { Common } from '@mapgis/webclient-es6-service'; const { Zondy, newGuid } = Common; import {Util} from './Util'; import {Transformable} from './Transformable'; import {Config} from './Config'; import {SUtil} from './SUtil'; import {SmicImage} from './SmicImage'; /** * @private * @class Zondy.LevelRenderer.Painter * @classdesc Painter 绘图模块。 */ class Painter { /** * @function Zondy.LevelRenderer.Painter.constructor * @description 构造函数。 * * @param {HTMLElement} root - 绘图区域(DIV)。 * @param {Zondy.LevelRenderer.Storage} storage - Storage 实例。 * */ constructor(root, storage) { /** * @member {HTMLElement} Zondy.LevelRenderer.Painter.prototype.root * @description 绘图容器。 * */ this.root = root; /** * @member {Array} Zondy.LevelRenderer.Painter.prototype.storage * @description 图形仓库。 * */ this.storage = storage; /** * @member {HTMLElement} Zondy.LevelRenderer.Painter.prototype._domRoot * @description 容器根 dom 对象。 * */ this._domRoot = null; /** * @member {Object} Zondy.LevelRenderer.Painter.prototype._layers * @description 绘制层对象。 * */ this._layers = {}; /** * @member {Array} Zondy.LevelRenderer.Painter.prototype._zlevelList * @description 层列表。 * */ this._zlevelList = []; /** * @member {Object} Zondy.LevelRenderer.Painter.prototype._layerConfig * @description 绘制层配置对象。 * */ this._layerConfig = {}; /** * @member {Object} Zondy.LevelRenderer.Painter.prototype._bgDom * @description 背景层 Canvas (Dom)。 * */ this._bgDom = null; /** * @member {Function} Zondy.LevelRenderer.Painter.prototype.shapeToImage * @description 形状转图像函数。 * */ this.shapeToImage = null; // retina 屏幕优化 Painter.devicePixelRatio = Math.max((window.devicePixelRatio || 1), 1); this.CLASS_NAME = "Zondy.LevelRenderer.Painter"; this.root.innerHTML = ''; this._width = this._getWidth(); // 宽,缓存记录 this._height = this._getHeight(); // 高,缓存记录 var domRoot = document.createElement('div'); this._domRoot = domRoot; // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬 domRoot.style.position = 'relative'; domRoot.style.overflow = 'hidden'; domRoot.style.width = this._width + 'px'; domRoot.style.height = this._height + 'px'; this.root.appendChild(domRoot); this.shapeToImage = this._createShapeToImageProcessor(); // 创建各层canvas // 背景 //this._bgDom = Painter.createDom('bg', 'div', this); this._bgDom = Painter.createDom(newGuid(), 'div', this); domRoot.appendChild(this._bgDom); this._bgDom.onselectstart = returnFalse; this._bgDom.style['-webkit-user-select'] = 'none'; this._bgDom.style['user-select'] = 'none'; this._bgDom.style['-webkit-touch-callout'] = 'none'; // 高亮 //var hoverLayer = new PaintLayer('_hoverLayer_', this); var hoverLayer = new PaintLayer(newGuid(), this); this._layers['hover'] = hoverLayer; domRoot.appendChild(hoverLayer.dom); hoverLayer.initContext(); hoverLayer.dom.onselectstart = returnFalse; hoverLayer.dom.style['-webkit-user-select'] = 'none'; hoverLayer.dom.style['user-select'] = 'none'; hoverLayer.dom.style['-webkit-touch-callout'] = 'none'; var me = this; this.updatePainter = function (shapeList, callback) { me.refreshShapes(shapeList, callback); }; // 返回false的方法,用于避免页面被选中 function returnFalse() { return false; } /* eslint-disable */ // 什么都不干的空方法 function doNothing() { //NOSONAR } /* eslint-enable */ } /** * @function Zondy.LevelRenderer.Painter.prototype.destroy * @description 销毁对象,释放资源。调用此函数后所有属性将被置为 null。 */ destroy() { this.dispose(); this._zlevelList = null; this._layerConfig = null; this._bgDom = null; this.shapeToImage = null; } /** * @function Zondy.LevelRenderer.Painter.prototype.render * @description 渲染。首次绘图,创建各种 dom 和 context。 * * @param {Function} callback - 绘画结束后的回调函数。 * @return {Zondy.LevelRenderer.Painter} this。 */ render(callback) { // TODO this.refresh(callback, true); return this; } /** * @function Zondy.LevelRenderer.Painter.prototype.refresh * @description 刷新。 * * @param {Function} callback - 刷新结束后的回调函数。 * @param {boolean} paintAll - 强制绘制所有 shape。 * @return {Zondy.LevelRenderer.Painter} this。 */ refresh(callback, paintAll) { var list = this.storage.getShapeList(true); this._paintList(list, paintAll); if (typeof callback == 'function') { callback(); } return this; } /** * Method: _paintList * 按列表绘制图形。 */ _paintList(list, paintAll) { if (typeof (paintAll) == 'undefined') { paintAll = false; } this._updateLayerStatus(list); var currentLayer; var currentZLevel; var ctx; for (var id in this._layers) { if (id !== 'hover') { this._layers[id].unusedCount++; this._layers[id].updateTransform(); } } var invTransform = []; for (var i = 0, l = list.length; i < l; i++) { var shape = list[i]; if (currentZLevel !== shape.zlevel) { if (currentLayer && currentLayer.needTransform) { ctx.restore(); } currentLayer = this.getLayer(shape.zlevel); ctx = currentLayer.ctx; currentZLevel = shape.zlevel; // Reset the count currentLayer.unusedCount = 0; if (currentLayer.dirty || paintAll) { currentLayer.clear(); } if (currentLayer.needTransform) { ctx.save(); currentLayer.setTransform(ctx); } } // Start group clipping if (ctx && shape.__startClip) { var clipShape = shape.__startClip; ctx.save(); // Set transform if (clipShape.needTransform) { let m = clipShape.transform; SUtil.Util_matrix.invert(invTransform, m); ctx.transform( m[0], m[1], m[2], m[3], m[4], m[5] ); } ctx.beginPath(); clipShape.buildPath(ctx, clipShape.style); ctx.clip(); // Transform back if (clipShape.needTransform) { let m = invTransform; ctx.transform( m[0], m[1], m[2], m[3], m[4], m[5] ); } } if (((currentLayer && currentLayer.dirty) || paintAll) && !shape.invisible) { if ( !shape.onbrush || (shape.onbrush && !shape.onbrush(ctx, false)) ) { if (Config.catchBrushException) { try { shape.brush(ctx, false, this.updatePainter); } catch (error) { } } else { shape.brush(ctx, false, this.updatePainter); } } } // Stop group clipping if (ctx && shape.__stopClip) { ctx.restore(); } shape.__dirty = false; } if (ctx && currentLayer && currentLayer.needTransform) { ctx.restore(); } for (let id in this._layers) { if (id !== 'hover') { var layer = this._layers[id]; layer.dirty = false; // 删除过期的层 // PENDING // if (layer.unusedCount >= 500) { // this.delLayer(id); // } if (layer.unusedCount === 1) { layer.clear(); } } } } /** * @function Zondy.LevelRenderer.Painter.prototype.getLayer * @description 获取 zlevel 所在层,如果不存在则会创建一个新的层。 * * @param {number} zlevel - zlevel。 * @return {Zondy.LevelRenderer.Painter} this。 */ getLayer(zlevel) { // Change draw layer var currentLayer = this._layers[zlevel]; if (!currentLayer) { var len = this._zlevelList.length; var prevLayer = null; var i = -1; if (len > 0 && zlevel > this._zlevelList[0]) { for (i = 0; i < len - 1; i++) { if ( this._zlevelList[i] < zlevel && this._zlevelList[i + 1] > zlevel ) { break; } } prevLayer = this._layers[this._zlevelList[i]]; } this._zlevelList.splice(i + 1, 0, zlevel); // Create a new layer //currentLayer = new PaintLayer(zlevel, this); currentLayer = new PaintLayer(newGuid(), this); var prevDom = prevLayer ? prevLayer.dom : this._bgDom; if (prevDom.nextSibling) { prevDom.parentNode.insertBefore( currentLayer.dom, prevDom.nextSibling ); } else { prevDom.parentNode.appendChild( currentLayer.dom ); } currentLayer.initContext(); this._layers[zlevel] = currentLayer; if (this._layerConfig[zlevel]) { new Util().merge(currentLayer, this._layerConfig[zlevel], true); } currentLayer.updateTransform(); } return currentLayer; } /** * @function Zondy.LevelRenderer.Painter.prototype.getLayers * @description 获取所有已创建的层。 * @return {Array.<Painter.Layer>} 已创建的层 */ getLayers() { return this._layers; } /** * Method: _updateLayerStatus * 更新绘制层状态。 */ _updateLayerStatus(list) { var layers = this._layers; var elCounts = {}; for (let z in layers) { if (z !== 'hover') { elCounts[z] = layers[z].elCount; layers[z].elCount = 0; } } for (let i = 0; i < list.length; i++) { var shape = list[i]; var zlevel = shape.zlevel; var layer = layers[zlevel]; if (layer) { layer.elCount++; // 已经被标记为需要刷新 if (layer.dirty) { continue; } layer.dirty = shape.__dirty; } } // 层中的元素数量有发生变化 for (let z in layers) { if (z !== 'hover') { if (elCounts[z] !== layers[z].elCount) { layers[z].dirty = true; } } } } /** * @function Zondy.LevelRenderer.Painter.prototype.refreshShapes * @description 更新的图形元素列表。 * * @param {number} shapeList - 需要更新的图形元素列表。 * @param {number} callback - 视图更新后回调函数。 * @return {Zondy.LevelRenderer.Painter} this。 */ refreshShapes(shapeList, callback) { for (var i = 0, l = shapeList.length; i < l; i++) { var shape = shapeList[i]; this.storage.mod(shape.id); } this.refresh(callback); return this; } /** * @function Zondy.LevelRenderer.Painter.prototype.clear * @description 清除 hover 层外所有内容。 * @return {Zondy.LevelRenderer.Painter} this。 */ clear() { for (var k in this._layers) { if (k === 'hover') { continue; } this._layers[k].clear(); } return this; } /** * @function Zondy.LevelRenderer.Painter.prototype.modLayer * @description 修改指定 zlevel 的绘制参数。 * * @param {string} zlevel - zlevel。 * @param {Object} config - 配置对象。 * @param {string} [config.clearColor=0] - 每次清空画布的颜色。 * @param {boolean} [config.motionBlur=false] - 是否开启动态模糊。 * @param {number} [config.lastFrameAlpha=0.7] - 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显。默认值:0.7。 * @param {Array.<number>} config.position - 层的平移。 * @param {Array.<number>} config.rotation - 层的旋转。 * @param {Array.<number>} config.scale - 层的缩放。 * @param {boolean} config.zoomable - 层是否支持鼠标缩放操作。默认值:false。 * @param {boolean} config.panable - 层是否支持鼠标平移操作。默认值:false。 * */ modLayer(zlevel, config) { if (config) { if (!this._layerConfig[zlevel]) { this._layerConfig[zlevel] = config; } else { new Util().merge(this._layerConfig[zlevel], config, true); } var layer = this._layers[zlevel]; if (layer) { new Util().merge(layer, this._layerConfig[zlevel], true); } } } /** * @function Zondy.LevelRenderer.Painter.prototype.delLayer * @description 删除指定层。 * * @param {string} zlevel - 层所在的 zlevel。 */ delLayer(zlevel) { var layer = this._layers[zlevel]; if (!layer) { return; } // Save config this.modLayer(zlevel, { position: layer.position, rotation: layer.rotation, scale: layer.scale }); layer.dom.parentNode.removeChild(layer.dom); delete this._layers[zlevel]; this._zlevelList.splice(new Util().indexOf(this._zlevelList, zlevel), 1); } /** * @function Zondy.LevelRenderer.Painter.prototype.refreshHover * @description 刷新 hover 层。 * @return {Zondy.LevelRenderer.Painter} this。 */ refreshHover() { this.clearHover(); var list = this.storage.getHoverShapes(true); for (var i = 0, l = list.length; i < l; i++) { this._brushHover(list[i]); } this.storage.delHover(); return this; } /** * @function Zondy.LevelRenderer.Painter.prototype.clearHover * @description 清除 hover 层所有内容。 * @return {Zondy.LevelRenderer.Painter} this。 */ clearHover() { var hover = this._layers.hover; hover && hover.clear(); return this; } /** * @function Zondy.LevelRenderer.Painter.prototype.resize * @description 区域大小变化后重绘。 * @return {Zondy.LevelRenderer.Painter} this。 */ resize() { var domRoot = this._domRoot; domRoot.style.display = 'none'; var width = this._getWidth(); var height = this._getHeight(); domRoot.style.display = ''; // 优化没有实际改变的resize if (this._width !== width || height !== this._height) { this._width = width; this._height = height; domRoot.style.width = width + 'px'; domRoot.style.height = height + 'px'; for (var id in this._layers) { this._layers[id].resize(width, height); } this.refresh(null, true); } return this; } /** * @function Zondy.LevelRenderer.Painter.prototype.clearLayer * @description 清除指定的一个层。 * @param {number} zLevel - 层。 */ clearLayer(zLevel) { var layer = this._layers[zLevel]; if (layer) { layer.clear(); } } /** * @function Zondy.LevelRenderer.Painter.prototype.dispose * @description 释放。 * */ dispose() { this.root.innerHTML = ''; this.root = null; this.storage = null; this._domRoot = null; this._layers = null; } /** * @function Zondy.LevelRenderer.Painter.prototype.getDomHover * @description 获取 Hover 层的 Dom。 */ getDomHover() { return this._layers.hover.dom; } /** * @function Zondy.LevelRenderer.Painter.prototype.toDataURL * @description 图像导出。 * @param {string} type - 图片类型。 * @param {string} backgroundColor - 背景色。默认值:'#fff'。 * @param {Object} args * @return {string} 图片的Base64 url。 */ toDataURL(type, backgroundColor, args) { //var imageDom = Painter.createDom('image', 'canvas', this); var imageDom = Painter.createDom(newGuid(), 'canvas', this); this._bgDom.appendChild(imageDom); var ctx = imageDom.getContext('2d'); Painter.devicePixelRatio !== 1 && ctx.scale(Painter.devicePixelRatio, Painter.devicePixelRatio); ctx.fillStyle = backgroundColor || '#fff'; ctx.rect( 0, 0, this._width * Painter.devicePixelRatio, this._height * Painter.devicePixelRatio ); ctx.fill(); var self = this; // 升序遍历,shape上的zlevel指定绘画图层的z轴层叠 this.storage.iterShape( function (shape) { if (!shape.invisible) { if (!shape.onbrush // 没有onbrush // 有onbrush并且调用执行返回false或undefined则继续粉刷 || (shape.onbrush && !shape.onbrush(ctx, false)) ) { if (Config.catchBrushException) { try { shape.brush(ctx, false, self.updatePainter); } catch (error) { } } else { shape.brush(ctx, false, self.updatePainter); } } } }, { normal: 'up', update: true } ); var image = imageDom.toDataURL(type, args); ctx = null; this._bgDom.removeChild(imageDom); return image; } /** * @function Zondy.LevelRenderer.Painter.prototype.getWidth * @description 获取绘图区域宽度。 * @return {number} 绘图区域宽度。 */ getWidth() { return this._width; } /** * @function Zondy.LevelRenderer.Painter.prototype.getHeight * @description 获取绘图区域高度。 * @return {number} 绘图区域高度。 */ getHeight() { return this._height; } /** * Method: _getWidth * */ _getWidth() { var root = this.root; var stl = root.currentStyle || document.defaultView.getComputedStyle(root); return ((root.clientWidth || parseInt(stl.width, 10)) - parseInt(stl.paddingLeft, 10) - parseInt(stl.paddingRight, 10)).toFixed(0) - 0; } /** * Method: _getHeight * */ _getHeight() { var root = this.root; var stl = root.currentStyle || document.defaultView.getComputedStyle(root); return ((root.clientHeight || parseInt(stl.height, 10)) - parseInt(stl.paddingTop, 10) - parseInt(stl.paddingBottom, 10)).toFixed(0) - 0; } /** * Method: _brushHover * */ _brushHover(shape) { var ctx = this._layers.hover.ctx; if (!shape.onbrush // 没有onbrush // 有onbrush并且调用执行返回false或undefined则继续粉刷 || (shape.onbrush && !shape.onbrush(ctx, true)) ) { var layer = this.getLayer(shape.zlevel); if (layer.needTransform) { ctx.save(); layer.setTransform(ctx); } // Retina 优化 if (Config.catchBrushException) { try { shape.brush(ctx, true, this.updatePainter); } catch (error) { } } else { shape.brush(ctx, true, this.updatePainter); } if (layer.needTransform) { ctx.restore(); } } } /** * Method: _shapeToImage * */ _shapeToImage(id, shape, width, height, devicePixelRatio) { var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var _devicePixelRatio = devicePixelRatio || window.devicePixelRatio || 1; canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; canvas.setAttribute('width', width * _devicePixelRatio); canvas.setAttribute('height', height * _devicePixelRatio); ctx.clearRect(0, 0, width * _devicePixelRatio, height * _devicePixelRatio); var shapeTransform = { position: shape.position, rotation: shape.rotation, scale: shape.scale }; shape.position = [0, 0, 0]; shape.rotation = 0; shape.scale = [1, 1]; if (shape) { shape.brush(ctx, false); } var imgShape = new SmicImage({ id: id, style: { x: 0, y: 0, image: canvas } }); if (shapeTransform.position != null) { imgShape.position = shape.position = shapeTransform.position; } if (shapeTransform.rotation != null) { imgShape.rotation = shape.rotation = shapeTransform.rotation; } if (shapeTransform.scale != null) { imgShape.scale = shape.scale = shapeTransform.scale; } return imgShape; } /** * Method: _createShapeToImageProcessor * */ _createShapeToImageProcessor() { var me = this; return function (id, e, width, height) { return me._shapeToImage( id, e, width, height, Painter.devicePixelRatio ); }; } // SMIC-方法扩展 - start /** * @function Zondy.LevelRenderer.Painter.prototype.updateHoverLayer * @description 更新设置显示高亮图层。 * @param {Array} shapes - 图形数组。 */ updateHoverLayer(shapes) { if (!(shapes instanceof Array)) { return this; } //清除高亮 this.clearHover(); this.storage.delHover(); for (var i = 0; i < shapes.length; i++) { this.storage.addHover(shapes[i]); this._brushHover(shapes[i]); } } /** * @function Zondy.LevelRenderer.Painter.prototype.createDom * @description 创建 Dom。 * * @param {string} id - Dom id * @param {string} type - Dom type * @param {Zondy.LevelRenderer.Painter} painter - Painter 实例。 * @return {Object} Dom */ static createDom(id, type, painter) { var newDom = document.createElement(type); var width = painter._width; var height = painter._height; newDom.style.position = 'absolute'; newDom.style.left = 0; newDom.style.top = 0; newDom.style.width = width + 'px'; newDom.style.height = height + 'px'; newDom.setAttribute('width', width * Painter.devicePixelRatio); newDom.setAttribute('height', height * Painter.devicePixelRatio); // id不作为索引用,避免可能造成的重名,定义为私有属性 //newDom.setAttribute('data-zr-dom-id', id); newDom.setAttribute('id', id); return newDom; } } /** * @private * @class Painter.Layer * @classdesc 绘制层类。 * @extends Zondy.LevelRenderer.Transformable */ class PaintLayer extends Transformable { /** * @function Painter.Layer.constructor * @description 构造函数。 * * @param {string} id - id。 * @param {Zondy.LevelRenderer.Painter} painter - Painter 实例。 * */ constructor(id, painter) { super(id, painter); /** * @member {Object} Painter.Layer.prototype.dom * @description dom。 */ this.dom = null; /** * @member {Object} Painter.Layer.prototype.domBack * @description domBack。 */ this.domBack = null; /** * @member {Object} Painter.Layer.prototype.ctxBack * @description ctxBack。 */ this.ctxBack = null; /** * @member {Zondy.LevelRenderer.Painter} Painter.Layer.prototype.painter * @description painter。 */ this.painter = painter; /** * @member {number} Painter.Layer.prototype.unusedCount * @description unusedCount。 */ this.unusedCount = 0; /** * @member {Object} Painter.Layer.prototype.config * @description config。 */ this.config = null; /** * @member {boolean} Painter.Layer.prototype.dirty * @description dirty。 */ this.dirty = true; /** * @member {number} Painter.Layer.prototype.elCount * @description elCount。 */ this.elCount = 0; // Configs /** * @member {string} Painter.Layer.prototype.clearColor * @description 每次清空画布的颜色。默认值:0; */ this.clearColor = 0; /** * @member {boolean} Painter.Layer.prototype.motionBlur * @description 是否开启动态模糊。默认值:false; */ this.motionBlur = false; /** * @member {number} Painter.Layer.prototype.lastFrameAlpha * @description 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显 */ this.lastFrameAlpha = 0.7; /** * @member {boolean} Painter.Layer.prototype.zoomable * @description 层是否支持鼠标平移操作。默认值:false; */ this.zoomable = false; /** * @member {boolean} Painter.Layer.prototype.panable * @description 层是否支持鼠标缩放操作。默认值:false; */ this.panable = false; /** * @member {number} Painter.Layer.prototype.maxZoom * @description maxZoom。默认值:Infinity。 */ this.maxZoom = Infinity; /** * @member {number} Painter.Layer.prototype.minZoom * @description minZoom。默认值:0。 */ this.minZoom = 0; /** * @member {number} Painter.Layer.prototype.ctx * @description Canvas 上下文。 */ this.ctx = null; this.dom = Painter.createDom(newGuid(), 'canvas', painter); this.dom.onselectstart = returnFalse; // 避免页面选中的尴尬 this.dom.style['-webkit-user-select'] = 'none'; this.dom.style['user-select'] = 'none'; this.dom.style['-webkit-touch-callout'] = 'none'; // Function // 返回false的方法,用于避免页面被选中 function returnFalse() { return false; } this.CLASS_NAME = "Zondy.LevelRenderer.Painter.Layer"; } /** * @function Painter.Layer.prototype.destroy * @description 销毁对象,释放资源。调用此函数后所有属性将被置为 null。 */ destroy() { this.dom = null; this.domBack = null; this.ctxBack = null; this.painter = null; this.unusedCount = null; this.config = null; this.dirty = null; this.elCount = null; this.clearColor = null; this.motionBlur = null; this.lastFrameAlpha = null; this.zoomable = null; this.panable = null; this.maxZoom = null; this.minZoom = null; this.ctx = null; Transformable.destroy.apply(this, arguments); } /** * @function Painter.Layer.prototype.initContext * @description 初始化 Canvan 2D 上下文。 */ initContext() { this.ctx = this.dom.getContext('2d'); if (Painter.devicePixelRatio !== 1) { this.ctx.scale(Painter.devicePixelRatio, Painter.devicePixelRatio); } } /** * @function Painter.Layer.prototype.createBackBuffer * @description 创建备份缓冲。 */ createBackBuffer() { this.domBack = Painter.createDom(newGuid(), 'canvas', this.painter); this.ctxBack = this.domBack.getContext('2d'); if (Painter.devicePixelRatio !== 1) { this.ctxBack.scale(Painter.devicePixelRatio, Painter.devicePixelRatio); } } /** * @function Painter.Layer.prototype.resize * @description 改变大小。 * * @param {number} width - 宽。 * @param {number} height - 高。 */ resize(width, height) { this.dom.style.width = width + 'px'; this.dom.style.height = height + 'px'; this.dom.setAttribute('width', width * Painter.devicePixelRatio); this.dom.setAttribute('height', height * Painter.devicePixelRatio); if (Painter.devicePixelRatio !== 1) { this.ctx.scale(Painter.devicePixelRatio, Painter.devicePixelRatio); } if (this.domBack) { this.domBack.setAttribute('width', width * Painter.devicePixelRatio); this.domBack.setAttribute('height', height * Painter.devicePixelRatio); if (Painter.devicePixelRatio !== 1) { this.ctxBack.scale(Painter.devicePixelRatio, Painter.devicePixelRatio); } } } /** * @function Painter.Layer.prototype.clear * @description 清空该层画布。 */ clear() { var dom = this.dom; var ctx = this.ctx; var width = dom.width; var height = dom.height; var haveClearColor = this.clearColor; var haveMotionBLur = this.motionBlur; var lastFrameAlpha = this.lastFrameAlpha; if (haveMotionBLur) { if (!this.domBack) { this.createBackBuffer(); } this.ctxBack.globalCompositeOperation = 'copy'; this.ctxBack.drawImage( dom, 0, 0, width / Painter.devicePixelRatio, height / Painter.devicePixelRatio ); } if (haveClearColor) { ctx.save(); ctx.fillStyle = this.config.clearColor; ctx.fillRect( 0, 0, width / Painter.devicePixelRatio, height / Painter.devicePixelRatio ); ctx.restore(); } else { ctx.clearRect( 0, 0, width / Painter.devicePixelRatio, height / Painter.devicePixelRatio ); } if (haveMotionBLur) { var domBack = this.domBack; ctx.save(); ctx.globalAlpha = lastFrameAlpha; ctx.drawImage( domBack, 0, 0, width / Painter.devicePixelRatio, height / Painter.devicePixelRatio ); ctx.restore(); } } } export {Painter}; Zondy.LevelRenderer.Painter = Painter; export {PaintLayer}; Zondy.LevelRenderer.PaintLayer = PaintLayer;