import { BaseToken } from '../../theme/index'; import Axis from './axis'; import { AxisOptions, AxisData } from '../../models'; import { AxisName } from './config'; import { getTextWidth } from '../../utils/textProcessor'; export default class YAxis extends Axis { constructor(chart, axisdata: AxisData, options: AxisOptions, axisIndex: number) { super(chart, AxisName.YAxis, axisdata, options, axisIndex); } /** * 支持多y轴TODO: * 1.option解析yAxis,识别多y轴 * 2.区分单/双y轴绘制 * 3.双y轴的max 分别从data计算;并对齐; * 4.双y轴的interval划分 分别从data计算; 并对齐; */ render() { const { axisLine, axisTick, splitLine } = this.options; axisLine?.show && this.drawLine(); axisTick?.show && this.drawTick(); splitLine?.show && this.drawSplitLine(); this.drawLabel(); } /** * 画坐标轴线 */ drawLine() { const { size } = this.canvas; if (this.axisIndex > 1) return; // 画线 if (this.axisIndex === 0) { this.painter.draw('Line', { x1: 0, y1: 0, x2: 0, y2: size.height, strokeStyle: BaseToken?.COLOR?.GRAY_5 ?? '#ddd', lineWidth: 1, }); } // 双yAxis绘制第二条y轴线 if (this.axisIndex === 1) { this.painter.draw('Line', { x1: size.width, y1: 0, x2: size.width, y2: size.height, strokeStyle: BaseToken?.COLOR?.GRAY_5 ?? '#ddd', lineWidth: 2, }); } } /** * 画坐标轴刻度 */ drawTick() { const { canvas, layoutData } = this; const { size } = canvas; if (!layoutData) return; const tickLength = 20; const tickPixelGap = size.height / (layoutData.length - 1); if (this.axisIndex > 1) return; // 画tick if (this.axisIndex === 0) { for (let i = 0; i <= layoutData.length; i++) { this.painter.draw('Line', { x1: -tickLength, y1: i * tickPixelGap, x2: 0, y2: i * tickPixelGap, lineWidth: 1, strokeStyle: BaseToken?.COLOR?.GRAY_5 ?? '#ddd', }); } } // 双yAxis绘制第二条y轴线 tick if (this.axisIndex === 1) { for (let i = 0; i <= layoutData.length; i++) { this.painter.draw('Line', { x1: size.width, y1: i * tickPixelGap, x2: size.width + tickLength, y2: i * tickPixelGap, lineWidth: 1, strokeStyle: BaseToken?.COLOR?.GRAY_5 ?? '#ddd', }); } } } /** * 画坐标轴文本 */ drawLabel() { const { canvas, options, layoutData } = this; const { size } = canvas; if (!layoutData) return; const PADDING_GAP = 4; const TEXT_FONT_WEIGHT = 12; const TEXT_WIDTH = 40; const { axisTextMode = 'classic', boundaryGap } = options; const tickGap = size.height / (boundaryGap ? layoutData.length : layoutData.length - 1); const generateLabelText = (text: string) => { if (!this.options?.axisLabel?.formatter) return text; const { formatter } = this.options?.axisLabel; if (typeof formatter === 'string') { return text.replace(/\{.*\}/, text); } return formatter(text); }; if (this.axisIndex > 1) return; // 画text if (this.axisIndex === 0) { layoutData.forEach((item, index) => { const { text } = item; switch (axisTextMode) { case 'classic': this.painter.draw('Text', { text: generateLabelText(text), x: - PADDING_GAP, y: index * tickGap - TEXT_FONT_WEIGHT / 2 + (boundaryGap ? tickGap / 2 : 0), textBaseline: 'bottom', textAlign: 'right', fontStyle: BaseToken?.COLOR?.FONTGRAY_2, }); break; case 'default': default: { const textWidth = getTextWidth(text) || TEXT_WIDTH; this.painter.draw('Text', { text: generateLabelText(String(text)), x: -textWidth / 2, y: index * tickGap + PADDING_GAP, textBaseline: 'bottom', fontStyle: BaseToken?.COLOR?.FONTGRAY_2, }); break; } } }); } // 双yAxis绘制第二条y轴线 // (第二轴线忽略axisTextMode,统一按照classicMode实现) if (this.axisIndex === 1) { layoutData.forEach((item, index) => { const { text } = item; this.painter.draw('Text', { text: generateLabelText(text), x: PADDING_GAP + size.width + PADDING_GAP, y: index * tickGap - TEXT_FONT_WEIGHT / 2, textBaseline: 'bottom', textAlign: 'left', fontStyle: BaseToken?.COLOR?.FONTGRAY_2, }); }); } } /** * 画坐标轴分隔线 */ drawSplitLine() { const { canvas: { size }, layoutData, } = this; if (!layoutData) return; const tickPixelGap = size.height / (layoutData.length - 1); if (this.axisIndex > 1) return; // 画分割线 if (this.axisIndex === 0) { layoutData.forEach((_, index) => { if (index === 0) return; this.painter.draw('Line', { x1: 0, y1: index * tickPixelGap, x2: size.width, y2: index * tickPixelGap, lineWidth: 1, strokeStyle: BaseToken?.COLOR?.GRAY_3 ?? '#ddd', }); }); } // 双yAxis绘制第二条y轴线 分割线 if (this.axisIndex === 1) { layoutData.forEach((_, index) => { if (index === 0) return; this.painter.draw('Line', { x1: 0, y1: index * tickPixelGap, x2: size.width, y2: index * tickPixelGap, lineWidth: 1, strokeStyle: BaseToken?.COLOR?.GRAY_3 ?? '#ddd', }); }); } } }