paperjs / paper.js

The Swiss Army Knife of Vector Graphics Scripting – Scriptographer ported to JavaScript and the browser, using HTML5 Canvas. Created by @lehni & @puckey
http://paperjs.org
Other
14.5k stars 1.23k forks source link

Large number for view center or zoom level, mess up strokes #460

Closed popara closed 9 years ago

popara commented 10 years ago

Hi,

Consider following example

var C = new Point(1, 1);

var p = new Path.Circle(C, 50/view.zoom);
p.fillColor = "red";
p.strokeColor = "blue";
p.strokeWidth = 3;
p.dashArray = [20, 10];

view.center = C;

produces following output screen shot 2014-04-27 at 11 23 40 am

but if for center put big numbers, like so:

var C = new Point(75778181.39572601, 49055387.11405588);

var p = new Path.Circle(C, 50/view.zoom);
p.fillColor = "red";
p.strokeColor = "blue";
p.strokeWidth = 3;
p.dashArray = [20, 10];

view.center = C;

produces this: screen shot 2014-04-27 at 11 27 36 am

Similar problem happens if I zoom too much.

lehni commented 10 years ago

What browser are you experiencing this on? And what value are you using for view.zoom in the second example?

popara commented 10 years ago

Chrome, latest. Zoom level is 1 in all cases.

I am playing in http://sketch.paperjs.org

also, check this out, when I try to "normalize" point by some amount, I get this:

var C = new Point(75778181.39572601, 49055387.11405588);
// NORMALISATION? :)
C = C - 75778181;

var p = new Path.Circle(C, 50/view.zoom);
p.fillColor = "red";
p.strokeColor = "blue";
p.strokeWidth = 3;
p.dashArray = [20, 10];

view.center = C;

screen shot 2014-04-27 at 11 57 02 am

My original intention is to create overlay over google maps, and big numbers and big decimals come from the need for precision.

If there is anyway to help to resolve this issue, I would gladly do it [only after I get with this deadline :) ]

popara commented 10 years ago

Also, same thing happens if I have points that are within 256 range, but with big floating precision, and big zoom level [tens of thousands];

lehni commented 10 years ago

Crazy stuff.... I need to investigate this, might be a canvas limitation?

lehni commented 10 years ago

It gets more extreme with larger values. The distortion is not the same across browsers, but it's always there:

var center = new Point(750000000, 5000000);
var path = new Path.Circle({
    center: center,
    radius: 50,
    fillColor: "red",
    strokeColor: "blue",
    strokeWidth: 3,
    dashArray: [20, 10]
});

view.center = center;

http://sketch.paperjs.org/#S/XU/LCsIwEPyVsKcKpfhAhIgH6Q8IHjwYDzFZSWhMJE0tUvrvpiT24F52dmYYZgew/IlA4dxgEApKEE5O95t7ItAG9ORALPbk5LQNxW67TFOSjBZ7Zifziwf1s0ZY1doLg8XALImTomjeZSI9l7praUzKxEMbUzvjopGBR8kgC23wrsFZupsO/7SLlkFRssmk5K06es8/lFzXsexqeWN2nLrGthr7av4tgSjA+AU=

lehni commented 10 years ago

Using paper.js' ProxyContext.js, I get these Canvas drawing commands:

ctx.clearRect(0, 0, 1433, 795);
ctx.save();
    ctx.transform(1, 0, 0, 1, -757780395, -4905133);
    ctx.save();
        ctx.globalAlpha = 1;
        ctx.transform(1, 0, 0, 1, 0, 0);
        ctx.save();
            ctx.globalAlpha = 1;
            ctx.transform(1, 0, 0, 1, 0, 0);
            ctx.beginPath();
            ctx.moveTo(757781061, 4905530);
            ctx.bezierCurveTo(757781061, 4905502.385762508, 757781083.3857625, 4905480, 757781111, 4905480);
            ctx.bezierCurveTo(757781138.6142375, 4905480, 757781161, 4905502.385762508, 757781161, 4905530);
            ctx.bezierCurveTo(757781161, 4905557.614237492, 757781138.6142375, 4905580, 757781111, 4905580);
            ctx.bezierCurveTo(757781083.3857625, 4905580, 757781061, 4905557.614237492, 757781061, 4905530);
            ctx.closePath();
            ctx.fillStyle = "rgb(255,0,0)";
            ctx.strokeStyle = "rgb(0,0,255)";
            ctx.lineWidth = 3;
            ctx.lineJoin = "miter";
            ctx.lineCap = "butt";
            ctx.miterLimit = 10;
            ctx.setLineDash([20,10]);
            ctx.lineDashOffset = 0;
            ctx.fill("nonzero");
            ctx.shadowColor = "rgba(0,0,0,0)";
            ctx.stroke();
        ctx.restore();
    ctx.restore();
ctx.restore(); 
lehni commented 10 years ago

And if I take these values, subtract the transformation and factor in the view centering, I get the normal values for the circle bezier curves:

var hor = -757780395;
var ver = -4905155;

var lists = [
    [757781061, 4905530],
    [757781061, 4905502.385762508, 757781083.3857625, 4905480, 757781111, 4905480],
    [757781138.6142375, 4905480, 757781161, 4905502.385762508, 757781161, 4905530],
    [757781161, 4905557.614237492, 757781138.6142375, 4905580, 757781111, 4905580],
    [757781083.3857625, 4905580, 757781061, 4905557.614237492, 757781061, 4905530]
];

var center = view.size / 2;
hor -= center.width;
ver -= center.height;

for (var i = 0; i < lists.length; i++) {
    var list = lists[i];
    for (var j = 0; j < list.length; j += 2) {
        console.log(list[j] + hor, list[j + 1] + ver);
    }
}

Results:

-50 0
-50 -27.614237491972744
-27.614237546920776 -50
0 -50
27.614237546920776 -50
50 -27.614237491972744
50 0
50 27.614237491972744
27.614237546920776 50
0 50
-27.614237546920776 50
-50 27.614237491972744
-50 0 
lehni commented 10 years ago

I'm pretty sure this a limitation of the internal precision of the canvas. I know Skia uses fixed point arithmetics, perhaps the other implementations do the same. Not sure what can be done here... The best solution to fixing this is probably to finish the work on the SVG backend. But maybe SVG has similar limitations?

popara commented 10 years ago

I guessed that this can't be easily fixed.
I've made a wrapper, offsetting all values so they fall in acceptable range.

Close it if you feel helpless :)

lehni commented 10 years ago

Yeah I don't think we can fix this reasonably inside the library. But I'm keeping it open for a bit, as a reminder that we need an SVG backend :)