zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    LeetCode 109 Convert Sorted List to Binary Search Tree
    LeetCode 108 Convert Sorted Array to Binary Search Tree
    LeetCode 107. Binary Tree Level Order Traversal II
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode 103 Binary Tree Zigzag Level Order Traversal
    LeetCode 102. Binary Tree Level Order Traversal
    LeetCode 104. Maximum Depth of Binary Tree
    接口和多态性
    C# 编码规范
  • 原文地址:https://www.cnblogs.com/guangluwutu/p/9902682.html
Copyright © 2011-2022 走看看