【D3.js实战】 品牌排名动态可视化

品牌排名动态可视化 @ D3.js

任务清单

  • 做出一个类似于下图所示的能根据时间更新变换的品牌动态排行榜

在这里插入图片描述

  • 数据地址
    https://gist.github.com/jrzief/70f1f8a5d066a286da3a1e699823470f
    整个clone下来即可

由于多位朋友反应,这个数据集比较难下载,我把它下载好了放在了我的网盘上,大家自行下载。
在文章结尾有源代码,复制下来即可运行。
数据链接: https://pan.baidu.com/s/1VQeqk5oDTTSysPI4SHGLwg 提取码: gpve

  • 要求:1.动画效果,2.各品牌的排名与数值根据年份进行修改

思路分析

  • 画布初始化
  • 数据预处理
  • 首次数据-图元绑定,即首次data-join
  • 设置时间触发器(d3.interval / setInterval)
  • 编写更新函数
    • 更新数据,即重新得到前12名数据
    • 更新x坐标轴(因为数据值会变大,原来的坐标轴不适用了)
    • 重新进行数据-图元绑定
    • 年份更新

画布初始化

首先要进行画布初始化,创建初始画布svg,定义全局变量,绘制标题,副标题,坐标轴等等。

let svg = d3.select('body').select('svg');
const top_n = 12;
const margin = {
   
    top : 80,
    right : 65,
    bottom : 5,
    left : 20 
};
let height = +(svg.attr('height'))
let width = +(svg.attr('width'))
let xAxis;
let xScale;
let yScale;
let yearText;

const barPadding = (+svg.attr('height')-margin.top-margin.bottom)/(top_n*5)

let title = svg.append('text')
.attr('class','Title')
.attr('y', 30)
.attr('x',width/2 )
.text('BrandRank')

let subTitle = svg.append('text')
.attr('y', 55 )
.attr('x', width-margin.right-70)
.attr('class', 'subTitle' )
.text("Brand value  ,  $m")
let year = 2000;

const tickDuration = 500;//执行间隔

数据预处理

这里的数据预处理有以下几点需要注意的

注意将所有值转换为数值类型

因为d3.csv默认读进来数据都是字符串类型的,因此为了方便后续计算,要转换成数值类型

注意设置缺失值的缺省值

由于数据中有许多 NaN,集中在value字段,因此在value字段要多进行一步缺省。
注意:缺省必须在转换为数值之后

d.value = +(d.value)
d.value = isNaN(d.value) ? 0 : d.value
为每个数据设置颜色

这里比较有意思,设置颜色这步完全可以挪到data-join的时候,但是这里可以默认为某个数据绑定上一个默认的颜色,使用到的是d3.hsl()这个接口。

d.color = d3.hsl(Math.random()*360,0.75,0.75,0.8)

这是设置完的color数据值,最后一个参数是透明度,缺省值为1。

在这里插入图片描述

过滤数据,仅保留当前年份的,数据切片,设置排名
  • data.filter()过滤数据。然后由于绑定只需要使用到前12名数据,因此这里用到了slice()切片函数进行了数据切片处理。

    let yearSlice = data.filter(d => d.year == year && !isNaN(d.value))
    .sort((a,b) => b.value - a.value)
    .slice(0,top_n)
    
  • 由于最终需要根据数值排名来设置矩形的位置,因此要设置一下yearSlice中的数据排名

    //此时索引就是排名了
    yearSlice.forEach((d,i) => d.rank = i)
    

首次数据绑定

首次数据绑定我这里为了让逻辑更加清晰,封装成了一个函数render_init(yearSlice),而没有写在d3.csv.then()中 ,参数是已经切分好的当前年份top12的数据。注意,render_init()中的内容是后续需要更新的图元,由于坐标轴后续也需要更新,因此将坐标轴也放在render_init()

//yearSilce:切片好了的数据
const render_init = function(yearSlice){
   
    //functionBody()
}
坐标轴
    xScale = d3.scaleLinear()
        .domain([0,d3.max(yearSlice,d => d.value)])
        .range([margin.left , width-margin.right])
        .nice()

    yScale = d3.scaleLinear()
        .domain([top_n, 0])
        .range([height-margin.bottom, margin.top]);

    xAxis = d3.axisTop(xScale)
        .ticks(width > 500 ? 5:2)
        .tickSize(-(height-margin.top-margin.bottom))
        .tickFormat(d => d3.format(',')(d))
    ;

    svg.append('g')
        .attr('class','xAxis')
        .call(xAxis)
        .attr('transform',`translate(${
     margin.left},${
     margin.top})`)
矩形bar
//首次join rect
svg.selectAll('rect.bar')
    .data(yearSlice,d => d.name)
    .enter()
    .append('rect')
    .attr('class','bar')
    .attr('x',xScale(0)+margin.left+2)
    .attr('width', d => xScale(d.value)-xScale(0))
    .attr('y', d => yScale(d.rank))
    .attr('height', yScale(1)-yScale(0)-barPadding)
    .attr('fill', d => d.color)
品牌名label
//首次join text,品牌名
svg.selectAll('text.label')
    .data(yearSlice, d => name)
    .enter()
    .append('text')
    .attr('class', 'label')
    .attr('x', d => xScale(d.value)-8)
    .attr('y', d => 
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值