Files
esengine/packages/ui/src/components/widgets/UISliderComponent.ts

391 lines
9.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Component, ECSComponent, Property, Serializable, Serialize } from '@esengine/ecs-framework';
/**
* 滑块方向
* Slider orientation
*/
export enum UISliderOrientation {
Horizontal = 'horizontal',
Vertical = 'vertical'
}
/**
* UI 滑块组件
* UI Slider Component - Value slider with handle
*/
@ECSComponent('UISlider')
@Serializable({ version: 1, typeId: 'UISlider' })
export class UISliderComponent extends Component {
// ===== 数值 Values =====
/**
* 当前值
* Current value
*/
@Serialize()
@Property({ type: 'number', label: 'Value' })
public value: number = 0;
/**
* 最小值
* Minimum value
*/
@Serialize()
@Property({ type: 'number', label: 'Min Value' })
public minValue: number = 0;
/**
* 最大值
* Maximum value
*/
@Serialize()
@Property({ type: 'number', label: 'Max Value' })
public maxValue: number = 100;
/**
* 步进值0 = 连续)
* Step value (0 = continuous)
*/
@Serialize()
@Property({ type: 'number', label: 'Step', min: 0 })
public step: number = 0;
/**
* 目标值(用于动画)
* Target value (for animation)
*/
public targetValue: number = 0;
/**
* 显示值(动画插值后)
* Display value (interpolated)
*/
public displayValue: number = 0;
// ===== 方向 Orientation =====
/**
* 滑块方向
* Slider orientation
*/
@Serialize()
@Property({
type: 'enum',
label: 'Orientation',
options: [
{ value: 'horizontal', label: 'Horizontal' },
{ value: 'vertical', label: 'Vertical' }
]
})
public orientation: UISliderOrientation = UISliderOrientation.Horizontal;
// ===== 轨道样式 Track Style =====
/**
* 轨道颜色
* Track color
*/
@Serialize()
@Property({ type: 'color', label: 'Track Color' })
public trackColor: number = 0x444444;
/**
* 轨道透明度
* Track alpha
*/
@Serialize()
@Property({ type: 'number', label: 'Track Alpha', min: 0, max: 1, step: 0.01 })
public trackAlpha: number = 1;
/**
* 轨道高度(水平)或宽度(垂直)
* Track thickness
*/
@Serialize()
@Property({ type: 'number', label: 'Track Thickness', min: 1 })
public trackThickness: number = 4;
/**
* 轨道圆角
* Track corner radius
*/
@Serialize()
@Property({ type: 'number', label: 'Track Radius', min: 0 })
public trackRadius: number = 2;
// ===== 填充样式 Fill Style =====
/**
* 填充颜色(已滑过的部分)
* Fill color (passed portion)
*/
@Serialize()
@Property({ type: 'color', label: 'Fill Color' })
public fillColor: number = 0x4A90D9;
/**
* 填充透明度
* Fill alpha
*/
@Serialize()
@Property({ type: 'number', label: 'Fill Alpha', min: 0, max: 1, step: 0.01 })
public fillAlpha: number = 1;
// ===== 手柄样式 Handle Style =====
/**
* 手柄宽度
* Handle width
*/
@Serialize()
@Property({ type: 'number', label: 'Handle Width', min: 1 })
public handleWidth: number = 16;
/**
* 手柄高度
* Handle height
*/
@Serialize()
@Property({ type: 'number', label: 'Handle Height', min: 1 })
public handleHeight: number = 16;
/**
* 手柄颜色
* Handle color
*/
@Serialize()
@Property({ type: 'color', label: 'Handle Color' })
public handleColor: number = 0xFFFFFF;
/**
* 手柄悬停颜色
* Handle hover color
*/
@Serialize()
@Property({ type: 'color', label: 'Handle Hover Color' })
public handleHoverColor: number = 0xE0E0E0;
/**
* 手柄按下颜色
* Handle pressed color
*/
@Serialize()
@Property({ type: 'color', label: 'Handle Pressed Color' })
public handlePressedColor: number = 0xCCCCCC;
/**
* 手柄圆角
* Handle corner radius
*/
@Serialize()
@Property({ type: 'number', label: 'Handle Radius', min: 0 })
public handleRadius: number = 8;
/**
* 手柄边框宽度
* Handle border width
*/
@Serialize()
@Property({ type: 'number', label: 'Handle Border Width', min: 0 })
public handleBorderWidth: number = 0;
/**
* 手柄边框颜色
* Handle border color
*/
@Serialize()
@Property({ type: 'color', label: 'Handle Border Color' })
public handleBorderColor: number = 0x000000;
/**
* 手柄阴影
* Handle shadow enabled
*/
@Serialize()
@Property({ type: 'boolean', label: 'Handle Shadow' })
public handleShadow: boolean = true;
// ===== 交互状态 Interaction State =====
/**
* 手柄是否被悬停
* Whether handle is hovered
*/
public handleHovered: boolean = false;
/**
* 是否正在拖拽
* Whether currently dragging
*/
public dragging: boolean = false;
/**
* 拖拽起始值
* Drag start value
*/
public dragStartValue: number = 0;
/**
* 拖拽起始位置
* Drag start position
*/
public dragStartPosition: number = 0;
// ===== 动画 Animation =====
/**
* 过渡时长(秒)
* Transition duration in seconds
*/
@Serialize()
@Property({ type: 'number', label: 'Transition Duration', min: 0, step: 0.01 })
public transitionDuration: number = 0.1;
// ===== 刻度 Ticks =====
/**
* 是否显示刻度
* Whether to show ticks
*/
@Serialize()
@Property({ type: 'boolean', label: 'Show Ticks' })
public showTicks: boolean = false;
/**
* 刻度数量(不包括首尾)
* Number of ticks (excluding ends)
*/
@Serialize()
@Property({ type: 'integer', label: 'Tick Count', min: 0 })
public tickCount: number = 4;
/**
* 刻度颜色
* Tick color
*/
@Serialize()
@Property({ type: 'color', label: 'Tick Color' })
public tickColor: number = 0x666666;
/**
* 刻度大小
* Tick size
*/
@Serialize()
@Property({ type: 'number', label: 'Tick Size', min: 1 })
public tickSize: number = 4;
// ===== 文本 Text =====
/**
* 是否显示值文本
* Whether to show value text
*/
@Serialize()
@Property({ type: 'boolean', label: 'Show Value' })
public showValue: boolean = false;
/**
* 值文本格式
* Value text format
*/
@Serialize()
@Property({ type: 'string', label: 'Value Format' })
public valueFormat: string = '{value}';
/**
* 小数位数
* Decimal places
*/
@Serialize()
@Property({ type: 'integer', label: 'Decimal Places', min: 0 })
public decimalPlaces: number = 0;
// ===== 回调 Callbacks =====
/**
* 值改变回调
* Value change callback
*/
public onChange?: (value: number) => void;
/**
* 拖拽开始回调
* Drag start callback
*/
public onDragStart?: (value: number) => void;
/**
* 拖拽结束回调
* Drag end callback
*/
public onDragEnd?: (value: number) => void;
/**
* 获取进度百分比 (0-1)
* Get progress as percentage (0-1)
*/
public getProgress(): number {
const range = this.maxValue - this.minValue;
if (range <= 0) return 0;
return Math.max(0, Math.min(1, (this.displayValue - this.minValue) / range));
}
/**
* 从百分比设置值
* Set value from percentage
*/
public setProgress(progress: number): this {
const range = this.maxValue - this.minValue;
return this.setValue(this.minValue + range * Math.max(0, Math.min(1, progress)));
}
/**
* 设置值
* Set value
*/
public setValue(value: number, animate: boolean = true): this {
let newValue = Math.max(this.minValue, Math.min(this.maxValue, value));
// 应用步进
if (this.step > 0) {
newValue = Math.round((newValue - this.minValue) / this.step) * this.step + this.minValue;
}
this.targetValue = newValue;
if (!animate) {
this.value = newValue;
this.displayValue = newValue;
}
return this;
}
/**
* 获取格式化的值文本
* Get formatted value text
*/
public getFormattedValue(): string {
const formattedValue = this.displayValue.toFixed(this.decimalPlaces);
return this.valueFormat.replace('{value}', formattedValue);
}
/**
* 计算手柄位置(归一化 0-1
* Calculate handle position (normalized 0-1)
*/
public getHandlePosition(): number {
return this.getProgress();
}
/**
* 获取当前手柄颜色
* Get current handle color based on state
*/
public getCurrentHandleColor(): number {
if (this.dragging) return this.handlePressedColor;
if (this.handleHovered) return this.handleHoverColor;
return this.handleColor;
}
}