Read the statement by Michael Teeuw here.
Nunjucks and Chartjs / Javascript
-
the dom looks like this before any content is output (no < > to save errors)
matching index.html, with a div for each module, in its position div section
in fifo orderhead body div class=fullscreen below" div id="module_id_1" div class="module-header" end-div div class="module-content" end div end-div div id="module_id_2" end-div div class="region top bar" div class="container", end-div div class="region top left" div class="container" end-div end-div etc </div>
then getDom() in each module is called, and its little html contribution is placed in its div id=“module-content” (by module_id)
but, until the dom.div.addChild(content) is done, the content is just in memory, NOT IN the dom…
then later the module signals the mirror runtime via updateDom()… ‘I have new content’,
and MM runtime calls the module’s getDom() and we repeat the process… note in the updateModule content
it REMOVES the prior content and injects the new…contentWrapper[0].innerHTML = ""; // < --- clear all content, the rough way contentWrapper[0].appendChild(newContent); // < --- append the new module content tree
SO, BIG dom object tree cleanup and rebuild…
i keep the module contribution, and modify it where appropriate, to reduce the change impact.
I always think the getDom() should be named getDomContribution()
-
@sdetweil
Well…I have to say I’m not through with this.getDom creates/updates the module-specific dom objects. Right?
So let’s say there’s two ways to have a canvas:- document.createElement in an overwritten getDom method
- Nunjucks template, which is being converted into HTML during getDom.
The Nunjucks way seems asynchronous, overwriting the getDom however makes it synchronous and has the advantage of “immediate full control”. You can then code your graph directly into the getdom method (like you have done as far as I understand). All good, but does not work with Nunjucks without messing with several layers of core MM code.
OR you can use another process (like socketNotification from Node_helper) to do
- getCanvasById and
- write the graph into it.
That should work with both options, the async nunjucks and the overwritten getDom, since it is on a completely different chain of commands.
That didn’t work for me with Nunjucks, because it seems to do rewrite more often than just with getDom. I remember that someone on this forum had the same assumption.
Thanks for the intersting discussion. Learned a lot and will try out a bit more.
-
@lavolp3 both your 1 and 2 are processed as async, just 1 is done when getDom() returns a dom object tree.
main.jsupdateDom() calls getDom() immediately. and then checks what it gets back.
either a promise (generated content will return later) or dom objects (all done generating)
if content, then it creates a promise and resolves it immediately with the data
(something will wait on the promise eventually)now we have a promise, so can wait (.then), get the data (either approach), and then inject it into the dom.(updateDomWithContent)
(via a promise, as it may take a while to do that update, don’t want to block everybody else)
and then call back whoever called updateDom()var updateDom = function(module, speed) { return new Promise(function(resolve) { var newContentPromise = module.getDom(); var newHeader = module.getHeader(); if (!(newContentPromise instanceof Promise)) { // convert to a promise if not already one to avoid if/else's everywhere newContentPromise = Promise.resolve(newContentPromise); } newContentPromise.then(function(newContent) { var updatePromise = updateDomWithContent(module, speed, newHeader, newContent); updatePromise.then(resolve).catch(Log.error); }).catch(Log.error); }); };
-
@sdetweil Sam, sorry to say that after such a long time I’m still not through with this.
Promises make my head explode, so I hope you can help me.scheduleUpdates: function() { var self = this; setInterval(function() { var conf = self.config; self.updateDom(conf.animationSpeed); setTimeout(function() { self.createBarChart(); }, 2000); }, this.config.updateInterval); },
This is an easified version of my loop to update the dom.
You can see the timeout function I have built in to wait 2 seconds and be sure the dom has been created. Then in the createBarChart function I can write the chart into the dom.
This works, but I don’t like it at all.
Isn’t there a way to “await” the resolved promise from outside of the updateDom function? After all updateDom() returns a promise.
I have tried to doself.updateDom().then( function() {self.createBarChart() });
It didn’t work.Thanks for your support. Really appreciated.
-
@lavolp3 updateDom() returns a promise, but then IMMEDIATELY calls getDom()…
so the wait is ineffective
all you can do is check the dom to see if your minimum content some anchoring div) is present, and retry that until it is.
then call updateDom() to force a refreshthis is what I do in getDom(). i have an array of different charts to present
// if we are not suspended/hidden due to sleep or whatever if (wself.suspended == false) { // make sure we don't start before the data gets here if (!this.loaded) { < - just a flag for first time this.loaded = true; return wself.wrapper; } else { // loop thru the data from the blynk server, one chart per data point/pin for (var pin_index = 0; pin_index < wself.config.Pins.length; pin_index++) { // get the pin text name. used for index into the data hash var this_pin = wself.config.Pins[pin_index]; // clear the work variable var canvas = null; // try to locate the existing chart if ((canvas = document.getElementById("myChart" + this_pin)) == null) { var c = document.createElement("div"); c.style.width = wself.config.width + "px"; c.style.height = wself.config.height + "px"; if (!wself.config.stacked) {c.style.display = "inline-block";} wself.wrapper.appendChild(c); canvas = document.createElement("canvas"); canvas.id = "myChart" + this_pin; c.appendChild(canvas); } // if the chart has been created if (wself.charts[pin_index] != null) { // destroy it, update doesn't work reliably wself.charts[pin_index].destroy(); // make it unreferenced wself.charts[pin_index] = 0; } // create it now, into the special div object for this chart wself.charts[pin_index] = new Chart(canvas, {
my ‘schedule update’ asks for more data from my node_helper…
it informs me when its back. and I call updateDom() after saving the data where getDom() will looku can see my code at https://github.com/sdetweil/WaterLevels