/**
 * 坐标轴和图例绘制函数
 *
 * 从 u-charts 核心库搬迁的坐标轴和图例绘制相关函数
 * 用于处理X轴、Y轴、网格线和图例的绘制操作
 */

// @ts-nocheck - 由于从 u-charts 搬迁，类型系统不兼容，暂时禁用类型检查

import type { ChartOptions, UChartsConfig, SeriesItem } from '../data-processing/series-calculator';
import { measureText } from '../utils/text';
import { convertCoordinateOrigin } from '../utils/coordinate';
import { hexToRgb } from '../utils/color';
import { assign } from '../config';

// Canvas 上下文类型（使用 any 以兼容小程序环境）
export type CanvasContext = any;

/**
 * 坐标点接口
 */
export interface Point {
  x: number;
  y: number;
}

/**
 * 仪表盘选项接口
 */
export interface GaugeOption {
  width?: number;
  labelOffset?: number;
  endAngle?: number;
  startAngle?: number;
  splitLine?: {
    splitNumber?: number;
  };
  endNumber?: number;
  startNumber?: number;
  formatter?: (val: number, index: number, opts: ChartOptions) => string;
  labelColor?: string;
}

/**
 * 雷达图选项接口
 */
export interface RadarOption {
  labelPointShow?: boolean;
  labelPointColor?: string;
  labelPointRadius?: number;
  labelShow?: boolean;
  labelColor?: string;
}

/**
 * 图例数据项接口
 */
export interface LegendItem {
  name: string;
  color: string;
  show?: boolean;
  legendShape?: string;
  legendText?: string;
  area?: number[];
  [key: string]: any;
}

/**
 * 图例数据接口
 */
export interface LegendData {
  points: LegendItem[][];
  area: {
    start: Point;
    width: number;
    height: number;
  };
  widthArr: number[];
  heightArr: number[];
}

/**
 * 绘制X轴
 * @param categories - X轴分类数据
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 */
export function drawXAxis(
  categories: string[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  let xAxisData = opts.chartData?.xAxisData;
  if (!xAxisData) return;

  let xAxisPoints = xAxisData.xAxisPoints;
  let startX = xAxisData.startX;
  let endX = xAxisData.endX;
  let eachSpacing = xAxisData.eachSpacing;
  let boundaryGap = 'center';
  if (opts.type == 'bar' || opts.type == 'line' || opts.type == 'area' || opts.type == 'scatter' || opts.type == 'bubble') {
    boundaryGap = opts.xAxis?.boundaryGap || 'center';
  }
  let startY = opts.height! - opts.area![2];
  let endY = opts.area![0];

  // 绘制滚动条
  if (opts.enableScroll && opts.xAxis?.scrollShow) {
    let scrollY = opts.height! - opts.area![2] + config.xAxisHeight;
    let scrollScreenWidth = endX - startX;
    let scrollTotalWidth = eachSpacing * (xAxisPoints.length - 1);
    if (opts.type == 'mount' && opts.extra?.mount && opts.extra.mount.widthRatio && opts.extra.mount.widthRatio > 1) {
      let widthRatio = opts.extra.mount.widthRatio > 2 ? 2 : opts.extra.mount.widthRatio;
      scrollTotalWidth += (widthRatio - 1) * eachSpacing;
    }
    let scrollWidth = scrollScreenWidth * scrollScreenWidth / scrollTotalWidth;
    let scrollLeft = 0;
    if (opts._scrollDistance_) {
      scrollLeft = -opts._scrollDistance_ * (scrollScreenWidth) / scrollTotalWidth;
    }
    context.beginPath();
    context.setLineCap('round');
    context.setLineWidth(6 * opts.pix);
    context.setStrokeStyle(opts.xAxis.scrollBackgroundColor || "#EFEBEF");
    context.moveTo(startX, scrollY);
    context.lineTo(endX, scrollY);
    context.stroke();
    context.closePath();
    context.beginPath();
    context.setLineCap('round');
    context.setLineWidth(6 * opts.pix);
    context.setStrokeStyle(opts.xAxis.scrollColor || "#A6A6A6");
    context.moveTo(startX + scrollLeft, scrollY);
    context.lineTo(startX + scrollLeft + scrollWidth, scrollY);
    context.stroke();
    context.closePath();
    context.setLineCap('butt');
  }
  context.save();
  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
    context.translate(opts._scrollDistance_, 0);
  }
  // 绘制X轴刻度线
  if (opts.xAxis?.calibration === true) {
    context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc");
    context.setLineCap('butt');
    context.setLineWidth(1 * opts.pix);
    xAxisPoints.forEach(function (item: number, index: number) {
      if (index > 0) {
        context.beginPath();
        context.moveTo(item - eachSpacing / 2, startY);
        context.lineTo(item - eachSpacing / 2, startY + 3 * opts.pix);
        context.closePath();
        context.stroke();
      }
    });
  }
  // 绘制X轴网格
  if (opts.xAxis && opts.xAxis.disableGrid !== true) {
    context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc");
    context.setLineCap('butt');
    context.setLineWidth(1 * opts.pix);
    if (opts.xAxis.gridType == 'dash') {
      const dashLength = opts.xAxis.dashLength || 4;
      context.setLineDash([dashLength * opts.pix, dashLength * opts.pix]);
    }
    let gridEval = opts.xAxis.gridEval || 1;
    xAxisPoints.forEach(function (item: number, index: number) {
      if (index % gridEval == 0) {
        context.beginPath();
        context.moveTo(item, startY);
        context.lineTo(item, endY);
        context.stroke();
      }
    });
    context.setLineDash([]);
  }
  // 绘制X轴文案
  if (opts.xAxis && opts.xAxis.disabled !== true) {
    // 对X轴列表做抽稀处理
    // 默认全部显示X轴标签
    let maxXAxisListLength = categories.length;
    // 如果设置了X轴单屏数量
    if (opts.xAxis.labelCount) {
      // 如果设置X轴密度
      if (opts.xAxis.itemCount) {
        maxXAxisListLength = Math.ceil(categories.length / opts.xAxis.itemCount * opts.xAxis.labelCount);
      } else {
        maxXAxisListLength = opts.xAxis.labelCount;
      }
      maxXAxisListLength -= 1;
    }

    let ratio = Math.ceil(categories.length / maxXAxisListLength);

    let newCategories: string[] = [];
    let cgLength = categories.length;
    for (let i = 0; i < cgLength; i++) {
      if (i % ratio !== 0) {
        newCategories.push("");
      } else {
        newCategories.push(categories[i]);
      }
    }
    newCategories[cgLength - 1] = categories[cgLength - 1];
    let xAxisFontSize = (opts.xAxis!.fontSize || config.fontSize) * opts.pix;
    if (config._xAxisTextAngle_ === 0) {
      newCategories.forEach(function (item, index) {
        let xitem = opts.xAxis!.formatter ? opts.xAxis!.formatter!(item, index, opts) : item;
        let offset = -measureText(String(xitem), xAxisFontSize, context) / 2;
        if (boundaryGap == 'center') {
          offset += eachSpacing / 2;
        }
        let scrollHeight = 0;
        if (opts.xAxis!.scrollShow) {
          scrollHeight = 6 * opts.pix;
        }
        // 如果在主视图区域内
        let _scrollDistance_ = opts._scrollDistance_ || 0;
        let truePoints = boundaryGap == 'center' ? xAxisPoints[index] + eachSpacing / 2 : xAxisPoints[index];
        if ((truePoints - Math.abs(_scrollDistance_)) >= (opts.area![3] - 1) && (truePoints - Math.abs(_scrollDistance_)) <= (opts.width! - opts.area![1] + 1)) {
          context.beginPath();
          context.setFontSize(xAxisFontSize);
          context.setFillStyle(opts.xAxis!.fontColor || opts.fontColor);
          const marginTop = opts.xAxis!.marginTop || 0;
          const lineHeight = opts.xAxis!.lineHeight || config.fontSize;
          const xAxisFontSizeVal = opts.xAxis!.fontSize || config.fontSize;
          context.fillText(String(xitem), xAxisPoints[index] + offset, startY + marginTop * opts.pix + (lineHeight - xAxisFontSizeVal) * opts.pix / 2 + xAxisFontSizeVal * opts.pix);
          context.closePath();
          context.stroke();
        }
      });
    } else {
      newCategories.forEach(function (item, index) {
        let xitem = opts.xAxis!.formatter ? opts.xAxis!.formatter!(item, index, opts) : item;
        // 如果在主视图区域内
        let _scrollDistance_ = opts._scrollDistance_ || 0;
        let truePoints = boundaryGap == 'center' ? xAxisPoints[index] + eachSpacing / 2 : xAxisPoints[index];
        if ((truePoints - Math.abs(_scrollDistance_)) >= (opts.area![3] - 1) && (truePoints - Math.abs(_scrollDistance_)) <= (opts.width! - opts.area![1] + 1)) {
          context.save();
          context.beginPath();
          context.setFontSize(xAxisFontSize);
          context.setFillStyle(opts.xAxis!.fontColor || opts.fontColor);
          let textWidth = measureText(String(xitem), xAxisFontSize, context);
          let offsetX = xAxisPoints[index];
          if (boundaryGap == 'center') {
            offsetX = xAxisPoints[index] + eachSpacing / 2;
          }
          let scrollHeight = 0;
          if (opts.xAxis!.scrollShow) {
            scrollHeight = 6 * opts.pix;
          }
          const marginTop = opts.xAxis!.marginTop || 0;
          let offsetY = startY + marginTop * opts.pix + xAxisFontSize - xAxisFontSize * Math.abs(Math.sin(config._xAxisTextAngle_!));
          const rotateAngle = opts.xAxis!.rotateAngle || 0;
          if (rotateAngle < 0) {
            offsetX -= xAxisFontSize / 2;
            textWidth = 0;
          } else {
            offsetX += xAxisFontSize / 2;
            textWidth = -textWidth;
          }
          context.translate(offsetX, offsetY);
          context.rotate(-1 * config._xAxisTextAngle_!);
          context.fillText(String(xitem), textWidth, 0);
          context.closePath();
          context.stroke();
          context.restore();
        }
      });
    }
  }
  context.restore();

  // 画X轴标题
  if (opts.xAxis && opts.xAxis.title) {
    context.beginPath();
    const titleFontSize = opts.xAxis!.titleFontSize || config.fontSize;
    context.setFontSize(titleFontSize * opts.pix);
    context.setFillStyle(opts.xAxis!.titleFontColor!);
    const titleOffsetX = opts.xAxis!.titleOffsetX || 0;
    const marginTop = opts.xAxis!.marginTop || 0;
    const lineHeight = opts.xAxis!.lineHeight || titleFontSize;
    const titleOffsetY = opts.xAxis!.titleOffsetY || 0;
    context.fillText(String(opts.xAxis.title), opts.width! - opts.area![1] + titleOffsetX * opts.pix, opts.height! - opts.area![2] + marginTop * opts.pix + (lineHeight - titleFontSize) * opts.pix / 2 + (titleFontSize + titleOffsetY) * opts.pix);
    context.closePath();
    context.stroke();
  }

  // 绘制X轴轴线
  if (opts.xAxis && opts.xAxis.axisLine) {
    context.beginPath();
    context.setStrokeStyle(opts.xAxis!.axisLineColor!);
    context.setLineWidth(1 * opts.pix);
    context.moveTo(startX, opts.height! - opts.area![2]);
    context.lineTo(endX, opts.height! - opts.area![2]);
    context.stroke();
  }
}

/**
 * 绘制Y轴网格
 * @param categories - Y轴分类数据
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 */
export function drawYAxisGrid(
  categories: string[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  if (opts.yAxis?.disableGrid === true) {
    return;
  }
  let spacingValid = opts.height! - opts.area![0] - opts.area![2];
  let eachSpacing = spacingValid / (opts.yAxis!.splitNumber || 5);
  let startX = opts.area![3];
  let xAxisPoints = opts.chartData?.xAxisData?.xAxisPoints || [];
  let xAxiseachSpacing = opts.chartData?.xAxisData?.eachSpacing || 0;
  let TotalWidth = xAxiseachSpacing * (xAxisPoints.length - 1);
  if (opts.type == 'mount' && opts.extra?.mount && opts.extra.mount.widthRatio && opts.extra.mount.widthRatio > 1) {
    let widthRatio = opts.extra.mount.widthRatio > 2 ? 2 : opts.extra.mount.widthRatio;
    TotalWidth += (widthRatio - 1) * xAxiseachSpacing;
  }
  let endX = startX + TotalWidth;
  let points: number[] = [];
  let startY = 1;
  if (opts.xAxis!.axisLine === false) {
    startY = 0;
  }
  for (let i = startY; i < (opts.yAxis!.splitNumber || 5) + 1; i++) {
    points.push(opts.height! - opts.area![2] - eachSpacing * i);
  }
  context.save();
  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
    context.translate(opts._scrollDistance_, 0);
  }
  if (opts.yAxis!.gridType == 'dash') {
    context.setLineDash([(opts.yAxis!.dashLength || 4) * opts.pix, (opts.yAxis!.dashLength || 4) * opts.pix]);
  }
  context.setStrokeStyle(opts.yAxis!.gridColor || '#cccccc');
  context.setLineWidth(1 * opts.pix);
  points.forEach(function (item, index) {
    context.beginPath();
    context.moveTo(startX, item);
    context.lineTo(endX, item);
    context.stroke();
  });
  context.setLineDash([]);
  context.restore();
}

/**
 * 绘制Y轴
 * @param series - 系列数据数组
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 */
export function drawYAxis(
  series: SeriesItem[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  if (opts.yAxis?.disabled === true) {
    return;
  }
  let spacingValid = opts.height! - opts.area![0] - opts.area![2];
  let eachSpacing = spacingValid / (opts.yAxis!.splitNumber || 5);
  let startX = opts.area![3];
  let endX = opts.width! - opts.area![1];
  let endY = opts.height! - opts.area![2];
  // set YAxis background
  context.beginPath();
  context.setFillStyle(opts.background || '#ffffff');
  if (opts.enableScroll == true && opts.xAxis!.scrollPosition && opts.xAxis!.scrollPosition !== 'left') {
    context.fillRect(0, 0, startX, endY + 2 * opts.pix);
  }
  if (opts.enableScroll == true && opts.xAxis!.scrollPosition && opts.xAxis!.scrollPosition !== 'right') {
    context.fillRect(endX, 0, opts.width!, endY + 2 * opts.pix);
  }
  context.closePath();
  context.stroke();

  let tStartLeft = opts.area![3];
  let tStartRight = opts.width! - opts.area![1];
  let tStartCenter = opts.area![3] + (opts.width! - opts.area![1] - opts.area![3]) / 2;
  if (opts.yAxis!.data) {
    for (let i = 0; i < opts.yAxis!.data.length; i++) {
      let yData = opts.yAxis!.data[i];
      let points: number[] = [];
      if (yData.type === 'categories') {
        for (let j = 0; j <= (yData.categories?.length || 0); j++) {
          points.push(opts.area![0] + spacingValid / (yData.categories!.length) / 2 + spacingValid / (yData.categories!.length) * j);
        }
      } else {
        for (let j = 0; j <= (opts.yAxis!.splitNumber || 5); j++) {
          points.push(opts.area![0] + eachSpacing * j);
        }
      }
      if (yData.disabled !== true) {
        let rangesFormat = opts.chartData?.yAxisData?.rangesFormat?.[i] || [];
        let yAxisFontSize = yData.fontSize ? yData.fontSize * opts.pix : config.fontSize;
        let yAxisWidth = opts.chartData?.yAxisData?.yAxisWidth?.[i];
        if (!yAxisWidth) continue;

        let textAlign = yData.textAlign || "right";
        // 画Y轴刻度及文案
        rangesFormat.forEach(function (item: any, index: any) {
          let pos = points[index];
          context.beginPath();
          context.setFontSize(yAxisFontSize);
          context.setLineWidth(1 * opts.pix);
          context.setStrokeStyle(yData.axisLineColor || '#cccccc');
          context.setFillStyle(yData.fontColor || opts.fontColor);
          let tmpstrat = 0;
          let gapwidth = 4 * opts.pix;
          if (yAxisWidth.position == 'left') {
            // 画刻度线
            if (yData.calibration == true) {
              context.moveTo(tStartLeft, pos);
              context.lineTo(tStartLeft - 3 * opts.pix, pos);
              gapwidth += 3 * opts.pix;
            }
            // 画文字
            switch (textAlign) {
              case "left":
                context.setTextAlign('left');
                tmpstrat = tStartLeft - yAxisWidth.width;
                break;
              case "right":
                context.setTextAlign('right');
                tmpstrat = tStartLeft - gapwidth;
                break;
              default:
                context.setTextAlign('center');
                tmpstrat = tStartLeft - yAxisWidth.width / 2;
            }
            context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);

          } else if (yAxisWidth.position == 'right') {
            // 画刻度线
            if (yData.calibration == true) {
              context.moveTo(tStartRight, pos);
              context.lineTo(tStartRight + 3 * opts.pix, pos);
              gapwidth += 3 * opts.pix;
            }
            switch (textAlign) {
              case "left":
                context.setTextAlign('left');
                tmpstrat = tStartRight + gapwidth;
                break;
              case "right":
                context.setTextAlign('right');
                tmpstrat = tStartRight + yAxisWidth.width;
                break;
              default:
                context.setTextAlign('center');
                tmpstrat = tStartRight + yAxisWidth.width / 2;
            }
            context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
          } else if (yAxisWidth.position == 'center') {
            // 画刻度线
            if (yData.calibration == true) {
              context.moveTo(tStartCenter, pos);
              context.lineTo(tStartCenter - 3 * opts.pix, pos);
              gapwidth += 3 * opts.pix;
            }
            // 画文字
            switch (textAlign) {
              case "left":
                context.setTextAlign('left');
                tmpstrat = tStartCenter - yAxisWidth.width;
                break;
              case "right":
                context.setTextAlign('right');
                tmpstrat = tStartCenter - gapwidth;
                break;
              default:
                context.setTextAlign('center');
                tmpstrat = tStartCenter - yAxisWidth.width / 2;
            }
            context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
          }
          context.closePath();
          context.stroke();
          context.setTextAlign('left');
        });
        // 画Y轴轴线
        if (yData.axisLine !== false) {
          context.beginPath();
          context.setStrokeStyle(yData.axisLineColor || '#cccccc');
          context.setLineWidth(1 * opts.pix);
          if (yAxisWidth.position == 'left') {
            context.moveTo(tStartLeft, opts.height! - opts.area![2]);
            context.lineTo(tStartLeft, opts.area![0]);
          } else if (yAxisWidth.position == 'right') {
            context.moveTo(tStartRight, opts.height! - opts.area![2]);
            context.lineTo(tStartRight, opts.area![0]);
          } else if (yAxisWidth.position == 'center') {
            context.moveTo(tStartCenter, opts.height! - opts.area![2]);
            context.lineTo(tStartCenter, opts.area![0]);
          }
          context.stroke();
        }
        // 画Y轴标题
        if (opts.yAxis!.showTitle) {
          let titleFontSize = (yData.titleFontSize || config.fontSize) * opts.pix;
          let title = yData.title || '';
          context.beginPath();
          context.setFontSize(titleFontSize);
          context.setFillStyle(yData.titleFontColor || opts.fontColor);
          if (yAxisWidth.position == 'left') {
            context.fillText(title, tStartLeft - measureText(title, titleFontSize, context) / 2 + (yData.titleOffsetX || 0), opts.area![0] - (10 - (yData.titleOffsetY || 0)) * opts.pix);
          } else if (yAxisWidth.position == 'right') {
            context.fillText(title, tStartRight - measureText(title, titleFontSize, context) / 2 + (yData.titleOffsetX || 0), opts.area![0] - (10 - (yData.titleOffsetY || 0)) * opts.pix);
          } else if (yAxisWidth.position == 'center') {
            context.fillText(title, tStartCenter - measureText(title, titleFontSize, context) / 2 + (yData.titleOffsetX || 0), opts.area![0] - (10 - (yData.titleOffsetY || 0)) * opts.pix);
          }
          context.closePath();
          context.stroke();
        }
        if (yAxisWidth.position == 'left') {
          tStartLeft -= (yAxisWidth.width + (opts.yAxis!.padding || 0) * opts.pix);
        } else {
          tStartRight += yAxisWidth.width + (opts.yAxis!.padding || 0) * opts.pix;
        }
      }
    }
  }
}

/**
 * 绘制图例
 * @param series - 系列数据数组
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 * @param chartData - 图表数据对象
 */
export function drawLegend(
  series: SeriesItem[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext,
  chartData: any
): void {
  if (opts.legend?.show === false) {
    return;
  }
  let legendData = chartData.legendData as LegendData;
  let legendList = legendData.points;
  let legendArea = legendData.area;
  let padding = (opts.legend.padding || 5) * opts.pix;
  let fontSize = (opts.legend.fontSize || 12) * opts.pix;
  let shapeWidth = 15 * opts.pix;
  let shapeRight = 5 * opts.pix;
  let itemGap = (opts.legend.itemGap || 10) * opts.pix;
  let lineHeight = Math.max((opts.legend.lineHeight || 15) * opts.pix, fontSize);
  // 画背景及边框
  context.beginPath();
  context.setLineWidth((opts.legend.borderWidth || 0) * opts.pix);
  context.setStrokeStyle(opts.legend.borderColor || '#cccccc');
  context.setFillStyle(opts.legend.backgroundColor || '#ffffff');
  context.moveTo(legendArea.start.x, legendArea.start.y);
  context.rect(legendArea.start.x, legendArea.start.y, legendArea.width, legendArea.height);
  context.closePath();
  context.fill();
  context.stroke();
  legendList.forEach(function (itemList, listIndex) {
    let width = 0;
    let height = 0;
    width = legendData.widthArr[listIndex];
    height = legendData.heightArr[listIndex];
    let startX = 0;
    let startY = 0;
    if (opts.legend.position == 'top' || opts.legend.position == 'bottom') {
      switch (opts.legend.float) {
        case 'left':
          startX = legendArea.start.x + padding;
          break;
        case 'right':
          startX = legendArea.start.x + legendArea.width - width;
          break;
        default:
          startX = legendArea.start.x + (legendArea.width - width) / 2;
      }
      startY = legendArea.start.y + padding + listIndex * lineHeight;
    } else {
      if (listIndex == 0) {
        width = 0;
      } else {
        width = legendData.widthArr[listIndex - 1];
      }
      startX = legendArea.start.x + padding + width;
      startY = legendArea.start.y + padding + (legendArea.height - height) / 2;
    }
    context.setFontSize(config.fontSize);
    for (let i = 0; i < itemList.length; i++) {
      let item = itemList[i];
      item.area = [0, 0, 0, 0];
      item.area[0] = startX;
      item.area[1] = startY;
      item.area[3] = startY + lineHeight;
      context.beginPath();
      context.setLineWidth(1 * opts.pix);
      context.setStrokeStyle(item.show !== false ? item.color : (opts.legend.hiddenColor || '#999999'));
      context.setFillStyle(item.show !== false ? item.color : (opts.legend.hiddenColor || '#999999'));
      switch (item.legendShape) {
        case 'line':
          context.moveTo(startX, startY + 0.5 * lineHeight - 2 * opts.pix);
          context.fillRect(startX, startY + 0.5 * lineHeight - 2 * opts.pix, 15 * opts.pix, 4 * opts.pix);
          break;
        case 'triangle':
          context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
          context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * lineHeight + 5 * opts.pix);
          context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * lineHeight + 5 * opts.pix);
          context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
          break;
        case 'diamond':
          context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
          context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * lineHeight);
          context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight + 5 * opts.pix);
          context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * lineHeight);
          context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
          break;
        case 'circle':
          context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight);
          context.arc(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight, 5 * opts.pix, 0, 2 * Math.PI);
          break;
        case 'rect':
          context.moveTo(startX, startY + 0.5 * lineHeight - 5 * opts.pix);
          context.fillRect(startX, startY + 0.5 * lineHeight - 5 * opts.pix, 15 * opts.pix, 10 * opts.pix);
          break;
        case 'square':
          context.moveTo(startX + 5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
          context.fillRect(startX + 5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix, 10 * opts.pix, 10 * opts.pix);
          break;
        case 'none':
          break;
        default:
          context.moveTo(startX, startY + 0.5 * lineHeight - 5 * opts.pix);
          context.fillRect(startX, startY + 0.5 * lineHeight - 5 * opts.pix, 15 * opts.pix, 10 * opts.pix);
      }
      context.closePath();
      context.fill();
      context.stroke();
      startX += shapeWidth + shapeRight;
      let fontTrans = 0.5 * lineHeight + 0.5 * fontSize - 2;
      const legendText = item.legendText ? item.legendText : item.name;
      context.beginPath();
      context.setFontSize(fontSize);
      context.setFillStyle(item.show !== false ? (opts.legend.fontColor || '#666666') : (opts.legend.hiddenColor || '#999999'));
      context.fillText(legendText, startX, startY + fontTrans);
      context.closePath();
      context.stroke();
      if (opts.legend.position == 'top' || opts.legend.position == 'bottom') {
        startX += measureText(legendText, fontSize, context) + itemGap;
        item.area[2] = startX;
      } else {
        item.area[2] = startX + measureText(legendText, fontSize, context) + itemGap;
        ;
        startX -= shapeWidth + shapeRight;
        startY += lineHeight;
      }
    }
  });
}

/**
 * 绘制仪表盘标签
 * @param gaugeOption - 仪表盘选项
 * @param radius - 半径
 * @param centerPosition - 中心点坐标
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 */
export function drawGaugeLabel(
  gaugeOption: GaugeOption,
  radius: number,
  centerPosition: Point,
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  radius -= (gaugeOption.width || 0) / 2 + (gaugeOption.labelOffset || 0) * opts.pix;
  radius = radius < 10 ? 10 : radius;
  let totalAngle: number;
  if ((gaugeOption.endAngle || 0) < (gaugeOption.startAngle || 0)) {
    totalAngle = 2 + (gaugeOption.endAngle || 0) - (gaugeOption.startAngle || 0);
  } else {
    totalAngle = (gaugeOption.startAngle || 0) - (gaugeOption.endAngle || 0);
  }
  let splitAngle = totalAngle / (gaugeOption.splitLine?.splitNumber || 5);
  let totalNumber = (gaugeOption.endNumber || 10) - (gaugeOption.startNumber || 0);
  let splitNumber = totalNumber / (gaugeOption.splitLine?.splitNumber || 5);
  let nowAngle = gaugeOption.startAngle || 0;
  let nowNumber = gaugeOption.startNumber || 0;
  for (let i = 0; i < (gaugeOption.splitLine?.splitNumber || 5) + 1; i++) {
    let pos = {
      x: radius * Math.cos(nowAngle * Math.PI),
      y: radius * Math.sin(nowAngle * Math.PI)
    };
    let labelText = gaugeOption.formatter ? gaugeOption.formatter(nowNumber, i, opts) : String(nowNumber);
    pos.x += centerPosition.x - measureText(labelText, config.fontSize, context) / 2;
    pos.y += centerPosition.y;
    let startX = pos.x;
    let startY = pos.y;
    context.beginPath();
    context.setFontSize(config.fontSize);
    context.setFillStyle(gaugeOption.labelColor || opts.fontColor);
    context.fillText(labelText, startX, startY + config.fontSize / 2);
    context.closePath();
    context.stroke();
    nowAngle += splitAngle;
    if (nowAngle >= 2) {
      nowAngle = nowAngle % 2;
    }
    nowNumber += splitNumber;
  }
}

/**
 * 绘制雷达图标签
 * @param angleList - 角度列表
 * @param radius - 半径
 * @param centerPosition - 中心点坐标
 * @param opts - 图表配置选项
 * @param config - uCharts配置对象
 * @param context - Canvas 渲染上下文
 */
export function drawRadarLabel(
  angleList: number[],
  radius: number,
  centerPosition: Point,
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  let radarOption = opts.extra?.radar || {};
  angleList.forEach(function (angle, index) {
    if (radarOption.labelPointShow === true && opts.categories && opts.categories[index] !== '') {
      let posPoint = {
        x: radius * Math.cos(angle),
        y: radius * Math.sin(angle)
      };
      let posPointAxis = convertCoordinateOrigin(posPoint.x, posPoint.y, centerPosition);
      context.setFillStyle(radarOption.labelPointColor || opts.fontColor);
      context.beginPath();
      context.arc(posPointAxis.x, posPointAxis.y, (radarOption.labelPointRadius || 3) * opts.pix, 0, 2 * Math.PI, false);
      context.closePath();
      context.fill();
    }
    if (radarOption.labelShow === true && opts.categories) {
      let pos = {
        x: (radius + config.radarLabelTextMargin * opts.pix) * Math.cos(angle),
        y: (radius + config.radarLabelTextMargin * opts.pix) * Math.sin(angle)
      };
      let posRelativeCanvas = convertCoordinateOrigin(pos.x, pos.y, centerPosition);
      let startX = posRelativeCanvas.x;
      let startY = posRelativeCanvas.y;
      if (Math.abs(pos.x) < 1e-10) {
        startX -= measureText(opts.categories[index] || '', config.fontSize, context) / 2;
      } else if (pos.x < 0) {
        startX -= measureText(opts.categories[index] || '', config.fontSize, context);
      }
      context.beginPath();
      context.setFontSize(config.fontSize);
      context.setFillStyle(radarOption.labelColor || opts.fontColor);
      context.fillText(opts.categories[index] || '', startX, startY + config.fontSize / 2);
      context.closePath();
      context.stroke();
    }
  });
}
