浏览代码

修改SignalTimingchart相位图组件缩放大小导致图标和文字显示不全的问题

画安 3 周之前
父节点
当前提交
72265b8f03
共有 1 个文件被更改,包括 83 次插入36 次删除
  1. 83 36
      src/components/ui/SignalTimingChart.vue

+ 83 - 36
src/components/ui/SignalTimingChart.vue

@@ -200,46 +200,83 @@ export default {
       children.push({ type: 'rect', shape: rectShape, style: { fill: fillStyle, stroke: 'none' } });
 
       // C. 绘制内部图标与文本
-      const fs = Math.max(0.8, s * 0.9); 
-      if (type === 'green' && blockWidth > 15) {
-        const darkWidth = Math.round(50 * fs); 
+      // 提取基础缩放率
+      const baseFs = Math.max(0.8, s * 0.9); 
+      // 只要宽度大于 5 像素就尝试去渲染(原版限制是 > 15,改小以支持极限压缩)
+      if (type === 'green' && blockWidth > 5) {
+        
+        // --- 1. 将 iconValue 统一解析为数组,提前判断需要多宽的背景 ---
+        let iconList = [];
+        if (Array.isArray(iconValue)) {
+          iconList = iconValue;
+        } else if (typeof iconValue === 'string' && iconValue.trim() !== '') {
+          iconList = iconValue.split(',');
+        } else if (iconValue) {
+          iconList = [iconValue];
+        }
+
+        // 判断是否有靠左(LT/LB)和靠右(RT/RB)的图标
+        let hasL = false, hasR = false;
+        iconList.forEach(icon => {
+          const valStr = String(icon).trim().toUpperCase();
+          const posConfig = POS_MAP[valStr] || { pos: 'RB' };
+          const pos = typeof posConfig === 'string' ? posConfig : (posConfig.pos || 'RB');
+          if (pos.includes('L')) hasL = true;
+          if (pos.includes('R')) hasR = true;
+        });
+        
+        // 核心:动态赋予深绿色区域的基础宽度!
+        // 如果左右都有图标,给46宽度;如果只有一侧有,收缩到28;啥都没给8
+        let idealDarkWidthBase = (hasL && hasR) ? 46 : (iconList.length > 0 ? 28 : 0);
+        if (idealDarkWidthBase === 0 && phaseName) idealDarkWidthBase = 8; 
+
+        // 计算当前缩放下,理想状态需要的总像素宽度
+        let idealDarkWidth = idealDarkWidthBase * baseFs;
+        let idealTextWidth = 26 * baseFs; // 预留给 "P1\n24" 这类文本的宽度
+        let totalNeededWidth = idealDarkWidth + 6 * baseFs + idealTextWidth;
+
+        // --- 2. 计算动态弹性缩放率 (如果外部方块太小,内部按比例整体缩小) ---
+        let innerScale = 1;
+        if (blockWidth < totalNeededWidth) {
+          // 最极限缩小到 15%,防止变成一个点引发渲染错误
+          innerScale = Math.max(0.15, blockWidth / totalNeededWidth);
+        }
+
+        // 应用弹性缩放
+        const dynamicFs = baseFs * innerScale;
+        const darkWidth = idealDarkWidthBase * dynamicFs;
         const midY = yPos + blockHeight / 2;
+        const pointerW = 4 * dynamicFs; // 中间那个小三角指针的大小也跟着缩放
         
         const innerGroup = {
           type: 'group',
+          // 用 clipPath 限制死边界,防止文字或图标因为四舍五入溢出色块
           clipPath: { type: 'rect', shape: { x: start[0], y: yPos, width: blockWidth, height: blockHeight } },
           children: [
             { type: 'rect', shape: { x: start[0], y: yPos, width: darkWidth, height: blockHeight }, style: { fill: COLORS.GREEN_DARK } },
             { 
               type: 'polygon', 
-              shape: { points: [ [start[0] + darkWidth, midY - 4 * fs], [start[0] + darkWidth, midY + 4 * fs], [start[0] + darkWidth + 4 * fs, midY] ] }, 
+              shape: { points: [ 
+                [start[0] + darkWidth, midY - pointerW], 
+                [start[0] + darkWidth, midY + pointerW], 
+                [start[0] + darkWidth + pointerW, midY] 
+              ] }, 
               style: { fill: COLORS.GREEN_DARK } 
             }
           ]
         };
 
-        // --- 核心修改:支持将传入的 iconValue 作为多个图标渲染 ---
-        // 将 iconValue 统一解析为数组,支持数组格式 ['A', 'B'] 或 字符串逗号分隔格式 'A,B'
-        let iconList = [];
-        if (Array.isArray(iconValue)) {
-          iconList = iconValue;
-        } else if (typeof iconValue === 'string' && iconValue.trim() !== '') {
-          iconList = iconValue.split(',');
-        } else if (iconValue) {
-          iconList = [iconValue];
-        }
-
-        // 遍历所有图标,按它们各自配置的 pos (LT/RB/RT/LB) 计算坐标并绘制
+        // --- 3. 绘制内部图标 ---
         iconList.forEach(icon => {
           const valStr = String(icon).trim().toUpperCase();
           const posConfig = POS_MAP[valStr] || { pos: 'RB', padX: 0, padY: 0, baseW: 20, baseH: 20 };
           const pos = typeof posConfig === 'string' ? posConfig : (posConfig.pos || 'RB');
           
-          const drawW = Math.round((posConfig.baseW || 20) * fs);
-          const drawH = Math.round((posConfig.baseH || 20) * fs);
-          
-          const padX = Math.round((posConfig.padX || 0) * fs); 
-          const padY = Math.round((posConfig.padY || 0) * fs);
+          // 图标尺寸和边距也应用了 dynamicFs 动态缩放
+          const drawW = Math.round((posConfig.baseW || 20) * dynamicFs);
+          const drawH = Math.round((posConfig.baseH || 20) * dynamicFs);
+          const padX = Math.round((posConfig.padX || 0) * dynamicFs); 
+          const padY = Math.round((posConfig.padY || 0) * dynamicFs);
 
           let iconX, iconY;
           if (pos === 'LT') {
@@ -256,7 +293,6 @@ export default {
             iconY = yPos + blockHeight - drawH - padY;
           }
 
-          // 绘制单个图标并推入容器
           if (IMAGE_MAP[valStr]) {
             innerGroup.children.push({
               type: 'image',
@@ -272,20 +308,31 @@ export default {
           }
         });
         
-        // 渲染文本 (相位号与时长)
-        innerGroup.children.push({
-          type: 'text',
-          style: {
-            text: `${phaseName}\n${duration}`,
-            x: start[0] + darkWidth + Math.round(6 * fs),
-            y: midY,
-            fill: COLORS.TEXT_DARK,
-            fontSize: Math.max(10, Math.round(12 * fs)),
-            fontWeight: 'bold',
-            align: 'left',
-            verticalAlign: 'middle'
-          }
-        });
+        // --- 4. 渲染右侧文字 (相位号与时长) ---
+        // 彻底移除 8px 的硬性下限兜底,让字体完全跟随 dynamicFs 比例等比缩小
+        const fontSize = Math.max(1, 12 * dynamicFs); 
+        
+        // 计算文本起点的X坐标
+        const textStartX = start[0] + darkWidth + pointerW + (2 * dynamicFs);
+
+        // 如果剩余空间大于 0(有哪怕一丁点空间),才进行文字渲染
+        if (blockWidth > (darkWidth + pointerW + 2)) {
+          innerGroup.children.push({
+            type: 'text',
+            style: {
+              text: `${phaseName}\n${duration}`,
+              x: textStartX,
+              y: midY,
+              fill: COLORS.TEXT_DARK,
+              fontSize: fontSize,
+              fontWeight: 'bold',
+              align: 'left',
+              verticalAlign: 'middle',
+              // 行高也严格跟随动态字号
+              lineHeight: fontSize * 1.2 
+            }
+          });
+        }
 
         children.push(innerGroup);
       }