最终效果图镇楼:
本文通过三个步骤来介绍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多个坐标轴柱状图
原文地址:http://www.cnblogs.com/sshoub/p/7474301.html