@planet-matrix/mobius-model 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +134 -21
- package/dist/index.js +45 -4
- package/dist/index.js.map +186 -11
- package/oxlint.config.ts +6 -0
- package/package.json +16 -10
- package/src/abort/README.md +92 -0
- package/src/abort/abort-manager.ts +278 -0
- package/src/abort/abort-signal-listener-manager.ts +81 -0
- package/src/abort/index.ts +2 -0
- package/src/basic/README.md +69 -117
- package/src/basic/enhance.ts +10 -0
- package/src/basic/function.ts +81 -62
- package/src/basic/index.ts +2 -0
- package/src/basic/is.ts +152 -71
- package/src/basic/object.ts +82 -0
- package/src/basic/promise.ts +29 -8
- package/src/basic/string.ts +2 -33
- package/src/color/README.md +105 -0
- package/src/color/index.ts +3 -0
- package/src/color/internal.ts +42 -0
- package/src/color/rgb/analyze.ts +236 -0
- package/src/color/rgb/construct.ts +130 -0
- package/src/color/rgb/convert.ts +227 -0
- package/src/color/rgb/derive.ts +303 -0
- package/src/color/rgb/index.ts +6 -0
- package/src/color/rgb/internal.ts +208 -0
- package/src/color/rgb/parse.ts +302 -0
- package/src/color/rgb/serialize.ts +144 -0
- package/src/color/types.ts +57 -0
- package/src/color/xyz/analyze.ts +80 -0
- package/src/color/xyz/construct.ts +19 -0
- package/src/color/xyz/convert.ts +71 -0
- package/src/color/xyz/index.ts +3 -0
- package/src/color/xyz/internal.ts +23 -0
- package/src/css/README.md +93 -0
- package/src/css/class.ts +559 -0
- package/src/css/index.ts +1 -0
- package/src/encoding/README.md +92 -0
- package/src/encoding/base64.ts +107 -0
- package/src/encoding/index.ts +1 -0
- package/src/environment/README.md +97 -0
- package/src/environment/basic.ts +26 -0
- package/src/environment/device.ts +311 -0
- package/src/environment/feature.ts +285 -0
- package/src/environment/geo.ts +337 -0
- package/src/environment/index.ts +7 -0
- package/src/environment/runtime.ts +400 -0
- package/src/environment/snapshot.ts +60 -0
- package/src/environment/variable.ts +239 -0
- package/src/event/README.md +90 -0
- package/src/event/class-event-proxy.ts +228 -0
- package/src/event/common.ts +19 -0
- package/src/event/event-manager.ts +203 -0
- package/src/event/index.ts +4 -0
- package/src/event/instance-event-proxy.ts +186 -0
- package/src/event/internal.ts +24 -0
- package/src/exception/README.md +96 -0
- package/src/exception/browser.ts +219 -0
- package/src/exception/index.ts +4 -0
- package/src/exception/nodejs.ts +169 -0
- package/src/exception/normalize.ts +106 -0
- package/src/exception/types.ts +99 -0
- package/src/identifier/README.md +92 -0
- package/src/identifier/id.ts +119 -0
- package/src/identifier/index.ts +2 -0
- package/src/identifier/uuid.ts +187 -0
- package/src/index.ts +18 -1
- package/src/log/README.md +79 -0
- package/src/log/index.ts +5 -0
- package/src/log/log-emitter.ts +72 -0
- package/src/log/log-record.ts +10 -0
- package/src/log/log-scheduler.ts +74 -0
- package/src/log/log-type.ts +8 -0
- package/src/log/logger.ts +543 -0
- package/src/orchestration/README.md +89 -0
- package/src/orchestration/coordination/barrier.ts +214 -0
- package/src/orchestration/coordination/count-down-latch.ts +215 -0
- package/src/orchestration/coordination/errors.ts +98 -0
- package/src/orchestration/coordination/index.ts +16 -0
- package/src/orchestration/coordination/internal/wait-constraints.ts +95 -0
- package/src/orchestration/coordination/internal/wait-queue.ts +109 -0
- package/src/orchestration/coordination/keyed-lock.ts +168 -0
- package/src/orchestration/coordination/mutex.ts +257 -0
- package/src/orchestration/coordination/permit.ts +127 -0
- package/src/orchestration/coordination/read-write-lock.ts +444 -0
- package/src/orchestration/coordination/semaphore.ts +280 -0
- package/src/orchestration/index.ts +1 -0
- package/src/random/README.md +78 -0
- package/src/random/index.ts +1 -0
- package/src/random/string.ts +35 -0
- package/src/reactor/README.md +4 -0
- package/src/reactor/reactor-core/primitive.ts +9 -9
- package/src/reactor/reactor-core/reactive-system.ts +5 -5
- package/src/singleton/README.md +79 -0
- package/src/singleton/factory.ts +55 -0
- package/src/singleton/index.ts +2 -0
- package/src/singleton/manager.ts +204 -0
- package/src/storage/README.md +107 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/table.ts +449 -0
- package/src/timer/README.md +86 -0
- package/src/timer/expiration/expiration-manager.ts +594 -0
- package/src/timer/expiration/index.ts +3 -0
- package/src/timer/expiration/min-heap.ts +208 -0
- package/src/timer/expiration/remaining-manager.ts +241 -0
- package/src/timer/index.ts +1 -0
- package/src/type/README.md +54 -307
- package/src/type/class.ts +2 -2
- package/src/type/index.ts +14 -14
- package/src/type/is.ts +265 -2
- package/src/type/object.ts +37 -0
- package/src/type/string.ts +7 -2
- package/src/type/tuple.ts +6 -6
- package/src/type/union.ts +16 -0
- package/src/web/README.md +77 -0
- package/src/web/capture.ts +35 -0
- package/src/web/clipboard.ts +97 -0
- package/src/web/dom.ts +117 -0
- package/src/web/download.ts +16 -0
- package/src/web/event.ts +46 -0
- package/src/web/index.ts +10 -0
- package/src/web/local-storage.ts +113 -0
- package/src/web/location.ts +28 -0
- package/src/web/permission.ts +172 -0
- package/src/web/script-loader.ts +432 -0
- package/tests/unit/abort/abort-manager.spec.ts +225 -0
- package/tests/unit/abort/abort-signal-listener-manager.spec.ts +62 -0
- package/tests/unit/basic/array.spec.ts +1 -1
- package/tests/unit/basic/object.spec.ts +32 -1
- package/tests/unit/basic/stream.spec.ts +1 -1
- package/tests/unit/basic/string.spec.ts +0 -9
- package/tests/unit/color/rgb/analyze.spec.ts +110 -0
- package/tests/unit/color/rgb/construct.spec.ts +56 -0
- package/tests/unit/color/rgb/convert.spec.ts +60 -0
- package/tests/unit/color/rgb/derive.spec.ts +103 -0
- package/tests/unit/color/rgb/parse.spec.ts +66 -0
- package/tests/unit/color/rgb/serialize.spec.ts +46 -0
- package/tests/unit/color/xyz/analyze.spec.ts +33 -0
- package/tests/unit/color/xyz/construct.spec.ts +10 -0
- package/tests/unit/color/xyz/convert.spec.ts +18 -0
- package/tests/unit/css/class.spec.ts +157 -0
- package/tests/unit/encoding/base64.spec.ts +40 -0
- package/tests/unit/environment/basic.spec.ts +20 -0
- package/tests/unit/environment/device.spec.ts +146 -0
- package/tests/unit/environment/feature.spec.ts +388 -0
- package/tests/unit/environment/geo.spec.ts +111 -0
- package/tests/unit/environment/runtime.spec.ts +364 -0
- package/tests/unit/environment/snapshot.spec.ts +4 -0
- package/tests/unit/environment/variable.spec.ts +190 -0
- package/tests/unit/event/class-event-proxy.spec.ts +225 -0
- package/tests/unit/event/event-manager.spec.ts +246 -0
- package/tests/unit/event/instance-event-proxy.spec.ts +187 -0
- package/tests/unit/exception/browser.spec.ts +213 -0
- package/tests/unit/exception/nodejs.spec.ts +144 -0
- package/tests/unit/exception/normalize.spec.ts +57 -0
- package/tests/unit/identifier/id.spec.ts +71 -0
- package/tests/unit/identifier/uuid.spec.ts +85 -0
- package/tests/unit/log/log-emitter.spec.ts +33 -0
- package/tests/unit/log/log-scheduler.spec.ts +40 -0
- package/tests/unit/log/log-type.spec.ts +7 -0
- package/tests/unit/log/logger.spec.ts +222 -0
- package/tests/unit/orchestration/coordination/barrier.spec.ts +96 -0
- package/tests/unit/orchestration/coordination/count-down-latch.spec.ts +63 -0
- package/tests/unit/orchestration/coordination/errors.spec.ts +29 -0
- package/tests/unit/orchestration/coordination/keyed-lock.spec.ts +109 -0
- package/tests/unit/orchestration/coordination/mutex.spec.ts +132 -0
- package/tests/unit/orchestration/coordination/permit.spec.ts +43 -0
- package/tests/unit/orchestration/coordination/read-write-lock.spec.ts +154 -0
- package/tests/unit/orchestration/coordination/semaphore.spec.ts +135 -0
- package/tests/unit/random/string.spec.ts +11 -0
- package/tests/unit/reactor/alien-signals-effect.spec.ts +11 -10
- package/tests/unit/reactor/preact-signal.spec.ts +1 -2
- package/tests/unit/singleton/singleton.spec.ts +49 -0
- package/tests/unit/storage/table.spec.ts +620 -0
- package/tests/unit/timer/expiration/expiration-manager.spec.ts +464 -0
- package/tests/unit/timer/expiration/min-heap.spec.ts +71 -0
- package/tests/unit/timer/expiration/remaining-manager.spec.ts +234 -0
- package/.oxlintrc.json +0 -5
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import {
|
|
2
|
+
internalRoundColorFloat,
|
|
3
|
+
} from "../internal.ts"
|
|
4
|
+
import {
|
|
5
|
+
internalGetLinearRgbChannelBySrgbChannel,
|
|
6
|
+
internalGetSrgbChannelByLinearRgbChannel,
|
|
7
|
+
internalNormalizeHslColorValue,
|
|
8
|
+
internalNormalizeHsvColorValue,
|
|
9
|
+
internalNormalizeLinearRgbColorValue,
|
|
10
|
+
internalNormalizeSrgbColorValue,
|
|
11
|
+
} from "./internal.ts"
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
HslColorValue,
|
|
15
|
+
HsvColorValue,
|
|
16
|
+
LinearRgbColorValue,
|
|
17
|
+
SrgbColorValue,
|
|
18
|
+
} from "../types.ts"
|
|
19
|
+
|
|
20
|
+
const internalGetHueByNormalizedRgbChannels = (red: number, green: number, blue: number, delta: number, max: number): number => {
|
|
21
|
+
if (delta === 0) {
|
|
22
|
+
return 0
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let hue = 0
|
|
26
|
+
|
|
27
|
+
if (max === red) {
|
|
28
|
+
hue = 60 * (((green - blue) / delta) % 6)
|
|
29
|
+
} else if (max === green) {
|
|
30
|
+
hue = 60 * (((blue - red) / delta) + 2)
|
|
31
|
+
} else {
|
|
32
|
+
hue = 60 * (((red - green) / delta) + 4)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (hue < 0) {
|
|
36
|
+
return hue + 360
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return hue
|
|
40
|
+
}
|
|
41
|
+
const internalGetNormalizedRgbChannelsByHue = (hue: number, chroma: number): { red: number, green: number, blue: number } => {
|
|
42
|
+
const segment = hue / 60
|
|
43
|
+
const secondary = chroma * (1 - Math.abs((segment % 2) - 1))
|
|
44
|
+
|
|
45
|
+
if (segment >= 0 && segment < 1) {
|
|
46
|
+
return { red: chroma, green: secondary, blue: 0 }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (segment >= 1 && segment < 2) {
|
|
50
|
+
return { red: secondary, green: chroma, blue: 0 }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (segment >= 2 && segment < 3) {
|
|
54
|
+
return { red: 0, green: chroma, blue: secondary }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (segment >= 3 && segment < 4) {
|
|
58
|
+
return { red: 0, green: secondary, blue: chroma }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (segment >= 4 && segment < 5) {
|
|
62
|
+
return { red: secondary, green: 0, blue: chroma }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { red: chroma, green: 0, blue: secondary }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 将 Linear RGB 颜色值转换为 sRGB 颜色值。
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```
|
|
73
|
+
* // Expect: { red: 255, green: 0, blue: 0, alpha: 1 }
|
|
74
|
+
* const example1 = linearRgbColorValueToSrgbColorValue({ red: 1, green: 0, blue: 0, alpha: 1 })
|
|
75
|
+
*
|
|
76
|
+
* // Expect: { red: 188, green: 188, blue: 188, alpha: 0.5 }
|
|
77
|
+
* const example2 = linearRgbColorValueToSrgbColorValue({ red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5 })
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export const linearRgbColorValueToSrgbColorValue = (color: LinearRgbColorValue): SrgbColorValue => {
|
|
81
|
+
const normalizedColor = internalNormalizeLinearRgbColorValue(color)
|
|
82
|
+
|
|
83
|
+
return internalNormalizeSrgbColorValue({
|
|
84
|
+
red: internalGetSrgbChannelByLinearRgbChannel(normalizedColor.red, "red"),
|
|
85
|
+
green: internalGetSrgbChannelByLinearRgbChannel(normalizedColor.green, "green"),
|
|
86
|
+
blue: internalGetSrgbChannelByLinearRgbChannel(normalizedColor.blue, "blue"),
|
|
87
|
+
alpha: normalizedColor.alpha,
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 将 sRGB 颜色值转换为 Linear RGB 颜色值。
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```
|
|
96
|
+
* // Expect: { red: 1, green: 0, blue: 0, alpha: 1 }
|
|
97
|
+
* const example1 = srgbColorValueToLinearRgbColorValue({ red: 255, green: 0, blue: 0, alpha: 1 })
|
|
98
|
+
*
|
|
99
|
+
* // Expect: { red: 0.215861, green: 0.215861, blue: 0.215861, alpha: 0.5 }
|
|
100
|
+
* const example2 = srgbColorValueToLinearRgbColorValue({ red: 128, green: 128, blue: 128, alpha: 0.5 })
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export const srgbColorValueToLinearRgbColorValue = (color: SrgbColorValue): LinearRgbColorValue => {
|
|
104
|
+
const normalizedColor = internalNormalizeSrgbColorValue(color)
|
|
105
|
+
|
|
106
|
+
return internalNormalizeLinearRgbColorValue({
|
|
107
|
+
red: internalGetLinearRgbChannelBySrgbChannel(normalizedColor.red),
|
|
108
|
+
green: internalGetLinearRgbChannelBySrgbChannel(normalizedColor.green),
|
|
109
|
+
blue: internalGetLinearRgbChannelBySrgbChannel(normalizedColor.blue),
|
|
110
|
+
alpha: normalizedColor.alpha,
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 将 sRGB 颜色值转换为 HSL 颜色值。
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```
|
|
119
|
+
* // Expect: { hue: 210, saturation: 0.5, lightness: 0.4, alpha: 1 }
|
|
120
|
+
* const example1 = srgbColorValueToHslColorValue({ red: 51, green: 102, blue: 153, alpha: 1 })
|
|
121
|
+
*
|
|
122
|
+
* // Expect: { hue: 0, saturation: 0, lightness: 0.501961, alpha: 1 }
|
|
123
|
+
* const example2 = srgbColorValueToHslColorValue({ red: 128, green: 128, blue: 128, alpha: 1 })
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export const srgbColorValueToHslColorValue = (color: SrgbColorValue): HslColorValue => {
|
|
127
|
+
const normalizedColor = internalNormalizeSrgbColorValue(color)
|
|
128
|
+
const red = normalizedColor.red / 255
|
|
129
|
+
const green = normalizedColor.green / 255
|
|
130
|
+
const blue = normalizedColor.blue / 255
|
|
131
|
+
const max = Math.max(red, green, blue)
|
|
132
|
+
const min = Math.min(red, green, blue)
|
|
133
|
+
const delta = max - min
|
|
134
|
+
const lightness = (max + min) / 2
|
|
135
|
+
const saturation = delta === 0 ? 0 : delta / (1 - Math.abs((2 * lightness) - 1))
|
|
136
|
+
const hue = internalGetHueByNormalizedRgbChannels(red, green, blue, delta, max)
|
|
137
|
+
|
|
138
|
+
return internalNormalizeHslColorValue({
|
|
139
|
+
hue: internalRoundColorFloat(hue),
|
|
140
|
+
saturation: internalRoundColorFloat(saturation),
|
|
141
|
+
lightness: internalRoundColorFloat(lightness),
|
|
142
|
+
alpha: normalizedColor.alpha,
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 将 HSL 颜色值转换为 sRGB 颜色值。
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```
|
|
151
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
152
|
+
* const example1 = hslColorValueToSrgbColorValue({ hue: 210, saturation: 0.5, lightness: 0.4, alpha: 1 })
|
|
153
|
+
*
|
|
154
|
+
* // Expect: { red: 128, green: 128, blue: 128, alpha: 1 }
|
|
155
|
+
* const example2 = hslColorValueToSrgbColorValue({ hue: 0, saturation: 0, lightness: 0.501961, alpha: 1 })
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export const hslColorValueToSrgbColorValue = (color: HslColorValue): SrgbColorValue => {
|
|
159
|
+
const normalizedColor = internalNormalizeHslColorValue(color)
|
|
160
|
+
const chroma = (1 - Math.abs((2 * normalizedColor.lightness) - 1)) * normalizedColor.saturation
|
|
161
|
+
const channels = internalGetNormalizedRgbChannelsByHue(normalizedColor.hue, chroma)
|
|
162
|
+
const match = normalizedColor.lightness - (chroma / 2)
|
|
163
|
+
|
|
164
|
+
return internalNormalizeSrgbColorValue({
|
|
165
|
+
red: Math.round((channels.red + match) * 255),
|
|
166
|
+
green: Math.round((channels.green + match) * 255),
|
|
167
|
+
blue: Math.round((channels.blue + match) * 255),
|
|
168
|
+
alpha: normalizedColor.alpha,
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 将 sRGB 颜色值转换为 HSV 颜色值。
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```
|
|
177
|
+
* // Expect: { hue: 210, saturation: 0.666667, value: 0.6, alpha: 1 }
|
|
178
|
+
* const example1 = srgbColorValueToHsvColorValue({ red: 51, green: 102, blue: 153, alpha: 1 })
|
|
179
|
+
*
|
|
180
|
+
* // Expect: { hue: 0, saturation: 0, value: 0.501961, alpha: 1 }
|
|
181
|
+
* const example2 = srgbColorValueToHsvColorValue({ red: 128, green: 128, blue: 128, alpha: 1 })
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export const srgbColorValueToHsvColorValue = (color: SrgbColorValue): HsvColorValue => {
|
|
185
|
+
const normalizedColor = internalNormalizeSrgbColorValue(color)
|
|
186
|
+
const red = normalizedColor.red / 255
|
|
187
|
+
const green = normalizedColor.green / 255
|
|
188
|
+
const blue = normalizedColor.blue / 255
|
|
189
|
+
const max = Math.max(red, green, blue)
|
|
190
|
+
const min = Math.min(red, green, blue)
|
|
191
|
+
const delta = max - min
|
|
192
|
+
const saturation = max === 0 ? 0 : delta / max
|
|
193
|
+
const hue = internalGetHueByNormalizedRgbChannels(red, green, blue, delta, max)
|
|
194
|
+
|
|
195
|
+
return internalNormalizeHsvColorValue({
|
|
196
|
+
hue: internalRoundColorFloat(hue),
|
|
197
|
+
saturation: internalRoundColorFloat(saturation),
|
|
198
|
+
value: internalRoundColorFloat(max),
|
|
199
|
+
alpha: normalizedColor.alpha,
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* 将 HSV 颜色值转换为 sRGB 颜色值。
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```
|
|
208
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
209
|
+
* const example1 = hsvColorValueToSrgbColorValue({ hue: 210, saturation: 0.666667, value: 0.6, alpha: 1 })
|
|
210
|
+
*
|
|
211
|
+
* // Expect: { red: 128, green: 128, blue: 128, alpha: 1 }
|
|
212
|
+
* const example2 = hsvColorValueToSrgbColorValue({ hue: 0, saturation: 0, value: 0.501961, alpha: 1 })
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
export const hsvColorValueToSrgbColorValue = (color: HsvColorValue): SrgbColorValue => {
|
|
216
|
+
const normalizedColor = internalNormalizeHsvColorValue(color)
|
|
217
|
+
const chroma = normalizedColor.value * normalizedColor.saturation
|
|
218
|
+
const channels = internalGetNormalizedRgbChannelsByHue(normalizedColor.hue, chroma)
|
|
219
|
+
const match = normalizedColor.value - chroma
|
|
220
|
+
|
|
221
|
+
return internalNormalizeSrgbColorValue({
|
|
222
|
+
red: Math.round((channels.red + match) * 255),
|
|
223
|
+
green: Math.round((channels.green + match) * 255),
|
|
224
|
+
blue: Math.round((channels.blue + match) * 255),
|
|
225
|
+
alpha: normalizedColor.alpha,
|
|
226
|
+
})
|
|
227
|
+
}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLinearRgbColorValue,
|
|
3
|
+
createSrgbColorValue,
|
|
4
|
+
} from "./construct.ts"
|
|
5
|
+
import {
|
|
6
|
+
internalAssertColorUnit,
|
|
7
|
+
internalRoundColorFloat,
|
|
8
|
+
} from "../internal.ts"
|
|
9
|
+
import {
|
|
10
|
+
linearRgbColorValueToSrgbColorValue,
|
|
11
|
+
srgbColorValueToLinearRgbColorValue,
|
|
12
|
+
} from "./convert.ts"
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
LinearRgbColorValue,
|
|
16
|
+
SrgbColorValue,
|
|
17
|
+
} from "../types.ts"
|
|
18
|
+
|
|
19
|
+
const internalOpaqueBlackLinearRgbColorValue: LinearRgbColorValue = { red: 0, green: 0, blue: 0, alpha: 1 }
|
|
20
|
+
const internalOpaqueWhiteLinearRgbColorValue: LinearRgbColorValue = { red: 1, green: 1, blue: 1, alpha: 1 }
|
|
21
|
+
const internalOpaqueGrayLinearRgbColorValue: LinearRgbColorValue = { red: 0.5, green: 0.5, blue: 0.5, alpha: 1 }
|
|
22
|
+
|
|
23
|
+
const internalMixNumber = (first: number, second: number, weight: number): number => {
|
|
24
|
+
return internalRoundColorFloat((first * (1 - weight)) + (second * weight))
|
|
25
|
+
}
|
|
26
|
+
const internalCompositeLinearRgbChannels = (foreground: number, background: number, foregroundAlpha: number, backgroundAlpha: number, outputAlpha: number): number => {
|
|
27
|
+
if (outputAlpha === 0) {
|
|
28
|
+
return 0
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return internalRoundColorFloat(((foreground * foregroundAlpha) + (background * backgroundAlpha * (1 - foregroundAlpha))) / outputAlpha)
|
|
32
|
+
}
|
|
33
|
+
const internalMixSrgbColorValueWithLinearReference = (color: SrgbColorValue, referenceColor: LinearRgbColorValue, amount: number): SrgbColorValue => {
|
|
34
|
+
internalAssertColorUnit(amount, "amount")
|
|
35
|
+
const normalizedColor = createSrgbColorValue(color)
|
|
36
|
+
|
|
37
|
+
return linearRgbColorValueToSrgbColorValue(mixLinearRgbColorValues(
|
|
38
|
+
srgbColorValueToLinearRgbColorValue(normalizedColor),
|
|
39
|
+
referenceColor,
|
|
40
|
+
amount,
|
|
41
|
+
))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 在 Linear RGB 层混合两个颜色值。
|
|
46
|
+
*
|
|
47
|
+
* `weight` 表示第二个颜色值的占比。
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```
|
|
51
|
+
* // Expect: { red: 0.5, green: 0, blue: 0.5, alpha: 1 }
|
|
52
|
+
* const example1 = mixLinearRgbColorValues(
|
|
53
|
+
* { red: 1, green: 0, blue: 0, alpha: 1 },
|
|
54
|
+
* { red: 0, green: 0, blue: 1, alpha: 1 },
|
|
55
|
+
* 0.5,
|
|
56
|
+
* )
|
|
57
|
+
*
|
|
58
|
+
* // Expect: { red: 0.75, green: 0.75, blue: 0.75, alpha: 1 }
|
|
59
|
+
* const example2 = mixLinearRgbColorValues(
|
|
60
|
+
* { red: 1, green: 1, blue: 1, alpha: 1 },
|
|
61
|
+
* { red: 0, green: 0, blue: 0, alpha: 1 },
|
|
62
|
+
* 0.25,
|
|
63
|
+
* )
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export const mixLinearRgbColorValues = (first: LinearRgbColorValue, second: LinearRgbColorValue, weight = 0.5): LinearRgbColorValue => {
|
|
67
|
+
internalAssertColorUnit(weight, "weight")
|
|
68
|
+
const normalizedFirst = createLinearRgbColorValue(first)
|
|
69
|
+
const normalizedSecond = createLinearRgbColorValue(second)
|
|
70
|
+
|
|
71
|
+
return createLinearRgbColorValue({
|
|
72
|
+
red: internalMixNumber(normalizedFirst.red, normalizedSecond.red, weight),
|
|
73
|
+
green: internalMixNumber(normalizedFirst.green, normalizedSecond.green, weight),
|
|
74
|
+
blue: internalMixNumber(normalizedFirst.blue, normalizedSecond.blue, weight),
|
|
75
|
+
alpha: internalMixNumber(normalizedFirst.alpha, normalizedSecond.alpha, weight),
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 在 sRGB 层混合两个颜色值。
|
|
81
|
+
*
|
|
82
|
+
* 该函数会沿合法路径 `sRGB -> Linear RGB -> mix -> sRGB` 计算。
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```
|
|
86
|
+
* // Expect: { red: 188, green: 0, blue: 188, alpha: 1 }
|
|
87
|
+
* const example1 = mixSrgbColorValues(
|
|
88
|
+
* { red: 255, green: 0, blue: 0, alpha: 1 },
|
|
89
|
+
* { red: 0, green: 0, blue: 255, alpha: 1 },
|
|
90
|
+
* 0.5,
|
|
91
|
+
* )
|
|
92
|
+
*
|
|
93
|
+
* // Expect: { red: 255, green: 188, blue: 188, alpha: 1 }
|
|
94
|
+
* const example2 = mixSrgbColorValues(
|
|
95
|
+
* { red: 255, green: 0, blue: 0, alpha: 1 },
|
|
96
|
+
* { red: 255, green: 255, blue: 255, alpha: 1 },
|
|
97
|
+
* 0.5,
|
|
98
|
+
* )
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export const mixSrgbColorValues = (first: SrgbColorValue, second: SrgbColorValue, weight = 0.5): SrgbColorValue => {
|
|
102
|
+
internalAssertColorUnit(weight, "weight")
|
|
103
|
+
const normalizedFirst = createSrgbColorValue(first)
|
|
104
|
+
const normalizedSecond = createSrgbColorValue(second)
|
|
105
|
+
const mixedLinearRgbColorValue = mixLinearRgbColorValues(
|
|
106
|
+
srgbColorValueToLinearRgbColorValue(normalizedFirst),
|
|
107
|
+
srgbColorValueToLinearRgbColorValue(normalizedSecond),
|
|
108
|
+
weight,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
return linearRgbColorValueToSrgbColorValue(mixedLinearRgbColorValue)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 将一个 Linear RGB 前景色合成到另一个 Linear RGB 背景色之上。
|
|
116
|
+
*
|
|
117
|
+
* 该函数在支线核心计算层直接执行 alpha 合成。
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```
|
|
121
|
+
* // Expect: { red: 0.5, green: 0.5, blue: 1, alpha: 1 }
|
|
122
|
+
* const example1 = compositeLinearRgbColorValueOverBackground(
|
|
123
|
+
* { red: 1, green: 1, blue: 1, alpha: 0.5 },
|
|
124
|
+
* { red: 0, green: 0, blue: 1, alpha: 1 },
|
|
125
|
+
* )
|
|
126
|
+
*
|
|
127
|
+
* // Expect: { red: 1, green: 0, blue: 0, alpha: 1 }
|
|
128
|
+
* const example2 = compositeLinearRgbColorValueOverBackground(
|
|
129
|
+
* { red: 1, green: 0, blue: 0, alpha: 1 },
|
|
130
|
+
* { red: 0, green: 0, blue: 1, alpha: 1 },
|
|
131
|
+
* )
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export const compositeLinearRgbColorValueOverBackground = (foreground: LinearRgbColorValue, background: LinearRgbColorValue): LinearRgbColorValue => {
|
|
135
|
+
const normalizedForeground = createLinearRgbColorValue(foreground)
|
|
136
|
+
const normalizedBackground = createLinearRgbColorValue(background)
|
|
137
|
+
const outputAlpha = internalRoundColorFloat(
|
|
138
|
+
normalizedForeground.alpha + (normalizedBackground.alpha * (1 - normalizedForeground.alpha)),
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
return createLinearRgbColorValue({
|
|
142
|
+
red: internalCompositeLinearRgbChannels(
|
|
143
|
+
normalizedForeground.red,
|
|
144
|
+
normalizedBackground.red,
|
|
145
|
+
normalizedForeground.alpha,
|
|
146
|
+
normalizedBackground.alpha,
|
|
147
|
+
outputAlpha,
|
|
148
|
+
),
|
|
149
|
+
green: internalCompositeLinearRgbChannels(
|
|
150
|
+
normalizedForeground.green,
|
|
151
|
+
normalizedBackground.green,
|
|
152
|
+
normalizedForeground.alpha,
|
|
153
|
+
normalizedBackground.alpha,
|
|
154
|
+
outputAlpha,
|
|
155
|
+
),
|
|
156
|
+
blue: internalCompositeLinearRgbChannels(
|
|
157
|
+
normalizedForeground.blue,
|
|
158
|
+
normalizedBackground.blue,
|
|
159
|
+
normalizedForeground.alpha,
|
|
160
|
+
normalizedBackground.alpha,
|
|
161
|
+
outputAlpha,
|
|
162
|
+
),
|
|
163
|
+
alpha: outputAlpha,
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 将一个 sRGB 前景色沿合法路径合成到另一个 sRGB 背景色之上。
|
|
169
|
+
*
|
|
170
|
+
* 该函数会沿合法路径 `sRGB -> Linear RGB -> composite -> sRGB` 计算。
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```
|
|
174
|
+
* // Expect: { red: 188, green: 188, blue: 255, alpha: 1 }
|
|
175
|
+
* const example1 = compositeSrgbColorValueOverBackground(
|
|
176
|
+
* { red: 255, green: 255, blue: 255, alpha: 0.5 },
|
|
177
|
+
* { red: 0, green: 0, blue: 255, alpha: 1 },
|
|
178
|
+
* )
|
|
179
|
+
*
|
|
180
|
+
* // Expect: { red: 255, green: 0, blue: 0, alpha: 1 }
|
|
181
|
+
* const example2 = compositeSrgbColorValueOverBackground(
|
|
182
|
+
* { red: 255, green: 0, blue: 0, alpha: 1 },
|
|
183
|
+
* { red: 0, green: 0, blue: 255, alpha: 1 },
|
|
184
|
+
* )
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
export const compositeSrgbColorValueOverBackground = (foreground: SrgbColorValue, background: SrgbColorValue): SrgbColorValue => {
|
|
188
|
+
const normalizedForeground = createSrgbColorValue(foreground)
|
|
189
|
+
const normalizedBackground = createSrgbColorValue(background)
|
|
190
|
+
|
|
191
|
+
return linearRgbColorValueToSrgbColorValue(compositeLinearRgbColorValueOverBackground(
|
|
192
|
+
srgbColorValueToLinearRgbColorValue(normalizedForeground),
|
|
193
|
+
srgbColorValueToLinearRgbColorValue(normalizedBackground),
|
|
194
|
+
))
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 调整一个 sRGB 颜色值的透明度。
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```
|
|
202
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 0.4 }
|
|
203
|
+
* const example1 = fadeSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.4)
|
|
204
|
+
*
|
|
205
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 0 }
|
|
206
|
+
* const example2 = fadeSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
export const fadeSrgbColorValue = (color: SrgbColorValue, alpha: number): SrgbColorValue => {
|
|
210
|
+
internalAssertColorUnit(alpha, "alpha")
|
|
211
|
+
const normalizedColor = createSrgbColorValue(color)
|
|
212
|
+
|
|
213
|
+
return createSrgbColorValue({
|
|
214
|
+
red: normalizedColor.red,
|
|
215
|
+
green: normalizedColor.green,
|
|
216
|
+
blue: normalizedColor.blue,
|
|
217
|
+
alpha,
|
|
218
|
+
})
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 沿合法路径将一个 sRGB 颜色值向白色方向推进。
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```
|
|
226
|
+
* // Expect: { red: 190, green: 198, blue: 212, alpha: 1 }
|
|
227
|
+
* const example1 = tintSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.5)
|
|
228
|
+
*
|
|
229
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
230
|
+
* const example2 = tintSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export const tintSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
|
|
234
|
+
return internalMixSrgbColorValueWithLinearReference(color, internalOpaqueWhiteLinearRgbColorValue, amount)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* 沿合法路径将一个 sRGB 颜色值向黑色方向推进。
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```
|
|
242
|
+
* // Expect: { red: 35, green: 73, blue: 111, alpha: 1 }
|
|
243
|
+
* const example1 = shadeSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.5)
|
|
244
|
+
*
|
|
245
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
246
|
+
* const example2 = shadeSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
export const shadeSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
|
|
250
|
+
return internalMixSrgbColorValueWithLinearReference(color, internalOpaqueBlackLinearRgbColorValue, amount)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* 沿合法路径将一个 sRGB 颜色值向中性灰方向推进。
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```
|
|
258
|
+
* // Expect: { red: 141, green: 153, blue: 171, alpha: 1 }
|
|
259
|
+
* const example1 = toneSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.5)
|
|
260
|
+
*
|
|
261
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
262
|
+
* const example2 = toneSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
export const toneSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
|
|
266
|
+
return internalMixSrgbColorValueWithLinearReference(color, internalOpaqueGrayLinearRgbColorValue, amount)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* 沿合法路径提高一个 sRGB 颜色值的亮度倾向。
|
|
271
|
+
*
|
|
272
|
+
* 该能力当前等价于向白色混合。
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```
|
|
276
|
+
* // Expect: { red: 143, green: 160, blue: 186, alpha: 1 }
|
|
277
|
+
* const example1 = lightenSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.25)
|
|
278
|
+
*
|
|
279
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
280
|
+
* const example2 = lightenSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
export const lightenSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
|
|
284
|
+
return tintSrgbColorValue(color, amount)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* 沿合法路径降低一个 sRGB 颜色值的亮度倾向。
|
|
289
|
+
*
|
|
290
|
+
* 该能力当前等价于向黑色混合。
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```
|
|
294
|
+
* // Expect: { red: 44, green: 89, blue: 134, alpha: 1 }
|
|
295
|
+
* const example1 = darkenSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.25)
|
|
296
|
+
*
|
|
297
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
298
|
+
* const example2 = darkenSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
export const darkenSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
|
|
302
|
+
return shadeSrgbColorValue(color, amount)
|
|
303
|
+
}
|