|
|
@@ -0,0 +1,595 @@
|
|
|
+/**
|
|
|
+ * 坐标轴计算函数
|
|
|
+ *
|
|
|
+ * 从 u-charts 核心库搬迁的坐标轴计算相关函数
|
|
|
+ * 用于计算X轴、Y轴的数据和刻度
|
|
|
+ */
|
|
|
+
|
|
|
+import { dataCombine, dataCombineStack, getDataRange } from './series-calculator';
|
|
|
+
|
|
|
+// 类型定义
|
|
|
+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;
|
|
|
+}
|
|
|
+
|
|
|
+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;
|
|
|
+ [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?: string;
|
|
|
+ [key: string]: any;
|
|
|
+}
|
|
|
+
|
|
|
+export interface TooltipOptions {
|
|
|
+ legendShape?: string;
|
|
|
+ [key: string]: any;
|
|
|
+}
|
|
|
+
|
|
|
+export interface MountOptions {
|
|
|
+ widthRatio?: number;
|
|
|
+ [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;
|
|
|
+ splitNumber?: 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;
|
|
|
+}
|
|
|
+
|
|
|
+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;
|
|
|
+}
|
|
|
+
|
|
|
+export interface XAxisDataResult {
|
|
|
+ angle: number;
|
|
|
+ xAxisHeight: number;
|
|
|
+ ranges: number[];
|
|
|
+ rangesFormat: string[];
|
|
|
+ xAxisPoints: number[];
|
|
|
+ startX: number;
|
|
|
+ endX: number;
|
|
|
+ eachSpacing: number;
|
|
|
+}
|
|
|
+
|
|
|
+export interface YAxisDataResult {
|
|
|
+ yAxisData: {
|
|
|
+ categories?: string[];
|
|
|
+ rangesFormat: string[][];
|
|
|
+ ranges: number[][];
|
|
|
+ }[];
|
|
|
+ yAxisWidth: {
|
|
|
+ position: string;
|
|
|
+ width: number;
|
|
|
+ }[];
|
|
|
+}
|
|
|
+
|
|
|
+export interface AxisPointsResult {
|
|
|
+ xAxisPoints?: number[];
|
|
|
+ startX: number;
|
|
|
+ endX: number;
|
|
|
+ eachSpacing: number;
|
|
|
+}
|
|
|
+
|
|
|
+// 工具函数
|
|
|
+const util = {
|
|
|
+ toFixed: function toFixed(num: number, limit: number = 2): number | string {
|
|
|
+ if (this.isFloat(num)) {
|
|
|
+ num = Number(num.toFixed(limit));
|
|
|
+ }
|
|
|
+ return num;
|
|
|
+ },
|
|
|
+ isFloat: function isFloat(num: number): boolean {
|
|
|
+ return num % 1 !== 0;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+function assign(target: any, ...sources: any[]): any {
|
|
|
+ if (target == null) {
|
|
|
+ throw new TypeError('[uCharts] Cannot convert undefined or null to object');
|
|
|
+ }
|
|
|
+ const result = { ...target };
|
|
|
+ sources.forEach(val => {
|
|
|
+ if (val != null) {
|
|
|
+ Object.keys(val).forEach(key => {
|
|
|
+ if (val[key] !== undefined) {
|
|
|
+ result[key] = val[key];
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+function measureText(text: string | number, fontSize: number, context?: any): number {
|
|
|
+ let width = 0;
|
|
|
+ text = String(text);
|
|
|
+ if (context !== false && context !== undefined && context.setFontSize && context.measureText) {
|
|
|
+ context.setFontSize(fontSize);
|
|
|
+ return context.measureText(text).width;
|
|
|
+ } else {
|
|
|
+ const textArray = text.split('');
|
|
|
+ for (let i = 0; i < textArray.length; i++) {
|
|
|
+ const item = textArray[i];
|
|
|
+ if (/[a-zA-Z]/.test(item)) {
|
|
|
+ width += 7;
|
|
|
+ } else if (/[0-9]/.test(item)) {
|
|
|
+ width += 5.5;
|
|
|
+ } else if (/\./.test(item)) {
|
|
|
+ width += 2.7;
|
|
|
+ } else if (/-/.test(item)) {
|
|
|
+ width += 3.25;
|
|
|
+ } else if (/:/.test(item)) {
|
|
|
+ width += 2.5;
|
|
|
+ } else if (/[\u4e00-\u9fa5]/.test(item)) {
|
|
|
+ width += 10;
|
|
|
+ } else if (/\(|\)/.test(item)) {
|
|
|
+ width += 3.73;
|
|
|
+ } else if (/\s/.test(item)) {
|
|
|
+ width += 2.5;
|
|
|
+ } else if (/%/.test(item)) {
|
|
|
+ width += 8;
|
|
|
+ } else {
|
|
|
+ width += 10;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return width * fontSize / 10;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 计算X轴数据
|
|
|
+ * 包括刻度、标签等
|
|
|
+ *
|
|
|
+ * @param series - 系列数据数组
|
|
|
+ * @param opts - 图表配置选项
|
|
|
+ * @param config - uCharts配置对象
|
|
|
+ * @param context - Canvas上下文
|
|
|
+ * @returns X轴数据结果
|
|
|
+ */
|
|
|
+export function calXAxisData(
|
|
|
+ series: SeriesItem[],
|
|
|
+ opts: ChartOptions,
|
|
|
+ config: UChartsConfig,
|
|
|
+ context?: any
|
|
|
+): XAxisDataResult {
|
|
|
+ const columnstyle = assign({}, {
|
|
|
+ type: ""
|
|
|
+ }, opts.extra?.column || {});
|
|
|
+ const result: XAxisDataResult = {
|
|
|
+ angle: 0,
|
|
|
+ xAxisHeight: (opts.xAxis?.lineHeight || 0) * (opts.pix || 1) + (opts.xAxis?.marginTop || 0) * (opts.pix || 1),
|
|
|
+ ranges: [],
|
|
|
+ rangesFormat: [],
|
|
|
+ xAxisPoints: [],
|
|
|
+ startX: 0,
|
|
|
+ endX: 0,
|
|
|
+ eachSpacing: 0
|
|
|
+ };
|
|
|
+ result.ranges = getXAxisTextList(series, opts, config, columnstyle.type || '');
|
|
|
+ result.rangesFormat = result.ranges.map(function(item) {
|
|
|
+ const numItem = Number(item);
|
|
|
+ return String(util.toFixed(numItem, 2));
|
|
|
+ });
|
|
|
+ const xAxisScaleValues = result.ranges.map(function(item) {
|
|
|
+ const numItem = Number(item);
|
|
|
+ return util.toFixed(numItem, 2);
|
|
|
+ });
|
|
|
+ Object.assign(result, getXAxisPoints(xAxisScaleValues as any, opts, config));
|
|
|
+ const eachSpacing = result.eachSpacing;
|
|
|
+ const textLength = xAxisScaleValues.map(function(item) {
|
|
|
+ return measureText(String(item), (opts.xAxis?.fontSize || 13) * (opts.pix || 1), context);
|
|
|
+ });
|
|
|
+ if (opts.xAxis?.disabled === true) {
|
|
|
+ result.xAxisHeight = 0;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 获取X轴文本列表
|
|
|
+ * 计算X轴刻度值范围
|
|
|
+ *
|
|
|
+ * @param series - 系列数据数组
|
|
|
+ * @param opts - 图表配置选项
|
|
|
+ * @param config - uCharts配置对象
|
|
|
+ * @param stack - 堆叠类型
|
|
|
+ * @param index - Y轴索引
|
|
|
+ * @returns 刻度值范围数组
|
|
|
+ */
|
|
|
+function getXAxisTextList(
|
|
|
+ series: SeriesItem[],
|
|
|
+ opts: ChartOptions,
|
|
|
+ config: UChartsConfig,
|
|
|
+ stack: string = '',
|
|
|
+ index: number = -1
|
|
|
+): number[] {
|
|
|
+ let data: (number | null)[];
|
|
|
+ if (stack == 'stack') {
|
|
|
+ data = dataCombineStack(series, opts.categories?.length || 0);
|
|
|
+ } else {
|
|
|
+ data = dataCombine(series);
|
|
|
+ }
|
|
|
+ const sorted: number[] = [];
|
|
|
+ data = data.filter(function(item) {
|
|
|
+ if (typeof item === 'object' && item !== null) {
|
|
|
+ if (Array.isArray(item)) {
|
|
|
+ return item !== null;
|
|
|
+ } else {
|
|
|
+ return (item as any).value !== null;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return item !== null;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ data.forEach(function(item) {
|
|
|
+ if (typeof item === 'object' && item !== null) {
|
|
|
+ if (Array.isArray(item)) {
|
|
|
+ if (opts.type == 'candle') {
|
|
|
+ (item as any).forEach(function(subitem: any) {
|
|
|
+ sorted.push(subitem as number);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ sorted.push((item as any)[0] as number);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ sorted.push((item as any).value);
|
|
|
+ }
|
|
|
+ } else if (item !== null) {
|
|
|
+ sorted.push(item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ let minData = 0;
|
|
|
+ let maxData = 0;
|
|
|
+ if (sorted.length > 0) {
|
|
|
+ minData = Math.min(...sorted);
|
|
|
+ maxData = Math.max(...sorted);
|
|
|
+ }
|
|
|
+ if (index > -1) {
|
|
|
+ const xAxisData = (opts.xAxis as any)?.data;
|
|
|
+ if (xAxisData && typeof xAxisData[index]?.min === 'number') {
|
|
|
+ minData = Math.min(xAxisData[index].min, minData);
|
|
|
+ }
|
|
|
+ if (xAxisData && typeof xAxisData[index]?.max === 'number') {
|
|
|
+ maxData = Math.max(xAxisData[index].max, maxData);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (typeof opts.xAxis?.min === 'number') {
|
|
|
+ minData = Math.min(opts.xAxis.min, minData);
|
|
|
+ }
|
|
|
+ if (typeof opts.xAxis?.max === 'number') {
|
|
|
+ maxData = Math.max(opts.xAxis.max, maxData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (minData === maxData) {
|
|
|
+ const rangeSpan = maxData || 10;
|
|
|
+ maxData += rangeSpan;
|
|
|
+ }
|
|
|
+ const minRange = minData;
|
|
|
+ const maxRange = maxData;
|
|
|
+ const splitNumber = opts.xAxis?.splitNumber || 5;
|
|
|
+ const range: number[] = [];
|
|
|
+ const eachRange = (maxRange - minRange) / splitNumber;
|
|
|
+ for (let i = 0; i <= splitNumber; i++) {
|
|
|
+ range.push(minRange + eachRange * i);
|
|
|
+ }
|
|
|
+ return range;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 获取X轴数据点坐标
|
|
|
+ *
|
|
|
+ * @param categories - 分类数据
|
|
|
+ * @param opts - 图表配置选项
|
|
|
+ * @param config - uCharts配置对象
|
|
|
+ * @returns X轴数据点结果
|
|
|
+ */
|
|
|
+export function getXAxisPoints(
|
|
|
+ categories: (string | number)[],
|
|
|
+ opts: ChartOptions,
|
|
|
+ config: UChartsConfig
|
|
|
+): AxisPointsResult {
|
|
|
+ const spacingValid = (opts.width || 0) - (opts.area?.[1] || 0) - (opts.area?.[3] || 0);
|
|
|
+ const dataCount = opts.enableScroll
|
|
|
+ ? Math.min(opts.xAxis?.itemCount || categories.length, categories.length)
|
|
|
+ : categories.length;
|
|
|
+ const type = opts.type;
|
|
|
+ let modifiedDataCount = dataCount;
|
|
|
+ if ((type == 'line' || type == 'area' || type == 'scatter' || type == 'bubble' || type == 'bar') &&
|
|
|
+ dataCount > 1 &&
|
|
|
+ opts.xAxis?.boundaryGap == 'justify') {
|
|
|
+ modifiedDataCount -= 1;
|
|
|
+ }
|
|
|
+ let widthRatio = 0;
|
|
|
+ if (type == 'mount' &&
|
|
|
+ opts.extra?.mount &&
|
|
|
+ opts.extra.mount.widthRatio &&
|
|
|
+ opts.extra.mount.widthRatio > 1) {
|
|
|
+ if (opts.extra.mount.widthRatio > 2) {
|
|
|
+ (opts.extra.mount.widthRatio as any) = 2;
|
|
|
+ }
|
|
|
+ widthRatio = opts.extra.mount.widthRatio - 1;
|
|
|
+ modifiedDataCount += widthRatio;
|
|
|
+ }
|
|
|
+ const eachSpacing = spacingValid / modifiedDataCount;
|
|
|
+ const xAxisPoints: number[] = [];
|
|
|
+ const startX = opts.area?.[3] || 0;
|
|
|
+ const endX = (opts.width || 0) - (opts.area?.[1] || 0);
|
|
|
+ categories.forEach(function(_item, index) {
|
|
|
+ xAxisPoints.push(startX + widthRatio / 2 * eachSpacing + index * eachSpacing);
|
|
|
+ });
|
|
|
+ if (opts.xAxis?.boundaryGap !== 'justify') {
|
|
|
+ if (opts.enableScroll === true) {
|
|
|
+ xAxisPoints.push(startX + widthRatio * eachSpacing + categories.length * eachSpacing);
|
|
|
+ } else {
|
|
|
+ xAxisPoints.push(endX);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ xAxisPoints,
|
|
|
+ startX,
|
|
|
+ endX,
|
|
|
+ eachSpacing
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 计算Y轴数据
|
|
|
+ * 包括刻度、标签等,支持多Y轴
|
|
|
+ *
|
|
|
+ * @param series - 系列数据数组
|
|
|
+ * @param opts - 图表配置选项
|
|
|
+ * @param config - uCharts配置对象
|
|
|
+ * @param context - Canvas上下文
|
|
|
+ * @returns Y轴数据结果
|
|
|
+ */
|
|
|
+export function calYAxisData(
|
|
|
+ series: SeriesItem[],
|
|
|
+ opts: ChartOptions,
|
|
|
+ config: UChartsConfig,
|
|
|
+ context?: any
|
|
|
+): YAxisDataResult {
|
|
|
+ const columnstyle = assign({}, {
|
|
|
+ type: ""
|
|
|
+ }, opts.extra?.column || {});
|
|
|
+ const YLength = opts.yAxis?.data?.length || 0;
|
|
|
+ const newSeries: SeriesItem[][] = new Array(YLength);
|
|
|
+ if (YLength > 0) {
|
|
|
+ for (let i = 0; i < YLength; i++) {
|
|
|
+ newSeries[i] = [];
|
|
|
+ for (let j = 0; j < series.length; j++) {
|
|
|
+ if (series[j].index == i) {
|
|
|
+ newSeries[i].push(series[j]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const rangesArr: (number[] | string[])[] = new Array(YLength);
|
|
|
+ const rangesFormatArr: string[][] = new Array(YLength);
|
|
|
+ const yAxisWidthArr: { position: string; width: number }[] = new Array(YLength);
|
|
|
+
|
|
|
+ for (let i = 0; i < YLength; i++) {
|
|
|
+ let yData = opts.yAxis?.data?.[i] as YAxisDataItem | undefined;
|
|
|
+ if (!yData) {
|
|
|
+ yData = {} as YAxisDataItem;
|
|
|
+ }
|
|
|
+ if (opts.yAxis?.disabled == true) {
|
|
|
+ yData.disabled = true;
|
|
|
+ }
|
|
|
+ if (yData.type === 'categories') {
|
|
|
+ if (!yData.formatter) {
|
|
|
+ yData.formatter = (val: any, _index: number, _opts: ChartOptions) => {
|
|
|
+ return String(val) + (yData?.unit || '');
|
|
|
+ };
|
|
|
+ }
|
|
|
+ yData.categories = yData.categories || opts.categories;
|
|
|
+ rangesArr[i] = yData.categories || [];
|
|
|
+ } else {
|
|
|
+ if (!yData.formatter) {
|
|
|
+ yData.formatter = (val: any, _index: number, _opts: ChartOptions) => {
|
|
|
+ return String(util.toFixed(Number(val), yData?.tofix || 0)) + (yData?.unit || '');
|
|
|
+ };
|
|
|
+ }
|
|
|
+ rangesArr[i] = getYAxisTextList(newSeries[i] || [], opts, config, columnstyle.type || '', yData, i);
|
|
|
+ }
|
|
|
+ const yAxisFontSizes = (yData.fontSize || opts.yAxis?.fontSize || config.fontSize) * (opts.pix || 1);
|
|
|
+ yAxisWidthArr[i] = {
|
|
|
+ position: yData.position ? yData.position : 'left',
|
|
|
+ width: 0
|
|
|
+ };
|
|
|
+ rangesFormatArr[i] = (rangesArr[i] as number[]).map(function(items, index) {
|
|
|
+ const formatted = yData.formatter!(items, index, opts);
|
|
|
+ yAxisWidthArr[i].width = Math.max(yAxisWidthArr[i].width, measureText(formatted, yAxisFontSizes, context) + 5);
|
|
|
+ return formatted;
|
|
|
+ });
|
|
|
+ const calibration = yData.calibration ? 4 * (opts.pix || 1) : 0;
|
|
|
+ yAxisWidthArr[i].width += calibration + 3 * (opts.pix || 1);
|
|
|
+ if (yData.disabled === true) {
|
|
|
+ yAxisWidthArr[i].width = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ yAxisData: rangesArr.map((ranges, i) => {
|
|
|
+ const isCategories = typeof ranges[0] === 'string';
|
|
|
+ return {
|
|
|
+ ranges: !isCategories ? [ranges as number[]] : [],
|
|
|
+ rangesFormat: [rangesFormatArr[i]],
|
|
|
+ categories: isCategories ? ranges as string[] : undefined
|
|
|
+ };
|
|
|
+ }),
|
|
|
+ yAxisWidth: yAxisWidthArr
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 获取Y轴文本列表
|
|
|
+ * 计算Y轴刻度值范围
|
|
|
+ *
|
|
|
+ * @param series - 系列数据数组
|
|
|
+ * @param opts - 图表配置选项
|
|
|
+ * @param config - uCharts配置对象
|
|
|
+ * @param stack - 堆叠类型
|
|
|
+ * @param yData - Y轴数据配置
|
|
|
+ * @param index - Y轴索引
|
|
|
+ * @returns 刻度值范围数组
|
|
|
+ */
|
|
|
+function getYAxisTextList(
|
|
|
+ series: SeriesItem[],
|
|
|
+ opts: ChartOptions,
|
|
|
+ config: UChartsConfig,
|
|
|
+ stack: string = '',
|
|
|
+ yData: YAxisDataItem = {},
|
|
|
+ index: number = -1
|
|
|
+): number[] {
|
|
|
+ let data: (number | null)[];
|
|
|
+ if (stack == 'stack') {
|
|
|
+ data = dataCombineStack(series, opts.categories?.length || 0);
|
|
|
+ } else {
|
|
|
+ data = dataCombine(series);
|
|
|
+ }
|
|
|
+ const sorted: number[] = [];
|
|
|
+ data = data.filter(function(item) {
|
|
|
+ if (typeof item === 'object' && item !== null) {
|
|
|
+ if (Array.isArray(item)) {
|
|
|
+ return item !== null;
|
|
|
+ } else {
|
|
|
+ return (item as any).value !== null;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return item !== null;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ data.forEach(function(item) {
|
|
|
+ if (typeof item === 'object' && item !== null) {
|
|
|
+ if (Array.isArray(item)) {
|
|
|
+ if (opts.type == 'candle') {
|
|
|
+ (item as any).forEach(function(subitem: any) {
|
|
|
+ sorted.push(subitem as number);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ sorted.push((item as any)[1] as number);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ sorted.push((item as any).value);
|
|
|
+ }
|
|
|
+ } else if (item !== null) {
|
|
|
+ sorted.push(item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ let minData = yData.min || 0;
|
|
|
+ let maxData = yData.max || 0;
|
|
|
+ if (sorted.length > 0) {
|
|
|
+ minData = Math.min(...sorted);
|
|
|
+ maxData = Math.max(...sorted);
|
|
|
+ }
|
|
|
+ if (minData === maxData) {
|
|
|
+ if (maxData == 0) {
|
|
|
+ maxData = 10;
|
|
|
+ } else {
|
|
|
+ minData = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const dataRange = getDataRange(minData, maxData);
|
|
|
+ const minRange = (yData.min === undefined || yData.min === null) ? dataRange.minRange : yData.min;
|
|
|
+ const maxRange = (yData.max === undefined || yData.max === null) ? dataRange.maxRange : yData.max;
|
|
|
+ const splitNumber = opts.yAxis?.splitNumber || 5;
|
|
|
+ const eachRange = (maxRange - minRange) / splitNumber;
|
|
|
+ const range: number[] = [];
|
|
|
+ for (let i = 0; i <= splitNumber; i++) {
|
|
|
+ range.push(minRange + eachRange * i);
|
|
|
+ }
|
|
|
+ return range.reverse();
|
|
|
+}
|