d3.js 绘制基本图形
最近开始学习d3.js 主要是,初步认识d3.js,并且运行D3.jsD3.js数据可视化(data visualization)环境.
因为之前没有接触郭d3,因为业务需求,需要绘制一系列的图表,所以上来直接学习绘制,刚开始经过一天的简单了解,懂得了d3绘制代码的基本格式,然后开始搜索自己需要的图形的基本模板,然后根据自己的 实际业务需求来进行基本的更改,这样就需要我们对自己需要使用的代码,全程了解,这样我们就可以更加便捷的进行修改。下面是我最近三天自己绘制一些基本图形的代码:
这里注意:因为没有认真的学习过d3知识,在绘制时,因为不同版本的方法使用不同,所以我在引入d3的时候,会同时插入两个版本的d3,使用方法,
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://npmcdn.com/@turf/turf/turf.min.js"></script>
1、条形图
首先贴上完整的代码进行展示:因为是是刚开始学习d3,所以代码里都做了基本的注释。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>条形图</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://npmcdn.com/@turf/turf/turf.min.js"></script>
<style>
.axis path,
.axis line{
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 15px;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script type="text/javascript">
//1、定义宽高
var height = 600;
var width = 600;
//2、添加数据
var dataset= [30,20,45,12,21,28,46,64,73,78,54];
// var num = 15;
//设置刷新事件,当没刷新一次数据变化一次,条形图也随之变化
// for(var i = 0; i < 4; i++){
// var tempnum = Math.floor(Math.random() * 50);
// dataset.push(tempnum);
// }
// console.log(dataset);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var xAxisScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, 500]);
var yAxisScale = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([500, 0]);
var xAxis = d3.svg.axis().scale(xAxisScale).orient("bottom");
var yAxis = d3.svg.axis().scale(yAxisScale).orient("left");
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0,500],0.05);
var yScale = d3.scale.linear()
.domain([0,d3.max(dataset)])
.range([0,500]);
// 绘制矩形
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
// .on("click", function(){
// d3.select(this).attr("fill","black");
// }) // 添加点击事件
.attr("x", function(d,i){
return 100 + xScale(i);
} )
.attr("y",function(d,i){
return 50 + 500 - yScale(d) ;
})
.attr("width", function(d,i){
return xScale.rangeBand();
})
.attr("height",yScale)
.attr("fill", "steelblue")
.transition()
.duration(2000)
.ease("bounce")
.delay(1000)
.attr("fill","red");
// 绘制文字标签
svg.selectAll("text")
.data(dataset)
.enter().append("text")
.attr("x", function(d,i){
return 100 + xScale(i);
} )
.attr("y",function(d,i){
return 50 + 500 - yScale(d) ;
})
.attr("dx", function(d,i){
return xScale.rangeBand()/3;
})
.attr("dy", 15)
.attr("text-anchor", "begin")
.attr("font-size", 14)
.attr("fill","white")
.text(function(d,i){
return d;
});
// 在<svg>中添加元素<g>,g是svg标准中定义的元素,是分组的意思,用于把相关的元素进行组合的容器元素
// 将包含坐标轴的元素组合在一个group里call(xAxis),调用函数xAxis并设置执行上下文为元素<g>。
// attr("transform","translate(100, 550)")表示将x轴右移100px,并下移550px
svg.append("g")
.attr("class","axis")
.attr("transform","translate(100,550)")
.call(xAxis);
svg.append("g")
.attr("class","axis")
.attr("transform","translate(100,50)")
.call(yAxis);
</script>
</body>
</html>
下面是图形展示:大家可以根据自己的需求,来进行代码的更改。
2、折线图
代码展示:
<!DOCTYPE html>
<meta charset="utf-8">
<style type="text/css">
.line {
fill: none;
stroke: #ffab00;
stroke-width: 3;
}
/* .dot {
fill: #ffab00;
stroke: #fff;
} */
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
//1、定义宽高
var margin = {top: 50, right: 50, bottom: 50, left: 50};
// var width = window.innerWidth - margin.left - margin.right ; // Use the window's width
// var height = window.innerHeight - margin.top - margin.bottom ;
var width = 400 - margin.left - margin.right ;
var height = 400 - margin.top - margin.bottom ;
// 把svg添加到页面并使用
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//2、初始化数据
var dataset = [{'y':0.2},{'y':0.2},{'y':0.4},{'y':0.5},{'y':0.55},{'y':0.5}] //d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)() } })
// 3、比例尺
var xScale = d3.scaleLinear()
.domain([0, dataset.length-1])
.range([0, width]);
var yScale = d3.scaleLinear()
.domain([0, 1])
.range([height, 0]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale)); // 使用d3.axisBottom创建axis组件
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale)); // 创建一个带有d3.axisLeft的axis组件
//4、绘制直线
var line = d3.line()
.x(function(d, i) { return xScale(i); })
.y(function(d) { return yScale(d.y); })
// .curve(d3.curveBasis) // 对折线进行平滑处理
// 5. 追加路径、绑定数据并调用行生成器
svg.append("path")
.datum(dataset) // 10. Binds data to the line
.attr("class", "line") // Assign a class for styling
.attr("d", line); // 11. Calls the line generator
//6. 为每个数据点追加一个圆
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("class", "dot") // 为样式分配一个类
.attr("cx", function(d, i) { return xScale(i) })
.attr("cy", function(d) { return yScale(d.y) })
.attr("r", 4)
.attr("stroke", "#5E5E5E")
.attr("stroke-width", 2)
.attr('fill',"none");
</script>
</body>
效果图展示:
3、散点图
代码展示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3-coordinate-test</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<style>
/* .cocoordinate-div {
margin: 100px 500px 100px;
border: 2px solid blue;
} */
.title {
font-size: 26px;
font-family: 'Microsoft YaHei';
fill: red;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: 'Microsoft YaHei';
font-size: 12px;
}
</style>
</head>
<body>
<script>
//1、设置宽高
var Width = 800;
var Height = 400;
var padding = 60;
//2、数据初始化
var dataset = [
[0, 0], [65.66, 420], [520, 260], [360, 320], [200, 200],
[130, 623], [652, 52], [333, 666], [729, 656], [134, 352],
[120, 56], [905, 177], [777, 888], [1200, 1000]
];
var svg = d3.select('body') //创建SVG
.append('svg')
.attr('width', Width)
.attr('height', Height);
// 3、设置标题
svg.append('text')
.attr('x', Width / 2 - 120)
.attr('y', 30)
.attr('class', 'title') //title定义样式属性
.text('这是一个用d3画的简略坐标轴');
// 4、创建比例尺
var xScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d[0]; })])
.range([padding, Width - padding * 2]);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d[1]; })])
.range([Height - padding, padding]);
var rScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d[1]; })])
.range([2, 4]);
// 5、设置散点的坐标, 半径
svg.selectAll('circle')
.data(dataset)
.enter().append('circle')
.attr('cx', function(d) {
return xScale(d[0]); })
.attr('cy', function(d) {
return yScale(d[1]); })
.attr('r', function(d) {
return rScale(d[1]);
});
// 6、设置文本
svg.selectAll('text')
.data(dataset)
.enter().append('text')
.text(function(d) {
return '(' + d[0] + ', ' + d[1] + ')'; })
.attr('x', function(d) {
// 设置偏移量,让文本位于上方
return xScale(d[0]) - 20; })
.attr('y', function(d) {
return yScale(d[1]) - 10; })
.attr('font-family', 'Microsoft YaHei')
.attr('font-size', '12px')
.attr('fill', '#9400D3');
//7、绘制坐标轴
// 设置精度和样式
var formatPrecision = d3.format('$');
var xAxis = d3.svg.axis() // 定义X轴
.scale(xScale)
.ticks(7) // 粗略的设置刻度线的数量,包括原点
.orient('bottom')
.tickFormat(formatPrecision);
var yAxis = d3.svg.axis() // 定义Y轴
.scale(yScale)
.orient('left')
.ticks(7)
.tickFormat(formatPrecision);
svg.append('g') // svg中: g元素是一个分组元素 创建X轴,
.attr('class', 'axis')
.attr('transform', 'translate(0, ' + (Height - padding) + ')')// 设置据下边界的距离
.call(xAxis);
svg.append('g') // 创建Y轴
.attr('class', 'axis')
.attr('transform', 'translate(' + padding + ', 0)') // Y轴离左边界的距离
.call(yAxis);
</script>
</body>
</html>
4、简单堆栈图
完整代码展示:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<style>
.tick text {
font-size: 10px;
}
</style>
</head>
<body>
<script>
//1、定义宽高
const width = 500;
const height = 450;
const margin = { top: 25, right: 35, bottom: 100, left: 50 };
//2、确定初始数据
const data = [
{year:2005, value1:3000 ,value2:200 ,value3:0.06},
{year:2006, value1:1400 ,value2:40,value3:0.02},
{year:2007, value1:3800 ,value2:100,value3:0.03},
{year:2008, value1:4900 ,value2:70,value3:0.01},
{year:2009, value1:2000 ,value2:80,value3:0.04}
];
//3、堆栈图颜色设置
const colors = ['orange', 'red']; //颜色分组
const groups = ['value1', 'value2']; //类别分组
const layout = d3.stack().keys(groups)(data);//用来生成一个以0到groups.length-1为主键的堆栈生成器
const svg = d3.select('body') //选择body元素
.append('svg') //在body元素中添加svg
.attr('width', width + margin.left + margin.right) //设定<svg>的宽度属性
.attr('height', height + margin.top + margin.bottom) //设定<svg>的高度属性
.append('g')
.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
//4、绘制坐标轴比例尺
const xScale = d3.scaleBand()
.padding(0.4) //设置条形图的间隔
.domain(data.map(d => d.year)) //对条形图的横坐标进行映射
.range([0, width]);
const yMax = 6000;
const yScale = d3.scaleLinear()
.domain([0, yMax])
.range([height, 0]);
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale).ticks(10);
svg.append('g')
.attr('transform', `translate(0, ${height})`)
.call(xAxis)
.selectAll('text')
// .attr('transform', 'rotate(-45)') //这是一个控制横坐标字体斜体;
svg.append('g').call(yAxis);
// 5、开始绘制堆栈图
//堆栈图
svg
.selectAll('.group')
.data(layout)
.enter()
.append('g')
.attr('year', ({key}) => key)
.attr('fill', (d, i) => colors[i])
.selectAll('body')
.data(d => d)
.enter()
.append('rect')
.attr('x', ({data: {year}}) => xScale(year))
.attr('y', ([y, h]) => yScale(h))
.attr('width', xScale.bandwidth())
.attr('height', ([y, h]) => height - yScale(h - y));
</script>
</body>
运行结果展示:
5、带有折线图的堆栈图:
完整代码展示:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<style>
.tick text {
font-size: 10px;
}
.axis path,
.axis line{
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 8px;
}
</style>
</head>
<body>
<script>
//1、定义宽高
const margin = { top: 25, right: 35, bottom: 100, left: 50 };
const width = 500;
const height = 450;
//2、确定初始数据
const data = [
{year:2005, value1:3000 ,value2:200 ,value3:0.06},
{year:2006, value1:1400 ,value2:40,value3:0.02},
{year:2007, value1:3800 ,value2:100,value3:0.03},
{year:2008, value1:4900 ,value2:70,value3:0.01},
{year:2009, value1:2000 ,value2:80,value3:0.04}
];
const svg = d3.select('body') //选择body元素
.append('svg') //在body元素中添加svg
.attr('width', width + margin.left + margin.right) //设定<svg>的宽度属性
.attr('height', height + margin.top + margin.bottom) //设定<svg>的高度属性
.append('g')
.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
//3、堆栈图颜色设置
const colors = ['#ff6633', '#CDAF95']; //颜色分组
const groups = ['value1', 'value2']; //类别分组
const layout = d3.stack().keys(groups)(data);//用来生成一个以0到groups.length-1为主键的堆栈生成器
//4、绘制坐标轴比例尺
//设置刻度格式
var formatAsPercentage = d3.format(".1%")
const xScale = d3.scaleBand()
.padding(0.4) //设置条形图的间隔
.domain(data.map(d => d.year)) //对条形图的横坐标进行映射
.range([0, width]);
const yMax = 6000;
const yScale = d3.scaleLinear()
.domain([0, yMax])
.range([height, 0]);
const zMax=0.06;
const zScale = d3.scaleLinear()
.domain([0,zMax])
.range([height,0]);
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale).ticks(10);
const zAxis= d3.axisRight(zScale).ticks(10).tickFormat(formatAsPercentage);
svg.append('g') //横坐标的显示
.attr('transform', `translate(0, ${height})`)
.call(xAxis)
.selectAll('text')
// .attr('transform', 'rotate(-45)') //这是一个控制横坐标字体斜体;
svg.append('g').call(yAxis);
svg.append('g').call(zAxis).attr("transform","translate("+width+",0)");
// 5、开始绘制堆栈图
//堆栈图
svg
.selectAll('.group')
.data(layout)
.enter()
.append('g')
.attr('year', ({key}) => key)
.attr('fill', (d, i) => colors[i])
.selectAll('body')
.data(d => d)
.enter()
.append('rect')
.attr('x', ({data: {year}}) => xScale(year))
.attr('y', ([y, h]) => yScale(h))
.attr('width', xScale.bandwidth())
.attr('height', ([y, h]) => height - yScale(h - y));
//6、开始绘制折线图
var lineGen = d3.svg.line()
.x(function(d) {
//设置折线图的偏移量,使折线点居中
return xScale(d.year)+xScale.bandwidth()/2;
})
.y(function(d) {
return zScale(d.value3);
});
svg.append('path')
.attr('d', lineGen(data))
.attr('stroke', '#ffcc33')
.attr('stroke-width', 3)
.attr('fill', 'none');
//为折线图每个点坐标添加透明圆圈
svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d) {
return xScale(d.year)+xScale.bandwidth()/2+0.5;
})
.attr('cy', function(d) {
return zScale(d.value3)-1;
})
.attr('r', 3.5)
.attr('fill',"none")
.attr("stroke", "#5E5E5E")
.attr("stroke-width", 1);
</script>
</body>
运行结果展示:
这是在上一个堆栈图的基础上进行的修改,因为日常的需求中是需要我们对堆栈图中的数据,通过折线图的形式进行更加直观的展示,折线图可以看出数据的变化,这里这一横坐标是年,年作为两个图形形式的同一个横坐标,是我们在绘制双图形时,需要特别注意的地方。