2
* Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
* you may not use this file except in compliance with the License.
5
* You may obtain a copy of the License at
7
* http://www.apache.org/licenses/LICENSE-2.0
9
* Unless required by applicable law or agreed to in writing, software
10
* distributed under the License is distributed on an "AS IS" BASIS,
11
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
* See the License for the specific language governing permissions and
13
* limitations under the License.
16
import { float64, isFiniteNumber, uint32 } from "@koalaui/common"
18
export class EasingSupport {
19
private x: Float32Array
20
private y: Float32Array
22
private constructor(size: uint32, xSupplier: (value: float64) => float64, ySupplier: (value: float64) => float64) {
23
if (!Number.isInteger(size) || size <= 1) throw new Error("easing size must be integer value greater than 1, but is " + size)
24
this.x = new Float32Array(size)
25
this.y = new Float32Array(size)
26
this.x[0] = xSupplier(0)
27
this.y[0] = ySupplier(0)
29
this.x[last] = xSupplier(1)
30
this.y[last] = ySupplier(1)
31
for (let i = 1; i < last; i++) {
32
const value = i / last
33
this.x[i] = xSupplier(value)
34
this.y[i] = ySupplier(value)
38
convert(value: float64): float64 {
39
let last = (this.x.length - 1) as uint32
40
let left = 0 as uint32
41
if (value < this.x[left]) return this.y[left]
43
if (value > this.x[right]) return this.y[right]
44
while (left <= right) {
45
const center = ((left + right) >>> 1) as uint32
46
if (value < this.x[center]) right = center - 1
47
else if (value > this.x[center]) left = center + 1
48
else return this.y[center]
50
return this.y[left > last ? last : left]
53
static newCubicBezier(p1x: float64, p1y: float64, p2x: float64, p2y: float64, size: uint32 = 1024): EasingSupport {
54
if (!isFiniteNumber(p1x) || !isFiniteNumber(p1y) || p1x < 0 || 1 < p1x) throw new Error(`illegal point: (${p1x},${p1y}), where 0 <= x <= 1`)
55
if (!isFiniteNumber(p2x) || !isFiniteNumber(p2y) || p2x < 0 || 1 < p2x) throw new Error(`illegal point: (${p2x},${p2y}), where 0 <= x <= 1`)
56
return new EasingSupport(size, (value: float64) => cubicBezierValue(value, p1x, p2x), (value: float64) => cubicBezierValue(value, p1y, p2y))
60
function cubicBezierValue(left: float64, p1: float64, p2: float64): float64 {
61
const right = 1 - left
62
return left * (3 * right * (p1 * right + p2 * left) + left * left)