Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
399 views
in Technique[技术] by (71.8m points)

d3.js datetime: hour not displaying correctly on y-axis

Using d3.js v4 I am trying to graph a time on the y-axis. The y-axis represents 24 hours of the clock.

The data is simply,

[{
    "start": "2016-11-14 20:00",
    "end": "2016-11-14 23:59"
  },
  {
    "start": "2016-11-16 01:00",
    "end": "2016-11-16 03:00"
  },
  {
    "start": "2016-11-15 00:00",
    "end": "2016-11-15 04:00"
  }
]

The first object should graph from 20 to 24 but it is going from 19 to 23. This would suggest a problem such as zero based counting.

Does anyone have an suggestions on how i might solve this?

Here is the full code snippet,

<!DOCTYPE html>
<html lang="en" dir="ltr">

<head>
  <meta charset="utf-8">
  <title>d3 datetime graph</title>
  <script src="https://d3js.org/d3.v4.min.js"></script>
</head>

<body>
  <svg width="800" height="400"></svg>
  </div>
  <div id="json">
  </div>
  <!-- <script type="text/javascript" src="script.js"></script> -->
  <script type="text/javascript">
    var svg = d3.select("svg"),
      margin = {
        top: 20,
        right: 60,
        bottom: 60,
        left: 40
      },
      width = +svg.attr("width") - margin.left - margin.right,
      height = +svg.attr("height") - margin.top - margin.bottom;
    var color = ["#2C93E8", "#838690", "#F56C4E", "#A60F2B", "#648C85", "#B3F2C9", "#528C18", "#C3F25C"];


    var data = [{
        "start": "2016-11-14 20:00",
        "end": "2016-11-14 23:59"
      },
      {
        "start": "2016-11-16 01:00",
        "end": "2016-11-16 03:00"
      },
      {
        "start": "2016-11-15 00:00",
        "end": "2016-11-15 04:00"
      }
    ]

    var parseTime = d3.timeParse("%Y-%m-%d %H:%M");
    var parseDay = d3.timeParse("%e %b %Y");
    var formatDay = d3.timeFormat("%e %b %Y");
    // data.forEach(function(d) {
    //   commence = parseTime(d.start);
    //   conclude = parseTime(d.end);
    //   if (commence.getDay() != conclude.getDay()) {
    //     // a check here in case they are more than a day apart
    //     // 2016-11-04 12:00
    //
    //     morning = conclude.getFullYear() + "-" + (conclude.getMonth() + 1) + "-" + conclude.getDate() + " 00:00";
    //     console.log("morning is " + morning);
    //     data.push({
    //       "start": morning,
    //       "end": d.end
    //     })
    //     midnight = commence.getFullYear() + "-" + (commence.getMonth() + 1) + "-" + commence.getDate() + " 23:59";
    //     console.log("midnight is " + midnight);
    //     d.end = midnight;
    //     //we need to remove current object
    //     //what element in the array is it, read the 'i'
    //     //use slice to remove that element data.slice(i,1) or soemthing like that
    //   }
    // });
    console.log(JSON.stringify(data, null, 2));

    data.forEach(function(d) {
        d.start = parseTime(d.start);
        d.end = parseTime(d.end);
        d.duration = ((d.end - d.start) / (60 * 1000) / 60); // session duration in hours
        d.starttime = d.start.getHours();
        d.endtime = d.end.getHours();
        d.daily = formatDay(d.start);
        d.day = parseDay(d.daily);

        return d;
      },
      function(error, data) {
        if (error) throw error;
      });

    document.getElementById("json").innerHTML = "<h5>data.json</h5>" + "<pre>" + JSON.stringify(data, null, 2) + "</pre>";

    var x = d3.scaleTime()
      .domain(d3.extent(data, function(d) {
        return d.day; //need to round to day
      }))
      .range([0, width]);

    var y = d3.scaleLinear()
      .domain([0, 24])
      .range([height, 0]);

    var group = svg.append("g");

    group.selectAll(".bar")
      .data(data)
      .enter()
      .append("rect")
      .style("fill", "blue")
      .attr("class", "bar")
      .attr("transform", "translate(80,0)")
      .attr("x", function(d) {
        return x(d.day) + 10;
      })
      .attr("y", function(d) {
        //if ((d.endtime + d.duration) > 24) {
        // console.log("oh no:")
        // console.log("d.starttime: " + d.starttime); //2
        // console.log("y(d.starttime): " + y(d.starttime)); //293.3333
        // console.log("d.endtime: " + d.endtime); //18
        // console.log("y(d.endtime): " + y(d.endtime)); //80
        // console.log("d.duration: " + d.duration); //16
        // console.log("y(d.duration): " + y(d.duration)); //106.6666
        // console.log("height: " + height); //320
        // console.log("y(16): " + y(16)); //106.6666
        // console.log("y(24): " + y(24)); //0
        // console.log("y(0): " + y(0)); //320
        // console.log("height - y(d.duration): " + (height - y(d.duration))); //320-106.666=213.333
        //  }
        return y(d.endtime);
      })
      .attr("width", 20)
      .attr("height", function(d) {
        return height - y(d.duration);
        // return y(d.starttime);
      })
      .style("fill", function(d, i) {
        return color[i];
      });

    svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(100," + (height + 2) + ")")
      .call(d3.axisBottom(x).ticks(d3.timeDay.every(1)).tickFormat(d3.timeFormat("%e %b %Y")))
      // axis.ticks(d3.timeMinute.every(15));
      // .call(d3.axisBottom(x))
      .selectAll("text")
      .style("text-anchor", "end")
      .attr("dx", "-.8em")
      .attr("dy", ".15em")
      .attr("transform", "rotate(-35)");

    svg.append("g")
      .attr("class", "axis axis--y")
      .attr("transform", "translate(80,0)")
      .call(d3.axisLeft(y).ticks(24))
      .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 0)
      .attr("x", 0)
      .attr("dy", "0.71em")
      .attr("text-anchor", "end")
      .text("duration (hours)");
  </script>
</body>

</html>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

So the first bar, the one that you're having issues with, is based on this data:

{
  "start": "2016-11-14 20:00",
  "end": "2016-11-14 23:59"
},

And you're positioning it based on its endtime, which is derived like

d.endtime = d.end.getHours();

So, that's the issue: if you get the hour of 23:59, it's 23, not 24: JavaScript doesn't round to the nearest hour, it just takes the hour part. If you want a more accurate y-axis, you can:

  • Use something that isn't hours, like minutes or seconds.
  • Create a time scale for each bar with its domain set to midnight before / after the bar's time range.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...