/** * 系列数据处理函数 * * 从 u-charts 核心库搬迁的系列数据处理相关函数 * 用于处理图表系列数据的填充、合并、颜色设置等操作 */ // 类型定义 export interface SeriesItem { data: (number | null)[] | number[] | { value: number }[]; name: string; color?: string; index?: number; linearIndex?: number; type?: string; show?: boolean; pointShape?: string; legendShape?: string; formatter?: (item: any, titleText: string, index: number, opts: ChartOptions) => string; style?: string; disableLegend?: boolean; connectNulls?: boolean; [key: string]: any; } export interface ChartOptions { type: string; categories?: string[]; extra?: ChartExtraOptions; xAxis?: XAxisOptions; yAxis?: YAxisOptions; area: number[]; width: number; height: number; pix: number; enableScroll?: boolean; chartData?: ChartData; background?: string; fontColor?: string; _scrollDistance_?: number; series?: any[]; tooltip?: any; dataLabel?: boolean; title?: any; subtitle?: any; dataPointShapeType?: string; legend?: any; [key: string]: any; } export interface ChartExtraOptions { bar?: BarOptions; column?: ColumnOptions; tooltip?: TooltipOptions; mount?: MountOptions; [key: string]: any; } export interface BarOptions { type?: string; [key: string]: any; } export interface ColumnOptions { type?: 'group' | 'stack' | 'meter'; width?: number; meterBorder?: number; meterFillColor?: string; barBorderCircle?: boolean; barBorderRadius?: number[]; seriesGap?: number; linearType?: string; linearOpacity?: number; customColor?: string[]; colorStop?: number; labelPosition?: string; borderWidth?: number; widthRatio?: number; [key: string]: any; } export interface TooltipOptions { legendShape?: string; [key: string]: any; } export interface MountOptions { widthRatio?: number; type?: 'bar' | 'triangle' | 'mount' | 'sharp'; [key: string]: any; } export interface XAxisOptions { lineHeight?: number; marginTop?: number; fontSize?: number; disabled?: boolean; rotateLabel?: boolean; rotateAngle?: number; scrollShow?: boolean; boundaryGap?: string; itemCount?: number; splitNumber?: number; formatter?: (item: any, index: number, opts: ChartOptions) => string; [key: string]: any; } export interface YAxisOptions { fontSize?: number; disabled?: boolean; data?: YAxisDataItem[]; formatter?: (val: number, index: number, opts: ChartOptions) => string; tofix?: number; unit?: string; min?: number; max?: number; [key: string]: any; } export interface YAxisDataItem { type?: string; disabled?: boolean; formatter?: (val: any, index: number, opts: ChartOptions) => string; categories?: string[]; tofix?: number; unit?: string; min?: number; max?: number; position?: string; calibration?: boolean; fontSize?: number; textAlign?: string; axisLineColor?: string; fontColor?: string; axisLine?: boolean; titleFontSize?: number; title?: string; titleFontColor?: string; titleOffsetX?: number; titleOffsetY?: number; } export interface ChartData { calPoints?: any[][]; xAxisPoints?: number[]; eachSpacing?: number; [key: string]: any; } export interface UChartsConfig { version: string; color: string[]; linearColor: string[]; yAxisWidth: number; xAxisHeight: number; padding: number[]; rotate: boolean; fontSize: number; fontColor: string; dataPointShape: string[]; pieChartLinePadding: number; pieChartTextPadding: number; titleFontSize: number; subtitleFontSize: number; radarLabelTextMargin: number; toolTipBackground?: string; toolTipOpacity?: number; _pieTextMaxLength_?: number; _xAxisTextAngle_?: number; } export interface DataRange { minRange: number; maxRange: number; } /** * 修复饼图系列数据 * 处理饼图的百分比和累计值 * * @param series - 系列数据数组 * @param opts - 图表配置选项 * @param config - uCharts配置对象 * @returns 修复后的系列数据数组 */ export function fixPieSeries( series: SeriesItem[], opts: ChartOptions, config: UChartsConfig ): SeriesItem[] { const pieSeriesArr: SeriesItem[] = []; if (series.length > 0 && series[0].data.constructor.toString().indexOf('Array') > -1) { (opts as any)._pieSeries_ = series; const oldseries = series[0].data as any[]; for (let i = 0; i < oldseries.length; i++) { oldseries[i].formatter = series[0].formatter; oldseries[i].data = oldseries[i].value; pieSeriesArr.push(oldseries[i]); } opts.series = pieSeriesArr; } else { return series; } return pieSeriesArr; } /** * 填充系列数据 * 确保所有系列数据都有完整的属性配置 * * @param series - 系列数据数组 * @param opts - 图表配置选项 * @param config - uCharts配置对象 * @returns 填充后的系列数据数组 */ export function fillSeries( series: SeriesItem[], opts: ChartOptions, config: UChartsConfig ): SeriesItem[] { let index = 0; for (let i = 0; i < series.length; i++) { const item = series[i]; if (!item.color) { item.color = config.color[index]; index = (index + 1) % config.color.length; } if (!item.linearIndex) { item.linearIndex = i; } if (!item.index) { item.index = 0; } if (!item.type) { item.type = opts.type; } if (typeof item.show === "undefined") { item.show = true; } if (!item.type) { item.type = opts.type; } if (!item.pointShape) { item.pointShape = "circle"; } if (!item.legendShape) { switch (item.type) { case 'line': item.legendShape = "line"; break; case 'column': case 'bar': item.legendShape = "rect"; break; case 'area': case 'mount': item.legendShape = "triangle"; break; default: item.legendShape = "circle"; } } } return series; } /** * 填充自定义颜色 * 为系列数据设置自定义颜色或使用默认渐变色 * * @param linearType - 线性类型 ('custom' 或其他) * @param customColor - 自定义颜色数组 * @param series - 系列数据数组 * @param config - uCharts配置对象 * @returns 颜色数组 */ export function fillCustomColor( linearType: string, customColor: string[], series: SeriesItem[], config: UChartsConfig ): string[] { let newcolor = customColor || []; if (linearType == 'custom' && newcolor.length == 0) { newcolor = config.linearColor; } if (linearType == 'custom' && newcolor.length < series.length) { const chazhi = series.length - newcolor.length; for (let i = 0; i < chazhi; i++) { newcolor.push(config.linearColor[(i + 1) % config.linearColor.length]); } } return newcolor; } /** * 获取数据范围 * 计算最小值和最大值的范围 * * @param minData - 最小数据值 * @param maxData - 最大数据值 * @returns 数据范围对象 */ export function getDataRange(minData: number, maxData: number): DataRange { let limit = 0; const range = maxData - minData; if (range >= 10000) { limit = 1000; } else if (range >= 1000) { limit = 100; } else if (range >= 100) { limit = 10; } else if (range >= 10) { limit = 5; } else if (range >= 1) { limit = 1; } else if (range >= 0.1) { limit = 0.1; } else if (range >= 0.01) { limit = 0.01; } else if (range >= 0.001) { limit = 0.001; } else if (range >= 0.0001) { limit = 0.0001; } else if (range >= 0.00001) { limit = 0.00001; } else { limit = 0.000001; } return { minRange: findRange(minData, 'lower', limit), maxRange: findRange(maxData, 'upper', limit) }; } /** * 查找范围边界 * 根据类型和限制查找合适的边界值 * * @param num - 数值 * @param type - 类型 ('upper' 或 'lower') * @param limit - 限制值 * @returns 边界值 */ function findRange(num: number, type: 'upper' | 'lower', limit: number): number { if (isNaN(num)) { throw new Error('[uCharts] series数据需为Number格式'); } limit = limit || 10; type = type ? type : 'upper'; let multiple = 1; while (limit < 1) { limit *= 10; multiple *= 10; } if (type === 'upper') { num = Math.ceil(num * multiple); } else { num = Math.floor(num * multiple); } while (num % limit !== 0) { if (type === 'upper') { if (num == num + 1) { break; } num++; } else { num--; } } return num / multiple; } /** * 数据合并 * 合并多个系列的数据 * * @param series - 系列数据数组 * @returns 合并后的数据数组 */ export function dataCombine(series: SeriesItem[]): (number | null)[] { return series.reduce(function(a, b) { return (a.data ? a.data : a).concat(b.data); }, [] as any); } /** * 堆叠数据合并 * 处理堆叠图表的数据合并 * * @param series - 系列数据数组 * @param len - 数据长度 * @returns 合并后的数据数组 */ export function dataCombineStack( series: SeriesItem[], len: number ): (number | null)[] { const sum = new Array(len); for (let j = 0; j < sum.length; j++) { sum[j] = 0; } for (let i = 0; i < series.length; i++) { for (let j = 0; j < sum.length; j++) { sum[j] += (series[i].data as number[])[j]; } } return series.reduce(function(a, b) { return (a.data ? a.data : a).concat(b.data).concat(sum); }, [] as any); }