JS计算渐变色

2021/10/16 JavaScriptWeb

# 1. 使用CanvascreateLinearGradient (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
Last Updated: 2021/10/15 18:10:28