import * as PIXI from 'pixi.js';
import '@pixi/graphics-extras';
const app = new PIXI.Application({
antialias: true,
background: '#1099bb',
});
document.body.appendChild(app.view);
class Projector extends PIXI.DisplayObject
{
constructor()
{
super();
this.content = new PIXI.Container();
this.originalTransform = new PIXI.Matrix();
this.boundary = new PIXI.EventBoundary(this.content);
this.boundary.copyMouseData = (from, to) =>
{
PIXI.EventBoundary.prototype.copyMouseData.call(this.boundary, from, to);
this.worldTransform.applyInverse(to.global, to.global);
to.target = this.boundary.hitTest(to.global.x, to.global.y);
};
[
'pointerdown',
'pointerup',
'pointermove',
'pointerover',
'pointerout',
'wheel',
].forEach((event) =>
{
this.addEventListener(event, (e) => this.boundary.mapEvent(e));
});
this.eventMode = 'static';
}
get cursor()
{
return this.boundary.cursor;
}
set cursor(value)
{
throw new Error('The camera\'s cursor is derived from its content!');
}
calculateBounds()
{
const contentBounds = this.content.getBounds();
this._bounds.addFrameMatrix(
this.worldTransform,
contentBounds.x,
contentBounds.y,
contentBounds.width,
contentBounds.height,
);
}
containsPoint(point)
{
return !!this.boundary.hitTest(point.x, point.y);
}
render(renderer)
{
renderer.batch.flush();
const projectionSystem = renderer.projection;
const renderTextureSystem = renderer.renderTexture;
projectionSystem.transform = projectionSystem.transform
|| new PIXI.Matrix();
projectionSystem.transform.copyTo(this.originalTransform);
projectionSystem.transform.append(this.worldTransform);
projectionSystem.update(null, null, 1, !renderTextureSystem.current);
this.content.render(renderer);
renderer.batch.flush();
projectionSystem.transform.copyFrom(this.originalTransform);
projectionSystem.update(null, null, 1, !renderTextureSystem.current);
}
updateTransform()
{
super.updateTransform();
this.content.enableTempParent();
this.content.updateTransform();
this.content.disableTempParent(null);
}
}
const projector = app.stage.addChild(new Projector());
projector.content.addChild(
new PIXI.Graphics()
.lineStyle({ color: 0, alpha: 0.2, width: 2 })
.moveTo(0, -300)
.lineTo(0, 600)
.moveTo(-100, 0)
.lineTo(700, 0),
);
const stars = [1, 2, 3].map((i) => new PIXI.Graphics()
.beginFill(0xffffff, 0.75)
.drawStar(0, 0, 18 / i, 100 * i / 2));
stars[0].x = 0;
stars[1].x = 200;
stars[2].x = 500;
projector.content.addChild(...stars);
projector.x = 100;
projector.y = 300;
projector.content.hitArea = new PIXI.Rectangle(-100, -300, app.screen.width, app.screen.height);
projector.hitArea = projector.content.hitArea;
projector.content.eventMode = 'static';
stars.forEach((star) =>
{
star.eventMode = 'static';
star.cursor = 'zoom-in';
star.addEventListener('wheel', (e) =>
{
const scroll = Math.sign(e.deltaY) * Math.min(15, Math.abs(e.deltaY));
star.rotation += scroll / 100;
});
star.addEventListener('click', (e) =>
{
if (star.scale.x === 1)
{
star.scale.set(1.33);
star.cursor = 'zoom-out';
}
else
{
star.scale.set(1);
star.cursor = 'zoom-in';
}
});
});
PIXI.BitmapFont.from('coordinates', {
fontFamily: 'Roboto',
fontSize: 16,
fill: '#272d37',
}, { chars: ['Global:() Screen-.,', ['0', '9']] });
const coordinates = new PIXI.BitmapText('Global: (0, 0)\nScreen: (0, 0)', {
fontName: 'coordinates',
});
coordinates.x = 110;
coordinates.y = 550;
app.stage.addChild(coordinates);
projector.content.addEventListener('pointermove', (e) =>
{
const global = `(${e.global.x | 0}, ${e.global.y | 0})`;
const screen = `(${e.screen.x | 0}, ${e.screen.y | 0})`;
coordinates.text = `Global: ${global}\nScreen: ${screen}`;
});
const description = new PIXI.Text(
'The (0, 0) world coordinates for the content is located at the center of the first star!'
+ '\n * Mouse wheel over stars to rotate them'
+ '\n * Click to zoom in or out', {
fontSize: 16,
fontFamily: 'Roboto',
fill: '#272d37',
},
);
description.position.set(110, 12);
app.stage.addChild(description);