diff --git a/examples/main.ts b/examples/main.ts index d0ce102e1..58c796062 100644 --- a/examples/main.ts +++ b/examples/main.ts @@ -48,12 +48,17 @@ export class Milestone { } } +let circle = new nc.Circle(100, { + x: 200, + y: 200 +}) export const defaultScene = new nc.Scene( new nc.Circle(100, { x: 200, y: 200 - }) - .animate(nc.focusOn().withAttr({ duration: 0.3 })) + }).animate(nc.useAnimate(ctx => { + ctx.widget.pos.value = nc.pp(0.5, 0.5) + }).withAttr({ duration: 1 })) ) const left = document.querySelector('.left') as HTMLDivElement @@ -70,10 +75,10 @@ window.addEventListener('keydown', e => { switch (e.key) { case 'ArrowLeft': left.dispatchEvent(new Event('click')) - break; + break case 'ArrowRight': right.dispatchEvent(new Event('click')) - break; + break } }) diff --git a/packages/core/src/app.ts b/packages/core/src/app.ts index eab959e0d..41c58e271 100644 --- a/packages/core/src/app.ts +++ b/packages/core/src/app.ts @@ -77,6 +77,7 @@ export class App { plugin.beforeCheckout(this, scene) } this.scene = scene + this.scene.root.canvasSize = [this.element.width, this.element.height] this.scene.startTime = performance.now() for (const plugin of this.plugins) { if (plugin.onCheckout) @@ -111,11 +112,11 @@ export class App { plugin.onUpdate(app, app.scene.elapsed) } + app.scene.root.canvasSize = [app.element.width, app.element.height] app.scene.root.update( app.scene.elapsed, app.ck, canvas, - app, ) if (app.config.unit === 'frame') diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c5fd4969d..157939f7a 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -16,3 +16,4 @@ export * from './localApp' export * from './event' export * from './prop' +export * from './physical' diff --git a/packages/core/src/localApp.ts b/packages/core/src/localApp.ts index c74ce227f..e4cef5e88 100644 --- a/packages/core/src/localApp.ts +++ b/packages/core/src/localApp.ts @@ -54,32 +54,24 @@ export class LocalApp { } static update(app: LocalApp): void { - for (const plugin of app.plugins) - plugin.beforeUpdate(app, app.scene.elapsed) - - initial(app.scene.root, app.ck, app.canvas) - // Contrast the old widget and the new widget and update them. - for (const plugin of app.plugins) - plugin.beforePatch(app, app.scene.elapsed, app.last, app.scene.root) + if (!app.playing) + return for (const plugin of app.plugins) { - plugin.onPatch(app, app.scene.elapsed, app.last, app.scene.root) + if (plugin.beforeUpdate) + plugin.beforeUpdate(app, app.scene.elapsed) + } + for (const plugin of app.plugins) { + if (plugin.onUpdate) + plugin.onUpdate(app, app.scene.elapsed) } - (function draw(widget: Widget) { - widget.init(app.ck) - app.canvas.save() - // widget.update(app.canvas) - for (const child of widget.children) draw(child) - - app.canvas.restore() - })(app.scene.root) - - // Animating. - app.scene.root.runAnimation(app.scene.elapsed, app.ck) - - for (const plugin of app.plugins) plugin.onUpdate(app, app.scene.elapsed) - app.scene.elapsed += 1 + app.scene.root.canvasSize = [app.width, app.height] + app.scene.root.update( + app.scene.elapsed, + app.ck, + app.canvas, + ) } /** diff --git a/packages/core/src/physical.ts b/packages/core/src/physical.ts index c8fbb32ec..678ad5575 100644 --- a/packages/core/src/physical.ts +++ b/packages/core/src/physical.ts @@ -15,31 +15,31 @@ export class Length { } } -export function r(value: number) { +export function rl(value: number) { return new Length('raw', value) } -export function p(value: number) { +export function pl(value: number) { return new Length('percent', value) } export class Position { constructor(public type: LengthUnitType, public x: number, public y: number) {} - resolve(originX: number, originY: number): [number, number] { + resolve(width: number, height: number): [number, number] { switch (this.type) { case 'raw': return [this.x, this.y] case 'percent': - return [this.x * originX, this.y * originY] + return [this.x * width, this.y * height] } } } -export function rp(value: number) { - return new Length('raw', value) +export function rp(x: number, y: number) { + return new Position('raw', x, y) } -export function pp(value: number) { - return new Length('percent', value) +export function pp(x: number, y: number) { + return new Position('percent', x, y) } diff --git a/packages/core/src/scene.ts b/packages/core/src/scene.ts index 807b84996..b681ce610 100644 --- a/packages/core/src/scene.ts +++ b/packages/core/src/scene.ts @@ -1,11 +1,21 @@ -import type { Widget } from './widget' +import { Widget } from './widget' + +export class RootWidget extends Widget { + canvasSize: [number, number] + + constructor() { + super() + } +} export class Scene { elapsed = 0 startTime: number + root: RootWidget = new RootWidget() - constructor(public root: Widget) { + constructor(root: Widget) { this.root.status = 'live' + this.root.add(root) } } diff --git a/packages/core/src/widget.ts b/packages/core/src/widget.ts index d24f88a48..c9adccd4a 100644 --- a/packages/core/src/widget.ts +++ b/packages/core/src/widget.ts @@ -5,9 +5,12 @@ import type { Event, EventInstance } from './event' import { defineEvent } from './event' import type { WidgetPlugin } from './plugin' import type { AnimateFunction } from './apiAnimate' -import type { ConvertToProp, Ref } from './prop' +import type { ConvertToProp, Reactive, Ref } from './prop' import type { App } from './app' -import { ref } from './prop' +import { changed, reactive, ref } from './prop' +import type { Position } from './physical' +import { rp } from './physical' +import { RootWidget } from './scene' export type WidgetRange = [number, number, number, number] // export type WidgetInstance = T @@ -19,6 +22,7 @@ export interface WidgetOptions { style?: WidgetStyle x?: number y?: number + pos?: Position | [number, number] centerX?: number // The rotation center x of the widget. centerY?: number // The rotation center y of the widget. progress?: number @@ -38,6 +42,7 @@ export interface WidgetStyle { export class Widget { plugins: WidgetPlugin[] = [] + pos: Ref x: Ref // The vector x of the widget. y: Ref // The vector y of the widget. centerX: Ref // The center vector x of the widget. @@ -61,7 +66,7 @@ export class Widget { .slice(2)}` parent: Widget | null - private status: Status = 'unborn' + status: Status = 'unborn' initialized: boolean = false registeredEvents: Map> = new Map() @@ -70,6 +75,7 @@ export class Widget { options ??= {} this.x = ref(options.x ?? 0) this.y = ref(options.y ?? 0) + this.pos = ref(rp(this.x.value, this.y.value)) this.centerX = ref(options.centerX ?? 0) this.centerY = ref(options.centerY ?? 0) this.progress = ref(options.progress ?? 1) @@ -102,7 +108,16 @@ export class Widget { * Called when the widget is registered. * @param _ck The CanvasKit namespace */ - init(_ck: CanvasKit) {} + init(_ck: CanvasKit) { + changed(this.pos, (pos) => { + if (this.parent instanceof RootWidget) { + [this.x.value, this.y.value] = pos.value.resolve(...this.parent.canvasSize) + } + else { + [this.x.value, this.y.value] = pos.value.resolve(this.parent.x.value, this.y.value) + } + }) + } /** * Draw the object according to the parameters of the widget. @@ -116,7 +131,11 @@ export class Widget { * Called when the style is changed. * @param canvas The canvas object of CanvasKit-WASM. */ - update(elapsed: number, ck: CanvasKit, canvas: Canvas, app: App) { + update( + elapsed: number, + ck: CanvasKit, + canvas: Canvas, + ) { if (!this.initialized) { this.init(ck) this.initialized = true @@ -141,7 +160,7 @@ export class Widget { } } for (const child of this.children) { - child.update(elapsed, ck, canvas, app) + child.update(elapsed, ck, canvas) } canvas.restore()