Jump to content

Beginner - Using PIXI.Matrix to perform zoom has strange initial behavior


Recommended Posts


The code is available here https://jsbin.com/hazogar/edit?html,js,output

What I do not understand is that initial behavior is not correct, past the first zoom, it will jump/jag then be proper to zoom to a point of the object.

I am zooming content inside container, so what am I missing ?

var initZoom = function(app, objectDocument) {
  var inZoomMode = true;
  var content = objectDocument.view;
  var container = objectDocument.board;
  var scale = { x: content.scale.x, y: content.scale.y };
  var zoom = function(x, y, isZoomIn) {
    var globalPosition = app.renderer.plugins.interaction.eventData.data.global;
    if (!globalPosition) {
    var containerPosition = container.toLocal(globalPosition, app.stage);
    var contentPosition = content.toLocal(containerPosition, container);
    var direction = isZoomIn ? 1 : -1;
    var factor = (1 + direction * 0.01);
    var nextScaleX = content.scale.x * factor;
    var nextScaleY = content.scale.y * factor;
    var p = contentPosition;
    console.debug('>> P', p.x, p.y);
    var mat = new PIXI.Matrix();
    mat.translate(-p.x, -p.y);
    mat.scale(nextScaleX, nextScaleY);
    mat.translate(p.x, p.y);
  documentView.on('mousewheel', function(e, delta) {
    if (!inZoomMode) {
    zoom(e.clientX, e.clientY, delta > 0);

Thank you!

Link to comment
Share on other sites

content.pivot.set(0, 0);

That one helps if you put it before calculation of contentMousePosition . 

We also need to add something to compensate pivot change.

This is code from one of my projects. I fix the global point that wont move in local coords - push it, and then pop it.

class CameraMover extends PIXI.Container {
memCoord = new PIXI.Point();
memCoord2 = new PIXI.Point();

pushPivot(pos) {
	this.toLocal(pos, null, this.memCoord);

popPivot(pos) {
	this.toLocal(pos, null, this.memCoord2);
	this.pivot.x -= this.memCoord2.x - this.memCoord.x;
	this.pivot.y -= this.memCoord2.y - this.memCoord.y;

//somewhere else

You can do the same thing, and in that case you wont need to set pivot to zero.

Link to comment
Share on other sites

:) absolute beginner with PIXI, yes, had solid flash background a while ago, miss it very much!

I love PIXI so far, but how I arrived at this is through known patterns, I wanted to try CreateJS but the community of PIXI is unbeatable, these two projects should actually join hands!

Coming back, why can't one do this directly on display objects ?

node.pivot.set(downLocation.x, downLocation.y);
node.scale.set(scaleX, scaleY);
node.pivot.set(0, 0);

I have tried with transformation matrix, but it was still not working after introducing the content.pivot.set(0, 0)

Thank you Ivan, very useful information, I do not use ES6 so I had to extend that container a bit different, hopefully nothing wrong with it:

var ZoomableContainer = (function() {
  var ct = function() {
  ct.prototype.constructor = ct;
  ct.prototype = Object.create(PIXI.Container.prototype);
  ct.prototype.pushPivot = function(pos) {
    if (!this.memCoordinates) {
      this.memCoordinates = new PIXI.Point();
    this.toLocal(pos, null, this.memCoordinates);
  ct.prototype.popPivot = function(pos) {
    var coordinates = new PIXI.Point();
    this.toLocal(pos, null, coordinates);
    this.pivot.x -= coordinates.x - this.memCoordinates.x;
    this.pivot.y -= coordinates.y - this.memCoordinates.y;
  return ct;

And then I use it as you instructed, in the end I have managed to have this code working, I was unable to compute the new positions, but found a formula to get the delta according to zoom level:

var inZoomMode = true;
var initZoom = function(app, content ) {
  var level = 1;
  var amount = 1.1;
  var zoomTo = function(level, p) {
    content.scale.x *= level;
    content.scale.y *= level;
    content.x -= (p.x - content.x) * (level - 1);
    content.y -= (p.y - content.y) * (level - 1);
  documentView.on('mousewheel', function(e, delta) {
    if (!inZoomMode) {
    var globalData = app.renderer.plugins.interaction.eventData.data;
    if (!globalData || !globalData.global) {
    var zoomIn = delta > 0;
    var zoomFactor = zoomIn ? amount : (1 / amount);
    zoomTo(zoomFactor * level, globalData.global);

The zoomTo function inside the init zoom is all there is (I am using jquery-mousewheel to normalize mouse delta)

PS: The forum does not let me save code as JavaScript



Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...