D3实现柱状图

前端之家收集整理的这篇文章主要介绍了D3实现柱状图前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

D3是一种数据可视化工具,数据的可视化其实就是把数据以图表等直观的方式展示给用户,让用户更直观的感受到数据的走势和变化。这种应用在项目中越来越多的被使用,话说,千句话不如一张图,说的一点都不为过。那么D3作为这种轻巧免费公开的图表制作工具,在应用中被越来越多的使用。D3有很多让人眼前一亮的功能,现在我们所处理的是一些基本的图表,比如柱状图,饼图,折线图等。

话不多说,这篇博客主要是在项目中用到的柱状图的画法。先看一下效果图:


显示报表的时候我们都喜欢将数据按照横纵坐标来展示数据的变化,Y轴一般是数值,X轴一般都是时间,当然也可以是其他的字符串用于显示某种类别。

代码的创建方式大同小异,都是绑定一个div,在div里面使用svg来做文章

前端代码详见:

<div id="ham-guest-summary-common-group-chart" class="ham-summary-common-group-chart" style="width: 100%"></div>

我们创建了一个容器来存放生成的svg。

我们来创建画布的高宽以及边距:

 //定义柱状图的宽高边距属性
            var margin = {top: 20,right:40,bottom: 0,left: 40},width = 900,height = 300;

定义X,Y轴的比例尺和作用范围:

//定义X轴作用范围
            var x0 = d3.scale.ordinal()
                .rangeRoundBands([0,width],.1);

            var x1 = d3.scale.ordinal();
            //定义Y轴作用范围
            var y = d3.scale.linear()
                .range([height,0]);
            //定义X比例尺
            var xAxis = d3.svg.axis()
                .scale(x0)
                .orient("bottom");
            //定义Y比例尺
            var yAxis = d3.svg.axis()
                .scale(y)
                .orient("left")
                .tickFormat(d3.format(".2s"));

定义柱状图颜色:

//定义标准颜色样式
            var colorRange = d3.scale.category20();
            var color = d3.scale.ordinal()
                    .range(colorRange.range());
定义svg画布:

var svg = d3.select("#ham-guest-summary-common-group-chart").append("svg")
                .attr("preserveAspectRatio","xMidYMid meet")
                .attr("viewBox","0 0 1000 350")
                .append("g")
                .attr("transform","translate(" + margin.left + "," + margin.top + ")");

这里preserveAspectRatio和viewBox可以让svg画布支持缩放功能,前提是该viewBox的宽高必须大于画布的宽高才能做到缩放的效果

接下来我们来使用data方法来绑定数据,以及x的作用域和y的值域:

var options = d3.keys(dataset[0]).filter(function(key) { return key !== "label"; });

            dataset.forEach(function(d) {
                d.valores = options.map(function(name) { return {name: name,value: +d[name]}; });
            });

            x0.domain(dataset.map(function(d) { return d.label; }));
            x1.domain(options).rangeRoundBands([0,x0.rangeBand()]);
            y.domain([0,d3.max(dataset,function(d) { return d3.max(d.valores,function(d) { return d.value; }); })]);


数据绑定之后需要创建x轴和y轴,使用前面定义到的比例尺和作用域和值域来构建x轴y轴:

 //画X轴
            svg.append("g")
                .attr("class","x axis")
                .attr("transform","translate(0," + height + ")")
                .call(xAxis);
            //画Y轴
            svg.append("g")
                .attr("class","y axis")
                .call(yAxis)
                .append("text")
                .attr("transform","rotate(-90)")
                .attr("y",6)
                .attr("dy",".71em")
                .style("text-anchor","end")
                .text("Numbers");
将数据绑定到画布区域中,每一个柱状图都成为bar:

var bar = svg.selectAll(".bar")
                .data(dataset)
                .enter().append("g")
                .attr("class","rect")
                .attr("transform",function(d) { return "translate(" + x0(d.label) + ",0)"; });
每一个bar都是由多个rect矩形组成,所以我们需要跟rect绑定数值,label属性

bar.selectAll("rect")
                .data(function(d) { return d.valores; })
                .enter().append("rect")
                .attr("width",x1.rangeBand())
                .attr("x",function(d) { return x1(d.name); })
                .attr("y",function(d) { return y(d.value); })
                .attr("value",function(d){return d.name;})
                .attr("height",function(d) { return height - y(d.value); })
                .style("fill",function(d) { return color(d.name); });

前面的代码就可以生成柱状图了,那么现在当我们鼠标移动到柱状图上时,我们需要提示当前bar的数值信息,需要添加tooltips功能,需要一些样式的支持

var divTooltip = d3.select("#ham-guest-summary-common-group-chart").append("div").attr("class","toolTip");
.ham-summary-common-group-chart .legend {
    font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
    font-size: 60%;
}

.ham-summary-common-group-chart rect {
    stroke-width: 2;
}

.ham-summary-common-group-chart text {
    font: 10px sans-serif;
}

.ham-summary-common-group-chart .axis text {
    font: 10px sans-serif;
}

.ham-summary-common-group-chart .axis path{
    fill: none;
    stroke: #000;
}

.ham-summary-common-group-chart .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
}

.ham-summary-common-group-chart .axis .tick line {
    stroke-width: 1;
    stroke: rgba(0,0.2);
}

.ham-summary-common-group-chart .axisHorizontal path{
    fill: none;
}

.ham-summary-common-group-chart .axisHorizontal line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
}

.ham-summary-common-group-chart .axisHorizontal .tick line {
    stroke-width: 1;
    stroke: rgba(0,0.2);
}

.ham-summary-common-group-chart .bar {
    fill: steelblue;
    fill-opacity: .9;
}

.ham-summary-common-group-chart .x.axis path {
    display: none;
}


所谓的提示信息就是鼠标移动时,bar去监听鼠标事件,然后追加一个div用于显示数据信息。

bar.on("mousemove",function(d){
                var scoll = getScrollTop();
                divTooltip.style("left",d3.event.pageX + "px");
                divTooltip.style("top",d3.event.pageY - scoll + "px");
                //divTooltip.style("top",d3.event.pageY+"px");
                divTooltip.style("display","inline-block");
                var x = d3.event.pageX,y = d3.event.pageY;
                var elements = document.querySelectorAll(':hover');
                var l = elements.length;
                l = l-1;
                var elementData = elements[l].__data__;
                var title_name = "";
                if(elementData.name == "newCreatedAccount"){
                    title_name = "New Created Account";
                }else if(elementData.name == "totalGuestAccount"){
                    title_name = "Total Guest Account";
                }else if(elementData.name == "activeGuestAccount"){
                    title_name = "Active Guest Account";
                }else if(elementData.name == "totalGuestDevice"){
                    title_name = "Total Guest Device";
                }
                divTooltip.html((d.label)+"<br>"+title_name+"<br>"+elementData.value);
            });
            bar.on("mouSEOut",function(d){
                divTooltip.style("display","none");
            });



在这里提到一个问题,当Y轴方向出现滚动条的时候,鼠标悬浮的提示信息,会发生变化,跟鼠标的位置有差距,这个问题我在其他的博客中写到过,可以参考:

获取滚动条的上边距,然后当前的坐标减去上边距就行:

//get scroll distance to top
        function getScrollTop() {
            var scrollPos;
            if (window.pageYOffset) {
                scrollPos = window.pageYOffset;
            }else if (document.compatMode && document.compatMode != 'BackCompat') {
                scrollPos = document.documentElement.scrollTop;
            }else if (document.body) {
                scrollPos = document.body.scrollTop;
            }
            return scrollPos;
        }
后台返回数据格式:

{
    "result": "success","errorCode": 0,"errorMessage": null,"data": [
        {
            "id": 20,"newCreatedAccount": 0,"totalGuestAccount": 3,"activeGuestAccount": 1,"totalGuestDevice": 1,"statisticalDate": "30/08/17"
        },{
            "id": 21,"statisticalDate": "31/08/17"
        },{
            "id": null,"totalGuestAccount": 0,"activeGuestAccount": 0,"totalGuestDevice": 0,"statisticalDate": "01/09/17"
        },"statisticalDate": "02/09/17"
        },"statisticalDate": "03/09/17"
        },"statisticalDate": "04/09/17"
        },"statisticalDate": "05/09/17"
        },"statisticalDate": "06/09/17"
        },"statisticalDate": "07/09/17"
        },"statisticalDate": "08/09/17"
        }
    ],"translated": {}
}
需要将后台的数据做处理,转为柱状图识别的json格式:

function getAccountAndDeviceNumber() {

            var dataset = [];
            amGuestHomeService.getAccountAndDeviceNumber()
                .then(function success(response) {
                    if (response.data != null && response.data.length > 0) {
                        angular.forEach(response.data,function (item) {
                            var data = {};
                            data.label = item.statisticalDate;
                            data.newCreatedAccount = item.newCreatedAccount;
                            data.totalGuestAccount = item.totalGuestAccount;
                            data.activeGuestAccount = item.activeGuestAccount;
                            data.totalGuestDevice = item.totalGuestDevice;
                            dataset.push(data);

                        })
                        amGuestHomeService.drawGroupChart(dataset);
                    }
                })
                .catch(function fail(/*e*/) {
                    //handle error
                })
                .finally(function () {
                    vm.hideLoading();
                });
        }


最后附上全部代码


function drawGroupChart(dataset){
            //定义柱状图的宽高边距属性
            var margin = {top: 20,height = 300;
            //定义X轴作用范围
            var x0 = d3.scale.ordinal()
                .rangeRoundBands([0,0]);
            //定义标准颜色样式
            var colorRange = d3.scale.category20();
            var color = d3.scale.ordinal()
                .range(colorRange.range());
            //定义X比例尺
            var xAxis = d3.svg.axis()
                .scale(x0)
                .orient("bottom");
            //定义Y比例尺
            var yAxis = d3.svg.axis()
                .scale(y)
                .orient("left")
                .tickFormat(d3.format(".2s"));
            //这里是牵扯到查询会不断切换柱状图,将之前生成的svg删除
            d3.select("#ham-guest-summary-common-group-chart svg").remove();
            //定义鼠标移动时提示信息
            var divTooltip = d3.select("#ham-guest-summary-common-group-chart").append("div").attr("class","toolTip");
            //创建svg画布preserveAspectRatio,viewBox这两个属性可以支持画布的缩放功能
            var svg = d3.select("#ham-guest-summary-common-group-chart").append("svg")
                .attr("preserveAspectRatio"," + margin.top + ")");
            //获取label
            var options = d3.keys(dataset[0]).filter(function(key) { return key !== "label"; });

            dataset.forEach(function(d) {
                d.valores = options.map(function(name) { return {name: name,function(d) { return d.value; }); })]);
            //画X轴
            svg.append("g")
                .attr("class","end")
                .text("Numbers");

            var bar = svg.selectAll(".bar")
                .data(dataset)
                .enter().append("g")
                .attr("class",0)"; });

            bar.selectAll("rect")
                .data(function(d) { return d.valores; })
                .enter().append("rect")
                .attr("width",function(d) { return color(d.name); });

            bar.on("mousemove","none");
            });

        }

猜你在找的Angularjs相关文章