Avoiding conflicts with multiple canvas elements in the same page

2,737 views
Skip to first unread message

Zack Grossbart

unread,
Dec 26, 2011, 5:53:55 PM12/26/11
to Paper.js
Hello Everyone,

I'm working on an application which create multiple canvas elements in
the same page and uses Paper.js to draw on each. I need to create
these with JavaScript, but they I draw on them with PaperScript like
this:

paper.setup(document.getElementById('mycanvas1'));
paper.evaluate(paperScript1);

paper.setup(document.getElementById('mycanvas2'));
paper.evaluate(paperScript2);

Everything works fine when I draw for the first time, but if I switch
back and forth or resize the window I see the contents which should be
in one canvas draw in the other.

Is there some other way I can force these two to separate so I don't
get the drawings in the wrong place?

Thanks,
Zack

Jürg Lehni

unread,
Dec 27, 2011, 5:41:10 AM12/27/11
to pap...@googlegroups.com
An accessible test-case online would be handy, thanks.

Jürg

Zack Grossbart

unread,
Dec 27, 2011, 8:56:27 AM12/27/11
to Paper.js
I posted a simple test case at:

http://zgrossbart.github.com/multipaper

Just resize the page to see the issue.

Thanks,
Zack

Jürg Lehni

unread,
Dec 27, 2011, 9:36:14 AM12/27/11
to pap...@googlegroups.com
Thanks for the example. I just looked into it and found multiple issues with using Paper in this way.

The first is easier to understand: By using paper.setup / evaluate directly, you're bypassing the mechanism that creates a PaperScope object per script, thus you end up reusing the same scope for both scripts, and evaluate the 2nd script into it, over the first one. The first time this is executed, it is fine, since the sequence of calling setup / evaluate works. But once callbacks are called (e.g. resize), it is messed up, because the references to view / canvas have been overridden.

This can be solved by creating a new PaperScope and associating it with the global paper variable, before using it:

paper = new paper.PaperScope();

The other issue is that when using jQuery callbacks rather than Paper ones, the variable pointing to the active scope, which is the same as the global paper variable, does not get updated. There is no clean solution to this right now, but the easiest workaround is setting paper to the view's associated scope:


$(window).resize(function() {
paper = view._scope;
doLayout();
});

I think I will put this into a View#activate() method, which you can call on any such handler that requires the view and its associated scope to be addressed.

Jürg

Zack Grossbart

unread,
Dec 27, 2011, 9:52:34 AM12/27/11
to Paper.js
That worked perfectly. Thank you for the help. I suspected the
scopes were getting mixed up.

By the way... you might be curious why I'm doing this. I'm
integrating Paper.js into a new product which is written in GWT. The
web UI is basically one very complex page which dynamically loads the
portions it needs. I need to delay loading of the PaperScript files
until they are actually needed to improve performance.

I need to interact with the drawings from GWT code. I do that by
exposing JavaScript functions from PaperScript and calling them from
GWT. This makes it possible to create hybrid UI which contains DOM
elements managed by GWT and Paper.js drawings interacting with them.

I'd be happy to give a demo in a couple of months when then product
comes into a more general release.

-Zack

tfor...@gmail.com

unread,
Jan 15, 2012, 2:14:34 PM1/15/12
to Paper.js
Thank you very much for paper.js !

I am going to use it in a large project based on jQuery where I also
extend the user interface when needed by loading js code and creating
widgets on the fly..
In short, I would like to create interactive widgets based on <canvas>
elements and managed by paper.js as easily as possible.
But the paper DOM is not yet really clear in my mind, mainly about
interactions between canvas elements, PaperScopes and Views. Why one
paperscope is not really attached to one canvas ?
I don't intend to use PaperScript but pure object oriented JavaScript.

Would it be possible to have an API like this:

var ps = new paper.PaperScope(); // or new
paper.PaperScope(canvas);
ps.setup(canvas);
var path = new paper.Path(); // or new ps.Path(); ?
ps.strokeColor = 'black';
...
ps.view.draw(); // or ps.draw() ?

The goal is to keep ps in an object (this.ps = ps) and to reuse it
when needed, always attached to the same canvas.

Another thing I don't really understand for now is the actual role of
"paper" in JavaScript mode: it's a global variable for a particular
PaperScope and also a sort of namespace for constructors of paper
Objects. It's probably usefull for PaperScript but quite confusing in
js.

Do you plan to add some explanations about this subjects in the doc ?

Thanks again.

Thierry Forgeard

Zack Grossbart

unread,
Feb 14, 2012, 11:07:51 PM2/14/12
to Paper.js
Hey Guys,

I'm running into this same issue on a new project my wife is writing,
but this one is all in JavaScript. When I fixed this with PaperScript
I had to add this to my PaperScript:

paper = view._scope;

What's the equivalent in JavaScript? You can see the code here:
https://github.com/maryvogt/paperpiechart.

This library is creating a jQuery plugin for writing pie charts in
Paper.js. It has two charts in my page. At first they load
correctly, but if you press the first button and then the second you
will see both pie charts draw on one canvas.

Is working with view._scope the right way to fix this, or should I do
something else to make sure these two canvas tags stay separate? I'm
already making to use a different paper scope for each of them.

Thanks,
Zack

Zack Grossbart

unread,
Feb 15, 2012, 2:42:23 PM2/15/12
to Paper.js
I figured out how to make this work. I'm storing the scope in jQuery
data for the canvas object. Then before I draw I call this:

paper = obj.data("paperscope");

That sets up the paper variable properly and each drawing shows up in
the right canvas.

Thanks,
Zack

Bruce MacNaughton

unread,
Oct 24, 2013, 1:02:42 PM10/24/13
to pap...@googlegroups.com
This makes a lot of sense to me. Being able to keep my own PaperScope list and invoking methods from the appropriate PaperScope would be a fantastic solution.

I use paper from Javascript and it is not clear what context is being used at any given time, what sets the global context, nor what is associated with a given context.

I've ended up approaching multiple canvases with multiple projects as opposed to multiple PaperScopes. My javascript code (an excerpt) looks like:

        ps0 = new paper.PaperScope();
        paper.setup(document.getElementById("canvas1"));
        paper.setup(document.getElementById("canvas2"));

        tool = new paper.Tool();

        tool.onMouseUp = function (e) {
            var canvas = e.event.toElement.id;
            var view = paper.View._viewsById[canvas];
            if (!view)
                return;
            view._project.activate();
            var c = new paper.Path.Circle(e.point, 10);
            c.strokeColor = 'black';
            c.strokeWidth = 4;
            paper.view.draw();
        }

I have to use paper's internal data structures to map the element back to the view back to the project but the approach is relatively straightforward.

But it seems like Thierry's approach is quite a bit cleaner and doesn't require any usage of paper's private data.
Reply all
Reply to author
Forward
0 new messages