import { Component } from '../component/Component' import { Text } from '../component/Text' import { Rect } from '../component/Rect' import { Ani } from './Ani' import { font } from '../Constant' import { easePolyOut } from 'd3-ease' import { format } from 'd3-format' import { scaleLinear } from 'd3-scale' import { easeInterpolate } from '../utils/ease' export interface ProgressOptions { position?: { x: number, y: number } shape?: { width: number, height: number } aniTime?: [number, number] color?: string } export class Progress extends Ani implements ProgressOptions { ani: Ani shape: { width: number, height: number } radius: number = 6 padding: number = 3 lineWidth: number = 2 aniTime: [number, number] position: { x: number, y: number } center = { x: 0, y: 0 } color: string constructor (options?: ProgressOptions) { super() if (options != null) { this.position = options.position ?? { x: 0, y: 0 } this.aniTime = options.aniTime ?? [0, 3] this.shape = options.shape ?? { width: 400, height: 18 } this.color = options.color ?? '#FFF' } const border0 = new Rect({ key: 'progress-border-0', shape: { width: this.shape.width, height: this.shape.height, }, center: { x: this.shape.width / 2, y: this.shape.height / 2 }, alpha: 1, radius: this.radius, fillStyle: '#0006', strokeStyle: this.color, lineWidth: this.lineWidth, }) const border1 = new Rect({ key: 'progress-border-1', shape: { width: this.shape.width * 1.75, height: this.shape.height, }, center: { x: (this.shape.width * 1.75) / 2, y: this.shape.height / 2, }, alpha: 1, radius: this.radius, fillStyle: '#0006', strokeStyle: this.color, lineWidth: this.lineWidth, }) const bar0 = new Rect({ key: 'progress-bar-0', position: { x: this.padding, y: this.padding }, center: { x: this.shape.width / 2, y: this.shape.height / 2 }, shape: { width: 0, height: this.shape.height - this.padding * 2 }, radius: this.radius, fillStyle: this.color, }) const bar1 = new Rect({ key: 'progress-bar-1', position: { x: this.padding, y: this.padding }, center: { x: (this.shape.width / 2) * 1.75, y: this.shape.height / 2 }, shape: { width: (this.shape.width - this.padding * 2) * 1.75, height: this.shape.height - this.padding * 2, }, radius: this.radius, fillStyle: this.color, }) const start = new Component({ key: 'progress-start', position: this.position, scale: { x: 2, y: 2 }, }) start.children.push(border0) start.children.push(bar0) const end = new Component({ key: 'progress-end', position: this.position, scale: { x: 1, y: 1 }, }) end.children.push(border1) end.children.push(bar1) const borderFinished = new Rect({ key: 'progress-border-finished', shape: { width: this.shape.width * 2, height: this.shape.height * 2, }, center: { x: (this.shape.width * 2) / 2, y: (this.shape.height * 2) / 2, }, alpha: 0, radius: this.radius, fillStyle: '#0006', strokeStyle: '#27C', lineWidth: this.lineWidth, }) const bar2 = new Rect({ key: 'progress-bar-2', center: { x: this.shape.width / 2, y: this.shape.height / 2 }, position: { x: this.padding, y: this.padding }, shape: { width: this.shape.width - this.padding * 2, height: this.shape.height - this.padding * 2, }, alpha: 0.0, radius: this.radius, fillStyle: '#27C', }) const final = new Component({ key: 'progress-final', position: this.position, alpha: 1, scale: { x: 1.2, y: 1.2 }, }) final.children.push(borderFinished) final.children.push(bar2) const objCopy = Object.assign({}, final) objCopy.alpha = 0 this.ani = new Ani() } getComponent (sec: number) { const val = scaleLinear(this.aniTime, [0, 100]) .clamp(true) .interpolate(easeInterpolate(easePolyOut.exponent(5)))(sec) const label = format('d')(val) const res = this.ani.getComponent(sec) const textLabel = new Text({ key: 'progress-label', text: val === 100 ? '' : `Loading ${label} %`, font, fontSize: 24, textAlign: 'center', textBaseline: 'top', position: { x: 0, y: this.shape.height }, fillStyle: '#fff', }) res?.children.push(textLabel) return res } }