Paperscope and paperjs - javascript

So I am trying to create a project with two canvas elements, each with its own paperscript, and with buttons on the outside of each that control certain functions within both.
Under the documentation under Paperscript, it says:
Please note:
When including more than one PaperScript in a page, each script will run >in its own scope and will not see the objects and functions declared in >the others. For PaperScript to communicate with other PaperScript or >JavaScript code, see the tutorial about PaperScript Interoperability.
... which is unfortunate because that tutorial reads as follows:
Coming very soon!
I've gotten stuck very quickly in this process. I've tried putting functions in global scope, calling them from outside their canvas, and seeing them print on the wrong canvas. I've tried exporting functions via a module and it seems to run the function (?!?!). And worst, the 'paper.projects' object is an array with one(!) project in it, the first canvas.
So I'm stumped.
Anyone know how to do this?
EDIT: So apparently there is this answer but I don't see how that gets me being able to call functions in the PaperScript scope from global scope scripts.
That just seems like a script to call global functions in the PaperScope, which doesn't work for me if I'm trying to make outside buttons do things.
Clearly I'm missing something.
SECOND EDIT: I have played around with various global functions, either in window.global or just sitting by themselves with no var declaration... but what seems to happen is that when I try to call a function which I have defined, say as:
globals.makecircle = function () {
var o = new Path.Circle({
radius: 50,
center: new Point (200,200)
})
}
in the main scope, it will just as soon run in the wrong window as the correct window. Also there is an incredible delay before it runs which I can't figure out.
THIRD EDIT: For clarity.
I have firstcanvas.js attached to canvas1 in my HTML, I have secondcanvas.js attached to canvas2. Both are referenced as paperscript type, as:
<script type="text/paperscript" src="scripts/firstcanvas.js" canvas="canvas1"></script>
<script type="text/paperscript" src="scripts/secondcanvas.js" canvas="canvas2"></script>
I create window.globals object as Jurg suggests. I call it from main.js with a button, such as:
window.globals = {}
`$('document').ready($('#dfs').on('click', window.globals.makecircle))`
I add this function to globals in firstcanvas.js as above.
If I have most recently clicked on canvas2, clicking on the button with id='DFS' will cause the function to run, extremely delayed, on canvas2.
And paper.projects does not list both projects, so I can't use the activate() functions.

Okay! SOLVED!!!
Here's how to reference/activate PaperScript-created scopes from the global scope. Although there is no user-accessible array of scopes (that I know of), PaperScope.get(id) will retrieve them. For some reason I find PaperScope.get(0) already populated, and my two canvas/PaperScript elements actually referring to scopes with ids 1 and 2.
Therefore:
pscope1 = PaperScope.get(1)
pscope2 = PaperScope.get(2)
Then, in any function where I want to do something on my first canvas:
pscope1.activate()
// cool paper.js graphics stuff
pscope1.view.update()
The last line is because paper.js won't automatically update a view that the user is not interacting with.
Thanks to Jurg Lehni for the hint to use .activate().
PS Make sure that your paperscript objects are created before using PaperScope.get. I used good 'ol JQuery $('document').ready() for this...
PPS Another little hit from Jurg Lehni himself: Inside a PaperScript, this will point to the current scope. You could use that and store it in the global object.

Related

When in the Chrome Debugger, is there anyway to reference data or functions inside an anonymous function block?

I'm trying to debug something live on a customer website and my code is all inside an anonymous function block. I don't know if there's anyway to reach that code to execute functions or look at variables in there. I can't put a breakpoint either because this code is dynamically generated each time the page is refreshed and the breakpoint doesn't stick.
(function() {
var Date = "14 September 2022 14:44:55"; // different every refresh for example
var Holder = {
var Items = {
item1: "Value1",
item2: "Value2"
};
function getItem(name) {
return Items[name];
};
function setItem(name, value) {
Items[name] = value;
};
setTimeout(DoSomething(), 2000);
})();
That's not the actual code, just a bare minimum example to illustrate the problem.
Is there anyway to get reach getItem() or Items?
Without a breakpoint that code probably runs to completion then POOF it's all gone anyway.
Redefine setTimeout
If it really is the case that the code inside the anonymous function calls other browser methods, you might be able to insert a detour at runtime that you can then put a breakpoint on.
For this to work, you will need to be able to inject new code into the page before the anonymous code, because there's no other way to invoke the IIFE.
Your example code uses setTimeout, so here's what I would try to insert:
let realSetTimeout = window.setTimeout
window.setTimeout = (...args) => {
debugger
return realSetTimeout(...args)
}
Lots of unrelated code might be calling setTimeout, in which case this could break the page or just make debugging really tedious. In that case, you might make it only debug if one of the setTimeout args has a value that's used in your example, e.g.:
// only break for our timeout
if(args[1] === 2000) debugger
Something like that might not trigger for only your code, but it would hugely reduce the number of other codepaths that get interrupted on their journey through the commonly-used browser capability.
Alternatively, use Charles Proxy to rewrite the body of the HTML page before it enters your browser. You could manually insert a debugger call directly into the anonymous function. Charles is not free, but I think they have a demo that might let you do this. If you do this professionally, it's probably a good purchase anyway. Your employer might even pay for the license.
If you can't use Charles (or a similar tool), you could instead set up a local proxy server using Node which does the rewrite for you. Something like that might only take an hour to throw together. But that is a bigger task, and deserves its own question if you need help with that.
No unfortunately.
The variables inside of the anonymous object are created in a scope which is inaccessible from the outside.
One of the main benefits of using a closure!
You’ll have to find a way to insert your own code inside of it by modifying the function that is generating those objects. If you can’t do that, then you’ll have to take the fork in the road and find another way.

Javascript local scopes and using objects - best practice?

I am currently working on large projects that make use of lots of javascript files.
I then start learning of using local scopes and using objects.
What I do not really understand is how to call them into you local scope?
E.g if I create an object in an local scope in file-a, how can I use them as in a function in the document.ready scope file-b?
I get that you can find this online, but I get demotivation by the high amount of javascript on the internet and can't really find good examples or material. Any help?
Not sure,but I think you might be referring to the use of namespaces within JavaScript as a way to avoid adding all your functions to the main window object.
The Ugly Way
Let's assume you have 3 functions related to cats:
Function AddCat(cat) {
}
Function DeleteCat(catId) {
}
Function BreedCat(cat,cat) {
}
The way these items are coded, they are globally available. Not only does that clutter up your window object, it's hard to share data between these functions in a discreet way.
As long as this js file is loaded, any function in your app can call these functions just by calling AddCat()
Cleaner
To solve that problem, we could create a Cats object that acts as a "namespace" here:
Cats = {
AddCat: function(cat) {
},
DeleteCat: function(catId) {
},
BreedCat: function(cat,cat) {
}
}
Now, you've only added ONE object to the windows class: Cats. In addition, other methods in your web app can call any of those 3 items by calling Cats.AddCat() for example.
This lets you encapsulate all of the Cat data in your entire system within a single "namespace, so it's easier to read.
This can get a lot more detailed. By encapsulating items like this, you can start to hide variables that all your cat routines require from the rest of your code.
There is an excellent set of resources on this type of namespacing (including tons of detail) here and here with links that lead you deeper.
Is that what you were looking for?

Function Undefined: Must a javascript function be defined within the same file?

I've got a file notifications.js containing one event bound to an element, and a function updateNotification(). This function uses jQuery to update certain elements on the page when a JSON object is passed as a parameter.
The problem:
I'm attempting to call this function within the page (via <script> tags), however rather than calling it, it breaks the page. I did some digging around within the Chrome Developer Console (not sure of the name), and an error is flagged:
/pleaseshare/views/install/:50 Uncaught ReferenceError:updateNotification is not defined
However, when I pan within the console, I can clearly see the file notifications.js listed under scripts, and the function is defined there. If I define the function within the current scope (e.g. the line above the call), it works fine.
What I've tried
The function contains some javascript that requires jQuery, so I've attempted both with and without encasing it in $(document).ready( function() {});, with neither seeming to have any affect.
I'm pretty stumped.
For good measure, here's a link to show the structure of my javascript and html: http://snippi.com/s/znk6xe9
Any help in figuring out why this is happening, or explanations of why javascript functions cannot be called cross-file (although I'd hope this isn't the case), would be greatly appreciated ;)!!
A function cannot be called unless it was defined in the same file or one loaded before the attempt to call it.
A function cannot be called unless it is in the same or greater scope then the one trying to call it.
You code looks like the structure should work, but is clearly a reduced test case that has been reduced to the point where it won't.
Got it working. The issue was definitely multi-faceted, but I figured it out.
First off the use of RequireJS had an impact on updateNotification(), in that it couldn't be called cross-file, and was therefore considered undefined. I assume this because of how RequireJS loads files, and I'll look into the documentation later (and post an edit if I find anything relevant).
Secondly, updateNotification() would again be considered undefined when encased within jQuery's DOM ready loader $(document).ready(function(){}). However updateNotification() contains executions which require jQuery, so I had to encase the contents of the function in $(document).ready(function(){}).
This is an issue very unique to RequireJS/jQuery, hence why in most use cases this wouldn't occur.
Side note: The tags are edited to reflect this.
you need to import your script into your page:
<script type="text/javascript" language="javascript" src="path/to/notifications.js"></script>
This needs to be added above the <script> tag that calls updateNotification()
Functions do not need to be declared in the same file. In fact, avoiding having every declaration dumped into the global namespace is usually a concern in JavaScript.
In the sample code in the link you provided, updateNotification is declared as a global, so there should not be a scoping problem.
However, in the same sample, you don't show notifications.js being included. You need to import it using a <script></script> element and that element must come before the script element that includes the call to updateNotification. You also must include jQuery before notifications.js, since it uses jQuery. So you need something like:
<body>
// One or two elements
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="notifications.js"></script>
<script type="text/javascript">
$(document).ready( function() {
var json = {status : 'ok', message: 'Hello'};
updateNotification(json);
});
</script>
// All other elements
</body>

jquery tmpl in a closure

i am working on this little javascript library and following various suggestions i am wrapping my functionality in a closure for the various reasons (encapsulation of variables, hidding of code and so on). since I query a JSON webservice and display the results I also use the jquery tmpl engine.
I think I understand what closures are good for but I sure don't understand them in general. meaning I get totally lost between all those scope changes and whatnot. especially annoying is this exception I get. consider the following code (a simplified ugly version of the code in question, but it reproduces the problem)
// something would be the object that handles all the library functionality
var something = function(){
// creating a local function that goes as a parameter into the Array.filter
function isBar(data){
return data.name === "bar";
}
// the template code
var bla = "<h1>${name}<\h1><h2>${attribute.filter(isBar)[0].value}</h2>";
// precompiling the the template
$.template("test", bla);
// and returning a function that should render the template with the provided data
return {
funny: function(){
$.tmpl("test", [{"name":"Fo", "attribute":[{"name":"bar", "value":"how"}]},
{"name":"Foo", "attribute":[{"name":"fnord","value":"can"}]},
{"name":"Fooo", "attribute":[{"name":"bar","value":"this"}]},
{"name":"Foooo", "attribute":[{"name":"Bar", "value":"be"}]}
]);
}
}
}();
// calling the function
something.funny();
So when calling the something.funny() I would the following expect to happen: the function funny, being a closure gets called in its original context (e.g. the function isBar and the variable bar are defined). So when I call $.tmpl I hoped that attribute.filter(isBar) within the template would also be in this scope. but it isn't. I Chrome i get ReferenceError: isBar is not defined.
If someone would be so nice to show me the error of my ways I would be very happy.
edit oops I missed the "()".
OK, well the problem is that those references to the local variables in the closure are not really references to local variables - they're part of a string. The template code has to parse that string, so when it does that the fact that there was a function called "isBar()" in the closure from where "$.tmpl()" was called really doesn't matter; jQuery can't access them because you just can't do that in JavaScript.
You can, however, pass in an "options" third parameter to "$.tmpl()" and provide extra stuff there. I'm not 100% sure how to do it as I've only played with the template plugin a little bit, but I'll try a jsfiddle when I have a chance. I think that you'd basically do something like this:
funny: function(){
$.tmpl("test", [{"name":"Fo", "attribute":[{"name":"bar", "value":"how"}]},
{"name":"Foo", "attribute":[{"name":"fnord","value":"can"}]},
{"name":"Fooo", "attribute":[{"name":"bar","value":"this"}]},
{"name":"Foooo", "attribute":[{"name":"Bar", "value":"be"}]}
], { isBar: isBar });
}
What I'm not sure of is whether you refer to that as "${isBar()}" or "${item.isBar()}" inside the template text.

Google Website Optimiser Control Javascript

Could someone explain the javascript that makes up Google's Website Optimiser Control script? Specifically: the first two lines, which seem to be empty functions, and why is the third function wrapped parentheses () ?
As far as I can tell this script is basically writing out a new <script> which presumably loads something for A/B testing.
function utmx_section(){}
function utmx(){}
(function() {
var k='0634742331',d=document,l=d.location,c=d.cookie;
function f(n) {
if(c) {
var i=c.indexOf(n+'=');
if (i>-1) {
var j=c.indexOf(';',i);
return escape(c.substring(i+n.length+1,j<0?c.length:j))
}
}
}
var x=f('__utmx'),xx=f('__utmxx'),h=l.hash;
d.write('<sc'+'ript src="'+'http'+(l.protocol=='https:'?'s://ssl':'://www')+'.google-analytics.com'+'/siteopt.js?v=1&utmxkey='+k+'&utmx='+(x?x:'')+'&utmxx='+(xx?xx:'')+'&utmxtime='+new Date().valueOf()+(h?'&utmxhash='+escape(h.substr(1)):'')+'" type="text/javascript" charset="utf-8"></sc'+'ript>')
}
)();
I've attempted to step through with the firebug debugger but it doesn't seem to like it. Any insights much appreciated.
Many thanks
inside anonymous function it shortens names of document and cookies inside it at first, function f(n) gets value of cookie under name n. Then Google reads its cookies and with help of d.write it loads its scripts (as I see they are related to Google Analytic). This way it makes On-Demand JavaScript loading... Actually you load these scripts all the time, Google just needs some additional parameters in url, so this is done this way - save parameters in cookie, which next time are used to get script again.
And finally back to the first two magic lines :) After Google loads its script (after executing d.write), there are some functions which uses utmx and utmx_section, as well as definition of these functions, or better to say overriding. I think they are empty at first just because another function can execute it before its real definition, and having empty functions nothing will happen (and no JS error), otherwise script would not work. E.g. after first iteration there is some data, which is used to make real definition of these functions and everything starts to work :)
The first 2 functions are in fact empty, and are probably overridden later on.
The third function is an anonymous self-executing function. The brackets are a convention to make you aware of the fact that it is self executing.
the "f" function looks up the value given to it in the document's cookies and returns it. Then a new script tag is written to document (and requested from server) with these values as part of its URL.

Categories

Resources