You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
298 lines
11 KiB
298 lines
11 KiB
4 weeks ago
|
import { __extends } from "tslib";
|
||
|
import * as util from '../core/util.js';
|
||
|
import { devicePixelRatio } from '../config.js';
|
||
|
import Eventful from '../core/Eventful.js';
|
||
|
import { getCanvasGradient } from './helper.js';
|
||
|
import { createCanvasPattern } from './graphic.js';
|
||
|
import BoundingRect from '../core/BoundingRect.js';
|
||
|
import { REDRAW_BIT } from '../graphic/constants.js';
|
||
|
import { platformApi } from '../core/platform.js';
|
||
|
function createDom(id, painter, dpr) {
|
||
|
var newDom = platformApi.createCanvas();
|
||
|
var width = painter.getWidth();
|
||
|
var height = painter.getHeight();
|
||
|
var newDomStyle = newDom.style;
|
||
|
if (newDomStyle) {
|
||
|
newDomStyle.position = 'absolute';
|
||
|
newDomStyle.left = '0';
|
||
|
newDomStyle.top = '0';
|
||
|
newDomStyle.width = width + 'px';
|
||
|
newDomStyle.height = height + 'px';
|
||
|
newDom.setAttribute('data-zr-dom-id', id);
|
||
|
}
|
||
|
newDom.width = width * dpr;
|
||
|
newDom.height = height * dpr;
|
||
|
return newDom;
|
||
|
}
|
||
|
;
|
||
|
var Layer = (function (_super) {
|
||
|
__extends(Layer, _super);
|
||
|
function Layer(id, painter, dpr) {
|
||
|
var _this = _super.call(this) || this;
|
||
|
_this.motionBlur = false;
|
||
|
_this.lastFrameAlpha = 0.7;
|
||
|
_this.dpr = 1;
|
||
|
_this.virtual = false;
|
||
|
_this.config = {};
|
||
|
_this.incremental = false;
|
||
|
_this.zlevel = 0;
|
||
|
_this.maxRepaintRectCount = 5;
|
||
|
_this.__dirty = true;
|
||
|
_this.__firstTimePaint = true;
|
||
|
_this.__used = false;
|
||
|
_this.__drawIndex = 0;
|
||
|
_this.__startIndex = 0;
|
||
|
_this.__endIndex = 0;
|
||
|
_this.__prevStartIndex = null;
|
||
|
_this.__prevEndIndex = null;
|
||
|
var dom;
|
||
|
dpr = dpr || devicePixelRatio;
|
||
|
if (typeof id === 'string') {
|
||
|
dom = createDom(id, painter, dpr);
|
||
|
}
|
||
|
else if (util.isObject(id)) {
|
||
|
dom = id;
|
||
|
id = dom.id;
|
||
|
}
|
||
|
_this.id = id;
|
||
|
_this.dom = dom;
|
||
|
var domStyle = dom.style;
|
||
|
if (domStyle) {
|
||
|
util.disableUserSelect(dom);
|
||
|
dom.onselectstart = function () { return false; };
|
||
|
domStyle.padding = '0';
|
||
|
domStyle.margin = '0';
|
||
|
domStyle.borderWidth = '0';
|
||
|
}
|
||
|
_this.painter = painter;
|
||
|
_this.dpr = dpr;
|
||
|
return _this;
|
||
|
}
|
||
|
Layer.prototype.getElementCount = function () {
|
||
|
return this.__endIndex - this.__startIndex;
|
||
|
};
|
||
|
Layer.prototype.afterBrush = function () {
|
||
|
this.__prevStartIndex = this.__startIndex;
|
||
|
this.__prevEndIndex = this.__endIndex;
|
||
|
};
|
||
|
Layer.prototype.initContext = function () {
|
||
|
this.ctx = this.dom.getContext('2d');
|
||
|
this.ctx.dpr = this.dpr;
|
||
|
};
|
||
|
Layer.prototype.setUnpainted = function () {
|
||
|
this.__firstTimePaint = true;
|
||
|
};
|
||
|
Layer.prototype.createBackBuffer = function () {
|
||
|
var dpr = this.dpr;
|
||
|
this.domBack = createDom('back-' + this.id, this.painter, dpr);
|
||
|
this.ctxBack = this.domBack.getContext('2d');
|
||
|
if (dpr !== 1) {
|
||
|
this.ctxBack.scale(dpr, dpr);
|
||
|
}
|
||
|
};
|
||
|
Layer.prototype.createRepaintRects = function (displayList, prevList, viewWidth, viewHeight) {
|
||
|
if (this.__firstTimePaint) {
|
||
|
this.__firstTimePaint = false;
|
||
|
return null;
|
||
|
}
|
||
|
var mergedRepaintRects = [];
|
||
|
var maxRepaintRectCount = this.maxRepaintRectCount;
|
||
|
var full = false;
|
||
|
var pendingRect = new BoundingRect(0, 0, 0, 0);
|
||
|
function addRectToMergePool(rect) {
|
||
|
if (!rect.isFinite() || rect.isZero()) {
|
||
|
return;
|
||
|
}
|
||
|
if (mergedRepaintRects.length === 0) {
|
||
|
var boundingRect = new BoundingRect(0, 0, 0, 0);
|
||
|
boundingRect.copy(rect);
|
||
|
mergedRepaintRects.push(boundingRect);
|
||
|
}
|
||
|
else {
|
||
|
var isMerged = false;
|
||
|
var minDeltaArea = Infinity;
|
||
|
var bestRectToMergeIdx = 0;
|
||
|
for (var i = 0; i < mergedRepaintRects.length; ++i) {
|
||
|
var mergedRect = mergedRepaintRects[i];
|
||
|
if (mergedRect.intersect(rect)) {
|
||
|
var pendingRect_1 = new BoundingRect(0, 0, 0, 0);
|
||
|
pendingRect_1.copy(mergedRect);
|
||
|
pendingRect_1.union(rect);
|
||
|
mergedRepaintRects[i] = pendingRect_1;
|
||
|
isMerged = true;
|
||
|
break;
|
||
|
}
|
||
|
else if (full) {
|
||
|
pendingRect.copy(rect);
|
||
|
pendingRect.union(mergedRect);
|
||
|
var aArea = rect.width * rect.height;
|
||
|
var bArea = mergedRect.width * mergedRect.height;
|
||
|
var pendingArea = pendingRect.width * pendingRect.height;
|
||
|
var deltaArea = pendingArea - aArea - bArea;
|
||
|
if (deltaArea < minDeltaArea) {
|
||
|
minDeltaArea = deltaArea;
|
||
|
bestRectToMergeIdx = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (full) {
|
||
|
mergedRepaintRects[bestRectToMergeIdx].union(rect);
|
||
|
isMerged = true;
|
||
|
}
|
||
|
if (!isMerged) {
|
||
|
var boundingRect = new BoundingRect(0, 0, 0, 0);
|
||
|
boundingRect.copy(rect);
|
||
|
mergedRepaintRects.push(boundingRect);
|
||
|
}
|
||
|
if (!full) {
|
||
|
full = mergedRepaintRects.length >= maxRepaintRectCount;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (var i = this.__startIndex; i < this.__endIndex; ++i) {
|
||
|
var el = displayList[i];
|
||
|
if (el) {
|
||
|
var shouldPaint = el.shouldBePainted(viewWidth, viewHeight, true, true);
|
||
|
var prevRect = el.__isRendered && ((el.__dirty & REDRAW_BIT) || !shouldPaint)
|
||
|
? el.getPrevPaintRect()
|
||
|
: null;
|
||
|
if (prevRect) {
|
||
|
addRectToMergePool(prevRect);
|
||
|
}
|
||
|
var curRect = shouldPaint && ((el.__dirty & REDRAW_BIT) || !el.__isRendered)
|
||
|
? el.getPaintRect()
|
||
|
: null;
|
||
|
if (curRect) {
|
||
|
addRectToMergePool(curRect);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (var i = this.__prevStartIndex; i < this.__prevEndIndex; ++i) {
|
||
|
var el = prevList[i];
|
||
|
var shouldPaint = el && el.shouldBePainted(viewWidth, viewHeight, true, true);
|
||
|
if (el && (!shouldPaint || !el.__zr) && el.__isRendered) {
|
||
|
var prevRect = el.getPrevPaintRect();
|
||
|
if (prevRect) {
|
||
|
addRectToMergePool(prevRect);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
var hasIntersections;
|
||
|
do {
|
||
|
hasIntersections = false;
|
||
|
for (var i = 0; i < mergedRepaintRects.length;) {
|
||
|
if (mergedRepaintRects[i].isZero()) {
|
||
|
mergedRepaintRects.splice(i, 1);
|
||
|
continue;
|
||
|
}
|
||
|
for (var j = i + 1; j < mergedRepaintRects.length;) {
|
||
|
if (mergedRepaintRects[i].intersect(mergedRepaintRects[j])) {
|
||
|
hasIntersections = true;
|
||
|
mergedRepaintRects[i].union(mergedRepaintRects[j]);
|
||
|
mergedRepaintRects.splice(j, 1);
|
||
|
}
|
||
|
else {
|
||
|
j++;
|
||
|
}
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
} while (hasIntersections);
|
||
|
this._paintRects = mergedRepaintRects;
|
||
|
return mergedRepaintRects;
|
||
|
};
|
||
|
Layer.prototype.debugGetPaintRects = function () {
|
||
|
return (this._paintRects || []).slice();
|
||
|
};
|
||
|
Layer.prototype.resize = function (width, height) {
|
||
|
var dpr = this.dpr;
|
||
|
var dom = this.dom;
|
||
|
var domStyle = dom.style;
|
||
|
var domBack = this.domBack;
|
||
|
if (domStyle) {
|
||
|
domStyle.width = width + 'px';
|
||
|
domStyle.height = height + 'px';
|
||
|
}
|
||
|
dom.width = width * dpr;
|
||
|
dom.height = height * dpr;
|
||
|
if (domBack) {
|
||
|
domBack.width = width * dpr;
|
||
|
domBack.height = height * dpr;
|
||
|
if (dpr !== 1) {
|
||
|
this.ctxBack.scale(dpr, dpr);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
Layer.prototype.clear = function (clearAll, clearColor, repaintRects) {
|
||
|
var dom = this.dom;
|
||
|
var ctx = this.ctx;
|
||
|
var width = dom.width;
|
||
|
var height = dom.height;
|
||
|
clearColor = clearColor || this.clearColor;
|
||
|
var haveMotionBLur = this.motionBlur && !clearAll;
|
||
|
var lastFrameAlpha = this.lastFrameAlpha;
|
||
|
var dpr = this.dpr;
|
||
|
var self = this;
|
||
|
if (haveMotionBLur) {
|
||
|
if (!this.domBack) {
|
||
|
this.createBackBuffer();
|
||
|
}
|
||
|
this.ctxBack.globalCompositeOperation = 'copy';
|
||
|
this.ctxBack.drawImage(dom, 0, 0, width / dpr, height / dpr);
|
||
|
}
|
||
|
var domBack = this.domBack;
|
||
|
function doClear(x, y, width, height) {
|
||
|
ctx.clearRect(x, y, width, height);
|
||
|
if (clearColor && clearColor !== 'transparent') {
|
||
|
var clearColorGradientOrPattern = void 0;
|
||
|
if (util.isGradientObject(clearColor)) {
|
||
|
var shouldCache = clearColor.global || (clearColor.__width === width
|
||
|
&& clearColor.__height === height);
|
||
|
clearColorGradientOrPattern = shouldCache
|
||
|
&& clearColor.__canvasGradient
|
||
|
|| getCanvasGradient(ctx, clearColor, {
|
||
|
x: 0,
|
||
|
y: 0,
|
||
|
width: width,
|
||
|
height: height
|
||
|
});
|
||
|
clearColor.__canvasGradient = clearColorGradientOrPattern;
|
||
|
clearColor.__width = width;
|
||
|
clearColor.__height = height;
|
||
|
}
|
||
|
else if (util.isImagePatternObject(clearColor)) {
|
||
|
clearColor.scaleX = clearColor.scaleX || dpr;
|
||
|
clearColor.scaleY = clearColor.scaleY || dpr;
|
||
|
clearColorGradientOrPattern = createCanvasPattern(ctx, clearColor, {
|
||
|
dirty: function () {
|
||
|
self.setUnpainted();
|
||
|
self.painter.refresh();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
ctx.save();
|
||
|
ctx.fillStyle = clearColorGradientOrPattern || clearColor;
|
||
|
ctx.fillRect(x, y, width, height);
|
||
|
ctx.restore();
|
||
|
}
|
||
|
if (haveMotionBLur) {
|
||
|
ctx.save();
|
||
|
ctx.globalAlpha = lastFrameAlpha;
|
||
|
ctx.drawImage(domBack, x, y, width, height);
|
||
|
ctx.restore();
|
||
|
}
|
||
|
}
|
||
|
;
|
||
|
if (!repaintRects || haveMotionBLur) {
|
||
|
doClear(0, 0, width, height);
|
||
|
}
|
||
|
else if (repaintRects.length) {
|
||
|
util.each(repaintRects, function (rect) {
|
||
|
doClear(rect.x * dpr, rect.y * dpr, rect.width * dpr, rect.height * dpr);
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
return Layer;
|
||
|
}(Eventful));
|
||
|
export default Layer;
|