美文网首页D3数据可视化Web前端之路
深入浅出d3.js数据可视化之道(2)

深入浅出d3.js数据可视化之道(2)

作者: 金字笙调 | 来源:发表于2017-08-16 16:53 被阅读401次

    上一节中,我们对数据可视化进行了一些基本的介绍,包括其选择器选择,数据绑定方式以及属性的设置,和图表数据的更新等一些操作,今天,我们来学习制作一些柱状图,并对其中用到的一些api 进行讲解。

    svg矩形位置设定

    x: 矩形左上角x轴坐标
    y: 矩形右上角y轴坐标
    width: 矩形的宽度
    height: 矩形的高度
    rx: 对于圆角矩形,指椭圆在x轴方向的半径
    ry: 对于圆角矩形,指椭圆在y轴方向的半径

    例如:

    <svg width="100mm" height="100mm"> <rect x="20" y="20" width="50" height="50" style="stroke: #f36; fill: rgba(123,123,23,.5);"/> </svg>
    
    坐标系统
    比例尺
    • 线性比例尺
      一个最简单的线性关系: y= 2x +1

    在d3 的v4版本中,运行可得下列结果:

    let yScale = d3.scaleLinear()
             .domain([0, 500])
             .range([0, 100]);
    
    console.log( yScale(50) )  //10
    console.log( yScale(250) )  // 50
    console.log( yScale(450) )  //90
    
    • 序数比例尺
      定量比例尺的定义域和值域都是连续的,在实际的使用中,很多时候定义域和值域都是是非连续的,这时候我们就要用到序数比例尺了。
    let xScale = d3.scaleBand()
                    .domain(["a", "b", "c", "d", "e"])
                    .rangeRound([0, 100])
    
    console.log(xScale("a"))  //0
    console.log(xScale("d"))   //60
    console.log(xScale("e"))    //80
    

    好了,学习上面两个知识点之后,我们开始我们的柱状图绘制!

    准备的数据

    const data =[
        {x:"上海", y:100},
        {x:"北京", y:200},
        {x:"天津", y:280},
        {x:"西安", y:100},
        {x:"武汉", y:240},
        {x:"长沙", y:210},
        {x:"深圳", y:100},
        {x:"郑州", y:220},
        {x:"驻马店", y:410},
        {x:"信阳", y:100},
        {x:"漯河", y:220},
        {x:"商丘", y:210},
        {x:"南阳", y:100},
        {x:"纽约", y:220},
        {x:"南昌", y:210}
    ]
    

    样式

    svg {
      box-sizing: content-box
    }
    

    界面初始化

    在进行渲染之前,我们会先在svg 各侧预留padding,这里做的主要目的是为了坐标轴数值部分超出的可以正常显示。

       var initWidth = 340
        var initHeight = 500
    
        var padding = { left:40, top:20, right:10, bottom: 20}
    
        var height = initWidth - padding.top - padding.bottom
        var width  = initHeight - padding.left - padding.right
    
    
        var svg = d3.select("body")
                    .append("svg")
                    .attr("width", width)
                    .attr("height", height)
                    .style("padding-left", padding.left)
                    .style("padding-right", padding.right)
                    .style("padding-top", padding.top)
                    .style("padding-bottom", padding.bottom)
    

    此时效果如下:


    初始效果

    定义坐标轴

             // y比例尺
            let ydata = data.map(function(e, i){ return e.y})  //拿到y轴所有数据
            let yScale = d3.scaleLinear()   //定义线性比例尺(数值型,等比缩放)
             .domain([0, d3.max(ydata)])    // 定义域
             .range([height , 0]);          //值域
             
            let _yScale = d3.scaleLinear()
             .domain([0, d3.max(ydata)])
             .range([0, height]); 
    
            ***上述yScale与 _yScale的差别就在于range恰恰相反,
            因此同样的数值在运算时拿到的正好是相反的数据,
            而这在待会的坐标轴数值计算和直方位置的计算中我们会用到***
    
            //定义y轴
            let yAxis = d3.axisLeft(yScale);   //这句话的意思是添加左侧坐标轴,比例尺使用yScale
    
            //添加y轴
            svg.append("g")
            .attr("class","axis")
            .attr("transform","translate(" + 0 + "," + 0 + ")")
            .call(yAxis);
    
         //添加x轴坐标轴
    
             //x轴比例尺
             let xData = data.map(function(e, i){ return e.x})
             let xScale = d3.scaleBand()  //定义序数比例尺
                            .domain(xData)
                            .rangeRound([0, width])
                            .padding(0.1)
            //定义x轴
            let xAxis = d3.axisBottom(xScale)
            
            //添加x轴
             svg.append("g")
                .attr("class","axis--x")
                .attr("transform","translate(" + "0 ," + height + ")")
                .call(xAxis);
    

    此时效果如下


    预览

    绘制直方

        var rect = svg.selectAll("rect")
                      .data(data)
                      .enter()
                      .append("rect")
                      .attr("x", function(d, i){
                          return xScale(d.x)
                      })
                      .attr("y", function(d){
                          return height -  _yScale(d.y)
                      })
                      .attr("width", xScale.bandwidth())
                      .attr("height", function(d){
                          return _yScale(d.y)
                      })
                      .attr("fill", "steelBlue")
    

    效果


    预览

    接下来,我们可以在柱上添加文字

    
        var text = svg.append("g")
                    .selectAll("text")
                    .data(data)
                    .enter()
                    .append("text")
                    .attr("x", function(d, i){
                          return xScale(d.x)
                      })
                    .attr("y", function(d){
                          return height -  _yScale(d.y)
                    })
                    .attr("dy", "1em")
                    .attr("dx", xScale.bandwidth() / 2)
                    .attr("text-anchor", "middle")
                    .attr("font-size", '14px')
                    .attr("fill", "#fff")
                    .text(function(d){
                        return d.y
                    })
    

    效果如下


    预览

    我们可以给坐标轴添加一些样式让他看起来活泼一些

     .axis--x path {
        display: none;
      }
    

    鼠标在上面移动时我们可以给他添加一些样式

    var rect = svg.selectAll("rect")
            .........
                      .attr("fill", "steelBlue")
                      .on("mouseover",function(){
                          d3.select(this).attr("fill", "yellow")
                      })
                      .on("mouseout", function(){
                          d3.select(this).attr("fill","steelBlue")
                      })
    

    预览


    预览

    接下来我们给它添加一些交互效果

    点击事件

    这个很简单只需这样一句

    var rect = svg.selectAll("rect")
            .........
                      .on("click",function(d){
                           console.log(d.x+":"+d.y)
                      })
    
    

    (框选和点击不能同时存在)

    框选
             var brush = svg.append("g")
                 .attr("class", "brush")
                .call(d3.brushX()
                        .on("start", function(){     })  
                        .on("brush", function(){     } )
                        .on("end", function(e) {
                            var selection = d3.event.selection;
                            console.log(selection)  //可以拿到框选的x轴坐标范围,我们通过这个数值拿到框选到的目标就很简单啦
                        })
                )
    

    最终效果


    预览
    一个小案例: 使用柱状图动态展示冒泡排序
    冒泡排序可视化动态展现
    本文所有图表源码

    好了,今天我们先学到这里,明天更新饼图制作 !

    相关文章

      网友评论

        本文标题:深入浅出d3.js数据可视化之道(2)

        本文链接:https://www.haomeiwen.com/subject/fawbrxtx.html