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

上一节中,我们对数据可视化进行了一些基本的介绍,包括其选择器选择,数据绑定方式以及属性的设置,和图表数据的更新等一些操作,今天,我们来学习制作一些柱状图,并对其中用到的一些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轴坐标范围,我们通过这个数值拿到框选到的目标就很简单啦
                    })
            )

最终效果


预览
一个小案例: 使用柱状图动态展示冒泡排序

冒泡排序可视化动态展现

本文所有图表源码

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容