diff --git a/src/model/price-scale.ts b/src/model/price-scale.ts index 9e77056ac3..6236dbefc1 100644 --- a/src/model/price-scale.ts +++ b/src/model/price-scale.ts @@ -349,7 +349,7 @@ export class PriceScale { return this._logicalToCoordinate(price, baseValue, keepItFloat); } - public pointsArrayToCoordinates(points: T[], baseValue: number, visibleRange?: SeriesItemsIndexesRange): void { + public pointsArrayToCoordinates(points: T[], baseValue: number, visibleRange?: SeriesItemsIndexesRange): Coordinate { this._makeSureItIsValid(); const bh = this._bottomMarginPx(); const range = ensureNotNull(this.priceRange()); @@ -364,6 +364,18 @@ export class PriceScale { const toIndex = (visibleRange === undefined) ? points.length : visibleRange.to; const transformFn = this._getCoordinateTransformer(); + + const getPoint = (price: BarPrice): Coordinate => { + let logical = price; + if (transformFn !== null) { + logical = transformFn(price, baseValue) as BarPrice; + } + + const invCoordinate = bh + hmm * (logical - min); + const coordinate = isInverted ? invCoordinate : this._height - 1 - invCoordinate; + return Math.round(coordinate) as Coordinate; + }; + for (let i = fromIndex; i < toIndex; i++) { const point = points[i]; const price = point.price; @@ -372,15 +384,10 @@ export class PriceScale { continue; } - let logical = price; - if (transformFn !== null) { - logical = transformFn(point.price, baseValue) as BarPrice; - } - - const invCoordinate = bh + hmm * (logical - min); - const coordinate = isInverted ? invCoordinate : this._height - 1 - invCoordinate; - point.y = Math.round(coordinate) as Coordinate; + point.y = getPoint(price); } + + return getPoint(0 as BarPrice); } public barPricesToCoordinates(pricesList: T[], baseValue: number, visibleRange?: SeriesItemsIndexesRange): void { diff --git a/src/renderers/area-renderer.ts b/src/renderers/area-renderer.ts index dc763c462b..9619927e0a 100644 --- a/src/renderers/area-renderer.ts +++ b/src/renderers/area-renderer.ts @@ -16,6 +16,7 @@ export interface PaneRendererAreaData { topColor: string; bottomColor: string; bottom: Coordinate; + zeroLine: Coordinate; visibleRange: SeriesItemsIndexesRange | null; } @@ -32,6 +33,8 @@ export class PaneRendererArea implements IPaneRenderer { return; } + const baseline = Math.min(this._data.bottom, this._data.zeroLine); + ctx.save(); ctx.lineCap = 'square'; @@ -43,16 +46,16 @@ export class PaneRendererArea implements IPaneRenderer { ctx.lineWidth = 1; ctx.beginPath(); - ctx.moveTo(this._data.items[this._data.visibleRange.from].x, this._data.bottom); + ctx.moveTo(this._data.items[this._data.visibleRange.from].x, baseline); ctx.lineTo(this._data.items[this._data.visibleRange.from].x, this._data.items[this._data.visibleRange.from].y); walkLine(ctx, this._data.items, this._data.lineType, this._data.visibleRange); - ctx.lineTo(this._data.items[this._data.visibleRange.to - 1].x, this._data.bottom); - ctx.lineTo(this._data.items[this._data.visibleRange.from].x, this._data.bottom); + ctx.lineTo(this._data.items[this._data.visibleRange.to - 1].x, baseline); + ctx.lineTo(this._data.items[this._data.visibleRange.from].x, baseline); ctx.closePath(); - const gradient = ctx.createLinearGradient(0, 0, 0, this._data.bottom); + const gradient = ctx.createLinearGradient(0, 0, 0, Math.min(baseline, this._data.zeroLine)); gradient.addColorStop(0, this._data.topColor); gradient.addColorStop(1, this._data.bottomColor); diff --git a/src/views/pane/area-pane-view.ts b/src/views/pane/area-pane-view.ts index 89b5c30811..6ebccc8367 100644 --- a/src/views/pane/area-pane-view.ts +++ b/src/views/pane/area-pane-view.ts @@ -35,6 +35,7 @@ export class SeriesAreaPaneView extends LinePaneViewBase<'Area', LineItem> { topColor: areaStyleProperties.topColor, bottomColor: areaStyleProperties.bottomColor, bottom: height as Coordinate, + zeroLine: this._itemsZeroLine, visibleRange: this._itemsVisibleRange, }; diff --git a/src/views/pane/line-pane-view-base.ts b/src/views/pane/line-pane-view-base.ts index 71fcd89664..71b9eba158 100644 --- a/src/views/pane/line-pane-view-base.ts +++ b/src/views/pane/line-pane-view-base.ts @@ -13,13 +13,15 @@ import { TimeScale } from '../../model/time-scale'; import { SeriesPaneViewBase } from './series-pane-view-base'; export abstract class LinePaneViewBase extends SeriesPaneViewBase { + protected _itemsZeroLine: Coordinate = NaN as Coordinate; + protected constructor(series: Series, model: ChartModel) { super(series, model, true); } protected _convertToCoordinates(priceScale: PriceScale, timeScale: TimeScale, firstValue: number): void { timeScale.indexesToCoordinates(this._items, undefinedIfNull(this._itemsVisibleRange)); - priceScale.pointsArrayToCoordinates(this._items, firstValue, undefinedIfNull(this._itemsVisibleRange)); + this._itemsZeroLine = priceScale.pointsArrayToCoordinates(this._items, firstValue, undefinedIfNull(this._itemsVisibleRange)); } protected abstract _createRawItem(time: TimePointIndex, price: BarPrice, colorer: SeriesBarColorer): ItemType;