如何在 Node-Red 中使用 D3

How to use D3 in Node-Red

我正在使用仪表板节点,但还想显示动画。 D3 非常适合动画,因此我想知道是否可以用 D3 填充 Node-Red 中的一组仪表板选项卡?

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.2/d3.min.js"></script>
<script src="https://rawgit.com/gka/d3-jetpack/master/d3-jetpack.js"></script>
<script>
var svg = d3.select("body")
    .append("svg")
    .attr("width", '800px')
    .attr("height", '800px');


var data = [{x: 100, y: 100, h: 10, w: 50, c: "red"}, {x: 200, y: 200, h: 20, w: 15, c: "yellow"}, {x: 300, y: 300, h: 60, w: 80, c: "green"}]

svg.selectAll("rect")
    .data(data)
    .enter().append("rect")
    .attr("x", function(d) { return d.x; })
    .attr("y", function(d) { return d.y; }) 
    .attr("width", function(d) { return d.w; })
    .attr("height", function(d) { return d.h; })
    .style("fill", function(d) { return d.c; })


//# sourceURL=userscript.js
</script>

您几乎可以在模板节点中放置任何您想要的东西。

值得注意的是,仪表板-ui 使用 Angular,因此您需要使用它才能使用传入的消息和数据。

为了从您的 ui_template 代码中使用外部 js 库,最好将 src 链接和 html/css/svg 代码放入单独的模板中。在第一个中,选择“Add to site section”选项,并包括您的图书馆参考:

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.2/d3.min.js"></script>
<script src="https://rawgit.com/gka/d3-jetpack/master/d3-jetpack.js"></script>

然后,将另一个 ui_template 节点添加到您的仪表板 tab/group,并包含此代码:

<style>
    #myBoxes {
        height: 800px;
        width: 800px;
    }
</style>

<svg id="myBoxes">
    <!-- svg content goes here -->
</svg>

<script>
(function(scope) { 
    // watch for msgs from node-red
    scope.$watch('msg.payload', function(payload) {
        drawBoxes("myBoxes", payload);
    })
})(scope);

function drawBoxes(id, data) {
    var svg = d3.select("#" + id);
    var rect = svg.selectAll("rect")
        .data(data);

    rect.enter()
        .append("rect");

    rect.attr("x", function(d) { return d.x; })
        .attr("y", function(d) { return d.y; }) 
        .attr("width", function(d) { return d.w; })
        .attr("height", function(d) { return d.h; })
        .style("fill", function(d) { return d.c; });

    rect.exit()
        .remove();
}
</script>

我对你的示例代码进行了多次修改--

  • 对固定的 DOM 元素使用 CSS 样式
  • 创建一个空的 <svg> 元素,具有唯一的 id
  • 包含 angular scope.$watch(...) 以接收来自 node-red
  • 的新消息
  • 将 D3 逻辑放在一个新函数中,从范围观察器调用
  • 使用 D3 enter/update/exit 选项支持 object constancy

这是一个包含几个不同输入的示例流程:

[{"id":"7b4017ce.0802d8","type":"inject","z":"76a6ae8d.8a35","name":"red/white/blue","topic":"","payload":"[{\"x\":100,\"y\":100,\"h\":40,\"w\":50,\"c\":\"red\"},{\"x\":200,\"y\":200,\"h\":20,\"w\":75,\"c\":\"white\"},{\"x\":300,\"y\":300,\"h\":20,\"w\":75,\"c\":\"blue\"}]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":210,"y":540,"wires":[["3adb8b4a.dbf3c4"]]},{"id":"3adb8b4a.dbf3c4","type":"ui_template","z":"76a6ae8d.8a35","group":"f2c8d56c.4d75b8","name":"D3 template","order":1,"width":0,"height":0,"format":"<style>\n    #myBoxes {\n        height: 800px;\n        width: 800px;\n    }\n</style>\n\n<svg id=\"myBoxes\">\n    <!-- svg content goes here -->\n</svg>\n\n<script>\n(function(scope) { \n    // watch for msgs from node-red\n    scope.$watch('msg.payload', function(payload) {\n        drawBoxes(\"myBoxes\", payload);\n    })\n})(scope);\n\nfunction drawBoxes(id, data) {\n    var svg = d3.select(\"#\" + id);\n    var rect = svg.selectAll(\"rect\")\n        .data(data);\n\n    rect.enter()\n        .append(\"rect\");\n    \n    rect.attr(\"x\", function(d) { return d.x; })\n        .attr(\"y\", function(d) { return d.y; }) \n        .attr(\"width\", function(d) { return d.w; })\n        .attr(\"height\", function(d) { return d.h; })\n        .style(\"fill\", function(d) { return d.c; });\n    \n    rect.exit()\n        .remove();\n}\n</script>","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":510,"y":540,"wires":[[]]},{"id":"e1ab2277.a8f19","type":"ui_template","z":"76a6ae8d.8a35","group":"d215108d.8b51b","name":"D3 libraries","order":0,"width":0,"height":0,"format":"<script src=\"https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.2/d3.min.js\"></script>\n<script src=\"https://rawgit.com/gka/d3-jetpack/master/d3-jetpack.js\"></script>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"global","x":510,"y":500,"wires":[[]]},{"id":"a4d0e22c.4689","type":"inject","z":"76a6ae8d.8a35","name":"black/white","topic":"","payload":"[{\"x\":100,\"y\":100,\"h\":40,\"w\":40,\"c\":\"black\"},{\"x\":200,\"y\":200,\"h\":40,\"w\":40,\"c\":\"white\"}]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":200,"y":580,"wires":[["3adb8b4a.dbf3c4"]]},{"id":"e7af594f.9862d8","type":"inject","z":"76a6ae8d.8a35","name":"red/yellow/green","topic":"","payload":"[{\"x\":100,\"y\":100,\"h\":10,\"w\":50,\"c\":\"red\"},{\"x\":200,\"y\":200,\"h\":20,\"w\":15,\"c\":\"yellow\"},{\"x\":300,\"y\":300,\"h\":60,\"w\":80,\"c\":\"green\"}]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":220,"y":500,"wires":[["3adb8b4a.dbf3c4"]]},{"id":"f2c8d56c.4d75b8","type":"ui_group","z":"","name":"D3","tab":"e3e3a35c.7a77f","order":2,"disp":true,"width":"12","collapse":false},{"id":"d215108d.8b51b","type":"ui_group","z":"","name":"Recalls","tab":"3c000bae.098b94","order":2,"disp":true,"width":"18"},{"id":"e3e3a35c.7a77f","type":"ui_tab","z":"","name":"Libraries","icon":"fa-bank","order":6},{"id":"3c000bae.098b94","type":"ui_tab","z":"","name":"Vehicles","icon":"fa-car"}]