diff --git a/packages/entity/src/persea/controllers/entity/stage/index.jsx b/packages/entity/src/persea/controllers/entity/stage/index.jsx index 3155bcb..6c3fa24 100644 --- a/packages/entity/src/persea/controllers/entity/stage/index.jsx +++ b/packages/entity/src/persea/controllers/entity/stage/index.jsx @@ -8,7 +8,7 @@ import { useState, } from '@latus/react'; -import {Stage} from '@avocado/graphics/persea'; +import {Stage} from '@avocado/graphics'; const EntityStage = ({entity}) => { const [size, setSize] = useState([0, 0]); diff --git a/packages/graphics/src/persea/components/stage/index.jsx b/packages/graphics/src/components/stage/index.jsx similarity index 98% rename from packages/graphics/src/persea/components/stage/index.jsx rename to packages/graphics/src/components/stage/index.jsx index 59b0043..a07a814 100644 --- a/packages/graphics/src/persea/components/stage/index.jsx +++ b/packages/graphics/src/components/stage/index.jsx @@ -11,7 +11,7 @@ import { } from '@latus/react'; import Slider from 'rc-slider'; -import Renderer from '../../../renderer'; +import Renderer from '../../renderer'; const marks = { 1: '1x', diff --git a/packages/graphics/src/persea/components/stage/index.scss b/packages/graphics/src/components/stage/index.scss similarity index 100% rename from packages/graphics/src/persea/components/stage/index.scss rename to packages/graphics/src/components/stage/index.scss diff --git a/packages/graphics/src/index.js b/packages/graphics/src/index.js index 7bd6f83..d624192 100644 --- a/packages/graphics/src/index.js +++ b/packages/graphics/src/index.js @@ -2,13 +2,13 @@ import {gatherWithLatus} from '@latus/core'; export {default as Canvas} from './canvas'; export {default as Color} from './color'; +export {default as Stage} from './components/stage'; export {default as Container} from './container'; export {Image} from './resources/image'; export {default as Primitives} from './primitives'; export {default as Renderable} from './renderable'; export {default as Renderer} from './renderer'; export {default as Sprite} from './sprite'; -// export {default as Stage} from './stage'; export {default as Text} from './text'; if ('client' === process.env.SIDE) { diff --git a/packages/graphics/src/persea/index.js b/packages/graphics/src/persea/index.js index 2c395dc..c401502 100644 --- a/packages/graphics/src/persea/index.js +++ b/packages/graphics/src/persea/index.js @@ -1,7 +1,5 @@ import ImageController from './controllers/image'; -export {default as Stage} from './components/stage'; - export { ImageController, }; diff --git a/packages/graphics/src/stage.js b/packages/graphics/src/stage.js deleted file mode 100644 index 193daad..0000000 --- a/packages/graphics/src/stage.js +++ /dev/null @@ -1,244 +0,0 @@ -import {Property} from '@avocado/core'; -import {InputNormalizer} from '@avocado/input'; -import {Vector} from '@avocado/math'; -import {compose} from '@latus/core'; - -import Container from './container'; -import Renderer from './renderer'; - -const ASPECT = 16 / 9; - -const decorate = compose( - Property('camera', { - track: true, - }), -); - -export default class Stage extends decorate(Container) { - - constructor(visibleSize, visibleScale) { - super(); - const size = Vector.mul(visibleSize, visibleScale); - // Container element. - this.element = window.document.createElement('div'); - this.element.className = 'avocado-stage'; - this.element.style.height = '100%'; - this.element.style.lineHeight = '0'; - this.element.style.position = 'relative'; - this.element.style.width = '100%'; - // DOM parent. - this.parent = undefined; - // Set scale. - this.scale = visibleScale; - // Canvas renderer. - this.renderer = new Renderer(size); - this.renderer.element.style.width = '100%'; - this.renderer.element.style.height = '100%'; - // "real" dimensions. - this.size = size; - // Precalc for position/dimension transformation. - this._transformRatio = 1; - // UI DOM node. - this.ui = this.createUiLayer(); - this._queuedFindSelectors = {}; - // Event handlers. - this.onWindowResize = this.onWindowResize.bind(this); - window.addEventListener('resize', this.onWindowResize); - // Normalize input. - this.inputNormalizer = new InputNormalizer(); - this.inputNormalizer.listen(this.element); - this.inputNormalizer.on('keyDown', this.onKeyDown, this); - this.inputNormalizer.on('keyUp', this.onKeyUp, this); - this.inputNormalizer.on('pointerDown', this.onPointerDown, this); - this.inputNormalizer.on('pointerMove', this.onPointerMove, this); - this.inputNormalizer.on('pointerUp', this.onPointerUp, this); - this.inputNormalizer.on('wheel', this.onWheel, this); - // Put the renderer and UI in the container element, and mark it - // focusable. - this.element.appendChild(this.renderer.element); - this.element.appendChild(this.ui); - this.element.tabIndex = 0; - } - - addToDom(parent) { - // Had a parent? Remove. - this.removeFromDom(); - this.parent = parent; - // Add to new parent (if any) and focus. - if (parent) { - parent.appendChild(this.element); - } - // Recalculate size and ratio. - this.onWindowResize(); - } - - createUiLayer() { - const node = window.document.createElement('div'); - node.className = 'ui'; - node.style.overflow = 'hidden'; - node.style.position = 'absolute'; - node.style.width = `${this.size[0] / this.scale[0]}px`; - node.style.height = `${this.size[1] / this.scale[1]}px`; - node.style.left = 0; - node.style.top = 0; - node.style.transformOrigin = '0 0 0'; - return node; - } - - destroy() { - window.removeEventListener('resize', this.onWindowResize); - this.renderer.destroy(); - super.destroy(); - if (this.parent) { - this.parent.removeChild(this.renderer.element); - } - this.inputNormalizer.off('keyDown', this.onKeyDown); - this.inputNormalizer.off('keyUp', this.onKeyUp); - this.inputNormalizer.off('pointerDown', this.onPointerDown); - this.inputNormalizer.off('pointerMove', this.onPointerMove); - this.inputNormalizer.off('pointerUp', this.onPointerUp); - this.inputNormalizer.off('wheel', this.onWheel); - this.inputNormalizer.destroy(); - } - - get displaySize() { - return [ - this.element.style.width, - this.element.style.height, - ]; - } - - findUiElement(selector) { - const node = this.ui.querySelector(selector); - if (node) { - return Promise.resolve(node); - } - const queued = this._queuedFindSelectors[selector]; - if (queued) { - return queued.promise; - } - let resolve; - const promise = new Promise((resolve_) => { - resolve = resolve_; - }); - this._queuedFindSelectors[selector] = {resolve, promise}; - return promise; - } - - flushUiElements() { - const selectors = Object.keys(this._queuedFindSelectors); - for (let i = 0; i < selectors.length; i++) { - const selector = selectors[i]; - const {resolve} = this._queuedFindSelectors[selector]; - resolve(this.ui.querySelector(selector)); - } - this._queuedFindSelectors = {}; - } - - focus() { - this.element.focus(); - } - - onKeyDown(event) { - this.emit('keyDown', event); - } - - onKeyUp(event) { - this.emit('keyUp', event); - } - - onPointerDown(event) { - // eslint-disable-next-line no-param-reassign - event.position = this.transformCanvasPosition(event.position); - this.emit('pointerDown', event); - } - - onPointerMove(event) { - // eslint-disable-next-line no-param-reassign - event.position = this.transformCanvasPosition(event.position); - this.emit('pointerMove', event); - } - - onPointerUp(event) { - // eslint-disable-next-line no-param-reassign - event.position = this.transformCanvasPosition(event.position); - this.emit('pointerUp', event); - } - - onWheel(event) { - this.emit('wheel', event); - } - - onWindowResize() { - if (!this.parent) { - return; - } - // Find the biggest axe, width or height. - const ratio = this.parent.clientWidth / this.parent.clientHeight; - const biggest = ratio > ASPECT ? 'height' : 'width'; - // Key parent client size by axe. - const parentClient = { - width: this.parent.clientWidth, - height: this.parent.clientHeight, - }; - ['height', 'width'].forEach((axe) => { - // Biggest axe? Inherit parent axe size. - if (axe === biggest) { - this.element.style[axe] = `${parentClient[biggest]}px`; - } - // Derive height from width. - else if ('width' === biggest) { - this.element.style.height = `${parentClient[biggest] * (1 / ASPECT)}px`; - } - // Derive width from height. - else { - this.element.style.width = `${parentClient[biggest] * ASPECT}px`; - } - }); - // Precalc the transformation ratio and apply it to the UI layer. - this._transformRatio = this.size[0] / this.element.clientWidth; - const scaleFactor = 1 / this._transformRatio; - const scaleX = scaleFactor * this.scale[0]; - const scaleY = scaleFactor * this.scale[1]; - this.ui.style.transform = `scaleX(${scaleX}) scaleY(${scaleY})`; - this.emit('displaySizeChanged', this.displaySize); - } - - removeFromDom() { - if (this.parent) { - this.parent.removeChild(this.element); - this.parent = undefined; - } - } - - renderTick(elapsed) { - super.renderTick(elapsed); - this.renderer.render(this); - if (this.camera) { - const inverseOffset = Vector.mul( - this.camera.realOffset, - Vector.scale(this.scale, -1), - ); - this.position = inverseOffset; - } - } - - resolveUiRendered() { - this._uiResolve(); - } - - transformCanvasPosition(position) { - const rect = this.renderer.element.getBoundingClientRect(); - const topLeft = [rect.x, rect.y]; - const offset = Vector.sub(position, topLeft); - return Vector.div( - Vector.scale(offset, this._transformRatio), - this.scale, - ); - } - - get transformRatio() { - return this._transformRatio; - } - -} diff --git a/packages/physics/src/persea/traits/emitter/particle.jsx b/packages/physics/src/persea/traits/emitter/particle.jsx index 274fad1..519e143 100644 --- a/packages/physics/src/persea/traits/emitter/particle.jsx +++ b/packages/physics/src/persea/traits/emitter/particle.jsx @@ -4,7 +4,7 @@ import {join} from 'path'; import {EntityListView} from '@avocado/entity'; import {EntityController} from '@avocado/entity/persea'; -import {Stage} from '@avocado/graphics/persea'; +import {Stage} from '@avocado/graphics'; import {Number} from '@avocado/persea'; import {useJsonPatcher} from '@avocado/resource/persea'; import { diff --git a/packages/timing/src/persea/components/animation-visualization.jsx b/packages/timing/src/persea/components/animation-visualization.jsx index 638f677..1bd6b2a 100644 --- a/packages/timing/src/persea/components/animation-visualization.jsx +++ b/packages/timing/src/persea/components/animation-visualization.jsx @@ -2,8 +2,7 @@ import './animation-visualization.scss'; import {join} from 'path'; -import {Container} from '@avocado/graphics'; -import {Stage} from '@avocado/graphics/persea'; +import {Container, Stage} from '@avocado/graphics'; import {Vector} from '@avocado/math'; import {vectorPropType} from '@avocado/math/persea'; import {useProject} from '@avocado/persea'; diff --git a/packages/timing/src/persea/traits/animated/animation.jsx b/packages/timing/src/persea/traits/animated/animation.jsx index af55212..94bc621 100644 --- a/packages/timing/src/persea/traits/animated/animation.jsx +++ b/packages/timing/src/persea/traits/animated/animation.jsx @@ -2,8 +2,8 @@ import { Color, Container, Primitives, + Stage, } from '@avocado/graphics'; -import {Stage} from '@avocado/graphics/persea'; import { Vector, } from '@avocado/math';