mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-04-15 11:37:24 +08:00
feat: 颜色渐变
This commit is contained in:
parent
c5101c9b29
commit
ebf65b8128
@ -67,13 +67,13 @@ export function onLoaded(hook: () => void) {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ITransitionedController {
|
||||
readonly ref: Ref<number>;
|
||||
readonly value: number;
|
||||
set(value: number): void;
|
||||
export interface ITransitionedController<T> {
|
||||
readonly ref: Ref<T>;
|
||||
readonly value: T;
|
||||
set(value: T): void;
|
||||
}
|
||||
|
||||
class RenderTransition implements ITransitionedController {
|
||||
class RenderTransition implements ITransitionedController<number> {
|
||||
private static key: number = 0;
|
||||
|
||||
private readonly key: string = `$${RenderTransition.key++}`;
|
||||
@ -94,6 +94,7 @@ class RenderTransition implements ITransitionedController {
|
||||
public readonly curve: TimingFn
|
||||
) {
|
||||
this.ref = ref(value);
|
||||
transition.value[this.key] = value;
|
||||
transition.ticker.add(() => {
|
||||
this.ref.value = transition.value[this.key];
|
||||
});
|
||||
@ -107,15 +108,133 @@ class RenderTransition implements ITransitionedController {
|
||||
}
|
||||
}
|
||||
|
||||
type ColorRGBA = [number, number, number, number];
|
||||
|
||||
class RenderColorTransition implements ITransitionedController<string> {
|
||||
private static key: number = 0;
|
||||
|
||||
private readonly keyR: string = `$colorR${RenderColorTransition.key++}`;
|
||||
private readonly keyG: string = `$colorG${RenderColorTransition.key++}`;
|
||||
private readonly keyB: string = `$colorB${RenderColorTransition.key++}`;
|
||||
private readonly keyA: string = `$colorA${RenderColorTransition.key++}`;
|
||||
|
||||
public readonly ref: Ref<string>;
|
||||
|
||||
set value(v: string) {
|
||||
this.set(v);
|
||||
}
|
||||
get value() {
|
||||
return this.encodeColor();
|
||||
}
|
||||
|
||||
constructor(
|
||||
value: string,
|
||||
public readonly transition: Transition,
|
||||
public readonly time: number,
|
||||
public readonly curve: TimingFn
|
||||
) {
|
||||
this.ref = ref(value);
|
||||
const [r, g, b, a] = this.decodeColor(value);
|
||||
transition.value[this.keyR] = r;
|
||||
transition.value[this.keyG] = g;
|
||||
transition.value[this.keyB] = b;
|
||||
transition.value[this.keyA] = a;
|
||||
transition.ticker.add(() => {
|
||||
this.ref.value = this.encodeColor();
|
||||
});
|
||||
}
|
||||
|
||||
set(value: string): void {
|
||||
this.transitionColor(this.decodeColor(value));
|
||||
}
|
||||
|
||||
private transitionColor([r, g, b, a]: ColorRGBA) {
|
||||
this.transition
|
||||
.mode(this.curve)
|
||||
.time(this.time)
|
||||
.transition(this.keyR, r)
|
||||
.transition(this.keyG, g)
|
||||
.transition(this.keyB, b)
|
||||
.transition(this.keyA, a);
|
||||
}
|
||||
|
||||
private decodeColor(color: string): ColorRGBA {
|
||||
if (color.startsWith('#')) {
|
||||
return this.decodeHash(color);
|
||||
} else if (color.startsWith('rgba')) {
|
||||
return this.decodeRGBA(color);
|
||||
} else if (color.startsWith('rgb')) {
|
||||
return this.decodeRGB(color);
|
||||
}
|
||||
return [0, 0, 0, 1];
|
||||
}
|
||||
|
||||
private decodeHash(color: string): ColorRGBA {
|
||||
switch (color.length) {
|
||||
case 4:
|
||||
return [
|
||||
Number(`0x${color.slice(1, 2).repeat(2)}`),
|
||||
Number(`0x${color.slice(2, 3).repeat(2)}`),
|
||||
Number(`0x${color.slice(3, 4).repeat(2)}`),
|
||||
1
|
||||
];
|
||||
case 5:
|
||||
return [
|
||||
Number(`0x${color.slice(1, 2).repeat(2)}`),
|
||||
Number(`0x${color.slice(2, 3).repeat(2)}`),
|
||||
Number(`0x${color.slice(3, 4).repeat(2)}`),
|
||||
Number(`0x${color.slice(4, 5).repeat(2)}`)
|
||||
];
|
||||
case 7:
|
||||
return [
|
||||
Number(`0x${color.slice(1, 3)}`),
|
||||
Number(`0x${color.slice(3, 5)}`),
|
||||
Number(`0x${color.slice(5, 7)}`),
|
||||
1
|
||||
];
|
||||
case 9:
|
||||
return [
|
||||
Number(`0x${color.slice(1, 3)}`),
|
||||
Number(`0x${color.slice(3, 5)}`),
|
||||
Number(`0x${color.slice(5, 7)}`),
|
||||
Number(`0x${color.slice(7, 9)}`)
|
||||
];
|
||||
}
|
||||
return [0, 0, 0, 0];
|
||||
}
|
||||
|
||||
private decodeRGBA(color: string): ColorRGBA {
|
||||
const data = color.slice(color.indexOf('(') + 1, color.indexOf(')'));
|
||||
const [r, g, b, a] = data.split(',');
|
||||
return [Number(r), Number(g), Number(b), Number(a)];
|
||||
}
|
||||
|
||||
private decodeRGB(color: string): ColorRGBA {
|
||||
const data = color.slice(color.indexOf('(') + 1, color.indexOf(')'));
|
||||
const [r, g, b] = data.split(',');
|
||||
return [Number(r), Number(g), Number(b), 1];
|
||||
}
|
||||
|
||||
private encodeColor() {
|
||||
const r = this.transition.value[this.keyR];
|
||||
const g = this.transition.value[this.keyG];
|
||||
const b = this.transition.value[this.keyB];
|
||||
const a = this.transition.value[this.keyA];
|
||||
return `rgba(${r},${g},${b},${a})`;
|
||||
}
|
||||
}
|
||||
|
||||
const transitionMap = new Map<ComponentInternalInstance, Transition>();
|
||||
|
||||
export function transitioned(
|
||||
value: number,
|
||||
time: number,
|
||||
curve: TimingFn
|
||||
): ITransitionedController | null {
|
||||
function checkTransition() {
|
||||
const instance = getCurrentInstance();
|
||||
if (!instance) return null;
|
||||
if (instance.isUnmounted) {
|
||||
const tran = transitionMap.get(instance);
|
||||
tran?.ticker.destroy();
|
||||
transitionMap.delete(instance);
|
||||
return null;
|
||||
}
|
||||
if (!transitionMap.has(instance)) {
|
||||
const tran = new Transition();
|
||||
transitionMap.set(instance, tran);
|
||||
@ -126,5 +245,52 @@ export function transitioned(
|
||||
}
|
||||
const tran = transitionMap.get(instance);
|
||||
if (!tran) return null;
|
||||
return tran;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个渐变数值,当数值发生变化时会缓慢变化值目标值而非突变,只可以用于组件内,不可用于组件外
|
||||
* ```tsx
|
||||
* const value = transitioned(10, 300, linear()); // 创建渐变,初始值为 10,渐变时长 300ms,线性变化
|
||||
* value.set(100); // 渐变至 100
|
||||
*
|
||||
* // 直接在元素上使用
|
||||
* <text text={value.ref.value} />
|
||||
* ```
|
||||
* @param value 初始值
|
||||
* @param time 渐变时长
|
||||
* @param curve 渐变的速率曲线
|
||||
*/
|
||||
export function transitioned(
|
||||
value: number,
|
||||
time: number,
|
||||
curve: TimingFn
|
||||
): ITransitionedController<number> | null {
|
||||
const tran = checkTransition();
|
||||
if (!tran) return null;
|
||||
return new RenderTransition(value, tran, time, curve);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个渐变颜色,当颜色发生变化时会缓慢变化值目标值而非突变,自动判断颜色字符串类型,只可用于组件内,不可用于组件外
|
||||
* ```tsx
|
||||
* // 创建渐变,初始值为 '#fff'(白色),渐变时长 300ms,线性变化
|
||||
* const color = transitionedColor('#fff', 300, linear());
|
||||
* color.set('rgba(129, 30, 40, 0.7)'); // 渐变至这个颜色
|
||||
*
|
||||
* // 直接在元素上使用
|
||||
* <text text='文本' fillStyle={color.ref.value} />
|
||||
* ```
|
||||
* @param color 颜色的初始值
|
||||
* @param time 渐变时长
|
||||
* @param curve 渐变的速率曲线
|
||||
*/
|
||||
export function transitionedColor(
|
||||
color: string,
|
||||
time: number,
|
||||
curve: TimingFn
|
||||
): ITransitionedController<string> | null {
|
||||
const tran = checkTransition();
|
||||
if (!tran) return null;
|
||||
return new RenderColorTransition(color, tran, time, curve);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user