# 1. 使用Canvas
的createLinearGradient (opens new window)方法和getImageData (opens new window)
createLinearGradient(x0, y0, x1, y1)方法创建一个沿参数坐标指定的直线的渐变。
getImageData() 返回一个ImageData对象,用来描述canvas区域隐含的像素数据,这个区域通过矩形表示,起始点为(sx, sy)、宽为sw、高为sh。
思路:创建一个宽度为256px高度为1px的canvas画布和一个线性渐变
,将配置的colors添加到渐变中,并使用该渐变填充一个宽度256px高度1px的矩形,最后利用canvas的getImageData
方法获取canvas内256*1范围的数据,得到的数组中存储的就是根据配置的颜色内插出来的颜色数组。然后根据输入值及最大最小值获取颜色索引取出对应的RGBA即可。
export interface ColorStop {
stop: number;//该颜色对应的值
color: string;//颜色字符串
}
export interface PaletteOptions {
colorStops: ColorStop[];
minValue: number;
maxValue: number;
saveCanvas?: boolean;//是否保留canvas元素
}
/**
* 调色板组件 根据值获取渐变色的颜色
*/
export class Palette {
private _data: Uint8ClampedArray;
private _canvas?: HTMLElement;
private _minValue: number;
private _maxValue: number;
public get canvas () {
return this._canvas;
}
public get minValue () {
return this._minValue;
}
public get maxValue () {
return this._maxValue;
}
constructor(options: PaletteOptions) {
this.update(options);
}
/**
* 更新配置项
* @param options
*/
public update (options: PaletteOptions) {
this._minValue = options.minValue;
this._maxValue = options.maxValue;
this._data = this.generateData(options.colorStops, options.saveCanvas);
if (!options.saveCanvas && this._canvas) {
this._canvas = undefined;
}
return this;
}
/**
* 生成调色板数据
*/
private generateData (colorStops: ColorStop[], saveCanvas?: boolean) {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let gradient = ctx.createLinearGradient(0, 0, 256, 0);
canvas.width = 256;
canvas.height = 1;
for (let i = 0; i < colorStops.length; i++) {
const colorStop = colorStops[i];
gradient.addColorStop(colorStop.stop, colorStop.color);
}
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 256, 1);
if (saveCanvas) {
this._canvas = canvas;
}
return ctx.getImageData(0, 0, 256, 1).data;
}
/**
* 根据输入值获取颜色
* @returns [r,g,b,a]
*/
public getColor (value: number): number[] {
let d = this._maxValue - this._minValue;
let relativeIndex = Math.min(Math.max((value - this._minValue) / d, 0), 1);
let index = (relativeIndex >= 1 ? 255 : relativeIndex < 0 ? 0 : Math.floor(relativeIndex * 256)) * 4;
return [this._data[index], this._data[index + 1], this._data[index + 2], this._data[index + 3]];
}
}
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
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