Skip to content

Commit

Permalink
fix: fix background drawer optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
Keelaro1 authored and dxpm committed Dec 11, 2023
1 parent 2e1fc04 commit f6dd213
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 47 deletions.
1 change: 1 addition & 0 deletions src/chart/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ export default class ChartBootstrap {
paneManager,
this.cursorHandler,
this.dynamicObjects,
this.chartResizeHandler,
);
this.chartComponents.push(chartComponent);
this.chartComponent = chartComponent;
Expand Down
22 changes: 20 additions & 2 deletions src/chart/components/chart/chart.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* 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 { Observable } from 'rxjs';
import { Observable, BehaviorSubject } from 'rxjs';
import { CHART_UUID, CanvasBoundsContainer, CanvasElement } from '../../canvas/canvas-bounds-container';
import { CursorHandler } from '../../canvas/cursor.handler';
import { ChartBaseElement } from '../../model/chart-base-element';
Expand Down Expand Up @@ -51,6 +51,7 @@ import { CandleWidthCalculator, ChartModel, LastCandleLabelHandler, VisualCandle
import { PrependedCandlesData } from './chart-base.model';
import { TrendHistogramDrawer } from '../../drawers/data-series-drawers/trend-histogram.drawer';
import { DynamicObjectsComponent } from '../dynamic-objects/dynamic-objects.component';
import { ChartResizeHandler } from '../../inputhandlers/chart-resize.handler';

/**
* Represents a financial instrument to be displayed on a chart
Expand Down Expand Up @@ -81,6 +82,7 @@ export class ChartComponent extends ChartBaseElement {
private readonly backgroundDrawer: BackgroundDrawer;
private readonly _dataSeriesDrawers: Record<DataSeriesType, SeriesDrawer> = {};
private readonly dataSeriesDrawer: DataSeriesDrawer;
private backgroundDrawPredicateSubj = new BehaviorSubject<boolean>(true);

constructor(
public readonly chartModel: ChartModel,
Expand All @@ -96,6 +98,7 @@ export class ChartComponent extends ChartBaseElement {
private paneManager: PaneManager,
cursorHandler: CursorHandler,
private dynamicObjects: DynamicObjectsComponent,
private chartResizeHandler: ChartResizeHandler,
) {
super();
this.addChildEntity(this.chartModel);
Expand All @@ -117,7 +120,11 @@ export class ChartComponent extends ChartBaseElement {
//#region data series drawers
this.registerDefaultDataSeriesDrawers();
//#endregion
this.backgroundDrawer = new BackgroundDrawer(backgroundCanvasModel, this.config);
this.backgroundDrawer = new BackgroundDrawer(
backgroundCanvasModel,
this.config,
() => this.backgroundDrawPredicateSubj.getValue(),
);
drawingManager.addDrawer(this.backgroundDrawer, 'MAIN_BACKGROUND');
cursorHandler.setCursorForCanvasEl(CanvasElement.PANE_UUID(CHART_UUID), config.components.chart.cursor);

Expand Down Expand Up @@ -154,6 +161,17 @@ export class ChartComponent extends ChartBaseElement {
this.dynamicObjects.model.removeObject(series.id);
}),
);
// redraw background only when chart is resized
this.addRxSubscription(
this.canvasBoundsContainer.observeAnyBoundsChanged().subscribe(() => {
this.backgroundDrawPredicateSubj.next(false);
}),
);
this.addRxSubscription(
this.chartResizeHandler.canvasResized.subscribe(() => {
this.backgroundDrawPredicateSubj.next(true);
}),
);
}

/**
Expand Down
59 changes: 14 additions & 45 deletions src/chart/drawers/chart-background.drawer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,25 @@
*/
import { Drawer } from './drawing-manager';
import { CanvasModel } from '../model/canvas.model';
import { FullChartConfig } from '../chart.config';
import { ChartAreaTheme, FullChartConfig } from '../chart.config';
import { getDPR } from '../utils/device/device-pixel-ratio.utils';
import { floor } from '../utils/math.utils';
import Color from 'color';
import { deepEqual } from '../utils/object.utils';

export class BackgroundDrawer implements Drawer {
constructor(private canvasModel: CanvasModel, private config: FullChartConfig) {}
constructor(
private canvasModel: CanvasModel,
private config: FullChartConfig,
private backgroundDrawPredicate: () => boolean = () => true,
) {}

draw(): void {
const ctx = this.canvasModel.ctx;
const shouldRedraw = this.shouldRedrawBackground(ctx);
// we need to save previous state to avoid unnecessary redraws
private prevState: Partial<ChartAreaTheme> = {};

if (shouldRedraw) {
draw(): void {
if (this.backgroundDrawPredicate() || !deepEqual(this.config.colors.chartAreaTheme, this.prevState)) {
this.canvasModel.clear();
const ctx = this.canvasModel.ctx;
if (this.config.colors.chartAreaTheme.backgroundMode === 'gradient') {
const grd = ctx.createLinearGradient(0, 0, this.canvasModel.width, this.canvasModel.height);
grd.addColorStop(0, this.config.colors.chartAreaTheme.backgroundGradientTopColor);
Expand All @@ -29,44 +34,8 @@ export class BackgroundDrawer implements Drawer {
}
ctx.fillRect(0, 0, this.canvasModel.width, this.canvasModel.height);
}
}

shouldRedrawBackground(ctx: CanvasRenderingContext2D): boolean {
// checking the gradient background
// it takes two edge pixels (far left and far right) and compares them with the config values
if (this.config.colors.chartAreaTheme.backgroundMode === 'gradient') {
const dpr = getDPR();

const imageDataLeft = ctx.getImageData(1, 1, 1, 1).data;
const rgbaLeft = `rgba(${imageDataLeft[0]}, ${imageDataLeft[1]}, ${imageDataLeft[2]}, ${
imageDataLeft[3] / 255
})`;

const imageDataRight = ctx.getImageData(
this.canvasModel.width * dpr - 1,
this.canvasModel.height * dpr - 1,
1,
1,
).data;
const rgbaRight = `rgba(${imageDataRight[0]}, ${imageDataRight[1]}, ${imageDataRight[2]}, ${
imageDataRight[3] / 255
})`;

if (
rgbaLeft === this.config.colors.chartAreaTheme.backgroundGradientTopColor &&
rgbaRight === this.config.colors.chartAreaTheme.backgroundGradientBottomColor
) {
return false;
}
}
// checking the regular background when one color is used
if (
this.config.colors.chartAreaTheme.backgroundMode === 'regular' &&
this.canvasModel.ctx.fillStyle === Color(this.config.colors.chartAreaTheme.backgroundColor).hex()
) {
return false;
}
return true;
// save prev state
this.prevState = { ...this.config.colors.chartAreaTheme };
}

getCanvasIds(): Array<string> {
Expand Down

0 comments on commit f6dd213

Please sign in to comment.