简体   繁体   中英

d3js does not enter into line function

I would like to draw a line by d3 with below codes.( http://jsfiddle.net/totaljj/L9n7qnv1 )

It draws x,y-axis, but does not enter into the line function when appending d attribute.

You can debug on line number 104 to see that the code does not enter into the line function.

Any help would be appreciated.

<!DOCTYPE html>
<html>
<style>
.axis--x path {
    display: none;
}

.line {
    fill: none;
    stroke: steelblue;
    stroke-width: 1.5px;
}
</style>

<body>
    <!-- Page Content -->

    <div>

            <svg width="430" height="250"></svg>
    </div>

    <section>

        <script src="https://d3js.org/d3.v4.min.js"></script>

        <script>

            var data=
            '{"recordsFiltered":5,"raCounts":[{"name":"comp_name","values":[{"date_":"2016","actual":170.0,"DT_RowId":"row_null"},{"date_":"2015","actual":198.0,"DT_RowId":"row_null"},{"date_":"2015","actual":149.0,"DT_RowId":"row_null"},{"date_":"2014","actual":197.0,"DT_RowId":"row_null"},{"date_":"2014","actual":146.0,"DT_RowId":"row_null"}],"DT_RowId":"row_null"}],"draw":null,"recordsTotal":5}';

            var d = JSON.parse(data);
            draw(d.raCounts);

            function draw(data){

                //svg
                var svg = d3.select("svg"),
                    margin = {top: 100, right: 80, bottom: 30, left: 50},
                    width = svg.attr("width") - margin.left - margin.right,
                    height = svg.attr("height") - margin.top - margin.bottom,
                    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");


                //time
                var parseTime = d3.timeParse("%Y%m%d");

                //domain
//              var x = d3.scaleTime().range([0, width]),
                var x = d3.scaleLinear().range([0, width]),
                    y = d3.scaleLinear().range([height, 0]),
                    z = d3.scaleOrdinal(d3.schemeCategory10);

                //line
                var line = d3.line()
                    .curve(d3.curveBasis)
                    .x(function(d) { 
                        return x(d.date_); })
                    .y(function(d) { 
                        return y(d.actual); });

                  //domain
                  x.domain(d3.extent(data[0].values, function(d) { 
                      return d.date_; }));

                  y.domain([
                    d3.min(data, function(c) { 
                        return d3.min(c.values, function(d) {
                            return d.actual; }); }),
                    d3.max(data, function(c) { 
                        return d3.max(c.values, function(d) {
                            return d.actual; }); })
                  ]);

                  z.domain(data.map(function(c) { 
                      return c.DT_RowId; }));

                  //axis
                  g.append("g")
                      .attr("class", "axis axis--x")
                      .attr("transform", "translate(0," + height + ")")
                      .call(d3.axisBottom(x));

                  g.append("g")
                      .attr("class", "axis axis--y")
                      .call(d3.axisLeft(y))
                    .append("text")
                      .attr("transform", "rotate(-90)")
                      .attr("y", 6)
                      .attr("dy", "0.71em")
                      .attr("fill", "#000")
                      .text("count");

                  var ra = g.selectAll(".ra")
                    .data(data)
                    .enter().append("g")
                      .attr("class", "ra");

                 //ra line
                  ra.append("path")
                      .attr("class", "line")
                      .attr("d",
                              function(d) { return 
                                  line(d.values); })
                      .style("stroke-dasharray", ("1","1"));
            }


            </script>
    </section>

</body>
</html>

JavaScript doesn't always require semicolons at the end of a line. It will automatically insert them in certain situations , and the place where you call your line function is one of them:

                  .attr("d",
                          function(d) { return 
                              line(d.values); })

The fix is therefore to remove the newline after return :

                  .attr("d",
                          function(d) { return line(d.values); })

I think both Gerardo Furtado's answer as well as Luke Woodward's answer have good points, but both circumvent the fact, that OP's solution is somewhat off the beaten track. To make full use of the data binding the typical approach would be something like the following:

//ra line
ra.selectAll("path.line")
  .data(function(d) { return [d.values]; })
  .enter().append("path")
    .attr("class", "line")
    .attr("d", line)

Passing just the line generator function get rids of the automatical semicolon insertion after the return statement. On the other hand, doing the data binding for the path.line element still allows for multiple lines drawn by the same statement.

Have a look at the following snippet for a working example:

  var data = '{"recordsFiltered":5,"raCounts":[{"name":"comp_name","values":[{"date_":"2016","actual":170.0,"DT_RowId":"row_null"},{"date_":"2015","actual":198.0,"DT_RowId":"row_null"},{"date_":"2015","actual":149.0,"DT_RowId":"row_null"},{"date_":"2014","actual":197.0,"DT_RowId":"row_null"},{"date_":"2014","actual":146.0,"DT_RowId":"row_null"}],"DT_RowId":"row_null"}],"draw":null,"recordsTotal":5}'; data = JSON.parse(data).raCounts; //svg var svg = d3.select("svg"), margin = { top: 100, right: 80, bottom: 30, left: 50 }, width = svg.attr("width") - margin.left - margin.right, height = svg.attr("height") - margin.top - margin.bottom, g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); //time var parseTime = d3.timeParse("%Y%m%d"); //domain // var x = d3.scaleTime().range([0, width]), var x = d3.scaleLinear().range([0, width]), y = d3.scaleLinear().range([height, 0]), z = d3.scaleOrdinal(d3.schemeCategory10); //line var line = d3.line() .curve(d3.curveBasis) .x(function(d) { return x(d.date_); }) .y(function(d) { return y(d.actual); }); //domain x.domain(d3.extent(data[0].values, function(d) { return d.date_; })); y.domain([ d3.min(data, function(c) { return d3.min(c.values, function(d) { return d.actual; }); }), d3.max(data, function(c) { return d3.max(c.values, function(d) { return d.actual; }); }) ]); z.domain(data.map(function(c) { return c.DT_RowId; })); //axis g.append("g") .attr("class", "axis axis--x") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x)); g.append("g") .attr("class", "axis axis--y") .call(d3.axisLeft(y)) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", "0.71em") .attr("fill", "#000") .text("count"); var ra = g.selectAll(".ra") .data(data) .enter().append("g") .attr("class", "ra"); //ra line ra.selectAll("path.line") .data(function(d) { return [d.values]; }) .enter().append("path") .attr("class", "line") .attr("d", line) .style("stroke-dasharray", ("1", "1")); 
 <style> .axis--x path { display: none; } .line { fill: none; stroke: steelblue; stroke-width: 1.5px; } </style> 
 <script src="https://d3js.org/d3.v4.js"></script> <svg width="430" height="250"> </svg> 

You're not passing the correct data to your line generator. It should be:

ra.append("path")
    .attr("class", "line")
    .attr("d", line(data[0].values))
    .style("stroke-dasharray", ("1", "1"));

Here is your updated fiddle: http://jsfiddle.net/67zs8ph7/

PS : this will plot just one line (see comment below)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM