namespace pxsim.visuals { function createMicroServoElement() { return svg.parseString(` `).firstElementChild as SVGGElement; } export function mkMicroServoPart(xy: Coord = [0, 0]): SVGElAndSize { return { el: createMicroServoElement(), x: xy[0], y: xy[1], w: 112.188, h: 299.674 }; } export class MicroServoView implements IBoardPart { public style: string = ""; public overElement: SVGElement = undefined; public element: SVGElement; public defs: SVGElement[] = []; public state: EdgeConnectorState; public bus: EventBus; private currentAngle = 0; private targetAngle = 0; private lastAngleTime = 0; private pin: number; private crankEl: SVGGElement; private crankTransform: string; public init(bus: EventBus, state: EdgeConnectorState, svgEl: SVGSVGElement, otherParams: Map) { this.state = state; this.pin = this.state.props.servos[ pxsim.readPin(otherParams["name"] || otherParams["pin"]) ]; this.bus = bus; this.defs = []; this.initDom(); this.updateState(); } initDom() { this.element = createMicroServoElement(); this.crankEl = this.element.querySelector("#crank") as SVGGElement; this.crankTransform = this.crankEl.getAttribute("transform"); } moveToCoord(xy: visuals.Coord): void { let [x, y] = xy; translateEl(this.element, [x, y]) } updateState(): void { this.targetAngle = 180.0 - this.state.getPin(this.pin).servoAngle; if (this.targetAngle != this.currentAngle) { const now = U.now(); const cx = 56.661; const cy = 899.475; const speed = 300; // 0.1s/60 degree const dt = Math.min(now - this.lastAngleTime, 50) / 1000; const delta = this.targetAngle - this.currentAngle; this.currentAngle += Math.min(Math.abs(delta), speed * dt) * (delta > 0 ? 1 : -1); this.crankEl.setAttribute("transform", this.crankTransform + ` rotate(${this.currentAngle}, ${cx}, ${cy})`) this.lastAngleTime = now; setTimeout(() => runtime.updateDisplay(), 20); } } updateTheme(): void { } } }