使用 Flotr2

Flying
2014-01-10 / 0 评论 / 161 阅读 / 正在检测是否收录...

Flotr2 是 Flotr 的分支,它有独立版和插件版。独立版对旧版本做了不少改进,不但移除了对 Prototype 的依赖还改进移动设备的支持,比如支持 Touch 事件。数据系列也有了改进,构成系列的每个数组可以支持多个元素,旧版的只支持两个(对应 x 和 y)。插件版可灵活选择并自由扩展插件。详见 Flotr2 官网

chart-bar.svg

快速入门

官网提供的插件版实例适合演示 Flotr2 的全部功能特性,但不太适合入门学习。其实只要你有 Flotr 的基础,只要导入必需的 js 文件就行了。通常情况下,除了 imagediff.jsyepnope.js,lib 和 js 根目录下的全部的 js 文件是不可少的,应该最先加载,然后导入相应图表类型和插件所需的 js 文件。比如要绘制直线或区域图,需要导入 lines.jspoints.js。如果要绘制标签、网格线和 ToolTip,需要导入 labels.jsgrid.jshit.js。其它的代码就和以前的一样了。具体请参看我用 Flotr2 插件版改写的实例:

$(function () {
  drawCharts("1d");
  $('button').click(function () {
    drawCharts(this.name);
  });
});
function drawCharts(rng) {
  var toolTip_dateFormat;
  if (rng.indexOf('d') != -1) {
    toolTip_dateFormat = '%m/%d/%y %h:%M:%S';
  } else {
    toolTip_dateFormat = '%m/%d/%y';
  }
  var container = document.getElementById('container');
  container.innerHTML = '<span class="info">Loading...</span>';
  $.get('stock.aspx', { symbol: 'YHOO', range: rng },
    function (data) {
      /**
      * Parse the text from the server.
      */
      var arr = data.split('\n');
      var dataProvider = [];
      var i, len, tmp, ms, close, open, high, low;
      len = arr.length;
      for (i = 0; i < len; i++) {
        tmp = arr[i].split(',');
        ms = parseInt(tmp[0]);
        close = parseFloat(tmp[1]);
        open = tmp[2];
        high = tmp[3];
        low = tmp[4];
        dataProvider[i] = [i, close, open, high, low, ms];
      }
      if (len > 1) {
        var n, t;
        var tu = Flotr.Date.timeUnits;
        var span = dataProvider[i - 1][5] - dataProvider[0][5];
        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'],
          xaxis: {
            mode: 'timeEx',
            tickFormatter: function (n) {
              var d = new Date(dataProvider[n][5]);
              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', '#0066DD'],
            fillOpacity: 0.9,
          },
          mouse: {
            track: true,
            trackAll: true,
            relative: true,
            position: 'ne',
            lineColor: '#06D',
            fillColor: '#fff',
            fillOpacity: 0.9,
            trackFormatter: function (obj) {
              var item = obj.series.data[obj.index];
              var d = new Date(item[5]);
              var str = "";
              str += "Date: " + Flotr.Date.format(d, toolTip_dateFormat) + "<br/>";
              str += "Open: " + item[4] + "<br/>";
              str += "<font color='#009045'>High: " + item[2] + "</font><br/>";
              str += "<font color='#BF272D'>Low: " + item[3] + "</font><br/>";
              str += "Close: " + item[1];
              return str;
            },
            crosshair: { mode: 'xy' }
          },
          grid: {
            outlineWidth: 1,
            outlineColor: '#2B4657'
          },
          shadowSize: 0
        }
        var D = Flotr.DOM;
        D.empty(container);
        chart_container = D.node('<div id="chart_container"></div>');
        D.insert(container, chart_container);
        Flotr.draw(chart_container, [dataProvider], options);
      } else {
        container.innerHTML = '<span class="info">This chart is not available.</span>';
      }
    }
  );
}

注意:stock.aspx 股票 Ajax 服务见使用 Flotr 绘制股票图

可以看到,上面的实例有用到 Jquery 而不是 Prototype。当然也可以都不用。另外个人觉得鼠标跟踪和十字线应该在 hit 事件触发时同时绘制,因此我将 Crosshair 功能整合到 hit.js 中了。还有对 xaxis 扩展了一种 mode:timeEx,详见我前面写的文章。

限制鼠标跟踪

Flotr2 hit 插件很好用,但有一个缺点:鼠标跟踪有时会超出图表范围显示。如果图表是满屏显示,那这就是个 Bug 了。其实,很容易就能限制鼠标跟踪始终在图表范围中显示。原理是这样的:鼠标跟踪显示后,如果它的位置超出图表右端,需要重新定位到 west 方向;它的位置超出图表顶端,重新定位到 south 方向。依次类推。如下代码:

//east
if(D.size(mouseTrack).width + n.xaxis.d2p(n.x) + m >= this.plotWidth){
  mouseTrack.style.left = 'auto';
  mouseTrack.style.right = m - left - n.xaxis.d2p(n.x) + this.canvasWidth + 'px';
}
//north
if(n.yaxis.d2p(n.y) - D.size(mouseTrack).height - m <= 0){
  mouseTrack.style.top = m + top + n.yaxis.d2p(n.y) + 'px';
  mouseTrack.style.bottom = 'auto';
}
//west 
if(n.xaxis.d2p(n.x) - D.size(mouseTrack).width - m <= 0){
  mouseTrack.style.left = m + left + n.xaxis.d2p(n.x) + 'px';
  mouseTrack.style.right = 'auto';
}
//south 
if(n.yaxis.d2p(n.y) + D.size(mouseTrack).height + m >= this.plotHeight){
  mouseTrack.style.top = 'auto';
  mouseTrack.style.bottom = m - top - n.yaxis.d2p(n.y) + this.canvasHeight + 'px';
}

警告:上述代码一定要加在 D.show(mouseTrack); 之后,不然取不到鼠标跟踪的宽度和高度。

同步鼠标跟踪

同步 Flotr2 Chart 的鼠标跟踪比起同步 Flex Chart 的数据提示要麻烦,而且 Flotr 与 Flotr2 调用的 API 还不一样。Flotr 中的 flotr:hit 事件对象有一个 memo 属性,而 Flotr2 中的 flotr:hit 事件对象其实就是一个 nearest 对象。不仅如此,在 Flotr2 中调用 graph.hit(mouse); 会报错,得使用 graph.hit.drawMouseTrack(n);graph.hit.drawHit(n); 来实现,详见本实例中的 doHit 函数:

function doHit(graph, e, container) {
  var n = Flotr.clone(e);
  graph.hit.clearHit();
  var offset = Flotr.DOM.position(container);
  var xaxis = graph.axes.x;
  var yaxis = graph.axes.y;
  var s = graph.series[0]; 
  var index = n.index;
  var point = s.data[index];
  n.xaxis = xaxis;
  n.yaxis = yaxis;
  n.x = point[0];
  n.y = point[1];
  graph.hit.drawMouseTrack(n);
  graph.hit.drawHit(n);
}

参考示例

访问 codepen 查看完整项目代码及最终效果

4

评论 (0)

取消