-
-
Notifications
You must be signed in to change notification settings - Fork 550
/
icon.render.ts
119 lines (108 loc) · 4.39 KB
/
icon.render.ts
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
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { IRange, IScale } from '@univerjs/core';
import { Range } from '@univerjs/core';
import type { SpreadsheetSkeleton, UniverRenderingContext } from '@univerjs/engine-render';
import { SheetExtension, SpreadsheetExtensionRegistry } from '@univerjs/engine-render';
import type { IIconType } from '../models/icon-map';
import { EMPTY_ICON_TYPE, iconMap } from '../models/icon-map';
import type { IIconSetCellData } from './type';
export const IconUKey = 'sheet-conditional-rule-icon';
const EXTENSION_Z_INDEX = 34;
export const DEFAULT_WIDTH = 15;
export const DEFAULT_PADDING = 2;
export class ConditionalFormattingIcon extends SheetExtension {
private _paddingRightAndLeft = DEFAULT_PADDING;
private _width = DEFAULT_WIDTH;
private _imageMap: Map<string, HTMLImageElement> = new Map();
override uKey = IconUKey;
override Z_INDEX = EXTENSION_Z_INDEX;
_radius = 1;
constructor() {
super();
this._init();
}
override draw(
ctx: UniverRenderingContext,
parentScale: IScale,
spreadsheetSkeleton: SpreadsheetSkeleton,
diffRanges?: IRange[]
) {
const { rowHeightAccumulation, columnWidthAccumulation, worksheet, dataMergeCache } =
spreadsheetSkeleton;
if (!worksheet) {
return false;
}
ctx.save();
// ctx.globalCompositeOperation = 'destination-over';
Range.foreach(spreadsheetSkeleton.rowColumnSegment, (row, col) => {
const cellData = worksheet.getCell(row, col) as IIconSetCellData;
if (cellData?.iconSet) {
if (!worksheet.getColVisible(col) || !worksheet.getRowRawVisible(row)) {
return;
}
const { iconType, iconId } = cellData.iconSet;
if (iconType === EMPTY_ICON_TYPE) {
return;
}
const icon = this._imageMap.get(this._createKey(iconType, iconId));
if (!icon) {
return;
}
const cellInfo = this.getCellIndex(row, col, rowHeightAccumulation, columnWidthAccumulation, dataMergeCache);
let { isMerged, isMergedMainCell, mergeInfo, startY, endY, startX, endX } = cellInfo;
if (isMerged) {
return;
}
if (isMergedMainCell) {
startY = mergeInfo.startY;
endY = mergeInfo.endY;
startX = mergeInfo.startX;
endX = mergeInfo.endX;
}
if (!this.isRenderDiffRangesByCell(mergeInfo, diffRanges)) {
return;
}
const borderWidth = endX - startX;
const borderHeight = endY - startY;
if (this._width > borderHeight || this._width > borderWidth + this._paddingRightAndLeft * 2) {
return;
}
// Highly centered processing
const y = (borderHeight - this._width) / 2 + startY;
ctx.drawImage(icon, startX + this._paddingRightAndLeft, y, this._width, this._width);
}
});
ctx.restore();
}
private _init() {
for (const type in iconMap) {
const list = iconMap[type as IIconType];
list.forEach((base64, index) => {
const key = this._createKey(type as IIconType, String(index));
const image = new Image();
image.onload = () => {
this._imageMap.set(key, image);
};
image.src = base64;
});
}
}
private _createKey(iconType: IIconType, iconIndex: string) {
return `${iconType}_${iconIndex}`;
}
}
SpreadsheetExtensionRegistry.add(ConditionalFormattingIcon);