summaryrefslogtreecommitdiff
path: root/scripts/gui-common/color.js
blob: b2d255abd412ac1cfa9ee36474901b96b5046a36 (plain)
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
class Color
{
    /** @type {Array<number>} */
    channels = []

    /**
     * Construct a color
     * @param  {...number} nums 
     */
    constructor(...nums)
    {
        this.channels = nums;
    }

    /**
     * @param {Color} b
     * @param {number} i
     * @returns {Color}
     */
    interpolate(b, i)
    {
        let out = new Color();
        for (let c = 0; c < this.channels.length && c < b.channels.length; c++)
        {
            out.channels.push(b.channels[c] * i + this.channels[c] * (1 - i))
        }
        return out;
    }

    /** Get the CSS string representing rgb
     * @returns {string}
     */
    rgb()
    {
        return `rgb(${Math.trunc(this.channels[0] * 255)}, ${Math.trunc(this.channels[1] * 255)}, ${Math.trunc(this.channels[2] * 255)})`;
    }

    /** Get the CSS string representing rgba
     * @returns {string}
     */
    rgba()
    {
        return `rgba(${Math.trunc(this.channels[0] * 255)}, ${Math.trunc(this.channels[1] * 255)}, ${Math.trunc(this.channels[2] * 255)}, ${this.channels[3]})`;
    }

    static from_rgb(r, g, b)
    {
        return new Color(r / 255, g / 255, b / 255);
    }

    static from_rgba(r, g, b)
    {
        return new Color(r / 255, g / 255, b / 255, a);
    }

    static d(h)
    {
        let d = Math.floor((h - (h % PI_THIRDS)) / PI_THIRDS);
        return (DIVS.length - 1 + d) % (DIVS.length - 1);
    }

    static from_hsv(h, s, v)
    {
        h = (((h % TWO_PI)) + TWO_PI) % TWO_PI;

        let d = Color.d(h);
        
        h = (h % PI_THIRDS) / PI_THIRDS;

        let out = DIVS[d].interpolate(DIVS[d + 1], h);
        out = WHITE.interpolate(out, s);
        
        return BLACK.interpolate(out, v);
    }

    static from_hsl(h, s, l)
    {
        h = (((h % TWO_PI)) + TWO_PI) % TWO_PI;
        
        let d = Color.d(h);
        
        h = (h % PI_THIRDS) / PI_THIRDS;

        let out = DIVS[d].interpolate(DIVS[d + 1], h);
        let L = BLACK.interpolate(WHITE, l);
        
        if (l < 0.5)
            out = BLACK.interpolate(out, l / 0.5);
        else
            out = out.interpolate(WHITE, (l - 0.5) / 0.5);
        
        return L.interpolate(out, s);
    }

    hsv_angle()
    {
        // TODO
    }

    hsv_mag()
    {
        // TODO
    }
}

const RED = new Color(1, 0, 0, 1);
const YELLOW = new Color(1, 1, 0, 1);
const GREEN = new Color(0, 1, 0, 1);
const CYAN = new Color(0, 1, 1, 1);
const BLUE = new Color(0, 0, 1, 1);
const MAGENTA = new Color(1, 0, 1, 1);
const WHITE = new Color(1, 1, 1, 1);
const BLACK = new Color(0, 0, 0, 1);

const PI_THIRDS = Math.PI / 3;
const TWO_PI = Math.PI * 2;

const DIVS = [RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA, RED];

/**
 * Interpolate between two colors
 * @param {Color} a 
 * @param {Color} b 
 * @param {number} p 
 */
function interpolate(a, b, p)
{

}