最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - D3 js set data from data-attribute - Stack Overflow

programmeradmin0浏览0评论

During creating graphs I need to set data. Those data(Array of Objects) I have already in HTML like this:

<svg  class="graph-n" data-stuff="{simplified data}"></svg>

Then with Javascript and D3 JS I initialize and setup graphs with the following code:

<script>
    var margin = { top: 20, right: 20, bottom: 30, left: 50},
        width = 1500 - margin.left - margin.right,
        height = 350 - margin.top - margin.bottom;

    var x = d3.scaleTime().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);


    var valueline = d3.line()
        .x(function(d) { return x(new Date(d.t)); })
        .y(function(d) { return y(d.y); });

    var svg = d3.selectAll(".graph-n")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


        x.domain(d3.extent(data, function(d) { return new Date(d.t); }));
        y.domain([0, d3.max(data, function(d) { return d.y; })]);

        svg.append("path")
            .attr("class", "line")
            .attr("d", valueline);

        svg.append("g")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(x));

        svg.append("g")
            .call(d3.axisLeft(y));
</script>

The question is how shall I say, that data are inside each element during Selection in data attribute 'data-stuff' ? Each SVG has data to plot in his own data attribute.

Or is my approach wrong and I shall use different approach?

Thank you for your responses.

During creating graphs I need to set data. Those data(Array of Objects) I have already in HTML like this:

<svg  class="graph-n" data-stuff="{simplified data}"></svg>

Then with Javascript and D3 JS I initialize and setup graphs with the following code:

<script>
    var margin = { top: 20, right: 20, bottom: 30, left: 50},
        width = 1500 - margin.left - margin.right,
        height = 350 - margin.top - margin.bottom;

    var x = d3.scaleTime().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);


    var valueline = d3.line()
        .x(function(d) { return x(new Date(d.t)); })
        .y(function(d) { return y(d.y); });

    var svg = d3.selectAll(".graph-n")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


        x.domain(d3.extent(data, function(d) { return new Date(d.t); }));
        y.domain([0, d3.max(data, function(d) { return d.y; })]);

        svg.append("path")
            .attr("class", "line")
            .attr("d", valueline);

        svg.append("g")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(x));

        svg.append("g")
            .call(d3.axisLeft(y));
</script>

The question is how shall I say, that data are inside each element during Selection in data attribute 'data-stuff' ? Each SVG has data to plot in his own data attribute.

Or is my approach wrong and I shall use different approach?

Thank you for your responses.

Share Improve this question asked May 17, 2018 at 12:06 user6690342user6690342 1
  • 2019 updating, see answer for modern browsers and using JSON at data-stuff. – Peter Krauss Commented Aug 17, 2019 at 21:06
Add a ment  | 

2 Answers 2

Reset to default 5

There is no way to just tell d3 explicitly "take data from this attribute". You can however set the data programatically, loading it from the attribute of your choosing. There are several ways on how to achieve it, as demonstrated on these selection examples (they use <ul> and <li> for simplicity, <svg> is usage is analogous):

// the pure D3 way
d3.selectAll("ul.d3-pure")                // select the element
    .datum(function() { return this.getAttribute("data-list").split(",")}) // set selection's data based on its data attribute
    .selectAll("li")                      // create new selection
        .data((d) => d)                   // set the data from the parent element
        .enter().append("li")             // create missing elements
            .text((content) => content);  // set elements' contents

// the DOM way      
var domUls = document.querySelectorAll("ul.dom");     // select elements
for(var i = 0; i < domUls.length; i++) {              // iterate over those elements
    const ul = domUls[i];
    const d3_ul = d3.select(ul);                      // create D3 object from the node
    const data = ul.getAttribute("data-list").split(",");
    d3_ul.selectAll("li").data(data)                  // create new selection and assign its data
        .enter().append("li")                         // create missing elements
            .text((content) => content)               // set elements' content
}

// the hybrid D3-DOM way
d3.selectAll("ul.d3-hybrid")                // select elements
    .each(function() {                      // iterate over each node of the selection
        const ul = d3.select(this);         // "this" is the "ul" HTML node
        const data = ul.attr("data-list").split(",");
        ul.selectAll("li").data(data)       // create new selection, assign its data
            .enter().append("li")           // create missing elements
                .text((content) => content) // set elements' content
        });
<script src="https://cdnjs.cloudflare./ajax/libs/d3/3.4.11/d3.min.js"></script>
<ul class="d3-pure" data-list="1,2,3">
</ul>
<ul class="dom" data-list="a,b,c">
</ul>
<ul class="d3-hybrid" data-list="I,II,III">
</ul>

Modern browsers accepts node().dataset

Using D3_selection.node() and pure Javascript's DOM-node dataset property, as mented by @altocumulus before.

It is an old Javascript standard for HTML elements (since Chorme 8 and Firefox 6) but new for SVG (since Chorme 55 and Firefox 51).

The values of dataset's key-values are pure strings, but a good practice is to adopt JSON string format for non-string datatypes, to parse it by JSON.parse().

Using it

Code snippet to get and set key-value datasets at HTML and SVG.

console.log("-- GET values --")
var x = d3.select("#html_example").node().dataset;
console.log("s:", x.s );
for (var i of JSON.parse(x.list)) console.log("list_i:",i)

var y = d3.select("#svg_example g").node().dataset;
console.log("s:", y.s );
for (var i of JSON.parse(y.list)) console.log("list_i:",i)

console.log("-- SET values --");
y.s="BYE!"; y.list="null";
console.log( d3.select("#svg_example").node().innerHTML )
<script src="https://d3js/d3.v5.min.js"></script>
<p id="html_example" data-list="[1,2,3]" data-s="Hello123">Hello dataset!</p>
<svg id="svg_example">
  <g data-list="[4,5,6]" data-s="Hello456 SVG"></g>
</svg>

发布评论

评论列表(0)

  1. 暂无评论