• Which the release of FS2020 we see an explosition of activity on the forun and of course we are very happy to see this. But having all questions about FS2020 in one forum becomes a bit messy. So therefore we would like to ask you all to use the following guidelines when posting your questions:

    • Tag FS2020 specific questions with the MSFS2020 tag.
    • Questions about making 3D assets can be posted in the 3D asset design forum. Either post them in the subforum of the modelling tool you use or in the general forum if they are general.
    • Questions about aircraft design can be posted in the Aircraft design forum
    • Questions about airport design can be posted in the FS2020 airport design forum. Once airport development tools have been updated for FS2020 you can post tool speciifc questions in the subforums of those tools as well of course.
    • Questions about terrain design can be posted in the FS2020 terrain design forum.
    • Questions about SimConnect can be posted in the SimConnect forum.

    Any other question that is not specific to an aspect of development or tool can be posted in the General chat forum.

    By following these guidelines we make sure that the forums remain easy to read for everybody and also that the right people can find your post to answer it.

MSFS Flashing light or label

Messages
425
Country
france
I am working on a gauge developed in JavaScript. I now need to have a flashing label and I don't know how to do this...
I used to work in C++ in the past (fs9/FSX/P3D) and I was using the ELPASED_SECONDS variable that was increased every 1/18 second. It was easy, I just had to use this timer to show the label every 0.5 second only, which was resulting in a flashing label.
Today, I don't find the equivalent of this variable in the Simvars available with MSFS and couldn't find any equivalent variable for the same effect. Maybe I can use the setInterval JavaScript function, but I am not sure this would be the most elegant solution, I'd rather base the flashing timer on the FS time.
Any idea to do this?

Thanks,
Eric
 
Messages
122
Country
unitedkingdom
The simple solution is use SimVar.GetSimVarValue("E:ABSOLUTE TIME", "seconds"); - it sounds like that's all you need to know, but for completeness:

In the html you have something like :

Code:
<div id="mylabel"></div>
<div id="mylabel_flash"></div>

The CSS has the usual
Code:
#mylabel {
     position: absolute;
     left: 400px; /* i.e. whatever positions your two divs over each other in the right place */
     top: 33px;
     width: 40px;
     height: 40px;
    overflow: hidden;
    background-image: url("/Pages/VCockpit/Instruments/your_plane/mylabel_background.png");
    background-repeat: no-repeat;
    display: block;
}

#mylabel_flash {
     same as above but with:
    background-image: url("/Pages/VCockpit/Instruments/your_plane/mylabel_background_flash.png");
    background-repeat: no-repeat;
    display: none;
}

The in the JS you have:

Code:
connectedCallback() {
    super.connectedCallback();
    ...
    this.mylabel_el = document.getElementById("mylabel");
    this.mylabel_flash_el = document.getElementById("mylabel_flash");
}

Update () {
    // Call simvar request in Update() and share between sub-procedures
    this.TIME_S = SimVar.GetSimVarValue("E:ABSOLUTE TIME", "seconds");

   // Call each sub-procedure for their 'update' stuff
    this.update_mylabel();
}

update_mylabel() {
    if (this.mylabel_time_s == null || this.TIME_S - this.mylabel_time_s > 0.5) {
        // here you toggle this.mylabel_flash_el.style.display between "block" and "none"
        ...
      this.mylabel_time_s = this.TIME_S;
    }
}

I usually only display=block|none the 'highlighted' version of the element, and leave the non-highlighted one as display: block. and rely on the element z-ordering to have the desired effect - obviously this depends on your actual content and you might end up toggling two divs on/off, not just the top one.

Re "E:ABSOLUTE TIME" - there are multiple uses for this in FSX --- in MSFS you have to be a bit more careful (the gauge update cycle is in a different thread from the underlying sim, so ABSOLUTE TIME isn't locked to the millisecond of the actual flight simvar update) but there are no issues at all for your requirement. Asobo has other (unannounced I think) simvar time variables that more accurately give you the exact millisecond delta between updates but for this requirement you don't need those. Even though E:ABSOLUTE TIME isn't in the MSFS SDK, Asobo's gauge code uses it absolutely everywhere so I think we're pretty safe.
 
Messages
425
Country
france
Thank you, this is exactly what I need. It doesn't need to be accurate by the millisecond, it is just for a flashing signal so it is perfect.
I have access to the exact delta time between updates because it is provided as a parameter on the 'onUpdate' function of the class I use, that derives from BaseAIrliners. But using ABSOLUTE TIME is definitely an easier solution.

[EDIT] I am surprised this variable is not in the SDK documentation, which is why I didn't find it :) The real source of information for developers is the source code Asobo left in the official packages.

Thank you !!
Eric
 
Last edited:
Messages
433
Country
us-wisconsin
Another possible idea, I don't own MSFS. All modern browsers support animated PNGs ("APNG" w/ a file suffix of .png).
You could build the blink into the image itself.
I use this site regularly.. https://ezgif.com/apng-maker
You can set the loop ( on/off ) and the delay, down to about 2-3 msecs per frame. IIRC transparency is supported.
Might be worth a test to see if it works in sim..
 
Last edited:
Messages
425
Country
france
Yes, good idea, this could be a good solution, but in that case I use vector graphics only so the first solution is better.
 

n4gix

Resource contributor
Messages
11,652
Country
unitedstates
I wonder if this simple bit of math could be adapted to C/C++ code. This depends on the modulo function to work:

XML:
<!--
With this universal code it's very simple to control not only the length of the cycle but the frequency of the
blink itself:
Pseudocode:<Visible>(P:Absolute time,seconds) "seed" % "blink lapse" > !</Visible>
The seed parameter is the total length of the blinking cycle. For example, if you want something to blink on every
second, you use 1, if you want it blink every half a second, use 0.5 , every two seconds, 2 ,etc.

For each seed, you can determine how long would be the duration of both the visible and invisible part.
Then:
(P:Absolute time,seconds) 1 % 0.5 > !
this will make the visible and invisible parts of half a second both.

(P:Absolute time,seconds) 1 % 0.7 > !
this will make the visible part 70% of the cycle (0.7 secs) and invisible parts of 30 % (0.3 secs).

(P:Absolute time,seconds) 0.5 % 0.25 > !
this will make the visible and invisible parts a quarter of second both.

You can invert the cycle by removing the "!" char.
-->
 
Messages
122
Country
unitedkingdom
FYI in case it helps anyone, a small optimisation: an Update function e.g.

Update() {
document.getElementById("blinker").style.display = SimVar.GetSimVarValue("E:ABSOLUTE TIME","seconds") % 2 > 1 ? "block" :"none";
}

will update the CSS for the element on *every* update cycle (i.e. 18 times/second) and it's easier to *not* do that in JS than it was in RPN XML.

An advantage of the code I listed in my earlier example is that for the same frequency it would only update the element once-per-second.

The example given in this post also has the document.getElementById() embedded in 'Update()' which can be optimised out into connectedCallback so that doesn't happen on every update also.
 
Messages
622
Country
australia
This is what I use based on some code in one of the default MSFS gauges (the KX155A in asobo-vcockpits-instruments-generic\html_ui\Pages\VCockpit\Instruments\Generic\Radios). The advantage is you can set your blink period and duration in milliseconds.

Code:
Adjust to whatever element you need in your gauge.

if (this.Indicator_Melem) { this.Indicator_Melem.style.visibility = (this.blinkState(400, 200)) ? "visible" : "hidden"; }

Function where _blinkPeriod is the milliseconds that you want the blink to last and _duration is the time it is visible or hidden I don't really know how this function even works.

   blinkState(_blinkPeriod, _duration) {
        return Math.round(Date.now() / _duration) % (_blinkPeriod / _duration) == 0;
    }
 

n4gix

Resource contributor
Messages
11,652
Country
unitedstates
It uses the "modulo %" function, same as the XML and JS examples above...

Modulo function may be used for many things to keep "code" simpler. For example, for a 3 position push button:
XML:
    <MouseRect>
      <Cursor>Hand</Cursor>
      <MouseFlags>LeftSingle+LeftRelease+LeftDrag</MouseFlags>
      <CallbackCode>
        (M:Event) 'LeftSingle' scmp 0 ==
        if{ (L:ClockMode, enum) ++ 3 % (>L:ClockMode, enum) 1 (>L:KA350i_ClockModeSel, enum)  }

        (M:Event) 'LeftRelease' scmp 0 ==
        if{ 0 (>L:KA350i_ClockModeSel, enum) }
      </CallbackCode>
    </MouseRect>
 
Messages
122
Country
unitedkingdom
Note that HTML/JS gauge update code should NOT unnecessarily update the gauge on every update cycle, even though that was common on XML gauges. I.e. the simple Update() code blinking a 1-second LED actually goes "set to ON; set to ON; set to ON; set to ON; set to ON; set to ON; set to ON; set to ON; set to ON; set to OFF; set to OFF; set to OFF; set to OFF; set to OFF; set to OFF; set to OFF; set to OFF; set to OFF;", with this repeating every second.

I.e. calculate the new required on/off status of the light (using modulo arithmetic, checking simvars, or whatever), check if that has changed, if so update the style for the html display element. The LED will blink exactly the same, but you'll reduce the number of HTML/CSS updates you're making by a factor of 10 even for a blinking LED. For something like a gear warning light which actually changes relatively rarely, this technique will avoid many thousands of redundant updates. A classic example would be a radio - the XML technique was typically to render the current frequency into the display area on each update cycle. In the HTML/JS world you'd do "radio_element.innerHTML = frequency" only at startup and when the pilot changes the frequency.

So if you have something like this (simplified a bit for frequency units):

Code:
Update() {
    radio_element.innerHTML = SimVar.GetSimVarValue("COM ACTIVE FREQUENCY:1",...);
}

this should be:

Code:
Update() {
    const new_freq = = SimVar.GetSimVarValue("COM ACTIVE FREQUENCY:1",...);
    if (this.freq == null || this.freq != new_freq) {
        radio_element.innerHTML = new_freq;
        this.freq = new_freq;
    }
}

With a panel full of gauges is it pretty much only the analog moving elements (e.g. needles) which need to update on every cycle.
 
Top