/**
 * 饼图和环形图绘制函数
 *
 * 从 u-charts 核心库搬迁的饼图和环形图绘制相关函数
 */

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

import type { ChartOptions, UChartsConfig, SeriesItem } from '../data-processing/series-calculator';
import { getPieDataPoints } from '../charts-data/pie-charts';
import { getRoseDataPoints } from '../charts-data/pie-charts';
import { getArcbarDataPoints } from '../charts-data/gauge-charts';
import { getGaugeAxisPoints, getGaugeArcbarDataPoints } from '../charts-data/gauge-charts';
import { measureText } from '../utils/text';
import { hexToRgb } from '../utils/color';
import { assign } from '../config';

export type CanvasContext = any;

export interface Point {
  x: number;
  y: number;
}

export interface PieSeriesItem extends SeriesItem {
  _start_?: number;
  _proportion_?: number;
  _rose_proportion_?: number;
  _radius_?: number;
  color?: string;
  labelText?: string;
  labelShow?: boolean;
  textColor?: string;
  textSize?: number;
  formatter?: (item: any, index: number, series: any[], opts: any) => string;
}

export interface TextObject {
  lineStart: Point;
  lineEnd: Point;
  start: Point;
  width: number;
  height: number;
  text: string;
  color: string;
  textColor?: string;
  textSize?: number;
}

export interface PieOption {
  activeOpacity: number;
  activeRadius: number;
  offsetAngle: number;
  labelWidth: number;
  ringWidth: number;
  customRadius: number;
  border: boolean;
  borderWidth: number;
  borderColor: string;
  centerColor: string;
  linearType: string;
  customColor: string[];
}

export interface RoseOption {
  type: string;
  activeOpacity: number;
  activeRadius: number;
  offsetAngle: number;
  labelWidth: number;
  border: boolean;
  borderWidth: number;
  borderColor: string;
  linearType: string;
  customColor: string[];
  minRadius?: number;
}

export interface ArcbarOption {
  startAngle: number;
  endAngle: number;
  type: string;
  direction: string;
  lineCap: string;
  width: number;
  gap: number;
  linearType: string;
  customColor: string[];
  backgroundColor?: string;
  centerX?: number;
  centerY?: number;
  radius?: number;
}

export interface GaugeOption {
  type: string;
  startAngle: number;
  endAngle: number;
  width: number;
  labelOffset: number;
  oldAngle?: number;
  oldData?: number;
  startNumber?: number;
  endNumber?: number;
  labelColor?: string;
  formatter?: (value: number, index: number, opts: any) => string;
  splitLine: {
    fixRadius: number;
    splitNumber: number;
    width: number;
    color: string;
    childNumber: number;
    childWidth: number;
  };
  pointer: {
    width: number;
    color: string;
  };
}

// 工具函数
const util = {
  toFixed: function toFixed(num: number, limit: number): string {
    limit = limit || 2;
    if (this.isFloat(num)) {
      return num.toFixed(limit);
    }
    return String(num);
  },
  isFloat: function isFloat(num: number): boolean {
    return num % 1 !== 0;
  },
  approximatelyEqual: function approximatelyEqual(num1: number, num2: number): boolean {
    return Math.abs(num1 - num2) < 1e-10;
  },
  isSameSign: function isSameSign(num1: number, num2: number): boolean {
    return Math.abs(num1) === num1 && Math.abs(num2) === num2 || Math.abs(num1) !== num1 && Math.abs(num2) !== num2;
  },
  isSameXCoordinateArea: function isSameXCoordinateArea(p1: Point, p2: Point): boolean {
    return this.isSameSign(p1.x, p2.x);
  }
};

function convertCoordinateOrigin(x: number, y: number, center: Point): Point {
  return {
    x: center.x + x,
    y: center.y - y
  };
}

function avoidCollision(obj: TextObject, target: TextObject | null): TextObject {
  if (target) {
    while (isCollision(obj, target)) {
      if (obj.start.x > 0) {
        obj.start.y--;
      } else if (obj.start.x < 0) {
        obj.start.y++;
      } else {
        if (obj.start.y > 0) {
          obj.start.y++;
        } else {
          obj.start.y--;
        }
      }
    }
  }
  return obj;
}

function isCollision(obj1: TextObject, obj2: TextObject): boolean {
  const obj1End = {
    x: obj1.start.x + obj1.width,
    y: obj1.start.y - obj1.height
  };
  const obj2End = {
    x: obj2.start.x + obj2.width,
    y: obj2.start.y - obj2.height
  };
  const flag = obj2.start.x > obj1End.x || obj2End.x < obj1.start.x || obj2End.y > obj1.start.y || obj2.start.y < obj1End.y;
  return !flag;
}

function fillCustomColor(linearType: string, customColor: string[], series: PieSeriesItem[], config: UChartsConfig): string[] {
  let newcolor = customColor || [];
  if (linearType == 'custom' && newcolor.length == 0) {
    newcolor = config.linearColor;
  }
  if (linearType == 'custom' && newcolor.length < series.length) {
    let chazhi = series.length - newcolor.length;
    for (let i = 0; i < chazhi; i++) {
      newcolor.push(config.linearColor[(i + 1) % config.linearColor.length]);
    }
  }
  return newcolor;
}

function drawRingTitle(opts: ChartOptions, config: UChartsConfig, context: CanvasContext, center: Point): void {
  // 简化实现，如果需要可以后续添加
}

export function drawPieDataPoints(
  series: PieSeriesItem[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): { center: Point; radius: number; series: PieSeriesItem[] } {
  let pieOption = assign({}, {
    activeOpacity: 0.5,
    activeRadius: 10,
    offsetAngle: 0,
    labelWidth: 15,
    ringWidth: 30,
    customRadius: 0,
    border: false,
    borderWidth: 2,
    borderColor: '#FFFFFF',
    centerColor: '#FFFFFF',
    linearType: 'none',
    customColor: [],
  }, opts.type == "pie" ? opts.extra.pie : opts.extra.ring) as PieOption;

  let centerPosition = {
    x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
    y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2
  };

  if (config.pieChartLinePadding == 0) {
    config.pieChartLinePadding = pieOption.activeRadius * opts.pix;
  }

  let radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_, (opts.height - opts.area[0] - opts.area[2]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding);
  radius = radius < 10 ? 10 : radius;

  if (pieOption.customRadius > 0) {
    radius = pieOption.customRadius * opts.pix;
  }

  series = getPieDataPoints(series, radius);
  let activeRadius = pieOption.activeRadius * opts.pix;
  pieOption.customColor = fillCustomColor(pieOption.linearType, pieOption.customColor, series, config);

  series = series.map(function(eachSeries) {
    eachSeries._start_! += (pieOption.offsetAngle) * Math.PI / 180;
    return eachSeries;
  });

  series.forEach(function(eachSeries, seriesIndex) {
    if (opts.tooltip) {
      if (opts.tooltip.index == seriesIndex) {
        context.beginPath();
        context.setFillStyle(hexToRgb(eachSeries.color!, pieOption.activeOpacity || 0.5));
        context.moveTo(centerPosition.x, centerPosition.y);
        context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_! + activeRadius, eachSeries._start_, eachSeries._start_! + 2 * eachSeries._proportion_! * Math.PI);
        context.closePath();
        context.fill();
      }
    }
    context.beginPath();
    context.setLineWidth(pieOption.borderWidth * opts.pix);
    context.lineJoin = "round";
    context.setStrokeStyle(pieOption.borderColor);
    let fillcolor = eachSeries.color;
    if (pieOption.linearType == 'custom') {
      let grd;
      if (context.createCircularGradient) {
        grd = context.createCircularGradient(centerPosition.x, centerPosition.y, eachSeries._radius_!);
      } else {
        grd = context.createRadialGradient(centerPosition.x, centerPosition.y, 0, centerPosition.x, centerPosition.y, eachSeries._radius_!);
      }
      grd.addColorStop(0, hexToRgb(pieOption.customColor[eachSeries.linearIndex!], 1));
      grd.addColorStop(1, hexToRgb(eachSeries.color!, 1));
      fillcolor = grd;
    }
    context.setFillStyle(fillcolor);
    context.moveTo(centerPosition.x, centerPosition.y);
    context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_!, eachSeries._start_, eachSeries._start_! + 2 * eachSeries._proportion_! * Math.PI);
    context.closePath();
    context.fill();
    if (pieOption.border == true) {
      context.stroke();
    }
  });

  if (opts.type === 'ring') {
    let innerPieWidth = radius * 0.6;
    if (typeof pieOption.ringWidth === 'number' && pieOption.ringWidth > 0) {
      innerPieWidth = Math.max(0, radius - pieOption.ringWidth * opts.pix);
    }
    context.beginPath();
    context.setFillStyle(pieOption.centerColor);
    context.moveTo(centerPosition.x, centerPosition.y);
    context.arc(centerPosition.x, centerPosition.y, innerPieWidth, 0, 2 * Math.PI);
    context.closePath();
    context.fill();
  }

  if (opts.dataLabel !== false && process === 1) {
    drawPieText(series, opts, config, context, radius, centerPosition);
  }

  if (process === 1 && opts.type === 'ring') {
    drawRingTitle(opts, config, context, centerPosition);
  }

  return {
    center: centerPosition,
    radius: radius,
    series: series
  };
}

export function drawRoseDataPoints(
  series: PieSeriesItem[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): { center: Point; radius: number; series: PieSeriesItem[] } {
  let roseOption = assign({}, {
    type: 'area',
    activeOpacity: 0.5,
    activeRadius: 10,
    offsetAngle: 0,
    labelWidth: 15,
    border: false,
    borderWidth: 2,
    borderColor: '#FFFFFF',
    linearType: 'none',
    customColor: [],
  }, opts.extra.rose) as RoseOption;

  if (config.pieChartLinePadding == 0) {
    config.pieChartLinePadding = roseOption.activeRadius * opts.pix;
  }

  let centerPosition = {
    x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
    y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2
  };

  let radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_, (opts.height - opts.area[0] - opts.area[2]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding);
  radius = radius < 10 ? 10 : radius;

  let minRadius = roseOption.minRadius || radius * 0.5;
  if (radius < minRadius) {
    radius = minRadius + 10;
  }

  series = getRoseDataPoints(series, roseOption.type, minRadius, radius);
  let activeRadius = roseOption.activeRadius * opts.pix;
  roseOption.customColor = fillCustomColor(roseOption.linearType, roseOption.customColor, series, config);

  series = series.map(function(eachSeries) {
    eachSeries._start_! += (roseOption.offsetAngle || 0) * Math.PI / 180;
    return eachSeries;
  });

  series.forEach(function(eachSeries, seriesIndex) {
    if (opts.tooltip) {
      if (opts.tooltip.index == seriesIndex) {
        context.beginPath();
        context.setFillStyle(hexToRgb(eachSeries.color!, roseOption.activeOpacity || 0.5));
        context.moveTo(centerPosition.x, centerPosition.y);
        context.arc(centerPosition.x, centerPosition.y, activeRadius + eachSeries._radius_!, eachSeries._start_, eachSeries._start_! + 2 * eachSeries._rose_proportion_! * Math.PI);
        context.closePath();
        context.fill();
      }
    }
    context.beginPath();
    context.setLineWidth(roseOption.borderWidth * opts.pix);
    context.lineJoin = "round";
    context.setStrokeStyle(roseOption.borderColor);
    let fillcolor = eachSeries.color;
    if (roseOption.linearType == 'custom') {
      let grd;
      if (context.createCircularGradient) {
        grd = context.createCircularGradient(centerPosition.x, centerPosition.y, eachSeries._radius_!);
      } else {
        grd = context.createRadialGradient(centerPosition.x, centerPosition.y, 0, centerPosition.x, centerPosition.y, eachSeries._radius_!);
      }
      grd.addColorStop(0, hexToRgb(roseOption.customColor[eachSeries.linearIndex!], 1));
      grd.addColorStop(1, hexToRgb(eachSeries.color!, 1));
      fillcolor = grd;
    }
    context.setFillStyle(fillcolor);
    context.moveTo(centerPosition.x, centerPosition.y);
    context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_!, eachSeries._start_, eachSeries._start_! + 2 * eachSeries._rose_proportion_! * Math.PI);
    context.closePath();
    context.fill();
    if (roseOption.border == true) {
      context.stroke();
    }
  });

  if (opts.dataLabel !== false && process === 1) {
    drawPieText(series, opts, config, context, radius, centerPosition);
  }

  return {
    center: centerPosition,
    radius: radius,
    series: series
  };
}

export function drawPieText(
  series: PieSeriesItem[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext,
  radius: number,
  center: Point
): void {
  let lineRadius = config.pieChartLinePadding;
  let textObjectCollection: TextObject[] = [];
  let lastTextObject: TextObject | null = null;

  let seriesConvert = series.map(function(item, index) {
    let text = item.formatter ? item.formatter(item, index, series, opts) : util.toFixed(item._proportion_! * 100, 2) + '%';
    text = item.labelText ? item.labelText : text;
    let arc = 2 * Math.PI - (item._start_! + 2 * Math.PI * item._proportion_! / 2);
    if (item._rose_proportion_) {
      arc = 2 * Math.PI - (item._start_! + 2 * Math.PI * item._rose_proportion_! / 2);
    }
    let color = item.color;
    let radius = item._radius_;
    return {
      arc: arc,
      text: text,
      color: color!,
      radius: radius!,
      textColor: item.textColor,
      textSize: item.textSize,
      labelShow: item.labelShow
    };
  });

  for (let i = 0; i < seriesConvert.length; i++) {
    let item = seriesConvert[i];
    // line end
    let orginX1 = Math.cos(item.arc) * (item.radius + lineRadius);
    let orginY1 = Math.sin(item.arc) * (item.radius + lineRadius);
    // line start
    let orginX2 = Math.cos(item.arc) * item.radius;
    let orginY2 = Math.sin(item.arc) * item.radius;
    // text start
    let orginX3 = orginX1 >= 0 ? orginX1 + config.pieChartTextPadding : orginX1 - config.pieChartTextPadding;
    let orginY3 = orginY1;
    let textWidth = measureText(item.text, item.textSize! * opts.pix || config.fontSize, context);
    let startY = orginY3;

    if (lastTextObject && util.isSameXCoordinateArea(lastTextObject.start, {
        x: orginX3
      })) {
      if (orginX3 > 0) {
        startY = Math.min(orginY3, lastTextObject.start.y);
      } else if (orginX1 < 0) {
        startY = Math.max(orginY3, lastTextObject.start.y);
      } else {
        if (orginY3 > 0) {
          startY = Math.max(orginY3, lastTextObject.start.y);
        } else {
          startY = Math.min(orginY3, lastTextObject.start.y);
        }
      }
    }

    if (orginX3 < 0) {
      orginX3 -= textWidth;
    }

    let textObject: TextObject = {
      lineStart: {
        x: orginX2,
        y: orginY2
      },
      lineEnd: {
        x: orginX1,
        y: orginY1
      },
      start: {
        x: orginX3,
        y: startY
      },
      width: textWidth,
      height: config.fontSize,
      text: item.text,
      color: item.color,
      textColor: item.textColor,
      textSize: item.textSize
    };

    lastTextObject = avoidCollision(textObject, lastTextObject);
    textObjectCollection.push(lastTextObject);
  }

  for (let i = 0; i < textObjectCollection.length; i++) {
    if (seriesConvert[i].labelShow === false) {
      continue;
    }
    let item = textObjectCollection[i];
    let lineStartPoistion = convertCoordinateOrigin(item.lineStart.x, item.lineStart.y, center);
    let lineEndPoistion = convertCoordinateOrigin(item.lineEnd.x, item.lineEnd.y, center);
    let textPosition = convertCoordinateOrigin(item.start.x, item.start.y, center);

    context.setLineWidth(1 * opts.pix);
    context.setFontSize(item.textSize! * opts.pix || config.fontSize);
    context.beginPath();
    context.setStrokeStyle(item.color);
    context.setFillStyle(item.color);
    context.moveTo(lineStartPoistion.x, lineStartPoistion.y);

    let curveStartX = item.start.x < 0 ? textPosition.x + item.width : textPosition.x;
    let textStartX = item.start.x < 0 ? textPosition.x - 5 : textPosition.x + 5;
    context.quadraticCurveTo(lineEndPoistion.x, lineEndPoistion.y, curveStartX, textPosition.y);
    context.moveTo(lineStartPoistion.x, lineStartPoistion.y);
    context.stroke();
    context.closePath();

    context.beginPath();
    context.moveTo(textPosition.x + item.width, textPosition.y);
    context.arc(curveStartX, textPosition.y, 2 * opts.pix, 0, 2 * Math.PI);
    context.closePath();
    context.fill();

    context.beginPath();
    context.setFontSize(item.textSize! * opts.pix || config.fontSize);
    context.setFillStyle(item.textColor || opts.fontColor);
    context.fillText(item.text, textStartX, textPosition.y + 3);
    context.closePath();
    context.stroke();
    context.closePath();
  }
}

export function drawArcbarDataPoints(
  series: SeriesItem[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  let arcbarOption = assign({}, {
    startAngle: 0.75,
    endAngle: 0.25,
    type: 'default',
    direction: 'cw',
    lineCap: 'round',
    width: 12,
    gap: 2,
    linearType: 'none',
    customColor: [],
  }, opts.extra.arcbar) as ArcbarOption;

  series = getArcbarDataPoints(series as any, arcbarOption) as any;

  let centerPosition: Point;
  if (arcbarOption.centerX || arcbarOption.centerY) {
    centerPosition = {
      x: arcbarOption.centerX ? arcbarOption.centerX : opts.width / 2,
      y: arcbarOption.centerY ? arcbarOption.centerY : opts.height / 2
    };
  } else {
    centerPosition = {
      x: opts.width / 2,
      y: opts.height / 2
    };
  }

  let radius: number;
  if (arcbarOption.radius) {
    radius = arcbarOption.radius;
  } else {
    radius = Math.min(centerPosition.x, centerPosition.y);
    radius -= 5 * opts.pix;
    radius -= arcbarOption.width / 2;
  }
  radius = radius < 10 ? 10 : radius;

  arcbarOption.customColor = fillCustomColor(arcbarOption.linearType, arcbarOption.customColor, series as any, config);

  for (let i = 0; i < series.length; i++) {
    let eachSeries = series[i];
    // 背景颜色
    context.setLineWidth(arcbarOption.width * opts.pix);
    context.setStrokeStyle(arcbarOption.backgroundColor || '#E9E9E9');
    context.setLineCap(arcbarOption.lineCap);
    context.beginPath();
    if (arcbarOption.type == 'default') {
      context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width * opts.pix + arcbarOption.gap * opts.pix) * i, arcbarOption.startAngle * Math.PI, arcbarOption.endAngle * Math.PI, arcbarOption.direction == 'ccw');
    } else {
      context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width * opts.pix + arcbarOption.gap * opts.pix) * i, 0, 2 * Math.PI, arcbarOption.direction == 'ccw');
    }
    context.stroke();

    // 进度条
    let fillColor = eachSeries.color;
    if (arcbarOption.linearType == 'custom') {
      let grd = context.createLinearGradient(centerPosition.x - radius, centerPosition.y, centerPosition.x + radius, centerPosition.y);
      grd.addColorStop(1, hexToRgb(arcbarOption.customColor[eachSeries.linearIndex!], 1));
      grd.addColorStop(0, hexToRgb(eachSeries.color!, 1));
      fillColor = grd;
    }

    context.setLineWidth(arcbarOption.width * opts.pix);
    context.setStrokeStyle(fillColor);
    context.setLineCap(arcbarOption.lineCap);
    context.beginPath();
    context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width * opts.pix + arcbarOption.gap * opts.pix) * i, arcbarOption.startAngle * Math.PI, (eachSeries as any)._proportion_ * Math.PI, arcbarOption.direction == 'ccw');
    context.stroke();
  }

  drawRingTitle(opts, config, context, centerPosition);
}

export function drawGaugeDataPoints(
  categories: any[],
  series: SeriesItem[],
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): { center: Point; radius: number; innerRadius: number } {
  let gaugeOption = assign({}, {
    type: 'default',
    startAngle: 0.75,
    endAngle: 0.25,
    width: 15,
    labelOffset: 13,
    splitLine: {
      fixRadius: 0,
      splitNumber: 10,
      width: 15,
      color: '#FFFFFF',
      childNumber: 5,
      childWidth: 5
    },
    pointer: {
      width: 15,
      color: 'auto'
    }
  }, opts.extra.gauge) as GaugeOption;

  if (gaugeOption.oldAngle == undefined) {
    gaugeOption.oldAngle = gaugeOption.startAngle;
  }
  if (gaugeOption.oldData == undefined) {
    gaugeOption.oldData = 0;
  }

  categories = getGaugeAxisPoints(categories, gaugeOption.startAngle, gaugeOption.endAngle);

  let centerPosition = {
    x: opts.width / 2,
    y: opts.height / 2
  };

  let radius = Math.min(centerPosition.x, centerPosition.y);
  radius -= 5 * opts.pix;
  radius -= gaugeOption.width / 2;
  radius = radius < 10 ? 10 : radius;
  let innerRadius = radius - gaugeOption.width;

  // 判断仪表盘的样式：default百度样式，progress新样式
  if (gaugeOption.type == 'progress') {
    // ## 第一步画中心圆形背景和进度条背景
    let pieRadius = radius - gaugeOption.width * 3;
    context.beginPath();
    let gradient = context.createLinearGradient(centerPosition.x, centerPosition.y - pieRadius, centerPosition.x, centerPosition.y + pieRadius);
    gradient.addColorStop('0', hexToRgb(series[0].color!, 0.3));
    gradient.addColorStop('1.0', hexToRgb("#FFFFFF", 0.1));
    context.setFillStyle(gradient);
    context.arc(centerPosition.x, centerPosition.y, pieRadius, 0, 2 * Math.PI, false);
    context.fill();

    // 画进度条背景
    context.setLineWidth(gaugeOption.width);
    context.setStrokeStyle(hexToRgb(series[0].color!, 0.3));
    context.setLineCap('round');
    context.beginPath();
    context.arc(centerPosition.x, centerPosition.y, innerRadius, gaugeOption.startAngle * Math.PI, gaugeOption.endAngle * Math.PI, false);
    context.stroke();

    // ## 第二步画刻度线
    let totalAngle = 0;
    if (gaugeOption.endAngle < gaugeOption.startAngle) {
      totalAngle = 2 + gaugeOption.endAngle - gaugeOption.startAngle;
    } else {
      totalAngle = gaugeOption.startAngle - gaugeOption.endAngle;
    }

    let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
    let childAngle = totalAngle / gaugeOption.splitLine.splitNumber / gaugeOption.splitLine.childNumber;
    let startX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius;
    let endX = -radius - gaugeOption.width - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.width;

    context.save();
    context.translate(centerPosition.x, centerPosition.y);
    context.rotate((gaugeOption.startAngle - 1) * Math.PI);
    let len = gaugeOption.splitLine.splitNumber * gaugeOption.splitLine.childNumber + 1;
    let proc = (series[0].data as number) * process;

    for (let i = 0; i < len; i++) {
      context.beginPath();
      // 刻度线随进度变色
      if (proc > (i / len)) {
        context.setStrokeStyle(hexToRgb(series[0].color!, 1));
      } else {
        context.setStrokeStyle(hexToRgb(series[0].color!, 0.3));
      }
      context.setLineWidth(3 * opts.pix);
      context.moveTo(startX, 0);
      context.lineTo(endX, 0);
      context.stroke();
      context.rotate(childAngle * Math.PI);
    }
    context.restore();

    // ## 第三步画进度条
    series = getGaugeArcbarDataPoints(series as any, gaugeOption) as any;
    context.setLineWidth(gaugeOption.width);
    context.setStrokeStyle(series[0].color);
    context.setLineCap('round');
    context.beginPath();
    context.arc(centerPosition.x, centerPosition.y, innerRadius, gaugeOption.startAngle * Math.PI, (series[0] as any)._proportion_ * Math.PI, false);
    context.stroke();

    // ## 第四步画指针
    let pointerRadius = radius - gaugeOption.width * 2.5;
    context.save();
    context.translate(centerPosition.x, centerPosition.y);
    context.rotate(((series[0] as any)._proportion_ - 1) * Math.PI);
    context.beginPath();
    context.setLineWidth(gaugeOption.width / 3);
    let gradient3 = context.createLinearGradient(0, -pointerRadius * 0.6, 0, pointerRadius * 0.6);
    gradient3.addColorStop('0', hexToRgb('#FFFFFF', 0));
    gradient3.addColorStop('0.5', hexToRgb(series[0].color!, 1));
    gradient3.addColorStop('1.0', hexToRgb('#FFFFFF', 0));
    context.setStrokeStyle(gradient3);
    context.arc(0, 0, pointerRadius, 0.85 * Math.PI, 1.15 * Math.PI, false);
    context.stroke();

    context.beginPath();
    context.setLineWidth(1);
    context.setStrokeStyle(series[0].color);
    context.setFillStyle(series[0].color);
    context.moveTo(-pointerRadius - gaugeOption.width / 3 / 2, -4);
    context.lineTo(-pointerRadius - gaugeOption.width / 3 / 2 - 4, 0);
    context.lineTo(-pointerRadius - gaugeOption.width / 3 / 2, 4);
    context.lineTo(-pointerRadius - gaugeOption.width / 3 / 2, -4);
    context.stroke();
    context.fill();
    context.restore();
  } else {
    // default百度样式
    context.setLineWidth(gaugeOption.width);
    context.setLineCap('butt');
    for (let i = 0; i < categories.length; i++) {
      let eachCategories = categories[i];
      context.beginPath();
      context.setStrokeStyle(eachCategories.color);
      context.arc(centerPosition.x, centerPosition.y, radius, eachCategories._startAngle_! * Math.PI, eachCategories._endAngle_! * Math.PI, false);
      context.stroke();
    }

    series = getGaugeArcbarDataPoints(series as any, gaugeOption) as any;
    let pointerRadius = radius - gaugeOption.width * 2.5;
    context.save();
    context.translate(centerPosition.x, centerPosition.y);
    context.rotate(((series[0] as any)._proportion_ - 1) * Math.PI);
    context.beginPath();
    context.setLineWidth(gaugeOption.width / 3);
    context.setStrokeStyle(series[0].color);
    context.arc(0, 0, pointerRadius, 0.85 * Math.PI, 1.15 * Math.PI, false);
    context.stroke();
    context.restore();
  }

  // 画标签
  drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context);

  return {
    center: centerPosition,
    radius: radius,
    innerRadius: innerRadius
  };
}

export function drawGaugeLabel(
  gaugeOption: GaugeOption,
  radius: number,
  centerPosition: Point,
  opts: ChartOptions,
  config: UChartsConfig,
  context: CanvasContext
): void {
  radius -= gaugeOption.width / 2 + gaugeOption.labelOffset * opts.pix;
  radius = radius < 10 ? 10 : radius;

  let totalAngle: number;
  if (gaugeOption.endAngle! < gaugeOption.startAngle!) {
    totalAngle = 2 + gaugeOption.endAngle! - gaugeOption.startAngle!;
  } else {
    totalAngle = gaugeOption.startAngle! - gaugeOption.endAngle!;
  }

  let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
  let totalNumber = (gaugeOption.endNumber || 10) - (gaugeOption.startNumber || 0);
  let splitNumber = totalNumber / gaugeOption.splitLine.splitNumber;
  let nowAngle = gaugeOption.startAngle!;
  let nowNumber = gaugeOption.startNumber || 0;

  for (let i = 0; i < gaugeOption.splitLine.splitNumber + 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;
  }
}
