how to target a MovieClip with createjs - javascript

Im trying to export an group photo animation that works fine in flash but not when exported in html5 canvas.
The trick is "simple" : each photo is a button and when you roll your mouse over the picture of someone, his jobtitle appears.
Ican't make it happen with createjs !
I have a MovieClip instance on my stage named "jobs_cont" whose timeline has different keyframes and labels for everyone's jobtitles.
The thing is i'm not successfull with targeting "jobs_cont" and using gotoAndPlay a specific frame or label in its timeline when a button is hovered.
the "alert instruction" alone is recognised but not the "jobs_cont.gotoAndPlay":
var frequency = 3;
stage.enableMouseOver(frequency);
this.mybutton.addEventListener("mouseover", fl_MouseOverHandler);
function fl_MouseOverHandler(){
this.jobs_cont.gotoAndPlay("mylabel");
alert("hovered by mouse");
// end of your personalized code
}
I think i must miss something targeting "jobs_cont" in createjs but i'm newbie in javascript and can't figure it out despite my day of researches.
If someone could give a hint.
Thank you.

You are dealing with scope issues. If you define a function on your timeline using the above syntax, the function doesn't have a scope, so this becomes Window.
You can change the function syntax to be defined on the current object:
this.fl_MouseOverHandler = function(){
this.jobs_cont.gotoAndPlay("mylabel");
alert("hovered by mouse");
// end of your personalized code
}
Lastly, JavaScript doesn't automatically provide function scope for event listeners (yet!) so you have to scope the function yourself. If you have a version 0.7.0 or later of EaselJS, you can use the on method instead of addEventListener (docs). Note that you have to use this.fl_MouseOverHandler as well.
this.mybutton.on("mouseover", this.fl_MouseOverHandler, this);
You can also scope the function using a utility method such as Function.prototype.bind() (docs):
this.mybutton.addEventListener("mouseover", this.fl_MouseOverHandler.bind(this));
Hope that helps!

Related

Nasaworldwind Web: Removing/reassigning a clickRecognizer with different callback

Good Afternoon,
There seems to not be a lot of documentation/examples using Nasa's worldwind api especially the web version. So say I have...
let clickRecognizer = new WorldWind.ClickRecognizer(wwd, clickHandler);
where wwd is the name of my WorldWind Canvas/Window and clickHandler is the function called on click. I just want to know if anyone know how do I remove this ClickRecognizer() once I add it? I have tried assigning a new ClickRecognizer() to clickRecognizer variable and setting it to null then assigning but it made no difference; the first/original clickHandler function is being used.
In short I am trying to switch between ClickRecognizer that uses different clickHandler functions but the change isn't reflected when I click (I verified that the variable (let clickRecognizer) is changed and the gestureCallbacks array (see docs) is correctly populated with the second clickHandler function).
Here are the docs, I tried using removeListener(clickHandler) to no avail.
(This isn't my actual code (ofcourse) I just wrote the question generally)
Thanks

What does window.__context do?

I know it’s usually better to answer these questions with a google search, but I can’t seem to find it anywhere online. I wrote a function for creating a GlowScript canvas and adding it to an inputted div. I based it off of the code given on the website with some changes. Here is the function (it won't run on here because you need to import libraries, but it does create a 3D shape and put it in the div):
make_box("my_div")
function make_box(my_div){
window.__context = {glowscript_container: document.getElementById(my_div)}
var scene = canvas();
// create some shapes:
box( {pos:vec(.25,-1.4,0), size:vec(4.8,.3,2.5), color:color.red} )
}
I think the first line is required to add the canvas to the div. Without the line, I get the error:
Uncaught TypeError: Cannot set property ‘canvas_selected’ of undefined
I don’t really understand what it’s doing, however, and what the window context means. Does anyone have any insight into the line? Thanks!
This is what I found when I searched for window and context separately via google.
Apparently window is an object and .__context is a version of this. More information can be found in the links below.
https://www.w3schools.com/js/js_window.asp
https://towardsdatascience.com/javascript-context-this-keyword-9a78a19d5786

How to re-evaluate a script that doesn't expose any global in a declarative-style component

I have been writing a reusable script, let's call it a plugin although it's not jQuery, that can be initialised in a declarative way from the HTML. I have extremely simplified it to explain my question so let's say that if a user inserts a tag like:
<span data-color="green"></span>
the script will fire because the attribute data-color is found, changing the color accordingly.
This approach proved very handy because it avoids anyone using the plugin having to initialise it imperatively in their own scripts with something like:
var elem = document.getElementsByTagName('span')[0];
myPlugin.init(elem);
Moreover by going the declarative way I could get away without defining any global (in this case myPlugin), which seemed to be a nice side effect.
I simplified this situation in an example fiddle here, and as you can see a user can avoid writing any js, leaving the configuration to the HTML.
Current situation
The plugin is wrapped in a closure like so:
;(function(){
var changeColor = {
init : function(elem){
var bg = elem.getAttribute('data-color');
elem.style.background = bg;
}
};
// the plugin itslef looks for appropriate HTML elements
var elem = document.querySelectorAll('[data-color]')[0];
// it inits itself as soon as it is evaluated at page load
changeColor.init(elem);
})();
The page loads and the span gets the correct colour, so everything is fine.
The problem
What has come up lately, though, is the need to let the user re-evaluate/re-init the plugin when he needs to.
Let's say that in the first example the HTML is changed dynamically after the page is loaded, becoming:
<span data-color="purple"></span>
With the first fiddle there's no way to re-init the plugin, so I am now testing some solutions.
Possible solutions
Exposing a global
The most obvious is exposing a global. If we go this route the fiddle becomes
http://jsfiddle.net/gleezer/089om9z5/4/
where the only real difference is removing the selection of the element, leaving it to the user:
// we remove this line
// var elem = document.querySelectorAll('[data-color]')[0];
and adding something like (again, i am simplifying for the sake of the question):
window.changeColor = changeColor;
to the above code in order to expose the init method to be called from anywhere.
Although this works I am not satisfied with it. I am really looking for an alternative solution, as I don't want to lose the ease of use of the original approach and I don't want to force anyone using the script adding a new global to their projects.
Events
One solution I have found is leveraging events. By putting something like this in the plugin body:
elem.addEventListener('init', function() {
changeColor.init(elem);
}, false);
anybody will be able to just create an event an fire it accordingly. An example in this case:
var event = new CustomEvent('init', {});
span.dispatchEvent(event);
This would re-init the plugin whenever needed. A working fiddle is to be found here:
http://jsfiddle.net/gleezer/tgztjdzL/1/
The question (finally)
My question is: is there a cleaner/better way of handling this?
How can i let people using this plugin without the need of a global or having to initialise the script themselves the first time? Is event the best way or am I missing some more obvious/better solutions?
You can override Element.setAttribute to trigger your plugin:
var oldSetAttribute = Element.prototype.setAttribute;
Element.prototype.setAttribute = function(name, value) {
oldSetAttribute.call(this, name, value);
if (name === 'data-color') {
changeColor.init(this);
}
}
Pros:
User does not have to explicitly re-initialize the plugin. It will happen automatically when required.
Cons:
This will, of course, only work if the user changes data-color attributes using setAttribute, and not if they create new DOM elements using innerHTML or via some other approach.
Modifying host object prototypes is considered bad practice by many, and for good reasons. Use at your own risk.

Any Way to Change JS on the Fly using web console?

Actually i wanted to debug one of the JS Function, but i dont have access to that file. is there any way to put alert inside the function through Web Console. i cannot use break point here is because those function are mosueover and mouse out. so when i even move my mouse pointer a lil, it breaks.
Without direct access to that function, there isn't much you can do.
If you have global access to it you can create a hook.
var original = myFunction;
myFunction = function() {
alert("something");
return original();
}
Or, you could clear the bound event handlers and bind your own.
element.removeEventListener("mouseover", myFunction);
element.addEventListener("mouseover", myDebugFunction);
Find the source code, add a debug point on corresponding line. Then, bring the mouse on the element.
But since, production js files are generally minified and uglified, it may not be possible.
There is a debugger is inbuilt in a browser. Practice using it.
Also, you could try switching off the mouse events from the element and then attach a new function in console. Play with it, by commenting out lines. This way you could change the code on the fly.
Something like this :
$("<myElement>").off().on(function() {
// Line 1 of original function
// Line 2 of original function
// Line 3 of original function
// ...
});

Trouble with calling javascript function within another using D3

I'm learning to use D3.js for some visualization ideas I have and I'm running into something that is probably quite easy and perhaps solely a javascript thing.
I want to call a function from within another function. I have created a basic scatter plot and want to reload it with new data points. Here is the JSFiddle. I'm really quite stumped!
I think in it's simplest form it looks like this:
function firstFunction() {
var something;
}
function secondFunction() {
firstFunction();
}
But it seems to sometimes works sometimes not and can't figure out why.
What's happening is that, in jsfiddle, the default is to encapsulate everything in a function that runs on window load. The code looks like this: window.onload=function(){your stuff}
When you try to set the onload, the code structure is then structured like this:
function firstFunction(){
function secondFunction(){
do stuff
}
}
onload = secondFunction;
The issue is that secondFunction is not accessible outside the scope of firstFunction. This is called variable scoping, and coding would suck without it.
The way to solve this issue is to move your onload assignment to the javascript block. I'd recommend the built in d3 way of doing this: d3.select('button').on('click',newScatter); here I'm selecting the button and adding a click event handler. This works because there is only one button, but it would be better to give the button a class or id and use that in d3.select().
If you do that, your code will still not work, but that's because you delete the SVG element that's supposed to contain the scatter plot in newScatter() (this line: elem.parentNode.removeChild(elem);). The button, however, will successfully do what you told it to do and delete your scatter plot.
I've created a working version of your fiddle here.

Categories