Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Raster image is off-center after fit-to-page zooming in Paper.js

I'm working on a Paper.js application that puts a raster (an image) in the view. Then it zooms to fit the image so that all of it is visible at one time. It's mostly working, but the image ends up offset, like this:

offset

When it should look more like this:

enter image description here

Here's the code that makes the view, adds the image, and makes the call to zoom to fit:

// Set up HTMLImage
var image = new Image(this.props.image.width, this.props.image.height);
image.src = 'data:image/png;base64,' + this.props.image.imageData;

//var canvas = React.findDOMNode(this.refs.canvas); // React 0.13 +
var canvas = this.refs.canvas.getDOMNode();

// Scale width based on scaled height; canvas height has been set to the height of the document (this.props.height)
var scalingFactor = canvas.height/image.height;
canvas.width = image.width * scalingFactor;

// Initialize Paper.js on the canvas
paper.setup(canvas);

// Add image to Paper.js canvas
var raster = new paper.Raster(image, new paper.Point(0,0));

// Fit image to page so whole thing is displayed
var delta = scalingFactor < 1 ? -1 : 1; // Arbitrary delta (for determining zoom in/out) based on scaling factor
var returnedValues = panAndZoom.changeZoom(paper.view.zoom, delta, paper.view.center, paper.view.center, scalingFactor);
paper.view.zoom = returnedValues[0];

And here is the panAndZoom.changeZoom method:

SimplePanAndZoom.prototype.changeZoom = function(oldZoom, delta, centerPoint, offsetPoint, zoomFactor) {
    var newZoom = oldZoom;
    if (delta < 0) {
        newZoom = oldZoom * zoomFactor;
    }
    if (delta > 0) {
        newZoom = oldZoom / zoomFactor;
    }

    var a = null;
    if(!centerPoint.equals(offsetPoint)) {
        var scalingFactor = oldZoom / newZoom;
        var difference = offsetPoint.subtract(centerPoint);
        a = offsetPoint.subtract(difference.multiply(scalingFactor)).subtract(centerPoint);
    }

    return [newZoom, a];
};

Any idea why it zooms to fit but loses the centering?

like image 202
Scotty H Avatar asked Oct 07 '15 21:10

Scotty H


1 Answers

TL;DR

Use either, but not both:

  • After the zoom:

      paper.view.setCenter(0,0);
    
  • When pasting the image:

      var raster = new paper.Raster(image, new paper.Point(canvas.width/2, canvas.height/2));
    

The long answer

As a disclaimer, I must point out I have no knowledge of paper.js and their documentation looks seemingly terrible. This answer is born from fiddling.

I more or less replicated your code and after some tinkering, I managed to fix the issue by using this:

paper.view.zoom = returnedValues[0];
paper.view.setCenter(0,0);

If you wonder why I'm not pointing at the documentation for setCenter, it's because I couldn't find any. I discovered that method by inspecting paper.view.center.

Although I wasn't satisfied as I could not understand why this would work. As such, I kept looking at your code and noticed this:

// Add image to Paper.js canvas
var raster = new paper.Raster(image, new paper.Point(0,0));

The documentation for raster tells us the following:

Raster

Creates a new raster item from the passed argument, and places it in the active layer. object can either be a DOM Image, a Canvas, or a string describing the URL to load the image from, or the ID of a DOM element to get the image from (either a DOM Image or a Canvas).

Parameters:

source: HTMLImageElement / HTMLCanvasElement / String — the source of the raster — optional

position: Point — the center position at which the raster item is placed — optional

My understanding is that the image is pasted on the canvas with its center at position 0,0, also known as the top left corner. Then the content of the canvas is resized, but based on its own center position. This pulls the image closer to the center of the canvas, but there is still a discrepancy.

Setting the center to 0,0 simply synchronizes the center points of both the image and the canvas.

There is also an alternative way, which is to paste the image at the current center of the canvas, which seems more proper:

// Add image to Paper.js canvas
var raster = new paper.Raster(image, new paper.Point(canvas.width/2, canvas.height/2));

Here is the rudimentary JSFiddle to experiment.

like image 76
spenibus Avatar answered Oct 19 '22 21:10

spenibus