瀏覽代碼

✨ feat(charts): 添加调试日志以辅助排查柱状图渲染问题

- 在 `getColumnDataPoints` 函数中添加日志,记录输入参数、有效绘图区域、第一个数据点详情和返回数组长度
- 在 `calYAxisData` 函数中重构 Y 轴数据处理逻辑,简化返回数据结构并处理未配置多 Y 轴的情况
- 在 `drawCharts` 函数中添加日志,记录 Y 轴数据计算过程及结果
- 在 `fixColumeData` 函数中添加日志,记录输入参数和第一个点的处理变化
- 在 `drawColumnDataPoints` 函数中添加日志,记录 Y 轴范围解析、数据点修复和第一个柱子的绘制详情
yourname 3 周之前
父節點
當前提交
a488d012a3

+ 29 - 0
mini-ui-packages/mini-charts/src/lib/charts-data/basic-charts.ts

@@ -344,9 +344,24 @@ export function getColumnDataPoints(
   zeroPoints: number[],
   process = 1
 ): (DataPoint | null)[] {
+  console.debug('[getColumnDataPoints] 输入参数:', {
+    optsWidth: opts.width,
+    optsHeight: opts.height,
+    area: opts.area,
+    pixelRatio: opts.pix,
+    eachSpacing,
+    xAxisPoints: xAxisPoints.slice(0, 3),
+    dataLength: data.length
+  });
+
   let points: (DataPoint | null)[] = [];
   let validHeight = opts.height - opts.area[0] - opts.area[2];
   let validWidth = opts.width - opts.area[1] - opts.area[3];
+
+  console.debug('[getColumnDataPoints] 有效绘图区域:', {
+    validHeight,
+    validWidth
+  });
   data.forEach(function(item, index) {
     if (item === null) {
       points.push(null);
@@ -375,9 +390,23 @@ export function getColumnDataPoints(
       point.x += eachSpacing / 2;
       let height = validHeight * (value * process - minRange) / (maxRange - minRange);
       point.y = opts.height - height - opts.area[2];
+
+      if (index === 0) {
+        console.debug('[getColumnDataPoints] 第一个数据点:', {
+          index,
+          value,
+          pointX: point.x,
+          pointY: point.y,
+          height,
+          xAxisPoint: xAxisPoints[index]
+        });
+      }
+
       points.push(point);
     }
   });
+
+  console.debug('[getColumnDataPoints] 返回的点数组长度:', points.length);
   return points;
 }
 

+ 93 - 41
mini-ui-packages/mini-charts/src/lib/data-processing/axis-calculator.ts

@@ -52,11 +52,8 @@ export interface XAxisDataResult {
 }
 
 export interface YAxisDataResult {
-  yAxisData: {
-    categories?: string[];
-    rangesFormat: string[][];
-    ranges: number[][];
-  }[];
+  rangesFormat: string[][];
+  ranges: (number[] | string[])[];
   yAxisWidth: {
     position: string;
     width: number;
@@ -369,56 +366,111 @@ export function calYAxisData(
   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 (YLength > 0) {
+    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;
+      }
     }
-    if (yData.type === 'categories') {
-      if (!yData.formatter) {
-        yData.formatter = (val: any, _index: number, _opts: ChartOptions) => {
-          return String(val) + (yData?.unit || '');
+  } else {
+    // 当没有配置多Y轴时,使用默认配置
+    rangesArr.length = 1;
+    rangesFormatArr.length = 1;
+    yAxisWidthArr.length = 1;
+
+    if (opts.type === 'bar') {
+      rangesArr[0] = opts.categories || [];
+      if (!opts.yAxis?.formatter) {
+        if (!opts.yAxis) {
+          opts.yAxis = {} as any;
+        }
+        (opts.yAxis as any).formatter = (val: any, _index: number, _opts: ChartOptions) => {
+          return String(val) + (opts.yAxis?.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 || '');
+      if (!opts.yAxis?.formatter) {
+        if (!opts.yAxis) {
+          opts.yAxis = {} as any;
+        }
+        (opts.yAxis as any).formatter = (val: any, _index: number, _opts: ChartOptions) => {
+          return String(util.toFixed(Number(val), (opts.yAxis as any)?.tofix || 0)) + (opts.yAxis?.unit || '');
         };
       }
-      rangesArr[i] = getYAxisTextList(newSeries[i] || [], opts, config, columnstyle.type || '', yData, i);
+      rangesArr[0] = getYAxisTextList(series, opts, config, columnstyle.type || '', {});
     }
-    const yAxisFontSizes = (yData.fontSize || opts.yAxis?.fontSize || config.fontSize) * (opts.pix || 1);
-    yAxisWidthArr[i] = {
-      position: yData.position ? yData.position : 'left',
+    yAxisWidthArr[0] = {
+      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 yAxisFontSize = ((opts.yAxis as any)?.fontSize || config.fontSize) * (opts.pix || 1);
+    rangesFormatArr[0] = rangesArr[0].map(function(item, index) {
+      const formatted = (opts.yAxis as any)?.formatter!(item, index, opts);
+      yAxisWidthArr[0].width = Math.max(yAxisWidthArr[0].width, measureText(formatted, yAxisFontSize, context) + 5);
+      return formatted as string;
     });
-    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;
+    yAxisWidthArr[0].width += 3 * (opts.pix || 1);
+    if ((opts.yAxis as any)?.disabled === true) {
+      yAxisWidthArr[0] = {
+        position: 'left',
+        width: 0
+      };
+      (opts.yAxis as any).data = [{
+        disabled: true
+      }];
+    } else {
+      (opts.yAxis as any).data = [{
+        disabled: false,
+        position: 'left',
+        max: (opts.yAxis as any)?.max,
+        min: (opts.yAxis as any)?.min,
+        formatter: (opts.yAxis as any)?.formatter
+      }];
+      if (opts.type === 'bar') {
+        (opts.yAxis as any).data[0].categories = opts.categories;
+        (opts.yAxis as any).data[0].type = 'categories';
+      }
     }
   }
 
   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
-      };
-    }),
+    rangesFormat: rangesFormatArr,
+    ranges: rangesArr,
     yAxisWidth: yAxisWidthArr
   };
 }

+ 18 - 0
mini-ui-packages/mini-charts/src/lib/draw-controllers/draw-charts.ts

@@ -184,9 +184,21 @@ export const drawCharts: DrawChartsFunction = function(
   if (opts.type === 'line' || opts.type === 'column' || opts.type === 'mount' ||
       opts.type === 'area' || opts.type === 'mix' || opts.type === 'candle' ||
       opts.type === 'scatter' || opts.type === 'bubble' || opts.type === 'bar') {
+    console.debug('[drawCharts] 准备计算 Y轴数据:', {
+      type: opts.type,
+      seriesLength: series.length,
+      seriesData: series.map(s => ({ name: s.name, dataLength: s.data?.length }))
+    });
     _calYAxisData = calYAxisData(series, opts, config, context);
     yAxisWidth = _calYAxisData.yAxisWidth;
 
+    console.debug('[drawCharts] Y轴数据计算完成:', {
+      yAxisWidth,
+      calYAxisDataKeys: Object.keys(_calYAxisData),
+      hasRanges: !!_calYAxisData.ranges,
+      rangesLength: _calYAxisData.ranges?.length
+    });
+
     // 如果显示Y轴标题
     if (opts.yAxis.showTitle) {
       let maxTitleHeight = 0;
@@ -221,6 +233,12 @@ export const drawCharts: DrawChartsFunction = function(
   }
   opts.chartData.yAxisData = _calYAxisData;
 
+  console.debug('[drawCharts] 设置 chartData.yAxisData:', {
+    yAxisDataSet: !!opts.chartData.yAxisData,
+    yAxisDataKeys: Object.keys(opts.chartData.yAxisData || {}),
+    hasRanges: !!(opts.chartData.yAxisData && opts.chartData.yAxisData.ranges)
+  });
+
   if (opts.categories && opts.categories.length && opts.type !== 'radar' &&
       opts.type !== 'gauge' && opts.type !== 'bar') {
     opts.chartData.xAxisData = getXAxisPoints(opts.categories, opts, config);

+ 28 - 0
mini-ui-packages/mini-charts/src/lib/helper-functions/data-fixers.ts

@@ -28,6 +28,15 @@ export function fixColumeData(
   config: UChartsConfig,
   opts: AnyChartOptions
 ): Array<{ x: number; width: number } | null> {
+  console.debug('[fixColumeData] 输入参数:', {
+    eachSpacing,
+    columnLen,
+    index,
+    optsPix: opts.pix,
+    extraColumn: opts.extra?.column,
+    firstPointX: points[0]?.x
+  });
+
   return points.map(function (item) {
     if (item === null) {
       return null;
@@ -55,6 +64,9 @@ export function fixColumeData(
       (eachSpacing - 2 * categoryGap - seriesGap * (columnLen - 1)) /
         columnLen
     );
+
+    const widthBeforeLimit = (item as any).width;
+
     if (
       opts.extra?.mix?.column?.width &&
       +opts.extra.mix.column.width > 0
@@ -76,7 +88,23 @@ export function fixColumeData(
     if ((item as any).width <= 0) {
       (item as any).width = 1;
     }
+
+    const originalX = item.x;
     item.x += (index + 0.5 - columnLen / 2) * ((item as any).width + seriesGap);
+
+    // 跟踪第一个点的变化
+    if (points.indexOf(item) === 0) {
+      console.debug('[fixColumeData] 第一个点处理:', {
+        originalX,
+        newX: item.x,
+        widthBeforeLimit,
+        finalWidth: (item as any).width,
+        seriesGap,
+        categoryGap,
+        appliedWidthLimit: opts.extra?.column?.width
+      });
+    }
+
     return item as { x: number; width: number };
   });
 }

+ 40 - 0
mini-ui-packages/mini-charts/src/lib/renderers/column-renderer.ts

@@ -137,9 +137,28 @@ export function drawColumnDataPoints(
     const ranges = opts.chartData?.yAxisData?.ranges
       ? [].concat(opts.chartData!.yAxisData!.ranges[(eachSeries.index || 0) as number])
       : [];
+
+    console.debug('[drawColumnDataPoints] Y轴数据范围:', {
+      seriesIndex,
+      eachSeriesIndex: eachSeries.index,
+      yAxisDataRanges: opts.chartData?.yAxisData?.ranges,
+      yAxisDataRangesLength: opts.chartData?.yAxisData?.ranges?.length,
+      ranges,
+      rangesLength: ranges.length,
+      rangesContent: ranges.length > 0 ? ranges[0] : 'empty array',
+      rangesFullContent: ranges
+    });
+
     const minRange = ranges.pop();
     const maxRange = ranges.shift();
 
+    console.debug('[drawColumnDataPoints] 解析后的 minRange/maxRange:', {
+      minRange,
+      maxRange,
+      minRangeType: typeof minRange,
+      maxRangeType: typeof maxRange
+    });
+
     // 计算0轴坐标
     const spacingValid = opts.height! - opts.area![0] - opts.area![2];
     const zeroHeight = (spacingValid * (0 - (minRange || 0))) / ((maxRange || 0) - (minRange || 0));
@@ -176,11 +195,32 @@ export function drawColumnDataPoints(
         calPoints.push(tooltipPoints);
         points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts);
 
+        console.debug('[drawColumnDataPoints] fixColumeData 后的第一个点:', {
+          x: points[0]?.x,
+          width: points[0]?.width,
+          eachSpacing,
+          seriesLength: series.length
+        });
+
         for (let i = 0; i < points.length; i++) {
           const item = points[i];
           if (item !== null && i > leftNum && i < rightNum) {
             const startX = item.x - item.width || 0 / 2;
             const height = opts.height! - item.y - opts.area![2];
+
+            if (i === 0) {
+              console.debug('[drawColumnDataPoints] 绘制第一个柱子:', {
+                i,
+                itemX: item.x,
+                itemWidth: item.width,
+                itemY: item.y,
+                startX,
+                height,
+                zeroPoints,
+                canvasWidth: opts.width,
+                canvasHeight: opts.height
+              });
+            }
             context.beginPath();
             let fillColor = item.color || eachSeries.color;
             const strokeColor = item.color || eachSeries.color;