Dasboard ui_template - Sizing of elements

Hi everyone,

Have been exploring the ui_template dashboard widget and find it very powerful. I can create basically a single page app with d3 charts and custom gauges etc, all in the one template. Saves having to organise everything using Node-reds colums format.

I am running into a recurring issue in that elements that are sized inside of a container div at 100% the ui_template widget size size, and their 100% sized children seem to be sized before the node is fully rendered and end up small. Example here (outlind of container div shown as border):
ui-template

Once the second message comes through, all renders fine, the zoom sliders work, etc. like below:
ui-template2

So the container div sizes fine, but the children charts and gauges at 100% are inconsistent. In this case the child SVG is sized to 100% using css but this issue is consistent accross D3 charts, canvas charts, and canvas gauges, but the parent container div is fine. Baffling.

This has been eating at me for some time, and I just can't seem to beat it. I think it may be angular related and it appears to be a problem in the wider community, I just couldn't figure out how to solve for the AngularJS version that Node Red uses.

Does any one have a clue to address this sizing on load issue? If i put the sizing in the update portion of the scope watches, it size properly on the second message, but i don't want to wait for second message, nor do I want to do resize logic on every message either.

Code below:

[{"id":"c8dc9b49.abc738","type":"template","z":"2c6e5ff2.bbfe3","name":"NVD3 Template","field":"template","fieldType":"msg","format":"html","syntax":"mustache","template":"<script src=\"../d3/d3.min.js\"></script>\n<script src=\"../nvd3/nv.d3.min.js\"></script>\n<link rel=\"stylesheet\" href=\"../nvd3/nv.d3.min.css\">\n\n<style>\n    #chartTest, svg {\n        margin: 0px;\n        padding: 0px;\n        height: 100%;\n        width: 100%;\n        border: solid 1px;\n        box-sizing: border-box;\n    }\n</style>\n\n<div id=\"chartTest\" class='with-3d-shadow with-transitions'>\n    <svg> </svg>\n</div>\n\n\n\n\n\n\n\n<script>\n\n\n//-- This is the angular message handler function used to receive messages -----\n//------------------------------------------------------------------------------\n(function(scope) {                                      \n    // This portion of the function fires only once on first message received and is the local 'global' scope\n    \n    var chart = nv.models.linePlusBarChart()\n            .margin({top: 50, right: 60, bottom: 30, left: 60})\n            .legendRightAxisHint(' [Using Right Axis]')\n            .color(d3.scale.category10().range());\n            \n    chart.xAxis.tickFormat(function(d) { \n        return d3.time.format('%x')(new Date(d));\n     }).showMaxMin(false);\n\n    chart.x2Axis.tickFormat(function(d) {\n        return d3.time.format('%x')(new Date(d))\n    }).showMaxMin(false);\n\n    chart.y1Axis.tickFormat(function(d) {\n        return d3.format('0.1f')(d) + ' mm ';\n    });\n    chart.bars.forceY([0]).padData(false);\n\n    chart.y2Axis.tickFormat(function(d) {\n        return ' ' + d3.format('0f')(d)+ ' mm';\n    });\n    chart.bars.forceY([0]).padData(false);\n\n\n    // This function fires everytime a msg.payload is received\n    scope.$watch('msg.payload', function(data) { \n\n\n        chart.bars.forceY([0]);\n\n        d3.select('#chartTest svg')\n            .datum(formatData(data))\n            .transition().duration(500)\n            .call(chart);\n        \n            nv.utils.windowResize(chart.update);\n        \n            return chart;\n\n    });\n    \n        \n    function formatData(data){\n        var formattedData = [{\n            key:    data[0].series[0],\n            values: data[0].data[0],\n            bar:    true\n        },{\n            key:    data[0].series[1],\n            values: data[0].data[1]\n        }];\n        return formattedData;\n    }\n})(scope);\n\n\n\n\n\n/*\nnv.addGraph(function() {\n    var chart = nv.models.linePlusBarChart()\n      .margin({top: 30, right: 60, bottom: 50, left: 70})\n      .x(function(d,i) { return i })\n      .y(function(d) { return d[1] })\n      .color(d3.scale.category10().range())\n      ;\n\n    chart.xAxis\n      .showMaxMin(false)\n      .tickFormat(function(d) {\n        var dx = data[0].values[d] && data[0].values[d][0] || 0;\n        return d3.time.format('%x')(new Date(dx))\n      });\n\n    chart.y1Axis\n      .tickFormat(d3.format(',f'));\n\n    chart.y2Axis\n      .tickFormat(function(d) { return '$' + d3.format(',f')(d) });\n\n    chart.bars.forceY([0]);\n\n    d3.select('#chart svg')\n      .datum(data)\n      .transition().duration(500)\n      .call(chart)\n      ;\n\n    nv.utils.windowResize(chart.update);\n\n    return chart;\n});\n*/\n\n\n\n/*\n    nv.addGraph(function() {\n        chart = nv.models.linePlusBarChart()\n            .margin({top: 50, right: 60, bottom: 30, left: 60})\n            .legendRightAxisHint(' [Using Right Axis]')\n            .color(d3.scale.category10().range());\n\n        chart.xAxis.tickFormat(function(d) {\n            return d3.time.format('%x')(new Date(d))\n        }).showMaxMin(false);\n\n        chart.y1Axis.tickFormat(function(d) { return d3.format('0.1f')(d) + ' mm ' });\n        chart.bars.forceY([0]).padData(false);\n\n        chart.y2Axis.tickFormat(function(d) { return ' ' + d3.format('0f')(d)+ ' mm' });\n        chart.bars.forceY([0]).padData(false);\n\n        //chart.x2Axis.tickFormat(function(d) {\n        //    return d3.time.format('%x')(new Date(d))\n        //}).showMaxMin(false);\n\n        chart.dispatch.on('stateChange', function(e) { nv.log('New State:', JSON.stringify(e)); });\n        nv.utils.windowResize(chart.update);\n        return chart;   \n    });\n\n    // This function fires everytime a msg.payload is received\n    scope.$watch('msg.payload', function(data) { \n        d3.select('#chartTest svg')\n            .datum(formatData(data))\n            .transition().duration(500).call(chart);\n\n    });\n*/\n\n\n</script>\n\n\n\n\n\n\n\n","output":"str","x":780,"y":340,"wires":[["22237b3e.6e93a4"]]}]

Thanks in advance!

Rob

Just sharing a bit of knowledge learned from last night's efforts.

The SVG background of the chart is sizing correctly, but the elements created by the library on the SVG are what is sizing improperly. I still believe this is done because the library is using DOM sizing information from Node-Red/Angular before it's ripe and rendering the chart prematurely.

What is really needed is an event that says 'Right! DOM content loaded and sized for this widget' and then i can fire an update on the chart to size it properly after loading.

Prefer not to use the body 'onload' event (not even sure if i can for angular) as this would be defined for each widget.

Any ideas?

Thanks!