@devexperts/dxcharts-lite
Version:
71 lines (70 loc) • 3.32 kB
JavaScript
/*
* Copyright (C) 2019 - 2026 Devexperts Solutions IE Limited
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { getDPR } from '../utils/device/device-pixel-ratio.utils';
import { floor } from '../utils/math.utils';
import { deepEqual } from '../utils/object.utils';
export class BackgroundDrawer {
constructor(canvasModel, config, drawPredicate = () => true) {
this.canvasModel = canvasModel;
this.config = config;
this.drawPredicate = drawPredicate;
// we need to save previous state to avoid unnecessary redraws
this.prevState = {};
this.isColorsChanged = () => !deepEqual(this.config.colors.chartAreaTheme, this.prevState);
}
draw() {
if (this.drawPredicate() || this.isColorsChanged()) {
this.canvasModel.clear();
const ctx = this.canvasModel.ctx;
if (this.config.colors.chartAreaTheme.backgroundMode === 'gradient') {
const grd = ctx.createLinearGradient(0, 0 + this.canvasModel.height / 2, this.canvasModel.width, 0 + this.canvasModel.height / 2);
grd.addColorStop(0, this.config.colors.chartAreaTheme.backgroundGradientTopColor);
grd.addColorStop(1, this.config.colors.chartAreaTheme.backgroundGradientBottomColor);
ctx.fillStyle = grd;
}
else {
ctx.fillStyle = this.config.colors.chartAreaTheme.backgroundColor;
}
ctx.fillRect(0, 0, this.canvasModel.width, this.canvasModel.height);
}
// save prev state
this.prevState = Object.assign({}, this.config.colors.chartAreaTheme);
}
getCanvasIds() {
return [this.canvasModel.canvasId];
}
}
// this function in used in case when
// some entity can overlap with another chart entity, so we need to hide the another entity
// it has very (!!!) poor perfomance, use it carefully
export const redrawBackgroundArea = (backgroundCtx, ctx, x, y, width, height, opacity) => {
const dpr = getDPR();
const backgroundCoords = [x * dpr, y * dpr, width * dpr, height * dpr];
let imageData = backgroundCtx.getImageData(...backgroundCoords);
if (opacity !== undefined) {
// convert rgba to rgb for black background
// Target.R = (Source.A * Source.R)
// Target.G = (Source.A * Source.G)
// Target.B = (Source.A * Source.B)
const alpha = imageData.data[3] / 255;
if (alpha === 1) {
// fast path
for (let i = 3; i < imageData.data.length; i += 4) {
imageData.data[i] = floor(imageData.data[i] * opacity);
}
}
else {
for (let i = 0; i < imageData.data.length; i++) {
const v = imageData.data[i];
imageData.data[i] = i % 4 === 3 ? floor(v * opacity) : floor(alpha * v);
}
}
imageData = new ImageData(
// i % 4 === 3 - this condition is for alpha channel
imageData.data, imageData.width, imageData.height, { colorSpace: imageData.colorSpace });
}
ctx.putImageData(imageData, backgroundCoords[0], backgroundCoords[1]);
};