Board index FlightGear Development Canvas

Event Click Listener on SVG element  Topic is solved

Canvas is FlightGear's new fully scriptable 2D drawing system that will allow you to easily create new instruments, HUDs and even GUI dialogs and custom GUI widgets, without having to write C++ code and without having to rebuild FlightGear.

Event Click Listener on SVG element

Postby omega95 » Sat Jul 26, 2014 12:44 am

For the A380 MFDs (known as mCDU in older Airbus aircraft and FMC in Boeing aircraft), I'm trying to make a custom widget-type system. (I would use the default widgets but they don't really have what I need it - and this looks really different)

So, what I'm doing is trying to set certain widget functions to svg elements on click.

Code: Select all
   obj_setfunc: {
      "click": func(object, svg_element, parent) {
         if(svg_element.getVisible()) {
            svg_element.addEventListener("click", object.function(me, parent));
         }
      }
                # More widget elements
   }


And I want to set these click listeners loaded from a separate hash. Like,
Code: Select all
var modes = {
   path: "/Aircraft/A380/Models/Instruments/MFD/modes.svg", # SVG Path
   svg: {}, # SVG Elements (must be empty)
   options: ["fms1", "fms2", "atc_com", "surv", "fcu_bkup"],
   objects: ["dropdown", "fms1_click", "fms2_click", "atc_com_click", "surv_click", "fcu_bkup_click", "flightnum", "fms_mode_box", "fms_mode_text", "msg_list"],
   widgets: [ # Widget Objects
      {
         element: "fms_mode_box",
         type: "click",
         function: func(mfd, parent) {
            # Open dropdown menu
            parent.svg["dropdown"].show();
            foreach(var obj; parent.objects) {
               parent.svg[obj~"_click"].show();
            }
            parent.svg["fms_mode_box"].setColorFill(220,220,220);
         }
      },

And so on...

From this function -
Code: Select all
# Load Permananent Section
      canvas.parsesvg(t.permObjects, t.modes.path, {'font-mapper':font_mapper});
      # Cache SVG Objects for use and load functions
      foreach(var svg_object; t.modes.objects) {
         t.modes.svg[svg_object] = t.permObjects.getElementById(svg_object);
      }
      foreach(var svg_object; t.modes.widgets) {
         t.obj_setfunc[svg_object.type](svg_object, t.modes.svg[svg_object.element], t.modes);
      }


But it doesn't seem to be working. I mean, the menu shows up fine on the canvas display (obviously, as it loads the svg) but it doesn't do anything when I click on the "fms_mode_box" element. It's supposed to call the listener function and show the drop down menu. So, what am I doing wrong here?

Thanks!

This is only for a permanaent MFD Mode dropdown menu, I need more of these with each page and menu.
Image
Image
Merlion Virtual Airlines - the experience of a flight time...
Get high quality aircraft, airports, video tutorials or development tools from my hangar.
omega95
 
Posts: 1223
Joined: Sat Jul 30, 2011 12:59 am
Location: -unknown-
Callsign: MIA0001, OM-EGA
IRC name: omega95
Version: 2.12 git
OS: Ubuntu 13.04

Re: Event Click Listener on SVG element

Postby Philosopher » Sat Jul 26, 2014 4:32 am

This is the error I can spot at the moment: missing a function closure for the callback.
Code: Select all
   obj_setfunc: {
      "click": func(object, svg_element, parent) {
         if(svg_element.getVisible()) {
            svg_element.addEventListener("click", func object.function(me, parent));
         }
      }
                # More widget elements
   }
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Event Click Listener on SVG element

Postby omega95 » Sat Jul 26, 2014 4:46 am

If the func was the only term missing, adding it doesn't really fix anything. :?
Merlion Virtual Airlines - the experience of a flight time...
Get high quality aircraft, airports, video tutorials or development tools from my hangar.
omega95
 
Posts: 1223
Joined: Sat Jul 30, 2011 12:59 am
Location: -unknown-
Callsign: MIA0001, OM-EGA
IRC name: omega95
Version: 2.12 git
OS: Ubuntu 13.04

Re: Event Click Listener on SVG element

Postby Philosopher » Sat Jul 26, 2014 5:07 am

Maybe you were hoping for more of these semantics? But I don't see an immediately effective difference here – because elements would be shown be default anyhow.
Code: Select all
   obj_setfunc: {
      "click": func(object, svg_element, parent) {
         svg_element.addEventListener("click", func if(svg_element.getVisible()) object.function(me, parent));
      }
                # More widget elements
   }
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Event Click Listener on SVG element

Postby Hooray » Sat Jul 26, 2014 8:37 am

But it doesn't seem to be working. I mean, the menu shows up fine on the canvas display (obviously, as it loads the svg) but it doesn't do anything when I click on the "fms_mode_box" element. It's supposed to call the listener function and show the drop down menu. So, what am I doing wrong here?


if in doubt, just add printlog/print statements to your event handling callbacks to see if they're invoked or not.
And please keep in mind that you need to set up your z-index properly, or the corresponding group may not even receive any events due to overlapping stuff.

I'm trying to make a custom widget-type system. (I would use the default widgets but they don't really have what I need it - and this looks really different)


actually, the best thing to do would be adding the missing widgets, e.g. a popup/combo menu, to $FG_ROOT/Nasal/canvas/gui/widgets and using a custom "style" for your A380.
Note that you can also use existing widgets (e.g. buttons) that way, without having to spend any time re-inventing the wheel.
The whole system is already designed such that it uses MVC, so there shouldn't be too much missing to make this work
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Event Click Listener on SVG element

Postby omega95 » Sat Jul 26, 2014 4:32 pm

and using a custom "style" for your A380.


It's not a general "button", or "label" - they look different and the text are placed different on each on too, so it doesn't make sense to make a universal "button" atm, it's just easier to have all the buttons on the SVG file and just link the click listeners.

Anyway, I'll try adding prints and seeing what happens.
Merlion Virtual Airlines - the experience of a flight time...
Get high quality aircraft, airports, video tutorials or development tools from my hangar.
omega95
 
Posts: 1223
Joined: Sat Jul 30, 2011 12:59 am
Location: -unknown-
Callsign: MIA0001, OM-EGA
IRC name: omega95
Version: 2.12 git
OS: Ubuntu 13.04

Re: Event Click Listener on SVG element

Postby omega95 » Sat Jul 26, 2014 6:57 pm

For some testing, I simplified the code into
Code: Select all
me.svg["fms_mode_static"].addEventListener("click", func {
         me.svg["dropdown"].show();
         foreach(var obj; me.options) {
            me.svg[obj~"_click"].show();
         }
         me.svg["fms_mode_box"].setColorFill(220,220,220);
         print("fms_mode_static - Function Called");
      });


But that makes it a little strange. It prints the "fms_mode_static - Function Called" string but doesn't do anything else in the function. :? What am I doing wrong here?
Merlion Virtual Airlines - the experience of a flight time...
Get high quality aircraft, airports, video tutorials or development tools from my hangar.
omega95
 
Posts: 1223
Joined: Sat Jul 30, 2011 12:59 am
Location: -unknown-
Callsign: MIA0001, OM-EGA
IRC name: omega95
Version: 2.12 git
OS: Ubuntu 13.04

Re: Event Click Listener on SVG element

Postby Hooray » Sat Jul 26, 2014 7:32 pm

that would suggest that your event listeners/handlers are properly set up and getting invoked - next, you need to change that your data structures are valid, too - i.e. check for shadowed variables (like me) - e.g. using debug.dump(), typeof() and id()
So far, without looking at the other code, I would guess that this is a closure issue - i.e. your me field is probably not what you want it to be - if in doubt, print/printlog some identifier to the console to see for yourself.
Do you understand closures ? Have you looked at the wiki docs ? It's easy to miss, I have posted buggy code like this, too - keep in mind that your listener will be invoked at a later time, so any variables used there, need to be "bound" and stored - or your callback will only ever refer to the reference of the last variable.

Subject: Nasal namespaces and callbacks
Philosopher wrote:The thing with a func{} expression is that it delays evaluation, so it can keep the proper syntax for the method call and therefore pass the correct me reference, which is preserved in its closure.

Subject: Segmentation fault on nasal interactions with the route man.Subject: Multiple event listeners from for loop

Hooray wrote:your function's callback cannot access the variable later on without first "saving it" inside a closure, see Philosoper's explanation at:
http://wiki.flightgear.org/Using_Nasal_ ... n_closures
http://flightgear.org/forums/viewtopic. ... re#p187744


TheTom wrote:You just pass a function to set timer, but not the object it needs to be called on. So the correct way is - like Hooray already said - to bind the object reference in a closure:
Code: Select all
settimer(func hello_task.stop(), 3);


For the sake of simplicity, you can easily work around such issues by directly using the call() API and its various "friends" :D
It surely will help you better understand the underlying technical issues.
I tend to use function generators for creating callbacks, so that the closure is created that way - I once wasted 15-20 minutes "debugging" such code (and looking at the C/C++ code !!), before I actually found the problem in my own Nasal code :lol:
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Event Click Listener on SVG element

Postby omega95 » Sat Jul 26, 2014 10:38 pm

Hmm, this is interesting - I can click on the left (capt_mfd) dropdown menu but the dropdown in shown on the right side (fo_mfd) menu.

Image

I suppose this means the object hasn't been instantiated properly - need to figure this out. :shock:
Merlion Virtual Airlines - the experience of a flight time...
Get high quality aircraft, airports, video tutorials or development tools from my hangar.
omega95
 
Posts: 1223
Joined: Sat Jul 30, 2011 12:59 am
Location: -unknown-
Callsign: MIA0001, OM-EGA
IRC name: omega95
Version: 2.12 git
OS: Ubuntu 13.04

Re: Event Click Listener on SVG element

Postby Hooray » Sat Jul 26, 2014 10:52 pm

this is interesting - I can click on the left (capt_mfd) dropdown menu but the dropdown in shown on the right side (fo_mfd) menu.

like I said several times previously, this would all suggest that you are making a simple closure mistake somewhere, and the callback is simply referencing the hash that got initialized last :D

If you don't understand the previous responses, you can see for yourself if that's the case by printing out some kind of identifier - even just adding a "name" field to each display will do, and then just do:
Code: Select all
print( me.name );


If I am right, you'll only ever see the 2nd display being accessed, which means that your callbacks are using variables that are not properly wrapped in a closure.
Last edited by Hooray on Sat Jul 26, 2014 10:56 pm, edited 1 time in total.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Event Click Listener on SVG element

Postby omega95 » Sat Jul 26, 2014 10:55 pm

Exactly, umm - I didn't really understand what Philosopher or you mean by a function closure. I was looking for missing '}'s but that can't be right as it would result in a parse error.
Merlion Virtual Airlines - the experience of a flight time...
Get high quality aircraft, airports, video tutorials or development tools from my hangar.
omega95
 
Posts: 1223
Joined: Sat Jul 30, 2011 12:59 am
Location: -unknown-
Callsign: MIA0001, OM-EGA
IRC name: omega95
Version: 2.12 git
OS: Ubuntu 13.04

Re: Event Click Listener on SVG element

Postby Hooray » Sat Jul 26, 2014 10:58 pm

another simple way to check if that's the case is to simply create a 3rd display, which should then be the one that's getting updated, instead of the 2nd one.

Regarding closures, please see the threads I linked to, and the wiki - I posted all those quotes and links for a reason :mrgreen:

If in doubt, just use a function generator for creating your callbacks dynamically, like I have demonstrated - that way, it's harder to make a mistake like this, believe me - been there more than once, and it was usually Philosopher pointing out that my code was making the exact same mistake ... :lol:

https://en.wikipedia.org/wiki/Closure_(computer_programming)

Again, here's the wiki link: http://wiki.flightgear.org/Using_Nasal_ ... n_closures

Obviously, we can only guess to fix this for you given the code that you've posted so far - so it's better to really understand the underlying issue, i.e. closures, anyway:
Code: Select all
var make_handler = func(me) return func {
         me.svg["dropdown"].show();
         foreach(var obj; me.options) {
            me.svg[obj~"_click"].show();
         }
         me.svg["fms_mode_box"].setColorFill(220,220,220);
         print("fms_mode_static - Function Called");
};

me.svg["fms_mode_static"].addEventListener("click", make_handler() );
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Event Click Listener on SVG element

Postby Philosopher » Sat Jul 26, 2014 11:39 pm

Function closures in 5 lines or less:
Code: Select all
var a = 9;
var f = func print(a);
f(); # 9
a = 10;
f(); #10


P.S. don't rely on any outer "me" variable – use a different name instead like "m".
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Event Click Listener on SVG element

Postby Hooray » Sat Jul 26, 2014 11:47 pm

note that I haven't tested the code, it was just intended as an example - and I agree that using "me" is unnecessarily confusing probably, using object would be less confusing - but would have involved more typing :oops:

And understanding anonymous functions is also useful in this context:

Code: Select all
# this creates an anonymous (unnamed) function and directly calls it:
(func () {
var x = 100;
print(x);
}
)();

# and here's the same thing using a variable:
(func (message) {
var x = 100;
print(message, x);
}
)( message:"Hello ");


Next, you only need to extend this to use function generators ...

Code: Select all
# a generator is a function that returns another function:
var generator = func(name) {
return func(action) {
 print("I am: ", name, " requested action is:", action);
 }
}

var et = generator("ET");
et("phone home");

var alf = generator("ALF");
alf("eat cat");
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Event Click Listener on SVG element

Postby omega95 » Sun Jul 27, 2014 12:49 am

Aha! Might take a while to properly understand this but I'm trying. :) Thank a lot!
Merlion Virtual Airlines - the experience of a flight time...
Get high quality aircraft, airports, video tutorials or development tools from my hangar.
omega95
 
Posts: 1223
Joined: Sat Jul 30, 2011 12:59 am
Location: -unknown-
Callsign: MIA0001, OM-EGA
IRC name: omega95
Version: 2.12 git
OS: Ubuntu 13.04

Next

Return to Canvas

Who is online

Users browsing this forum: No registered users and 1 guest