Загрузка данных
import { CanvasRenderingTarget2D } from 'fancy-canvas';
import { IPrimitivePaneRenderer } from 'lightweight-charts';
import { getThemeStore } from '@src/theme';
import type { VolumeProfile } from './volumeProfile';
const UI = {
borderWidth: 1,
handleRadius: 5,
handleBorderWidth: 2,
rowGap: 1,
pocLineWidth: 1,
};
const { colors } = getThemeStore();
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 = colors.volumeProfileAreaFill;
context.fillRect(left, top, right - left, bottom - top);
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, left, rowTop, rowHeight, buyWidth, sellWidth, pixelRatio);
});
if (data.pocY !== null) {
context.strokeStyle = colors.volumeProfilePocLine;
context.lineWidth = UI.pocLineWidth * pixelRatio;
context.beginPath();
context.moveTo(left, data.pocY * verticalPixelRatio);
context.lineTo(right, data.pocY * verticalPixelRatio);
context.stroke();
}
drawSideBorders(context, left, right, top, bottom, pixelRatio);
if (data.showHandles) {
drawHandle(
context,
data.startPoint.x * horizontalPixelRatio,
data.startPoint.y * verticalPixelRatio,
pixelRatio,
);
drawHandle(
context,
data.endPoint.x * horizontalPixelRatio,
data.endPoint.y * verticalPixelRatio,
pixelRatio,
);
}
context.restore();
});
}
}
function drawVolumeRow(
context: CanvasRenderingContext2D,
left: number,
top: number,
height: number,
buyWidth: number,
sellWidth: number,
pixelRatio: number,
): void {
const safeHeight = Math.max(1, height - UI.rowGap * pixelRatio);
if (buyWidth <= 0 && sellWidth <= 0) {
return;
}
if (buyWidth > 0 && sellWidth > 0) {
const halfHeight = Math.max(1, safeHeight / 2);
context.fillStyle = colors.volumeProfileBuyFill;
context.fillRect(left, top, buyWidth, halfHeight);
context.fillStyle = colors.volumeProfileSellFill;
context.fillRect(left, top + halfHeight, sellWidth, halfHeight);
return;
}
context.fillStyle = buyWidth > 0 ? colors.volumeProfileBuyFill : colors.volumeProfileSellFill;
context.fillRect(left, top, Math.max(buyWidth, sellWidth), safeHeight);
}
function drawSideBorders(
context: CanvasRenderingContext2D,
left: number,
right: number,
top: number,
bottom: number,
pixelRatio: number,
): void {
context.strokeStyle = colors.chartLineColor;
context.lineWidth = UI.borderWidth * pixelRatio;
context.beginPath();
context.moveTo(Math.round(left), top);
context.lineTo(Math.round(left), bottom);
context.moveTo(Math.round(right), top);
context.lineTo(Math.round(right), bottom);
context.stroke();
}
function drawHandle(context: CanvasRenderingContext2D, x: number, y: number, pixelRatio: number): void {
context.save();
context.fillStyle = colors.chartBackground;
context.strokeStyle = colors.chartLineColor;
context.lineWidth = UI.handleBorderWidth * pixelRatio;
context.beginPath();
context.arc(x, y, UI.handleRadius * pixelRatio, 0, Math.PI * 2);
context.fill();
context.stroke();
context.restore();
}