刘光辉
11 小时以前 0dfe84494048ce27ba8449831782128412d3eb13
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import type { IScale } from '@univerjs/core';
 
import {
  DEFAULT_FONTFACE_PLANE,
  FIX_ONE_PIXEL_BLUR_OFFSET,
  getColor,
  SheetExtension,
  SpreadsheetSkeleton,
  UniverRenderingContext,
} from '@univerjs/engine-render';
 
type CellCoordinates = Array<{ col: number; row: number }>; // 单元格坐标数组
 
interface ClearSheetRelationCellProps {
  key: string;
  sheetId: string;
}
 
interface SetSheetRelationCellProps extends ClearSheetRelationCellProps {
  downArrowCells?: CellCoordinates;
  rightArrowCells?: CellCoordinates;
}
 
interface RenderArrowsProps {
  arrow: string;
  cells: CellCoordinates;
  colWidths: number[];
  ctx: UniverRenderingContext;
  endCol: number;
  endRow: number;
  offsetsX?: number;
  offsetsY?: number;
  rowHeights: number[];
  startCol: number;
  startRow: number;
}
 
// 定义主要扩展类,用于在表格中绘制自定义内容
export class SetSheetRelationCellExtension extends SheetExtension {
  override uKey: string;
  // 设置扩展的层级(z-index),必须大于 50
  override get zIndex() {
    return 50;
  }
  private readonly _downArrowCells: CellCoordinates; // 渲染 ↓ 的条件数组
  private readonly _rightArrowCells: CellCoordinates; // 渲染 → 的条件数组
 
  private readonly _sheetId: string; // 用于存储动态传入的 SheetId
 
  constructor(props: SetSheetRelationCellProps) {
    super();
 
    const { downArrowCells, key, rightArrowCells, sheetId } = props ?? {};
    this.uKey = key;
    this._sheetId = sheetId;
    this._rightArrowCells = rightArrowCells ?? [];
    this._downArrowCells = downArrowCells ?? [];
  }
 
  // 重写绘制方法
  override draw(ctx: UniverRenderingContext, _parentScale: IScale, skeleton: SpreadsheetSkeleton) {
    if (!this.isValidSkeleton(skeleton)) {
      return;
    }
 
    if (!this._rightArrowCells?.length && !this._downArrowCells?.length) {
      return;
    }
 
    const { columnTotalWidth, columnWidthAccumulation, rowColumnSegment, rowHeightAccumulation, rowTotalHeight } = skeleton;
    const { endColumn, endRow, startColumn, startRow } = rowColumnSegment;
    if (!rowHeightAccumulation || !columnWidthAccumulation || columnTotalWidth === undefined || rowTotalHeight === undefined) {
      return;
    }
 
    this.setupCanvas(ctx);
 
    // 绘制 → 箭头
    this.renderArrows({
      arrow: '→',
      cells: this._rightArrowCells,
      colWidths: columnWidthAccumulation,
      ctx,
      endCol: endColumn,
      endRow,
      offsetsX: undefined,
      offsetsY: -2,
      rowHeights: rowHeightAccumulation,
      startCol: startColumn,
      startRow,
    });
 
    // 绘制 ↓ 箭头
    this.renderArrows({
      arrow: '↓',
      cells: this._downArrowCells,
      colWidths: columnWidthAccumulation,
      ctx,
      endCol: endColumn,
      endRow,
      offsetsX: 0,
      offsetsY: 12,
      rowHeights: rowHeightAccumulation,
      startCol: startColumn,
      startRow,
    });
 
    // 绘制分隔线
    ctx.stroke();
  }
 
  // 验证骨架和必要属性是否有效
  private isValidSkeleton(skeleton: SpreadsheetSkeleton): boolean {
    // 如果骨架信息不存在,则退出绘制
    if (!skeleton) {
      return false;
    }
 
    // 限制扩展仅在指定的工作表上生效
    return skeleton?.worksheet?.getSheetId() === this._sheetId;
  }
 
  // 渲染箭头
  private renderArrows(props: RenderArrowsProps) {
    const { arrow, cells, colWidths, ctx, endCol, endRow, offsetsX, offsetsY = 0, rowHeights, startCol, startRow } = props ?? {};
 
    for (const { col, row } of cells) {
      if (row >= startRow - 1 && row <= endRow && col >= startCol - 1 && col <= endCol) {
        const rowStart = rowHeights[row - 1] || 0;
        const colStart = colWidths[col - 1] || 0;
 
        const colEnd = colWidths[col] || colWidths[col - 1] || 0;
        const cellWidth = colEnd - colStart;
 
        const xPosition = offsetsX === undefined ? colStart + cellWidth / 2 - 6 : colStart + offsetsX;
        const yPosition = rowStart + offsetsY;
 
        ctx.fillText(arrow, xPosition, yPosition);
      }
    }
  }
 
  // 设置 Canvas 的绘图属性
  private setupCanvas(ctx: UniverRenderingContext) {
    // 设置背景色为浅灰色
    ctx.fillStyle = getColor([255, 255, 255]);
    // 设置文本水平对齐方式
    ctx.textAlign = 'left';
    // 设置文本垂直对齐方式
    ctx.textBaseline = 'top';
    // 设置文本颜色为黑色
    ctx.fillStyle = getColor([24, 144, 255])!;
    // 开始绘制路径
    ctx.beginPath();
    // 设置线宽为 1
    ctx.lineWidth = 1;
    // 防止边界模糊的偏移值,使绘制的边界在高分辨率屏幕下更清晰
    ctx.translateWithPrecisionRatio(FIX_ONE_PIXEL_BLUR_OFFSET, FIX_ONE_PIXEL_BLUR_OFFSET);
    // 设置分隔线颜色为浅灰色
    ctx.strokeStyle = getColor([217, 217, 217]);
    // 设置字体样式
    ctx.font = `10px ${DEFAULT_FONTFACE_PLANE}`;
  }
}
 
// 定义清理扩展类,用于覆盖并清除扩展效果
export class ClearSheetRelationCellExtension extends SheetExtension {
  override uKey: string;
  private readonly _sheetId: string; // 用于存储动态传入的 SheetId
 
  constructor(props: ClearSheetRelationCellProps) {
    super();
 
    const { key, sheetId } = props ?? {};
    this.uKey = key;
    this._sheetId = sheetId; // 将传入的 SheetId 存储到类中
  }
 
  // 空的绘制方法,不进行任何绘制操作
  override draw(_ctx: UniverRenderingContext, _parentScale: IScale, skeleton: SpreadsheetSkeleton) {
    if (skeleton?.worksheet?.getSheetId() !== this._sheetId) {
    }
  }
}