Загрузка данных
import { CanvasRenderingTarget2D } from 'fancy-canvas';
import { IPrimitivePaneRenderer } from 'lightweight-charts';
import type { VolumeProfile, VolumeProfileKind } from './volumeProfile';
const UI = {
rowGap: 1,
pocLineWidth: 2,
};
type DrawDirection = 'leftToRight' | 'rightToLeft';
export class VolumeProfilePaneRenderer implements IPrimitivePaneRenderer {
private readonly volumeProfile: VolumeProfile;
constructor(volumeProfile: VolumeProfile) {
this.volumeProfile = volumeProfile;
}
public draw(target: CanvasRenderingTarget2D): void {
const data = this.volumeProfile.getRenderData();
if (!data) {
return;
}
target.useBitmapCoordinateSpace(({ context, horizontalPixelRatio, verticalPixelRatio }) => {
const pixelRatio = Math.max(horizontalPixelRatio, verticalPixelRatio);
const left = data.left * horizontalPixelRatio;
const right = data.right * horizontalPixelRatio;
const top = data.top * verticalPixelRatio;
const bottom = data.bottom * verticalPixelRatio;
context.save();
context.fillStyle = data.areaFillColor;
context.fillRect(left, top, right - left, bottom - top);
const direction: DrawDirection = data.profileKind === 'visibleRange' ? 'rightToLeft' : 'leftToRight';
const rowStartX = data.profileKind === 'visibleRange' ? right : left;
data.rows.forEach((row) => {
const rowTop = row.top * verticalPixelRatio;
const rowHeight = row.height * verticalPixelRatio;
const buyWidth = row.buyWidth * horizontalPixelRatio;
const sellWidth = row.sellWidth * horizontalPixelRatio;
drawVolumeRow(
context,
rowStartX,
rowTop,
rowHeight,
buyWidth,
sellWidth,
pixelRatio,
data.buyFillColor,
data.sellFillColor,
direction,
);
});
if (data.pocY !== null) {
const pocY = data.pocY * verticalPixelRatio;
drawPocLine(context, data.profileKind, left, right, pocY, pixelRatio, data.pocLineColor);
}
context.restore();
});
}
}
function drawVolumeRow(
context: CanvasRenderingContext2D,
startX: number,
top: number,
height: number,
buyWidth: number,
sellWidth: number,
pixelRatio: number,
buyFillColor: string,
sellFillColor: string,
direction: DrawDirection,
): void {
const safeHeight = Math.max(1, height - UI.rowGap * pixelRatio);
if (buyWidth <= 0 && sellWidth <= 0) {
return;
}
if (direction === 'rightToLeft') {
const buyLeft = startX - buyWidth;
const sellLeft = buyLeft - sellWidth;
if (sellWidth > 0) {
context.fillStyle = sellFillColor;
context.fillRect(sellLeft, top, sellWidth, safeHeight);
}
if (buyWidth > 0) {
context.fillStyle = buyFillColor;
context.fillRect(buyLeft, top, buyWidth, safeHeight);
}
return;
}
if (buyWidth > 0) {
context.fillStyle = buyFillColor;
context.fillRect(startX, top, buyWidth, safeHeight);
}
if (sellWidth > 0) {
context.fillStyle = sellFillColor;
context.fillRect(startX + buyWidth, top, sellWidth, safeHeight);
}
}
function drawPocLine(
context: CanvasRenderingContext2D,
profileKind: VolumeProfileKind,
left: number,
right: number,
y: number,
pixelRatio: number,
color: string,
): void {
const lineLeft = profileKind === 'visibleRange' ? 0 : left;
const lineRight = profileKind === 'visibleRange' ? context.canvas.width : right;
context.strokeStyle = color;
context.lineWidth = UI.pocLineWidth * pixelRatio;
context.beginPath();
context.moveTo(lineLeft, y);
context.lineTo(lineRight, y);
context.stroke();
}