自定义 Flotr 线性轴

Flying
2013-12-26 / 0 评论 / 131 阅读 / 正在检测是否收录...

Flotr 的轴默认为线性轴 mode='normal'。为什么要使用 Flotr 自定义线性轴来显示时间呢?正如上一篇文章所言:如果使用时间轴,当时间范围为五天时,会在当天与下一天之间绘制一大段多余的 连接线,而且轴标签有时会找不到对应的数据点而缺少实际意义。因此,有必要自定义线性轴而不是使用时间轴。

chart-axis.svg

具体实现

这里的所有日期标签是用 axis.ticks 数组来管理的,同样在一种日期格式下,当前标签与下一日期标签和上一标签的文本不相同时才显示出来。请参考下面代码:

...
else if (o.mode == 'timeEx') { 
  // store all possible ticks.
  var preLabel;
  var nextLabel;
  var r = axis.max - axis.min; 
  for(i = 0; i < r; ++i){
    preLabel = o.tickFormatter(i);
    nextLabel = o.tickFormatter(i + 1);
    if(nextLabel != preLabel)
      axis.ticks.push({ v: i + 1, label: nextLabel });
  }
}

当两个日期标签间隔太近容易重叠时,我们也用了类似方法来移除,只不过在 Flex 中参照间距是相对的,而此处是绝对的。如下面代码:

function filterTicks(graph, axis){
  if(axis.options.mode == 'timeEx'){
    var w = axis.maxLabel.width;
    //filter the labels
    var len = axis.ticks.length;
    if(len > 3){
    var preTick;
    var nextTick;
    for (i = len - 1; i > 0; i--) {
      preTick = axis.ticks[i - 1];
      nextTick = axis.ticks[i];
      //remove the middle label
      if(nextTick){
        if(axis.d2p(nextTick.v) - axis.d2p(preTick.v) < 9 * nextTick.label.length)
          axis.ticks.splice(i - 1, 1);
        }
        //remove the last label
        if(i == len - 1){
          if(graph.plotWidth - axis.d2p(nextTick.v) < 3 * nextTick.label.length){
            axis.ticks.pop();
          }
        }
        //remove the first label
        if(i == 1){
          if(axis.d2p(preTick.v) < w / 3 ){
            axis.ticks.shift();
          }
        }
      }
    }
    len = axis.ticks.length;
    xBoxWidth = graph.plotWidth / len;
  }
}

使用方法很简单,将 xaxismode 指定为自定义的线性轴就行了。

参考代码

完整代码如下:

Html 代码

<div align="center" style="width:800px; padding:50px;">
  <div id="chart_container"></div>
  <div id="btn_container">
    <button value="1 D" name="1d">1 D</button>
    <button value="5 D" name="5d">5 D</button>
    <button value="3 M" name="3m">3 M</button>
    <button value="6 M" name="6m">6 M</button>
    <button value="1 Y" name="1y">1 Y</button>
    <button value="3 Y" name="3y">3 Y</button>
    <button value="5 Y" name="5y">5 Y</button>
    <button value="10Y" name="10y">10Y</button>
    <button value="All" name="my">All</button>
  </div>
</div>

JavaScript 代码

document.observe('dom:loaded', function () {
  drawCharts("1d", false);
});
$('btn_container').childElements().each(function (btn) {
  btn.observe('click', function () {
    drawCharts(btn.name, true);
  });
});
function drawCharts(range, initialized) {
  $('chart_container').update('<span class="info">Loading...</span>');
  var toolTip_dateFormat;
  if (range.include('d')) {
    toolTip_dateFormat = '%m/%d/%y %h:%M:%S';
  } else {

    toolTip_dateFormat = '%m/%d/%y';
  }
  new Ajax.Request('stock.aspx?symbol=YHOO&range=' + range, {
    method: 'get',
    onSuccess: function (transport) {
      /**
        * Parse the text from the server.
        */
      var str = transport.responseText;
      var arr = str.split('\n');
      var len = arr.length;
      if (len > 1) {
        var closeData = [], hitData = [], ms;
        for (var i = 0; i < len; i++) {
          var tmp = arr[i].split(',');
          ms = parseInt(tmp[0]);
          closeData[i] = [i, parseFloat(tmp[1])];
          hitData[i] = [ms, tmp[2], tmp[3], tmp[4], tmp[1]];
        }
        //get tick date format
        var n, t, tu = Flotr.Date.timeUnits;
        var span = hitData[len - 1][0] - hitData[0][0];
        for (var pair in tu) {
          n = Math.floor(span / tu[pair]);
          // less than 3 times
          if (0 < n && n < 72) {
            t = Flotr.Date.timeUnits[pair];
          }
        }
        var tick_dateFormat = Flotr.Date.getFormat(t, span);
        var options = {
          colors: ['#06D'],
          title: "Yahoo Inc.",
          xaxis: {
            mode: 'timeEx',
            tickFormatter: function (n) {
              var d = new Date(hitData[n][0]);
              var str = Flotr.Date.format(d, tick_dateFormat);
              if (str == '0:00') {
                return Flotr.Date.format(d, '%d');
              }
              if (str == 'Jan') {
                return Flotr.Date.format(d, '%y');
              }
              return str;
            },
            background: '#CCD6DB'
          },
          yaxis: { tickDecimals: 2 },
          lines: {
            lineWidth: 1,
            fill: true,
            fillColor: '#CDE2F8',
            fillOpacity: 0.9,
            lineColor: null
          },
          mouse: {
            track: true,
            trackAll: true,
            relative: true,
            position: 'ne',
            lineColor: '#06D',
            fillColor: '#fff',
            fillOpacity: 0.75,
            trackFormatter: function (obj) {
              var x = Math.floor(obj.x);
              var item = hitData[x];
              var str = "";
              str += "Date: " + Flotr.Date.format(new Date(item[0]), toolTip_dateFormat) + "<br/>";
              str += "Open: " + item[3] + "<br/>";
              str += "<font color='#009045'>High: " + item[1] + "</font><br/>";
              str += "<font color='#BF272D'>Low: " + item[2] + "</font><br/>";
              str += "Close: " + closeData[x][1];
              return str;
            }
          },
          grid: { outlineWidth: 1 },
          shadowSize: 0
        }
        $('chart_container').update();
        Flotr.draw($('chart_container'), [closeData], options);
      } else {
        $('chart_container').update('<span class="info">This chart is not available.</span>');
      }
    }
  })
}

后端服务代码

stock.aspx 股票 Ajax 服务见使用 Flotr 绘制股票图
5

评论 (0)

取消