Open aureole82 opened 9 years ago
I'm having the exact same issues and have to say the paperjs API is very confusing in this regard.
You have to point the global paper
object to whatever scope you're working with. Just using a constructor through the paper
object doesn't do that.
We could of course solve that with get accessor functions for each constructor that handles these switches, but it would add overheard...
You have to point the global paper object to whatever scope you're working with.
AFAIK, this is problematic if there are custom view events. For example, if there are two scopes (say scope1 and scope2), and you set scope1.view.onFrame, then it will re-assign the global variable paper
to be scope1
every time the event fires. jsfiddle.
It seems like relying on setting and using a global paper object is confusing, and can lead to unexpected outcomes. Since parts of the library reassign the global paper variable, it's hard to know when it might change.
Relatedly, because parts of the library use that variable, it produces the unintuitive scope behavior that OP mentions. Since items are methods of a PaperScope object, using that object (i.e. this
) rather than a global paper object in their constructor (e.g. here) might produce the behavior OP is looking for, and allow paper to be "imported" under a different name.
What do you think? I realize that paperjs is pretty extensive, so I'm sure I overlooked important cases where the global paper variable is set / used. Overall, however, it seems like this issue is very important for allowing paper to work in modern environments (e.g. var paper2 = require('paper');
).
Hey @lehni I just checked this with 0.22, and it still seems to be an issue.
The problem is that it seems that this makes paperjs almost useless when working with multiple canvases. And in modern env as @machow pointed out. Can you suggest a workaround in the meantime to work with multiple canvases?
Not sure if this is still relevant, but here is an example of 2 independent PaperScopes using js,
<!DOCTYPE html>
<html>
<head>
<style>
#myCanvas { background-color:blue; }
#myCanvas2 { background-color:red; }
</style>
<!-- Load the Paper.js library -->
<script type="text/javascript" src="paperjs-v0.11.3/dist/paper-full.js"></script>
<!-- Define inlined JavaScript -->
<script type="text/javascript">
paper.install(window);
var paper1, paper2;
var tool1, tool2;
window.onload = function() {
paper1 = new PaperScope();
paper.setup('myCanvas');
// Create a simple drawing tool:
tool1 = new Tool();
var path1;
// Define a mousedown and mousedrag handler
tool1.onMouseDown = function(event) {
path1 = new Path();
path1.strokeColor = 'white';
path1.add(event.point);
}
tool1.onMouseDrag = function(event) {
path1.add(event.point);
}
////////////////////////////////////////////
paper2 = new PaperScope();
paper.setup('myCanvas2');
// Create a simple drawing tool:
tool2 = new Tool();
var path2;
// Define a mousedown and mousedrag handler
tool2.onMouseDown = function(event) {
path2 = new Path();
path2.strokeColor = 'black';
path2.add(event.point);
}
tool2.onMouseDrag = function(event) {
path2.add(event.point);
}
}
</script>
</head>
<body>
<canvas id="myCanvas"></canvas>
<canvas id="myCanvas2"></canvas>
</body>
</html>
Ahh.. Nevermind, I then tried adding a rectangle to the first PaperScope, paper1, by pressing a button, but the rectangle appeared on the last view.
Conclusion: Paper.js does indeed require switching between scopes to work between different canvases. I think the above example worked because the tools were tied to the scopes upon creation.
@tomknappramos What specifically was the problem you encountered in your example? I tried it and it seemed to work OK?
Ahh... I think I might see what you're saying. I guess things can get tricky if you initialize your variables in the wrong order.
This is an issue that has been posted back in 2013. https://github.com/paperjs/paper.js/issues/234
Paper losing track of it's scope is not solved by the latest release (0.12.11). The problem manifests (for us) when we have multiple (4+) scopes and something async happens. E.g. A mouse event where we change the canvas or a promise coming back with map data to be drawn.
What does help is issuing a "scopeX.activate();" at the top of any handler before calling paper methods but I assume this could still break if web worker threads preempt each other.
https://stackoverflow.com/a/40690184/2856949
Can we up the priority and get a bonifide thread-safe fix?
Thanks!
Please up the priority for this issue. It makes Paper useless in context of frameworks like React where I would need multiple Paper canvas instances and where nothing is bound to window
object. Other React + Paper packages don't function well or don't have a good API. It shouldn't be this inconvenient to use multiple canvases. I don't understand the point of switching between scopes manually. They should be working independent of each other. p5.js
handles instance modes gracefully.
I have also issues with paperjs in React. Probably after components get unmounted. When remounted nothing is drawn on the new canvas. It does work when I put a one second delay before calling into my Paperscript code with window.myfunc() . It is very unclear to me what is happening.
I am having the same problems, I wanted to use Paper for multiple Vue Components as a tool to draw shared objects in multiple canvases, however right now it is very hard to do and not all solutions work very well...
It'd be great to get an example that shows this working in React. I'm able to run some simple examples that don't involve Point calculation. But, as soon as I try to do Point calcs, it is clear that PaperJS isn't properly loaded.
For instance, the Tadpoles example keeps throwing the following error.
I don't understand where new PaperScope().activate()
or what scope to use in order to activate it.
TypeError: Cannot assign to read only property 'length' of string 'NaN{ x: 0, y: 0 }NaN{ x: 0, y: 0 }{ x: 0, y: 0 }'
I also made the following hook, but it's honestly not extremely helpful at this point.
/**
* @file usePaperJS
* Helper to initial PaperJS
*/
import * as React from 'react';
import Paper from 'paper';
import { useLayoutEffect } from '@/hooks/useIsoLayoutEffect';
/**
*
* @param {object} ref is a reference to the PaperJS canvas
* @param {function} callback is a drawing function (PaperJS script)
* @returns
*/
export const usePaperJS = ({ ref, callback }) => {
const [project, setProject] = React.useState();
useLayoutEffect(() => {
if (!project && ref && ref.current) {
const canvas = ref.current;
Paper.install(window);
// Setup the canvas
Paper.setup(canvas);
const { project: p } = window.paper;
setProject(p);
callback();
}
}, [project, callback, ref]);
return project;
};
I also have the same problem. If I want to create multiple canvases on the same page, can there be a way to solve this problem? Thanks!
@scherbatsky-jr have you tried embedding canvas in a same origin iframe? With some postmessage facade to save/load documents from parent. Haven't tried paperjs for a long time, but that might work!
Hi
here I am again with my multiple canvases. Take a look at this snippet:
That works. But I have more than one canvas and I do the
scope.setup(..)
thing a the very beginning for all canvases and store the canvas objects for later usage. Only at the end I iterate over all initialized scopes and do the plotting part. Here's an example: http://jsfiddle.net/0gayvasu/The issue is everything I draw will be plotted on the last
PaperScope
I've calledscope.setup(..)
on. And not the scope where I callnew scope.Path.Rectangle(..)
.Here's my question: Is there an opportunity to draw items without using
scope.activate()
? Where is the sense of thePaperScope
if I only can draw to the active one? Always callingscope.activate()
in advance of eachnew scope.xyz()
call is quite challenging even I don't use loose coupling and callback handlers running in parallel.