2019-04-19 00:50:15 -05:00
|
|
|
import {Proton} from './proton';
|
|
|
|
|
|
|
|
import {Vector} from '@avocado/math';
|
|
|
|
|
|
|
|
export class TextNode {
|
|
|
|
|
|
|
|
constructor(text) {
|
2019-04-21 19:24:45 -05:00
|
|
|
this.lastAlpha = undefined;
|
|
|
|
this.lastColor = undefined;
|
|
|
|
this.lastPosition = undefined;
|
|
|
|
this.lastAngle = undefined;
|
|
|
|
this.lastScale = undefined;
|
2019-04-21 14:58:11 -05:00
|
|
|
this.parent = null;
|
|
|
|
const wrapper = window.document.createElement('div');
|
|
|
|
this.wrapper = wrapper;
|
|
|
|
wrapper.style.position = 'absolute';
|
2019-04-19 00:50:15 -05:00
|
|
|
const div = window.document.createElement('div');
|
2019-04-21 14:58:11 -05:00
|
|
|
wrapper.appendChild(div);
|
2019-04-19 00:50:15 -05:00
|
|
|
div.className = 'particle';
|
|
|
|
const span = window.document.createElement('span');
|
|
|
|
span.className = 'text';
|
|
|
|
span.textContent = text;
|
|
|
|
this.span = span;
|
|
|
|
div.appendChild(span);
|
|
|
|
this.div = div;
|
|
|
|
}
|
|
|
|
|
2019-04-21 14:58:11 -05:00
|
|
|
copyFrom(other) {
|
|
|
|
this.span.textContent = other.span.textContent;
|
2019-04-19 00:50:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
update(particle, stage) {
|
|
|
|
const {div, span} = this;
|
2019-04-21 14:58:11 -05:00
|
|
|
if (particle.useAlpha) {
|
2019-04-21 19:24:45 -05:00
|
|
|
const alpha = Math.floor(256 * particle.alpha) / 256;
|
|
|
|
if (this.lastAlpha !== alpha) {
|
|
|
|
div.style.opacity = alpha;
|
|
|
|
this.lastAlpha = alpha;
|
|
|
|
}
|
2019-04-21 14:58:11 -05:00
|
|
|
}
|
|
|
|
if (particle.useColor) {
|
|
|
|
const color = particle.color;
|
2019-04-21 19:24:45 -05:00
|
|
|
color.r = Math.floor(255 * color.r) / 255;
|
|
|
|
color.g = Math.floor(255 * color.g) / 255;
|
|
|
|
color.b = Math.floor(255 * color.b) / 255;
|
|
|
|
if (
|
|
|
|
!this.lastColor
|
|
|
|
|| this.lastColor.r !== color.r
|
|
|
|
|| this.lastColor.g !== color.g
|
|
|
|
|| this.lastColor.b !== color.b
|
|
|
|
) {
|
|
|
|
div.style.color = `rgb(
|
|
|
|
${color.r * 255},
|
|
|
|
${color.g * 255},
|
|
|
|
${color.b * 255}
|
|
|
|
)`;
|
|
|
|
this.lastColor = {
|
|
|
|
r: color.r,
|
|
|
|
g: color.g,
|
|
|
|
b: color.b,
|
|
|
|
};
|
|
|
|
}
|
2019-04-21 14:58:11 -05:00
|
|
|
}
|
2019-04-21 19:24:45 -05:00
|
|
|
let transformsChanged;
|
2019-04-19 00:50:15 -05:00
|
|
|
const camera = stage.camera;
|
2019-04-20 02:15:04 -05:00
|
|
|
const position = [particle.p.x, particle.p.y];
|
2019-04-19 00:50:15 -05:00
|
|
|
if (camera) {
|
2019-04-20 02:15:04 -05:00
|
|
|
const realOffset = camera.realOffset;
|
2019-04-19 00:50:15 -05:00
|
|
|
position[0] -= realOffset[0];
|
|
|
|
position[1] += realOffset[1];
|
|
|
|
}
|
2019-04-21 20:37:01 -05:00
|
|
|
position[0] = Math.round(position[0] * 4) / 4;
|
|
|
|
position[1] = Math.round(position[1] * 4) / 4;
|
2019-04-21 19:24:45 -05:00
|
|
|
if (
|
|
|
|
!this.lastPosition
|
|
|
|
|| this.lastPosition[0] !== position[0]
|
|
|
|
|| this.lastPosition[1] !== position[1]
|
|
|
|
) {
|
|
|
|
transformsChanged = true;
|
|
|
|
this.lastPosition = position;
|
|
|
|
}
|
|
|
|
const angle = Math.floor(1440 * (particle.rotation.x / (Math.PI * 2))) / 1440;
|
|
|
|
if (this.lastAngle !== angle) {
|
|
|
|
const normalAngle = (360 + angle * 360) % 360;
|
|
|
|
transformsChanged = true;
|
|
|
|
this.lastAngle = angle;
|
|
|
|
}
|
|
|
|
let scale = particle.scale;
|
|
|
|
scale += particle.p.z > 0 ? particle.p.z / 70 : 0;
|
|
|
|
scale = Math.floor(100 * scale) / 100;
|
|
|
|
if (this.lastScale !== scale) {
|
|
|
|
transformsChanged = true;
|
|
|
|
const spanTranslate = 50 * (1 / particle.scale);
|
|
|
|
span.style.transform = `translate(-${spanTranslate}%, -${spanTranslate}%)`;
|
|
|
|
this.lastScale = scale;
|
|
|
|
}
|
|
|
|
if (transformsChanged) {
|
|
|
|
const transforms = [];
|
|
|
|
const normalAngle = (360 + this.lastAngle * 360) % 360;
|
|
|
|
transforms.push(`translate(${this.lastPosition[0]}px, ${-this.lastPosition[1]}px)`);
|
|
|
|
transforms.push(`rotate(${normalAngle}deg)`);
|
|
|
|
transforms.push(`scale(${this.lastScale})`);
|
|
|
|
div.style.transform = transforms.join(' ');
|
|
|
|
}
|
2019-04-19 00:50:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
export class TextNodeRenderer extends Proton.BaseRender {
|
|
|
|
|
2019-04-22 14:06:12 -05:00
|
|
|
static clearFreeList() {
|
|
|
|
this._freeList = [];
|
|
|
|
}
|
|
|
|
|
2019-04-21 14:58:11 -05:00
|
|
|
static get freeList() {
|
|
|
|
if (!this._freeList) {
|
|
|
|
this._freeList = [];
|
|
|
|
}
|
|
|
|
return this._freeList;
|
|
|
|
}
|
|
|
|
|
2019-04-19 00:50:15 -05:00
|
|
|
constructor(selector, stage) {
|
|
|
|
super();
|
2019-04-19 23:11:57 -05:00
|
|
|
this._body = new TextNode('');
|
2019-04-19 00:50:15 -05:00
|
|
|
this.name = 'NodeRenderer';
|
|
|
|
this.queued = [];
|
|
|
|
this.stage = stage;
|
2019-04-20 21:35:07 -05:00
|
|
|
const promise = stage.findUiElement(selector);
|
|
|
|
promise.then((element) => {
|
2019-04-22 14:36:39 -05:00
|
|
|
if (this.parent) {
|
|
|
|
const freeList = this.constructor.freeList;
|
|
|
|
while (freeList.length > 0) {
|
|
|
|
const node = freeList.pop();
|
|
|
|
this.parent.removeChild(node);
|
|
|
|
}
|
|
|
|
}
|
2019-04-20 21:35:07 -05:00
|
|
|
this.parent = element;
|
2019-04-19 00:50:15 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onParticleCreated(particle) {
|
2019-04-21 14:58:11 -05:00
|
|
|
const freeList = this.constructor.freeList;
|
|
|
|
if (freeList.length > 0) {
|
|
|
|
particle.target = freeList.pop();
|
|
|
|
// ...
|
|
|
|
if (particle.body) {
|
|
|
|
particle.target.copyFrom(particle.body);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!particle.body) {
|
|
|
|
particle.body = this._body.clone();
|
|
|
|
}
|
|
|
|
particle.target = particle.body;
|
|
|
|
particle.target.wrapper.style.opacity = 0;
|
2019-04-19 00:50:15 -05:00
|
|
|
}
|
|
|
|
if (!this.parent) {
|
2019-04-21 14:58:11 -05:00
|
|
|
this.queued.push(particle.target);
|
2019-04-19 00:50:15 -05:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (let i = 0; i < this.queued.length; ++i) {
|
2019-04-21 14:58:11 -05:00
|
|
|
this.parent.appendChild(this.queued[i].wrapper);
|
|
|
|
this.queued[i].parent = this.parent;
|
|
|
|
this.queued[i].wrapper.style.opacity = 1;
|
|
|
|
}
|
|
|
|
this.queued = [];
|
|
|
|
if (!particle.target.parent) {
|
|
|
|
this.parent.appendChild(particle.target.wrapper);
|
|
|
|
particle.target.parent = this.parent;
|
2019-04-19 00:50:15 -05:00
|
|
|
}
|
2019-04-21 14:58:11 -05:00
|
|
|
particle.target.wrapper.style.opacity = 1;
|
2019-04-19 00:50:15 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onParticleUpdate(particle) {
|
|
|
|
if (!particle.target) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
particle.target.update(particle, this.stage);
|
|
|
|
}
|
|
|
|
|
|
|
|
onParticleDead(particle) {
|
2019-04-21 14:58:11 -05:00
|
|
|
particle.target.wrapper.style.opacity = 0;
|
|
|
|
const freeList = this.constructor.freeList;
|
|
|
|
freeList.push(particle.target);
|
2019-04-19 00:50:15 -05:00
|
|
|
particle.target = undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|