D3.js-柱形图

柱形图,是使用柱形的长短来表示数据变化的图表,也是最简单的图表之一。一般情况下,柱形图包括:矩形、坐标轴和文字。

一、矩形和文字

定义一个数组,每个数据项表示矩形的长短:

var dataset = [50, 43, 120, 87, 99, 167, 142];  // 数据集

定义一个SVG,表示绘制区域:

var width = 400;    // svg可视区域宽度
var height = 400;   // svg可视区域高度
var svg = d3.select("body")
        .append("svg")      // 在body中添加SVG
        .attr("width", width)
        .attr("height", height);

添加SVG后,定义几个变量:

var padding = {top: 20, right: 20, bottom: 20, left: 20};   // 边距
var rectStep = 35;  // 矩形所占宽度(包括空格)
var rectWidth = 30; // 矩形所占宽度(不包括空格)

data()的工作过程: data()能将数组各项分别绑定到选择集的各元素上,并且能指定绑定的规则。当数组长度与元素数量不一致时,data()也能够处理。当数组长度大于元素数量时,为多余数据预留元素位置,以便将来插入新元素;当数组长度小于元素数量时,能够获取多余元素的位置,以便将来删除。 在D3中,根据数组长度和元素数量的关系,分别把各种情况归纳如下:

  • update:数组长度 = 元素数量;
  • enter:数组长度 > 元素数量;
  • exit:数组长度 < 元素数量。

绘制矩形:

/* rect */
var rect = svg.selectAll("rect")
        .data(dataset)          // 绑定数据
        .enter()                // 获取enter部分
        .append("rect")         // 添加rect元素,使其与绑定数组的长度一致
        .attr("fill", "steelblue")
        .attr("x", function(d, i){
            return padding.left + i * rectStep;
        })
        .attr("y", function(d){
            return height - padding.bottom - d;
        })
        .attr("width", rectWidth)
        .attr("height", function(d){
            return d;
        });

绘制文字:

/* text */
var text = svg.selectAll("text")
        .data(dataset)          // 绑定数据
        .enter()                // 获取enter部分
        .append("text")         // 添加text元素,使其与绑定数组的长度一致
        .attr("fill", "white")
        .attr("font-size", "14px").attr("text-anchor", "middle")
        .attr("x", function(d, i){
            return padding.left + i * rectStep;
        })
        .attr("y", function(d){
            return height - padding.bottom - d;
        })
        .attr("dx", rectWidth/2).attr("dy", "1em")
        .text(function(d){
            return d;
        });

二、更新数据

更新数据后,柱形图也得跟着变化。 update部分的处理方法是更新属性,enter部分的处理方法是添加元素后再赋予其相应的属性,exit部分的处理方法则是删除掉多余的元素。

矩形:

var updateRect = svg.selectAll("rect").data(dataset);   // 错误 d3.selectAll() 出了svg范围
var enterRect = updateRect.enter();
var exitRect = updateRect.exit();
// update处理方法
updateRect.attr("fill", "steelblue")
    .attr("x", function(d, i){
        return padding.left + i * rectStep;
    })
    .attr("y", function(d){
        return height - padding.bottom - d;
    })
    .attr("width", rectWidth)
    .attr("height", function(d){
        return d;
    });
// enter处理方法
enterRect.append("rect").attr("fill", "steelblue")
    .attr("x", function(d, i){
        return padding.left + i * rectStep;
    })
    .attr("y", function(d){
        return height - padding.bottom - d;
    })
    .attr("width", rectWidth)
    .attr("height", function(d){
        return d;
    });
// exit处理方法
exitRect.remove();

文字:

var updateText = svg.selectAll("text").data(dataset);
var enterText = updateText.enter();
var exitText = updateText.exit();
// update处理方法
updateText.attr("fill", "white")
    .attr("font-size", "14px").attr("text-anchor", "middle")
    .attr("x", function(d, i){
        return padding.left + i * rectStep;
    })
    .attr("y", function(d){
        return height - padding.bottom - d;
    })
    .attr("dx", rectWidth/2).attr("dy", "1em")
    .text(function(d){
        return d;
    });
// enter处理方法
enterText.append("text").attr("fill", "white")
    .attr("font-size", "14px").attr("text-anchor", "middle")
    .attr("x", function(d, i){
        return padding.left + i * rectStep;
    })
    .attr("y", function(d){
        return height - padding.bottom - d;
    })
    .attr("dx", rectWidth/2).attr("dy", "1em")
    .text(function(d){
        return d;
    });
// exit处理方法
exitText.remove();

三、坐标轴

比例尺分为:定量比例尺(定义域是连续的)和序数比例尺(定义域是不连续的)。

// 定义柱形图比例尺
var xAxisWidth = 300; // x轴宽度
var yAxisWidth = 300; // y轴宽度

/* x轴比例尺(序数比例尺) */
var xScale = d3.scale.ordinal()
        .domain(d3.range(dataset.length))
        .rangeRoundBands([0, xAxisWidth], 0.2);

/* y轴比例尺(线性比例尺) */
var yScale = d3.scale.linear()
        .domain([0, d3.max(dataset)])
        .range([0, yAxisWidth]);

有了比例尺后,矩形的位置、长度都要用比例尺来计算。这么做之后,数据和绘制就能完全分开,而且只需要修改比例尺,即可将图表自由伸缩。

selection.attr("fill", "steelblue")
    .attr("x", function(d, i){
        return padding.left + xScale(i);
    })
    .attr("y", function(d){
        return height - padding.bottom - yScale(d);
    })
    .attr("width", xScale.rangeBand())
    .attr("height", function(d){
        return yScale(d);
    });
/* 添加坐标轴 */
var xAxis = d3.svg.axis().scale(xScale).orient("bottom");
yScale.range([yAxisWidth, 0]);  // 重新设置y轴比例尺的值域,与原来的相反
var yAxis = d3.svg.axis().scale(yScale).orient("left");

svg.append("g").attr("class", "axis")
        .attr("transform", "translate("+ padding.left +","+ (height - padding.bottom) +")")
        .call(xAxis);

svg.append("g").attr("class", "axis")
        .attr("transform", "translate("+ padding.left +","+ (height - padding.bottom - yAxisWidth) +")")
        .call(yAxis);

四、使用call减少冗余

call允许将选择集自身作为参数,传递给某一函数。

d3.selectAll("div").call(myfun);

等价于

function myfun(selection){
    // 这里进行相关操作
    selection.attr("name", "value");
}
myfun(d3.selectAll("div"));

使用call的完整示例

var dataset = [50, 43, 120, 87, 99, 167, 142];  // 数据集

var width = 400;    // svg可视区域宽度
var height = 400;   // svg可视区域高度
var svg = d3.select("body")
        .append("svg")
        .attr("width", width).attr("height", height);

var padding = {top: 20, right: 20, bottom: 20, left: 50};   // 边距

var xAxisWidth = 300; // x轴宽度
var yAxisWidth = 300; // y轴宽度

/* x轴比例尺(序数比例尺) */
var xScale = d3.scale.ordinal()
        .domain(d3.range(dataset.length))
        .rangeRoundBands([0, xAxisWidth], 0.2);

/* y轴比例尺(线性比例尺) */
var yScale = d3.scale.linear()
        .domain([0, d3.max(dataset)])
        .range([0, yAxisWidth]);

/* rect */
var rect = svg.selectAll("rect")
        .data(dataset)
        .enter()
        .append("rect")
        .call(rectFun);

/* text */
var text = svg.selectAll("text")
        .data(dataset)
        .enter()
        .append("text")
        .call(textFun);

/* 添加坐标轴 */
var xAxis = d3.svg.axis().scale(xScale).orient("bottom");
yScale.range([yAxisWidth, 0]);  // 重新设置y轴比例尺的值域,与原来的相反
var yAxis = d3.svg.axis().scale(yScale).orient("left");

svg.append("g").attr("class", "axis")
        .attr("transform", "translate("+ padding.left +","+ (height - padding.bottom) +")")
        .call(xAxis);

svg.append("g").attr("class", "axis")
        .attr("transform", "translate("+ padding.left +","+ (height - padding.bottom - yAxisWidth) +")")
        .call(yAxis);

/* rect处理函数 */
function rectFun(selection) {
    selection.attr("fill", "steelblue")
            .attr("x", function(d, i){
                return padding.left + xScale(i);
            })
            .attr("y", function(d){
                return height - padding.bottom - yScale(d);
            })
            .attr("width", xScale.rangeBand())
            .attr("height", function(d){
                return yScale(d);
            });
}

/* text处理函数 */
function textFun(selection){
    selection.attr("fill", "white")
            .attr("font-size", "14px").attr("text-anchor", "middle")
            .attr("x", function(d, i){
                return padding.left + xScale(i);
            })
            .attr("y", function(d){
                return height - padding.bottom - yScale(d);
            })
            .attr("dx", xScale.rangeBand()/2).attr("dy", "1em")
            .text(function(d){
                return d;
            });
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏电商工具

将图片压缩90%但不折损画质的5个免费工具

为什么要压缩图片?因为图片太大,加载太慢,影响体验,超过6秒访问者就走了。但普通的压缩方式,会导致图片画质折损。这里推荐5个最顶级的免费的高比例无损压缩工具。

44540
来自专栏服务化进程

Flex动态加载svg图片

在FLEX应用程序中可以使用SVG资源, 但只能象JPG和GIF那样作为一种图像引入, 而不包括SVG的一些高级特性, 而且无法在运行时加载, 只能...

12250
来自专栏前端技术地图

React组件设计实践总结03 - 样式的管理

CSS 是前端开发的重要组成部分,但是它并不完美,本文主要探讨 React 样式管理方面的一些解决方案,目的是实现样式的高度可定制化, 让大型项目的样式代码更容...

11820
来自专栏相约机器人

自制全息伦敦地铁站数据可视化

爱德华·图夫特(Edward Tufte)在他的“展望信息”(Envisioning Information)一书中谈到了视觉形象被捕获在屏幕和纸张的二维平原中...

16230
来自专栏Super 前端

D3.js-基础知识

数据可视化起源于18世纪,当时使用柱形图和折线图来表示国家进出口量。近年,随着大数据时代的到来,数据可视化作为大数据量的呈现方式,成为当前重要的课题。数据可视化...

34540
来自专栏蚂蚁开源社区

【前端艺术】超酷圆形导航菜单特效(基于SVG)

这是一款基于SVG的超酷圆形导航菜单特效。该导航菜单通过SVG进行布局,然后通过js和CSS代码来在鼠标hover菜单时,制作菜单项的动画效果。

14650
来自专栏蚂蚁开源社区

简单实用的商品购物和添加购物车UI设计

这是一款使用jQuery和CSS3制作的简单实用的商品购物和添加购物车界面设计方案。用户可以在商品购物界面中预览各种型号、颜色、尺寸的商品。然后通过点击添加到购...

17740
来自专栏Web技术布道师

程序狗必备:5个功能丰富的交互式Javascript库

在javascript的帮助下,可以为几乎每个领域(如移动、桌面应用程序和游戏Web开发)创建Web应用程序,因为该编程语言用作服务器端编程语言以实现最大功能,...

9110
来自专栏Super 前端

【实例】调整区域大小&动态隐藏区域

实例参照地址:https://jsfiddle.net/381510688/fb6Lz9rm/

11010

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励