Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2015-1-13 D3(Data-Driven Documents) #23

Open
hjzheng opened this issue Jan 13, 2015 · 1 comment
Open

2015-1-13 D3(Data-Driven Documents) #23

hjzheng opened this issue Jan 13, 2015 · 1 comment

Comments

@hjzheng
Copy link
Owner

hjzheng commented Jan 13, 2015

D3(Data-Driven Documents)

什么是D3?

这里的D3,首先不是尼康相机也不是暗黑破坏神3更不是维生素。

摘自数据可视化实战:使用D3设计交互式图表

D3(有时候也叫D3或d3.js)是一个JavaScript库,用于创建数据可视化图形。
事实上,D3是一个缩写,它的全称叫Data-Driven Documents(数据驱动的文档)。
数据来源于你,而文档就是基于Web的文档(或者网页),代表可以在浏览器中展现的一切,
比如HTML、SVG。D3扮演的是一个驱动程序的角色,因为它联系着数据和文档。

D3优点

  • 资料丰富,案例非常多。
  • SVG矢量图形的特点是无损缩放,这个优势在显示2D图形式会有非常好的效果,并且兼容各种分辨率。
  • SVG图形的节点可以像dom元素一样控制,这就让自主创作图形变得更容易。相对于canvas这也是非常大的优势。

D3缺点

  • SVG是2D矢量图,不能画3D图形。(用2D矢量可以画很多带透视效果的伪3D图,那并不是真正的3D图!)
    d3.
  • 不支持IE6,7,8。如果想要IE8使用d3,请用r2d3.js(一个结合了 Raphael.js的扩展库)。Raphael.js是一个跨浏览器的矢量图形库,它实现IE6,7,8兼容的方法是:在IE6,7,8中使用VML,在其他浏览器中使用SVG。另外,如果图形复杂,就不要指望用Raphael.js在IE上能跟D3画出一样酷炫的效果。
  • SVG的节点都是对象,非常占用内存。例如论坛里一个朋友使用d3绘制超过12000个节点的图,直接导致每个试图打开它的浏览器都崩溃了。这个时候如果不愿意做简化那么应该试试canvas绘图。

一个例子, 基于AngularJS (http://projects.delimited.io/experiments/last-fm/)

angular.module('viz').directive('toptagChart', ['lastfm', 

  function (lastfm) {

    var link = function ($scope, $el, $attrs) {
      //定义大小
      var diameter = 500;

      //使用pack布局,关于pack你可以查看D3 API
      var bubble = d3.layout.pack()
        .sort(null)
        .size([diameter, diameter])
        .padding(2.5);

      //创建svg元素,并定义大小 
      var svg = d3.select($el[0]).append("svg")
        .attr({width: diameter, height: diameter})
        .attr("viewBox", "0 0 " + diameter + " " + diameter);

      //追加g元素 
      var chart = svg.append("g");

      //追加text元素,显示loading
      chart.append("text").attr("id", "loading")
        .text("Loading...")
        .attr("transform", "translate(200,250)");

      var update = function () {
        var data = $scope.toptags.map(function (d) {
          d.value = d[$scope.tagsize];
          return d;
        });

        //将数据塞入pack布局中,pack布局会
        //自动帮我们计算坐标和bubble的半径大小根据value
        bubble.nodes({children: data});

        //data如果有数据,删除text元素
        if (data.length) chart.select("#loading").remove();

        //选取所有class为node元素
        //很多人很奇怪,为啥元素没有创建,却要去选取
        //这就是D3的特点,通过下面的enter()方法先占位
        //enter(), 这个方法会分析当前选择的DOM 元素和传给它的数据,
        //如果数据值比对应的DOM 元素多,就创建一个新的占位元素。
        //然后把这个新占位元素的引用交给链中的下一个方法
        var selection = chart.selectAll(".node")
          .data(data);

        //enter方法占位,追加g元素,并添加node class
        var enter = selection.enter()
          .append("g").attr("class", "node")
          .attr("transform", function (d) { 
            return "translate(" + d.x + "," + d.y + ")"; 
          });

        //在g元素里面添加圆,利用pack布局计算好的圆心坐标和半径
        enter.append("circle")
          .attr("r", function (d) { return d.r; })
          .style("fill", '#FFCB72')
          .on("click", function (d) {
            svg.selectAll("circle").style("fill", '#FFCB72');
            d3.select(this).style("fill", "#19314A");

            lastfm.topArtists(d.name)
              .success(function (res) {
                if (res.error) {
                  throw new Error(res.message);
                } else {
                 $scope.currtag = d.name;
                  var artists = res.topartists.artist.map(function (a) {
                    a.genre = d.name;
                    a.arank = +a['@attr'].rank;
                    return a;
                  });
                  $scope.artists = artists;
                }
              });
          });

        //在g元素里追加文本
        enter.append("text")
          .attr("dy", ".3em")
          .style("text-anchor", "middle")
          .text(function (d) { return d.name; });

        //当圆心坐标改变时,增加translation效果
        selection.transition().duration(2000)
          .attr("transform", function (d) { 
            return "translate(" + d.x + "," + d.y + ")";
          });

        //当圆的半径改变时,增加translation效果
        selection.selectAll("circle").transition().duration(3000)
          .attr("r", function (d) { return d.r; });

        resize();
      };

      function resize() {
        svg.attr("width", $el[0].clientWidth);
        svg.attr("height", $el[0].clientWidth); //It's a square
      }

      $scope.$on('windowResize',resize);
      //tagsize如果有变化,调用update方法
      $scope.$watch('tagsize', update);
      $scope.$watch('toptags', update);

    };
    return {
      template: '<div class="chart col-sm-12 col-md-12 col-lg-12 col-xl-12"></div>',
      replace: true,
      link: link, 
      restrict: 'E' 
    };
}]);

另一个例子,是我自己写的(http://get-set.cn/front-end-chart/)

代码: https://github.com/hjzheng/front-end-collect

参考资料

我涉及的数据可视化的实现技术和工具
数据可视化实战:使用D3设计交互式图表
Creating Custom D3 Directives in AngularJS

@hjzheng
Copy link
Owner Author

hjzheng commented Jan 13, 2015

2015年 第一篇,祝福CUF Team越来越强!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant