【问题标题】:Compare two time objects in D3.js比较 D3.js 中的两个时间对象
【发布时间】:2016-03-30 11:32:24
【问题描述】:

在 D3.js 中,我目前正在尝试根据数据数组是否包含该时间来填充一个空数组(数组仅包含每 5 分钟后的时间戳)。如果数据数组包含时间,则应复制该值,否则为 null。但是当我尝试比较两个时间对象时,它无法正常工作。

以下是代码(当前代码不是复制值,而是打印以方便调试):

var data = [{"mytime": "2015-12-01T23:10:00.000Z", "value": 64},
{"mytime": "2015-12-01T23:15:00.000Z", "value": 67},
{"mytime": "2015-12-01T23:20:00.000Z", "value": 70},
{"mytime": "2015-12-01T23:25:00.000Z", "value": 64},
{"mytime": "2015-12-01T23:30:00.000Z", "value": 72},
{"mytime": "2015-12-01T23:35:00.000Z", "value": 75},
{"mytime": "2015-12-01T23:40:00.000Z", "value": 71},
{"mytime": "2015-12-01T23:45:00.000Z", "value": 80},
{"mytime": "2015-12-02T00:00:00.000Z", "value": 80},
{"mytime": "2015-12-02T00:05:00.000Z", "value": 85}
];

var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%S.%LZ").parse;

data.forEach(function(d) {
          d.mytime = parseDate(d.mytime);
 });

var act_data = [];

  var x_extent = d3.extent(data, function(d){
      return d['mytime']});

  time_arr = d3.time.minute.range(x_extent[0],x_extent[1],5);
  for(var key in time_arr){
  var temp;
  temp = contains(data,time_arr[key],'mytime');
}


function contains(data,value,variable)
{
  var i =data.length;
  while(i--){

   if (data[i][variable] === value)
   {
    console.log('found');
    return i;
   } 
  }
  return false;
}

输出应该是这样的:

data = [{"mytime": "2015-12-01T23:10:00.000Z", "value": 64},
{"mytime": "2015-12-01T23:15:00.000Z", "value": 67},
{"mytime": "2015-12-01T23:20:00.000Z", "value": 70},
{"mytime": "2015-12-01T23:25:00.000Z", "value": 64},
{"mytime": "2015-12-01T23:30:00.000Z", "value": 72},
{"mytime": "2015-12-01T23:35:00.000Z", "value": 75},
{"mytime": "2015-12-01T23:40:00.000Z", "value": 71},
{"mytime": "2015-12-01T23:45:00.000Z", "value": 80},
{"mytime": "2015-12-01T23:50:00.000Z", "value": null},
{"mytime": "2015-12-01T23:55:00.000Z", "value": null},
{"mytime": "2015-12-02T00:00:00.000Z", "value": 80},
{"mytime": "2015-12-02T00:05:00.000Z", "value": 85}
];

【问题讨论】:

    标签: javascript arrays d3.js


    【解决方案1】:

    你可以使用

    这给了我们

    var data = [...];
    
    // for parsing and formatting
    var timeformat = d3.time.format("%Y-%m-%dT%H:%M:%S.%LZ");
    
    // range to operate on
    var extent = d3.extent(data, function(d){ 
        return timeformat.parse(d.mytime); 
    });
    
    // scale representing the time stamps
    var scale = d3.time.scale()
        .domain(extent) // the boundaries
        .ticks(d3.time.minute, 5); // 5 minutes intervals
    
    // easier to determine if a value exists
    var hashed = d3.map(data, function(d) { return d.mytime; });
    
    // or if your version < 3.5
    /*
    var hashed = d3.map();
    data.forEach(function(d) { 
        hashed.set(d.mytime, d);
    });
    */
    
    
    // transforms the scale into the desired output
    var res = scale.map(function(t) {
        var ft = timeformat(t);
        return {
            mytime: ft,
            value: (hashed.has(ft)) ? hashed.get(ft).value : null
        };
    });
    

    还有一个演示http://jsfiddle.net/nikoshr/qxcLry8z/

    var data = [
    {"mytime": "2015-12-01T23:10:00.000Z", "value": 64},
    {"mytime": "2015-12-01T23:15:00.000Z", "value": 67},
    {"mytime": "2015-12-01T23:20:00.000Z", "value": 70},
    {"mytime": "2015-12-01T23:25:00.000Z", "value": 64},
    {"mytime": "2015-12-01T23:30:00.000Z", "value": 72},
    {"mytime": "2015-12-01T23:35:00.000Z", "value": 75},
    {"mytime": "2015-12-01T23:40:00.000Z", "value": 71},
    {"mytime": "2015-12-01T23:45:00.000Z", "value": 80},
    {"mytime": "2015-12-02T00:00:00.000Z", "value": 80},
    {"mytime": "2015-12-02T00:05:00.000Z", "value": 85}
    ];
    
    
    var timeformat = d3.time.format("%Y-%m-%dT%H:%M:%S.%LZ");
    
    var extent = d3.extent(data, function(d){ 
        return timeformat.parse(d.mytime); 
    });
    
    var scale = d3.time.scale()
        .domain(extent)
        .ticks(d3.time.minute, 5);
      
    var hashed = d3.map();
    data.forEach(function(d) { 
        hashed.set(d.mytime, d);
    });
      
    var res = scale.map(function(t) {
        var ft = timeformat(t);
        return {
            mytime: ft,
            value: (hashed.has(ft)) ? hashed.get(ft).value : null
        };
    });
    
    var $table = $('<table></table>'); 
    res.forEach(function(d) {
        $table.append('<tr><td>'+d.mytime+'</td><td>'+d.value+'</td></tr>')
    });
    $('body').append($table);
      
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

    【讨论】:

    • 感谢您的回复。这正是我想要的。但是当我在本地机器上运行时。不知何故,我将所有值都设为“null”。我检查了 jsfiddle 并复制了代码,但仍然给出了 null。
    • 我实际上只是复制了您的代码并在本地运行它并执行了 console.log(res[1]) 。所以不知道为什么这不起作用。我正在使用 d3 的下载版本(只有 2 周大)。
    • 您的 d3 版本可能是 d3.map(array) 的地方,也是您获得空值的原因。我会尝试写一个替代方案。
    • 我添加了一个应该与 3.5 之前的 d3 兼容的版本。 jsfiddle.net/nikoshr/qxcLry8z/1
    【解决方案2】:

    你可以这样做:

    var extent = d3.extent(data, function(d){ return d.mydate});//get the max min limit
    var data1 = []; make an empty array
    for (var i =0; i < data.length -1; i++){
        var diff = data[i + 1].mytime.getTime() - data[i].mytime.getTime();
        if (diff <= 300000){ //less than equal to 5 minutes
            data1.push(data[i])
        } else { //greater than 5 minutes
          var t1 = new Date(data[i].mytime.getTime() + 300000)
            var t2 = new Date(data[i +1].mytime.getTime() - 300000)
            data1.push({"mytime": t1, "value": null})
            data1.push({"mytime": t2, "value": null})
        }
    }
    data1.push(data[data.length -1]); //take the last value as it was not processed
    data = data1
    

    工作代码here

    【讨论】:

      【解决方案3】:

      随着 ES6 的出现,有更多选项可用于处理该任务。根据需要支持的浏览器版本,以下代码可能是一种可行的方法。我已经在 Chrome 49 和 FF 45 上成功测试了。

      该解决方案将自定义generator function 添加到data 数组,该数组将返回符合新iteration protocolsGenerator 对象。这将遍历 data 数组,并用将其 value 属性设置为 null 的对象填充它沿途检测到的任何空白。

      sn-p 进一步利用spread operator 创建一个新数组并通过隐式调用迭代器来填充它。

      data[Symbol.iterator] = function*() {
        var i = 0,
            t = this[0],
            nextStep;
        while (i < this.length) {
          nextStep = t.mytime.getTime() + FIVE_MINUTES_IN_MS;
          yield t = nextStep < this[i].mytime.getTime()
            ? {"mytime": new Date(nextStep), "value": null}
            : this[i++];
        }
      };
      
      
      // use the spread operator to create a new array which will implicitly call
      // the iterator
      data = [...data];
      

      查看以下 sn-p 以了解在 Chrome 49 和 FF 45 中运行的演示:

      "use strict";
      
      ///////////////////////////////////////////////////////////////////////////
      // Setup
      ///////////////////////////////////////////////////////////////////////////
      
      const FIVE_MINUTES_IN_MS = 5 * 60 * 1000;
      
      var data = [
      {"mytime": "2015-12-01T23:10:00.000Z", "value": 64},
      {"mytime": "2015-12-01T23:15:00.000Z", "value": 67},
      {"mytime": "2015-12-01T23:20:00.000Z", "value": 70},
      {"mytime": "2015-12-01T23:25:00.000Z", "value": 64},
      {"mytime": "2015-12-01T23:30:00.000Z", "value": 72},
      {"mytime": "2015-12-01T23:35:00.000Z", "value": 75},
      {"mytime": "2015-12-01T23:40:00.000Z", "value": 71},
      {"mytime": "2015-12-01T23:45:00.000Z", "value": 80},
      {"mytime": "2015-12-02T00:00:00.000Z", "value": 80},
      {"mytime": "2015-12-02T00:05:00.000Z", "value": 85}
      ];
      
      var parse = d3.time.format("%Y-%m-%dT%H:%M:%S.%LZ").parse;
      
      data.forEach(function(d) {
        d.mytime = parse(d.mytime);
      });
      
      ///////////////////////////////////////////////////////////////////////////
      // Implement iterator to fill in gaps in data array
      ///////////////////////////////////////////////////////////////////////////
      
      data[Symbol.iterator] = function*() {
        var i = 0,
            t = this[0],
            nextStep;
        while (i < this.length) {
          nextStep = t.mytime.getTime() + FIVE_MINUTES_IN_MS;
          yield t = nextStep < this[i].mytime.getTime()
            ? {"mytime": new Date(nextStep), "value": null}
            : this[i++];
        }
      };
      
      // use the spread operator to create a new array which will implicitly call the iterator
      data = [...data];
      
      ///////////////////////////////////////////////////////////////////////////
      // Just output below.
      ///////////////////////////////////////////////////////////////////////////
      
      //console.dir(data);
      
      d3.select("body").append("div")
      	.style({
          "font-family": "monospace",
          "white-space": "pre"
        })
        .text(JSON.stringify(data, null, 2));
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"&gt;&lt;/script&gt;

      或者,您可以提供iterator 协议的显式实现。这写起来有点冗长,但不会改变整体概念:

      data[Symbol.iterator] = function() {
        var self = this;
        return {
          i: 0,
          t: self[0],
          next() {
            if (this.i < self.length) {
              var nextStep = this.t.mytime.getTime() + FIVE_MINUTES_IN_MS;
              this.t = nextStep < self[this.i].mytime.getTime()
                ? { "mytime": new Date(nextStep), "value": null }
                : self[this.i++];
              return {
                value: this.t,
                done:  false
              }
            } else {
              return {
                done: true
              }
            } 
          }
        }
      };
      

      下面的 sn-p 演示了这一点:

      "use strict";
      
      ///////////////////////////////////////////////////////////////////////////
      // Setup
      ///////////////////////////////////////////////////////////////////////////
      
      const FIVE_MINUTES_IN_MS = 5 * 60 * 1000;
      
      var data = [
      {"mytime": "2015-12-01T23:10:00.000Z", "value": 64},
      {"mytime": "2015-12-01T23:15:00.000Z", "value": 67},
      {"mytime": "2015-12-01T23:20:00.000Z", "value": 70},
      {"mytime": "2015-12-01T23:25:00.000Z", "value": 64},
      {"mytime": "2015-12-01T23:30:00.000Z", "value": 72},
      {"mytime": "2015-12-01T23:35:00.000Z", "value": 75},
      {"mytime": "2015-12-01T23:40:00.000Z", "value": 71},
      {"mytime": "2015-12-01T23:45:00.000Z", "value": 80},
      {"mytime": "2015-12-02T00:00:00.000Z", "value": 80},
      {"mytime": "2015-12-02T00:05:00.000Z", "value": 85}
      ];
      
      var parse = d3.time.format("%Y-%m-%dT%H:%M:%S.%LZ").parse;
      
      data.forEach(function(d) {
        d.mytime = parse(d.mytime);
      });
      
      ///////////////////////////////////////////////////////////////////////////
      // Implement iterator to fill in gaps in data array
      ///////////////////////////////////////////////////////////////////////////
      
      data[Symbol.iterator] = function() {
        var self = this;
        return {
          i: 0,
          t: self[0],
          next() {
            if (this.i < self.length) {
              var nextStep = this.t.mytime.getTime() + FIVE_MINUTES_IN_MS;
              this.t = nextStep < self[this.i].mytime.getTime()
                ? { "mytime": new Date(nextStep), "value": null }
                : self[this.i++];
              return {
                value: this.t,
                done:  false
              }
            } else {
              return {
                done: true
              }
            } 
          }
        }
      };
      
      // use the spread operator to create a new array which will implicitly call the iterator
      data = [...data];
      
      ///////////////////////////////////////////////////////////////////////////
      // Just output below.
      ///////////////////////////////////////////////////////////////////////////
      
      //console.dir(data);
      
      d3.select("body").append("div")
      	.style({
          "font-family": "monospace",
          "white-space": "pre"
        })
        .text(JSON.stringify(data, null, 2));
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"&gt;&lt;/script&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-29
        • 2013-09-21
        • 1970-01-01
        • 1970-01-01
        • 2016-08-02
        • 1970-01-01
        • 2012-12-12
        相关资源
        最近更新 更多