最终效果图镇楼:

本文通过三个步骤来介绍d3.js。

1、简单的柱状图;

2、多个x轴的柱状图;

3、多个x轴、y轴的柱状图;

学习心得:

d3.js入门相对比较困难,一旦掌握了核心思想,不断熟悉API,就可以做出很灵活、实用的图表。

canvas中,d3帮我们计算好了每个图形的位置,我们再一个一个的画上即可。

不要担心代码看起来很多,一个一个的分析出来,就会发现其实还是有套路的。

一、简单图表

示意图:

代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<canvas id="myCanvas" width="600" height="400"></canvas>
<script src="d3.min.js"></script>
<script>
"use strict";
(function () {
function init() {
initData();
}
function initData() {var oneData = [
{'name': '办公用品', 'value': 100},
{'name': '家具', 'value': 20},
{'name': '技术', 'value': 60}
];
initUI(oneData);
}
function initUI(data) {
var canvas = document.querySelector('#myCanvas');
var context = canvas.getContext('2d');
var margin = {top: 20, right: 20, bottom: 30, left: 40};
var width = canvas.width - margin.left - margin.right;
var height = canvas.height - margin.top - margin.bottom;
var x0 = d3.scaleBand()
.domain(data.map(function (d) {
return d.name;
}))
.rangeRound([0, width])
.padding(0.5);
var y0 = d3.scaleLinear()
.domain([0, d3.max(data, function (d) {
return d.value;
})])
.range([height, 0]);
context.translate(margin.left, margin.top);
context.beginPath();
x0.domain().forEach(function (d) {
context.moveTo(x0(d) + x0.bandwidth() / 2, height);
context.lineTo(x0(d) + x0.bandwidth() / 2, height + 6);
});
context.strokeStyle = 'black';
context.stroke();
context.textAlign = "center";
context.textBaseline = "top";
x0.domain().forEach(function (d) {
context.fillText(d, x0(d) + x0.bandwidth() / 2, height + 6);
});
context.beginPath();
context.moveTo(0.5, height + 0.5);
context.lineTo(width + 0.5, height + 0.5);
context.strokeStyle = "black";
context.stroke();
var yTickCount = 10;
var yTicks = y0.ticks(yTickCount);
context.beginPath();
yTicks.forEach(function (d) {
context.moveTo(0, y0(d) + 0.5);
context.lineTo(-6, y0(d) + 0 / 5);
});
context.strokeStyle = 'black';
context.stroke();
context.textAlign = "right";
context.textBaseline = "middle";
yTicks.forEach(function (d) {
context.fillText(d, -9, y0(d));
});
context.beginPath();
context.moveTo(-6.5, 0 + 0.5);
context.lineTo(0.5, 0 + 0.5);
context.lineTo(0.5, height + 0.5);
context.lineTo(-6.5, height + 0.5);
context.strokeStyle = "black";
context.stroke();
context.fillStyle = "steelblue";
data.forEach(function (d) {
context.fillRect(x0(d.name), y0(d.value), x0.bandwidth(), height - y0(d.value));
});
}
init();
}());
</script>
</body>
</html>

二、多个x轴

示意图:

代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<canvas id="myCanvas" width="600" height="400"></canvas>
<script src="d3.min.js"></script>
<script>
"use strict";
(function () {
function init() {
initData();
}
function initData() {var data =
[
{
'name': '东北',
'value': [
{'name': '办公用品', 'value': 100},
{'name': '家具', 'value': 20},
{'name': '技术', 'value': 60}
]
},
{
'name': '华北',
'value': [
{'name': '办公用品', 'value': 100},
{'name': '家具', 'value': 80},
{'name': '技术', 'value': 60}
]
},
{
'name': '西南',
'value': [
{'name': '办公用品', 'value': 100},
{'name': '家具', 'value': 80},
{'name': '技术', 'value': 60}
]
}
];
initUI(data);
}
function initUI(data) {
var canvas = document.querySelector('#myCanvas');
var context = canvas.getContext('2d');
var margin = {top: 20, right: 20, bottom: 45, left: 40};
var width = canvas.width - margin.left - margin.right;
var height = canvas.height - margin.top - margin.bottom;
var xAxis0 = d3.scaleBand()
.domain(data.map(function (d) {
return d.name;
}))
.rangeRound([0, width]);
var firstRow = data[0];
var xAxis1 = d3.scaleBand()
.domain(firstRow.value.map(function (d) {
return d.name;
}))
.rangeRound([0, xAxis0.bandwidth()])
.padding(0.5);
var yAxis0 = d3.scaleLinear()
.domain([0, d3.max(data, function (d0) {
return d3.max(d0.value, function (d1) {
return d1.value;
})
})])
.range([height, 0]);
context.translate(margin.left, margin.top);
context.beginPath();
context.textAlign = "center";
context.textBaseline = "top";
xAxis0.domain().forEach(function (d) {
context.fillText(d, xAxis0(d) + xAxis0.bandwidth() / 2, height + 23);
});
data.forEach(function (d0) {
var pX0 = xAxis0(d0.name);
d0.value.forEach(function (d1) {
context.moveTo(pX0 + xAxis1(d1.name) + xAxis1.bandwidth() / 2, height);
context.lineTo(pX0 + xAxis1(d1.name) + xAxis1.bandwidth() / 2, height + 6);
context.fillText(d1.name, pX0 + xAxis1(d1.name) + xAxis1.bandwidth() / 2, height + 6);
});
});
context.strokeStyle = 'black';
context.stroke();
context.beginPath();
context.moveTo(0.5, height + 0.5);
context.lineTo(width + 0.5, height + 0.5);
context.strokeStyle = "black";
context.stroke();
var yTickCount = 10;
var yTicks = yAxis0.ticks(yTickCount);
context.beginPath();
yTicks.forEach(function (d) {
context.moveTo(0, yAxis0(d) + 0.5);
context.lineTo(-6, yAxis0(d) + 0 / 5);
});
context.strokeStyle = 'black';
context.stroke();
context.textAlign = "right";
context.textBaseline = "middle";
yTicks.forEach(function (d) {
context.fillText(d, -9, yAxis0(d));
});
context.beginPath();
context.moveTo(-6.5, 0 + 0.5);
context.lineTo(0.5, 0 + 0.5);
context.lineTo(0.5, height + 0.5);
context.lineTo(-6.5, height + 0.5);
context.strokeStyle = "black";
context.stroke();
context.fillStyle = "steelblue";
data.forEach(function (d0) {
var pX0 = xAxis0(d0.name);
d0.value.forEach(function (d1) {
var pX1 = pX0 + xAxis1(d1.name);
var pY1 = yAxis0(d1.value);
var pWidth = xAxis1.bandwidth();
var pHeight = height - yAxis0(d1.value);
context.fillRect(pX1, pY1, pWidth, pHeight);
})
});
}
init();
}());
</script>
</body>
</html>

三、多个x、y轴

示意图:

代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<canvas id="myCanvas" width="600" height="400"></canvas>
<script src="d3.min.js"></script>
<script>
"use strict";
(function () {
function init() {
initData();
}
function initData() {var data =
[
{
'name': '利润',
'value': [
{
'name': '东北',
'value': [
{'name': '办公用品', 'value': 100},
{'name': '家具', 'value': 50},
{'name': '技术', 'value': 60}
]
},
{
'name': '华北',
'value': [
{'name': '办公用品', 'value': 90},
{'name': '家具', 'value': 70},
{'name': '技术', 'value': 60}
]
},
{
'name': '西南',
'value': [
{'name': '办公用品', 'value': 100},
{'name': '家具', 'value': 80},
{'name': '技术', 'value': 50}
]
}
]
},
{
'name': '销售额',
'value': [
{
'name': '东北',
'value': [
{'name': '办公用品', 'value': 100},
{'name': '家具', 'value': 20},
{'name': '技术', 'value': 60}
]
},
{
'name': '华北',
'value': [
{'name': '办公用品', 'value': 100},
{'name': '家具', 'value': 80},
{'name': '技术', 'value': 60}
]
},
{
'name': '西南',
'value': [
{'name': '办公用品', 'value': 100},
{'name': '家具', 'value': 80},
{'name': '技术', 'value': 60}
]
}
]
}
];
initUI(data);
}
function initUI(data) {
var canvas = document.querySelector('#myCanvas');
var context = canvas.getContext('2d');
var margin = {top: 20, right: 20, bottom: 45, left: 40};
var width = canvas.width - margin.left - margin.right;
var height = canvas.height - margin.top - margin.bottom;
var firstRow = data[0].value;
var firstFirstRow = firstRow[0].value;
var xAxis0 = d3.scaleBand()
.domain(firstRow.map(function (d) {
return d.name;
}))
.rangeRound([0, width]);
var xAxis1 = d3.scaleBand()
.domain(firstFirstRow.map(function (d) {
return d.name;
}))
.rangeRound([0, xAxis0.bandwidth()])
.padding(0.5);
var yAxis0 = d3.scaleBand()
.domain(data.map(function (d) {
return d.name;
}))
.range([height, 0])
.paddingInner(0.1);
var yAxis1 = d3.scaleLinear()
.domain([0, d3.max(data, function (d0) {
return d3.max(d0.value, function (d1) {
return d3.max(d1.value, function (d2) {
return d2.value;
})
})
})])
.range([yAxis0.bandwidth(), 0]);
context.translate(margin.left, margin.top);
context.beginPath();
context.textAlign = "center";
context.textBaseline = "top";
xAxis0.domain().forEach(function (d) {
context.fillText(d, xAxis0(d) + xAxis0.bandwidth() / 2, height + 23);
});
firstRow.forEach(function (xData0) {
var pX0 = xAxis0(xData0.name);
xData0.value.forEach(function (xData1) {
context.moveTo(pX0 + xAxis1(xData1.name) + xAxis1.bandwidth() / 2, height);
context.lineTo(pX0 + xAxis1(xData1.name) + xAxis1.bandwidth() / 2, height + 6);
context.fillText(xData1.name, pX0 + xAxis1(xData1.name) + xAxis1.bandwidth() / 2, height + 6);
})
});
context.strokeStyle = 'black';
context.stroke();
context.beginPath();
data.forEach(function (yData0) {
var pY0 = yAxis0(yData0.name);
var y = +(pY0 + yAxis0.bandwidth()).toFixed(0) + 0.5;
context.moveTo(0.5, y);
context.lineTo(width + 0.5, y);
});
context.strokeStyle = "black";
context.stroke();
var yTickCount = 10;
var yTicks = yAxis1.ticks(yTickCount);
context.beginPath();
data.forEach(function (yData0) {
var pY0 = yAxis0(yData0.name);
for (var idx = 0; idx < yData0.name.length; idx++) {
context.fillText(yData0.name[idx], -30, pY0 + yAxis0.bandwidth() / 2 - 15 + idx * 15);
}
yTicks.forEach(function (d) {
var y = +(pY0 + yAxis1(d)).toFixed(0) + 0.5;
context.moveTo(0, y);
context.lineTo(-6, y);
});
});
context.strokeStyle = 'black';
context.stroke();
context.textAlign = "right";
context.textBaseline = "middle";
data.forEach(function (yData0) {
var pY0 = yAxis0(yData0.name);
yTicks.forEach(function (d) {
var y = pY0 + yAxis1(d);
context.fillText(d, -9, y);
});
});
context.beginPath();
context.moveTo(-6.5, 0 + 0.5);
context.lineTo(0.5, 0 + 0.5);
context.lineTo(0.5, height + 0.5);
context.lineTo(-6.5, height + 0.5);
context.strokeStyle = "black";
context.stroke();
context.fillStyle = "steelblue";
data.forEach(function (yData0) {
var pY0 = yAxis0(yData0.name);
yData0.value.forEach(function (xData0) {
var pX0 = xAxis0(xData0.name);
xData0.value.forEach(function (xData1) {
var pX1 = pX0 + xAxis1(xData1.name);
var pY1 = pY0 + yAxis1(xData1.value);
var pWidth = xAxis1.bandwidth();
var pHeight = yAxis0.bandwidth() - yAxis1(xData1.value);
context.fillRect(pX1, pY1, pWidth, pHeight);
})
})
});
}
init();
}());
</script>
</body>
</html>

源码下载:src

d3.js多个x轴y轴canvas柱状图的更多相关文章

  1. vue中使用v-chart改变柱状图颜色以及X轴Y轴的文字颜色和大小以及标题

    1.html部分 <ve-histogram :tooltip-visible="true" :x-axis="xAxis" :y-axis=" ...

  2. highcharts 不显示X轴 Y轴 刻度

    xAxis: { tickWidth:0,        //设置刻度标签宽度 lineColor:'#ffffff',//设置坐标颜色 lineWidth:0,        //设置坐标宽度 la ...

  3. 3d照片环效果(修改版--添加了x轴y轴双向转动和修复模糊度的bug)

    今天用用前两天总结的css3新效果写了一个3d照片环的效果,其中还有些bug大家可以看一看,一起改进. <!DOCTYPE html> <html lang="en&quo ...

  4. JS逆向实战6-- x轴 y轴 过点触验证码

    点触验证码是一种常见的反爬手段 解决方案有两种:一种是直接解决,这需要深度学习机器学习等图像处理技术,以大量的数据训练识别模型,最终达到模型足矣识别图片中的文字提示和应该点击的区域之间的对应关系. 这 ...

  5. PhoneGap 加速计 api 获取加速计 x 轴 y 轴 z 轴信息

    一.PhoneGap 加速计 Accelerometer 对象介绍 1.主要方法 accelerometer.getCurrentAcceleration 获取当前设备在 x,y,z 轴上的加速度信息 ...

  6. Echarts X轴 Y轴 线的类型、颜色、及标签字体颜色 设置

    // 人均效能 var initRjxnChart = function () { var rjxnChart = echarts.init(document.getElementById(" ...

  7. svg 动画 透明度 放大缩小 x轴Y轴

    参考链接:https://www.cnblogs.com/Chrimisia/p/6670303.html vue 中封装svg:http://www.cnblogs.com/Jiangchuanwe ...

  8. 绕X 轴 Y轴 Z轴旋转的结果

    void warp_perspect_3_angle(cv::Mat face, float roll, float yaw, float pitch) { cv::Mat face_img = fa ...

  9. Opencv中图像height width X 轴 Y轴 rows cols之间的对应关系

    这里做一个备忘录:

随机推荐

  1. Java以及PHP安装环境

    开学前想把web的知识系统掌握一下,跟着极客学院学html5. 安装了intellij idead.xampp.jdk.eclipse for php. 下面列举一些安装过程中会出现的问题,以及解决. ...

  2. Opencv探索之路(二十):制作一个简易手动图像配准工具

    近日在做基于sift特征点的图像配准时遇到匹配失败的情况,失败的原因在于两幅图像分辨率相差有点大,而且这两幅图是不同时间段的同一场景的图片,所以基于sift点的匹配已经找不到匹配点了.然后老师叫我尝试 ...

  3. 【分支结构】Jcc 的一些助记

    eax > ebx OF=0 SF=0 ZF=0 AF=0 PF=0 CF=0 eax = ebx OF=0 SF=0 ZF=1 AF=0 PF=1 CF=0 eax < ebx OF=0 ...

  4. Hbase单机安装部署

    Hbase单机安装部署 http://blogxinxiucan.sh1.newtouch.com/2017/07/27/Hbase单机安装部署/ 下载Hbase Hbase官网下载地址 http:/ ...

  5. 一步一步学Vue(九)

    接上篇,这次是真的接上篇,针对上篇未完成的部分,增加鉴权功能,开始之前,我们先要介绍一个新的知识,路由元数据. 在vue-router中,定义元数据的方式: const router = new Vu ...

  6. JSON风格指南

    中文版:https://github.com/darcyliu/google-styleguide/blob/master/JSONStyleGuide.md 英文版:https://google.g ...

  7. ajax访问controller,无法通过return $this->goHome()跳转

    第一次在yii2中使用ajax来请求controller,做的是第三方登录,facebook和google登录. 登录成功应该跳转到首页,想当然的以为用return $this->goHome( ...

  8. vim 配置插件

    vim插件可以用bundle管理,我这里面用的是一个开源的Vundle工具,git上操作步骤说的很清楚https://github.com/VundleVim/Vundle.vim 之前PluginI ...

  9. 暑假集训D9总结

    考试 几乎绝望的考试= =,感觉自己啥都打不出来= =,就一道DP打了个贪心,剩下两道骗分,然而竟然排到前一半= =,不可思议= = 真是令人窒息的操作啊= = T1  [bzoj1592] Maki ...

  10. JavaScript获取客户端IP地址

    1. 第三方接口 1) 这里提供一个搜狐接口的地址:http://pv.sohu.com/cityjson?ie=utf-8 ,将这个js引入到页面即可得到returnCitySN. 2) api.i ...