• D3.js 基于数据的绘图


    这里涉及了 HTML & CSS 的知识,比如说元素的样式和元素块,以后我会把相关知识补上。


    绘制直线图

    条形图实际上是矩形,而 HTML 的 div 元素是绘制矩形的最简单手段。(对于浏览器来说,HTML 中的一切元素都可以用来表示矩形)。

    所以我们可以定义一个叫 bar 的 div 类,用于存放图表的公共属性。(除了高度,其他的属性应该是共享的)

    div.bar {
                    display: inline-block;   20px;  height: 75px;    /*最后这里会被覆写*/  margin-right: 2px;  background-color: green;
    •  关于类

    元素的类作为 HTML 属性存在于标记代码中,同时 CSS 规则也可以引用它。除了为元素设定类以外,直接给元素应用样式也可以。(这里不太懂,下次遇到案例再写上)

    D3 有一种方法用于快速添加或者删除元素的类:

    .classed("bar",true) // 给选中的元素添加类 bar  .classed("bar",false) //从元素总删除类 bar 
    • 关于样式

    .style 方法用于直接为 HTML 元素应用 CSS 属性和值。这方法执行的结果等价于在 HTML 的 style 属性中直接写入 CSS 规则

    <div style="height: 75px;"></div>

    如果要生成条形图,每个条形图的高度必须是对应数据值得函数,D3 代码中可以对这个高度之进行重写:

    .style("height", function(d) {
            var barHeight = d * 5; //这里是因为原始生成高度太矮了
            return barHeight + "px"; 
    });
    • 关于属性设定

    attr() 用于设定HTML 元素的属性和值。我们要给我们生成的 div 中添加 bar 类,需要这样写:

    .attr("class","bar")

     

    代码如下:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>D3: Our first bar chart with data</title>
            <script type="text/javascript" src="../d3.js"></script>
            <style type="text/css">
                div.bar {
                    display: inline-block;
                     20px;
                    height: 75px;    /* Gets overridden by D3-assigned height below */
                    margin-right: 2px;
                    background-color: green;
                }
            </style>
        </head>
        <body>
            <script type="text/javascript">
                var dataset = [ 25, 7, 5, 26, 11 ];
                d3.select("body").selectAll("div")
                    .data(dataset)
                    .enter()
                    .append("div")
                    .attr("class", "bar")
                    .style("height", function(d) {
                        var barHeight = d * 5;
                        return barHeight + "px";
                    });

    随机数据

    教材上面用了一个可以生成随机数值得方法,在这里记录一下:

    这里是创建了一个名为 dataset 得空数组;

    初始化一个循环25次的 for 循环,执行25次

    每次生成一个介于0到30之间的随机数

    把新数值追加到数组中(push() 是数组的方法,每次执行都会把一个新值推进数组末尾)。

    var dataset = [];
    for( var i = 0; i < 25 ;i ++){
        var newNumber= Math.random() * 30;
        dataset.push( newNumber);}

    注意:

    此时 push 进去的都是浮点数,可以用 Math.round() 或者Math.floor () 方法取整。前者是将数值想上取整,后者是向下取整。

    var newNumber = Math.floor(Math.random() * 30);
    dataset.push( newNumber();)

    绘制 SVG

    SVG 元素是通过标签中的属性 / 值对来指定SVG元素的个各方面特征,如:

    <element property = "value"></element>

    因为 SVG 元素存在于 DOM 中,与其他 HTML 元素一样,因此生成 SVG 图形依然要使用 append() 和 attr() 方法。

    创建 SGV

    首先要创建一个元素,以便在其中保存所有图形。这行代码先找到文档的 body 元素,然后再结束的 </body> 标签前添加一个新的 svg 元素。

     d3.select("body").append("svg");

    也可以使用一种更好的方式,把append() 返回的新元素保存在了变量 svg 中。有了这个引用,将来可以少些很多代码,从而不用总是写 da.select("svg") ,而是只要写 svg 即可:

    var svg = d3.select("body").append("svg");

     完整代码如下,DOM 中将创建一个新的空的 SVG元素。其中高度和宽度保存于变量中,可以方便引用。

    var w =500;
    var h = 50;
    var svg = d3.select("body")     .append("svg")  .attr("width",w)  .attr("height",h);

     然使用data() 迭代每个数据节点,创建一个圆形。同时创建一个新的变量保存引用

    var circles = svg.selectAll("circle")  .data(dataset)  .enter  .append("circle");

    创建位置和大小信息:

    circle.attr( "cx", function(d, i)){
        return (i*50) +25;  
      // 这里是通过引用所有的圆形的变量来设置每一个圆形的属性。(在SVG中,cx 是圆形圆心的 x 坐标,由于数据已经绑定到了圆形,所以对于每个圆形来说,都有其对应于原始数据的值。
      // 并且其中的i值是自动生成的),同时,索引 i 是从function(d,i)中传入的,使其与 d 元素一致。
    }) .attr("cry", h/2) .attr("r", function(d) { return d; });
      // cy 是圆形圆心的 Y 的坐标,这里把 cy 设置成了 h 的一半。由于 h 保存着整个SVG元素的高度,所以这里是将所有圆形垂直居中
      // 每个圆形的半径被设为 d,从而反映数据的大小

    最后生成如图示:

    也可以在上面添加色彩:

    色彩填充( fill )和描边( stroke )同样也是属性,所以也可以通过attr()方法来设定。

    .attr("fill", "yellow")
    .attr("stroke", "orange")
    .attr("stroke-width", function(d) {
    return d/2;}

    最后图像如下:

    源代码为:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>D3: Using color in SVG</title>
            <script type="text/javascript" src="../d3.js"></script>
            <style type="text/css">
                /* No style rules here yet */        
            </style>
        </head>
        <body>
            <script type="text/javascript">
                //Width and height
                var w = 500;
                var h = 100;
                //Data
                var dataset = [ 5, 10, 15, 20, 25 ];
                //Create SVG element
                var svg = d3.select("body")
                            .append("svg")
                            .attr("width", w)
                            .attr("height", h);
                var circles = svg.selectAll("circle")
                    .data(dataset)
                    .enter()
                    .append("circle");
                circles.attr("cx", function(d, i) {
                            return (i * 50) + 25;
                        })
                       .attr("cy", h/2)
                       .attr("r", function(d) {
                            return d;
                       })
                       .attr("fill", "yellow")
                       .attr("stroke", "orange")
                       .attr("stroke-width", function(d) {
                            return d/2;
                       });
            </script>
        </body>
    </html>

     关于绘制条形图的改进:

     我们也可以通过 SVG 的方式来绘制条形图:

    首先确定 SVG 的大小:

    var w = 500;
    var h = 500;

    然后让 D3 创建一个空元素,将其添加到 DOM 中.复习一下,这些代码会在结束的</body>标签前面插入新的 svg 元素,并将结果保存在了变量 svg 中,因此以后可以方便引用这个 sv g元素,而不用每次再使用 select() 之类的代码重新选择。

    var svg = d3.select("body")
                        .append("svg")
                        .attr("width",w)
                        .attr("height",h);

    然后不创建 div,而是生成矩形元素 rect 并将其添加到 svg 中。

    这段代码选择了 svg 中所有的矩形。但是,现在什么也没有,所以会返回一个空的元素集。

     接下来 data(dataset) 看到了数据集中有20个值,就把这些值交给了 enter() 处理。每个rect  必须有 x, y width 和 height 属性。这里就是用 attr() 为每个新创建的 rect 设置了这些属性。但是这样会出现一个问题,就是所有的条形生成以后就重叠在了一起,而且此时并没有反映数据。 

    svg.selectAll("rect")
        .data(dataset)
        .enter()
        .append("rect")
        .attr("x",0)
        .attr("y",0)
        .attr("width",20)
        .attr("height",100);

    为了解决重叠问题们同样需要使用 function() 函数:

    .attr("x",function(d,i)) {
        return i*21; //由于矩形宽20像素,所以外加一个像素作为间距。
    };

    动态缩放:

    当数据比较多的时候,最右边的矩形很有可能跑到 SVG 外面去,这时候就需要使用灵活、动态的坐标方案了。

    首先,从改进设置每条矩阵 x 坐标的那行代码进行修改,这样的话,每个矩形就会进行缩放生成。当数据密的时候就会密集,当数据稀疏的时候间距就会拉大。

    .attr("x",function(d,i) {
        return i * (w / dataset.length);
    })

    以图为例:

    当数据密集的时候:

    当数据稀疏的时候:

    这种解决方式并不好看。为了更加的美观,可以将矩形的宽度也成比例的缩放。

    var w = 500;
    var h = 100;
    var barPadding = 1; //这里的变量是减去的间距的值
    .attr("width",w / dataset.length - Padding)

    然后再让数据值决定条形高度:

    .attr("height",function(d)){
        return d*4; // 放大四倍
    });

    结果如图所示:

    由于 SVG 在绘制时,x 和 y 值指定的是它们左上角的坐标,所以 SVG 支持的只有左上角坐标系。如果我们需要改成一般的矩形图,就需要将每个图形的“下沿”与 SVG 的下沿对齐,每个 rect 的 height可以就设置为数据值的本身。

    .attr("y", function(d){
        return h - d;
    })
    .attr("height",function(d){
        return d;
    });

    结果如图示:

    上色

    使用 fill 属性可以对其添加颜色:

    .attr(" fill", "teal");

    我们也可以让颜色反映数据的某些特性,对着条形图而言,这样做叫做双重编码,即同样的数据值可以被编码成俩种可以见的特性:条形高度和颜色。

    .attr( "fill", function(d){
        return "rgb( 0, 0, "+(d * 10) +" )";

    附录:关于多值映射

    D3 拥有多值映射机制,从而可以一次性设置多个值。而且依然是用 attr( ) 方法。假设要把一个圆形平移到 SVG 左上角,再设置成红色,可以每次单独调用 attr( ) :

    svg.select("circlr")
        .attr("cx",0)
        .attr("cy",0)
        .attr( "fill", "red")

    也可以把这三个属性的值都封装在一个对象中,然后统一交给 attr( ) :

    svg.select("circlr")
        .attr({
            cx: 0;
            cy: 0;
            fill: "red"
        });

    源代码为:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>D3: Adding dynamic color, based on data</title>
            <script type="text/javascript" src="../d3.js"></script>
            <style type="text/css">
                /* No style rules here yet */        
            </style>
        </head>
        <body>
            <script type="text/javascript">
    
                //Width and height
                var w = 500;
                var h = 100;
                var barPadding = 1;
                
                var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
                                11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
                
                //Create SVG element
                var svg = d3.select("body")
                            .append("svg")
                            .attr("width", w)
                            .attr("height", h);
    
                svg.selectAll("rect")
                   .data(dataset)
                   .enter()
                   .append("rect")
                   .attr("x", function(d, i) {
                           return i * (w / dataset.length);
                   })
                   .attr("y", function(d) {
                           return h - (d * 4);
                   })
                   .attr("width", w / dataset.length - barPadding)
                   .attr("height", function(d) {
                           return d * 4;
                   })
                   .attr("fill", function(d) {
                        return "rgb(0, 0, " + Math.round(d * 10) + ")";
                   });
                
            </script>
        </body>
    </html>
  • 相关阅读:
    Regular进阶: 几点性能优化的建议
    总结常见的违背Rest原则的接口设计做法
    如何进行用户访谈更容易获得全面而有效的信息
    关于以太坊智能合约在项目实战过程中的设计及经验总结(2)
    关于以太坊智能合约在项目实战过程中的设计及经验总结(1)
    字节码执行方式--解释执行和JIT
    Redis数据库结构与读写原理
    移动端工程架构与后端工程架构的思想摩擦之旅(2)
    类文件结构与javap的使用
    JVM垃圾收集器(1)
  • 原文地址:https://www.cnblogs.com/guangluwutu/p/9902682.html
Copyright © 2020-2023  润新知