What does all the position properties and functions on a pixi.js sprite / DisplayObject actually do? You can access sprite.x, sprite.width, sprite.getBounds(), sprite.toLocal(), sprite.toGlobal(), sprite.getGlobalPosition(), sprite.getLocalBounds().
And how are they affected by scale, pivot, position and parent properties?
I was very confused with all the various ways to get positioning from PIXI.js sprites, and didn't find the documentation helpful, so I created an example, to help me get an overview (at the end of this post).
This example also creates a camera, that can be used to center the view on selectable sprites.
// Size of the rectangles
const rectSize = 10;
// Rotation of the rotated rectangle
const rotation = 45;
// Zoom level of the camera, higher is closer
const zoomLevel = 2;
// Resolution of the app
const resolution = 1;
// Create the pixi app
const app = new PIXI.Application({
width: 100,
height: 100,
backgroundColor: 0x000000,
interactive: true,
resolution: resolution
});
// HTML elements
const $body = $('body');
const $pixi = $('#pixi');
const $info = $('#info').find('tbody');
$pixi.append(app.view);
// Camera controls what we see
const camera = new PIXI.Container();
camera.scale.set(zoomLevel, zoomLevel);
app.stage.addChild(camera);
// Origin is the stage position - never move the stage
const origin = app.stage.position;
// Create some sprites
const rect = new PIXI.Graphics();
rect.beginFill(0xffffff);
rect.drawRect(0, 0, rectSize, rectSize);
const texture = app.renderer.generateTexture(rect);
const zeroedChild = PIXI.Sprite.from(texture);
const positionedChild = PIXI.Sprite.from(texture);
positionedChild.tint = 0xd83131
positionedChild.position.set(rectSize, rectSize);
const rotatedChild = PIXI.Sprite.from(texture);
rotatedChild.tint = 0x34d839;
rotatedChild.position.set(rectSize, rectSize);
rotatedChild.rotation = rotation * Math.PI / 180;
const scaledChild = PIXI.Sprite.from(texture);
scaledChild.tint = 0x4065d6;
scaledChild.position.set(rectSize, rectSize);
scaledChild.scale.set(2, 2);
const pivotedChild = PIXI.Sprite.from(texture);
pivotedChild.tint = 0xb637d6;
pivotedChild.position.set(rectSize, rectSize);
pivotedChild.pivot.set(pivotedChild.width / 2, pivotedChild.height / 2);
// Add all sprites to the camera
camera.addChild(zeroedChild, positionedChild, rotatedChild, scaledChild, pivotedChild);
updateInfo();
function updateInfo() {
$info.html('');
$info.append(info('Camera', camera, origin));
$info.append(info('Zeroed Child', zeroedChild, origin));
$info.append(info('Positioned Child', positionedChild, origin));
$info.append(info(`Rotated Child (${rotation})`, rotatedChild, origin));
$info.append(info('Scaled Child (2)', scaledChild, origin));
$info.append(info('Pivoted Child (center)', pivotedChild, origin));
}
function info(name, sprite, origin) {
const $row = $('<tr></tr>');
if (sprite.parent) {
if (!sprite.originalTint) {
sprite.originalTint = sprite.tint;
}
$row.on('mouseenter', () => {
const parent = sprite.parent;
sprite.tint = 0xf4ff2b;
parent.removeChild(sprite);
parent.addChild(sprite);
});
$row.on('mouseleave', () => {
sprite.tint = sprite.originalTint;
});
$row.on('click', () => {
centerOn(sprite);
sprite.parent.children.forEach((child) => {
child.tint = child.originalTint;
});
sprite.tint = 0xf4ff2b;
})
}
$row.append(`<td><b>${name}</b></td>`);
$row.append(`<td>(${r(sprite.x)}, ${r(sprite.y)})</td>`);
$row.append(`<td>(${r(sprite.toLocal(origin).x)}, ${r(sprite.toLocal(origin).y)})</td>`);
$row.append(`<td>(${r(sprite.toGlobal(origin).x)}, ${r(sprite.toGlobal(origin).y)})</td/>`);
$row.append(`<td>(${r(sprite.getGlobalPosition().x)}, ${r(sprite.getGlobalPosition().y)})</td>`);
$row.append(`<td> (${r(sprite.scale.x)}, ${r(sprite.scale.y)})</td>`);
$row.append(`<td>(${r(sprite.width)}, ${r(sprite.height)})</td>`);
$row.append(`<td>(${r(sprite.getBounds().x)}, ${r(sprite.getBounds().y)}) | w: ${r(sprite.getBounds().width)}, h: ${r(sprite.getBounds().height)})</td>`);
$row.append(`<td>(${r(sprite.getLocalBounds().x)}, ${r(sprite.getLocalBounds().y)}) | (${r(sprite.getLocalBounds().width)}, ${r(sprite.getLocalBounds().height)})</td></tr>`);
return $row;
}
function r(n) {
return Math.round(n * 100) / 100;
}
// Centers the camera on the given sprite
function centerOn(sprite) {
if (sprite === camera) {
camera.position.set(0, 0)
updateInfo();
return;
}
// Find the center of the renderer = canvas
const centerRendererX = (app.renderer.width / resolution) / 2;
const centerRendererY = (app.renderer.height / resolution) / 2;
// Get the bounds of the sprite
const bounds = sprite.getBounds();
// Get the current position of the camera
const cPos = camera.getGlobalPosition();
// The bounds of the sprite is affected by the position of the camera (parent)
// Subtract the camera position from the sprite position to put the sprite at it's original location
// Then center it in the renderer/canvas, and find the middle of the sprite
const x = centerRendererX - ((bounds.x - cPos.x) + bounds.width / 2);
const y = centerRendererY - ((bounds.y - cPos.y) + bounds.height / 2);
camera.position.set(x, y);
updateInfo();
}
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
font-size: 13px;
font-family: courier;
}
b {
display: block;
font-size: 15px;
width: 100%;
text-align: center;
}
#info {
width: 100%;
border: 1px solid #fff;
color: #fff;
background-color: #000;
}
#info td {
border: 1px solid #fff;
}
#info tr:hover {
cursor: default;
background-color: #252525;
color: red !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.7.0/pixi.min.js"></script>
<table id="info">
<thead>
<tr>
<th>Name</th>
<th>(x, y)</th>
<th>toLocal(stage)</th>
<th>toGlobal(stage)</th>
<th>getGlobalPosition()</th>
<th>scale</th>
<th>width/height</th>
<th>getBounds()</th>
<th>getLocalBounds()</th>
</tr>
</thead>
<tbody></tbody>
</table>
<div id="pixi">
</div>
(Source)