公司项目需要动态条形图,即条形图竞赛。想在网上找个demo,发现没有合适的,就自己写了一个。完整代码可以在我的GitHub上查看。动态条形图非常适合比较多个数据集的趋势。该演示基于d3的v6版本。由于它只使用了一些最基本的API,所以它应该可以在以前的版本中运行。本文仅提供一个实现思路,并没有详细解释api和“进入、更新、退出”模式,所以在阅读之前对它们有一个基本的了解。首先,您需要找到合适的数据源。这里我刚从网上找了一个。初始化变量constwidth=1200,height=600,margin={top:20,bottom:0,left:50,right:80};constchartWidth=width-(margin.left+margin.right),chartHeight=height-(margin.top+margin.bottom);constdata=[];constcount=10;constduration=500;constbarPadding=20;constbarHeight=(chartHeight-(barPadding*count))/count;constgetDate=()=>dataOri[0][dateIndex];让dateIndex=1;让date=getDate();让dataSlice=[];让图表=null,scale=null,axis=null,svg=null,dateTitle=null;首先设置高度、宽度、边距和图表大小。data存储格式化后的数据。由于图表不可能显示数据源中的所有行,所以这里只取前10行。每10秒切换一列。列间距为20。每个条形的宽度是通过从图表高度中减去条形间距除以条形数再除以条形数获得的。定义一个函数获取当前列表头,这里是日期,赋值给date。定义dataSlice存储当前日期下的所有数据。最后定义chart存放图表实例,scale存放刻度,axis存放坐标轴,svg存放画布,dateTitle存放当前列表头。constcreateSvg=()=>svg=d3.select('#chart').append('svg').attr('width',width).attr('高度',高度);创建一个svg来设置宽度和高度,并附加到预先编写的容器中。格式化数据函数randomRgbColor(){constr=Math.floor(Math.random()*256);constg=Math.floor(Math.random()*256);constb=Math.floor(Math.random()*256);return`rgb(${r},${g},${b})`;}首先声明一个函数来创建随机颜色,用于给条形图着色。我们的数据源是这种形式,需要简单格式化成为一个itemconstformatData=()=>{dataOri[0].forEach((date,index)=>{if(index>0){dataOri.forEach((row,rowIndex)=>{if(rowIndex>0){data.push({name:row[0],value:Number(row[index]),lastValue:index>1?Number(row[index-1]):0,date:date,color:randomRgbColor()});}});}});}两层循环,第一层循环列,第二层循环行,保存输入行标题、数据和上一列的数据。如果不是,则写入0、列标题和随机颜色来为条形图着色。至于lastValue的使用,后面会详细说明。格式化数据如图:constsliceData=()=>dataSlice=data.filter(d=>d.date===date).sort((a,b)=>b.value-a.value).slice(0,计数);筛选出当天的数据,倒序取前10。创建坐标轴constcreateScale=()=>scale=d3.scaleLinear().domain([0,d3.max(dataSlice,d=>d.value)]).range([0,chartWidth]);首先把刻度创建好,定义范围从0到当天的最大值,取值范围从0到图表的宽度。对d3.jsAPI不熟悉的同学可以去官网辅导或者自行百度。常用的基本就那么几个。坐标轴的最终效果如下图所示:需要简单配置坐标轴constrenderAxis=()=>{createScale();axis=d3.axisTop().scale(scale).ticks(5).tickPadding(10).tickSize(0);svg.append('g').classed('axis',true).style('transform',`translate3d(${margin.left}px,${margin.top}px,0)`).call(axis);}调用之前定义的scale函数创建一个scale,然后设置顶轴,ticks设置5个scale(这个方法比较有意思,虽然设置了5,但不一定是5,可能大于5或者小于5),tickPadding设置刻度和值的距离,tickSize设置刻度线的长度,这里不显示。设置完成后,追加到图表上,水平移动让位给margin的位置。创建一条参考线这条垂直线就是参考线,它从坐标轴刻度延伸出来,贯穿整个图表。constrenderAxisLine=()=>{d3.selectAll('g.axisg.tick').select('line.grid-line').remove();d3.selectAll('g.axisg.tick').append('line').classed('grid-line',true).attr('stroke','black').attr('x1',0).attr('y1',0).attr('x2',0).attr('y2',chartHeight);}由于参考线随着数据的变化而不断变化,所以这个函数会被反复调用,所以需要在开始Wire时清除上一组数据的引用。然后用刻度线在坐标轴的每个位置附加一条线。x1和y1是直线相对于父元素的左端点,x2和y2是右端点。由于需要贯穿整个图表,所以右端点的y坐标设置为chartHeight。在列标题图表的右下按钮创建日期,即列标题constrenderDateTitle=()=>{dateTitle=svg.append('text').classed('date-title',true).text(日期).attr('x',chartWidth-margin.top).attr('y',chartHeight-margin.left).attr('fill','rgb(128,128,128)').attr('font-size',40).attr('text-anchor','end')}移动到右下角,设置颜色。这里重点介绍text-anchor,它主要作为svg中
