跨越浏览器的d3.js图表显示

最近一段时间对正在采用的图表组件不满意了。看过d3.js之后,别的图表显示确实很难入眼。问题的难度是d3.js采用的SVG技术导致它只能在几种浏览器里使用,在我们客户大量使用的IE,特别是IE6的客户里很难显示正常。SVG之于IE的问题要想解决有几个思路:
一个可以想像的方式是采用svgweb,不过在调试的时候发现IE在加载d3.js经常出非常小且2的问题。比如一个函数里使用了两次while(++i < j)之后,d3.js就不能正常载入,提示的错误居然是“缺少’)’”。
二一个是在后端生成图片,这样就不存在SVG格式的问题了。这个世界近两年来流行的node.js可以在后台执行javascript,这让人有柳暗花明的感觉。
第三个方式是我们后端生成svg文件,前端使用svgweb加载。

沿着第一个思路太耗费时间,不符合想快速解决问题的思路。所以第二、三个方法做了重点测试。
首先可以参照的方法是d3.js里自带的node-canvas例子us-counties。如果将这个图片通过http输出到客户端第二个方法的技术问题就解决了。
然后是@mattbaker提交的gist 1511770,这个例子通过node.js完成了svg文件的生成。加上svgweb,在IE里显示svg图表的问题也就完全不存在了。
@mattbaker提供的gist 1509145提供了直接通过http输出png图片的例子。
我们聊加改造,其实是去除了一些功能就可以得到如下代码:

var http = require('http'),
    url = require('url'),
    jsdom = require('jsdom'),
    child_proc = require('child_process'),
    w = 400,
    h = 400,
    scripts = ["file://"+__dirname+"/../d3.min.js",
               "file://"+__dirname+"/../d3.layout.min.js",
               "file://"+__dirname+"/pie.js"],
    htmlStub = '<!DOCTYPE html><div id="pie" style="width:'+w+'px;height:'+h+'px;"></div>';

http.createServer(function (req, res) {
  var values = (url.parse(req.url, true).query['values'] || ".5,.5")
        .split(",")
        .map(function(v){return parseFloat(v)});  
  // 去除生成图片的代码
  //convert.stdout.on('data', function (data) {
  //  res.write(data);
  //});
  //convert.on('exit', function(code) {
  //  res.end();
  //});

  jsdom.env({features:{QuerySelector:true}, html:htmlStub, scripts:scripts, done:function(errors, window) {
    var svgsrc = window.insertPie("#pie", w, h, values).innerHTML;
    //jsdom's domToHTML will lowercase element names
    svgsrc = svgsrc.replace(/radialgradient/g,'radialGradient');
    res.writeHead(200, {'Content-Type': 'image/svg+xml'});
    res.write(svgsrc);
    res.end();
  // 去除生成图片的代码
  //  convert.stdin.write(svgsrc);
  //  convert.stdin.end();
  }});
}).listen(8888, "0.0.0.0");

console.log('Pie SVG server running at http://127.0.0.1:8888/');
console.log('ex. http://127.0.0.1:8888/?values=.4,.3,.2,.1');

用node.js运行后,使用下面页面即可:

<!DOCTYPE html>
<html>
  <!-- Tests using the OBJECT syntax to embed an SVG file -->

  <head>

    <!-- Optional meta tag; if left off, we default to only using the Flash
         renderer for Internet Explorer and using native support on other
         browsers. You can force the Flash renderer for all browsers by
         setting the META tag below to true. -->
    <!-- meta name="svg.render.forceflash" content="true" / -->  <!-- disabled  -->

    <script src="../../src/svg.js" data-path="../../src/"></script>
  </head>

  <body>
    <h1>Tests using the OBJECT syntax to embed an SVG file</h1>

    <!--[if !IE]>-->
      <object data="http://localhost:8888/?values=.4,.3,.2,.1" type="image/svg+xml"
              width="1250" height="750" id="mySVGObject"> <!--<![endif]-->
    <!--[if lt IE 9]>
      <object src="http://localhost:8888/?values=.4,.3,.2,.1" classid="image/svg+xml"
              width="1250" height="750" id="mySVGObject"> <![endif]-->
    <!--[if gte IE 9]>
      <object data="http://localhost:8888/?values=.4,.3,.2,.1" type="image/svg+xml"
              width="1250" height="750" id="mySVGObject"> <![endif]-->
      </object>

    <h1>Test HTML H1</h1>
  </body>
</html>

龙年将至,发文记之,期待腾飞。

打赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注