目的:掌握基于HTML的D3.js与ECharts数据可视化开发流程,能够运用两类工具实现多维度数据的图表绘制与交互设计,提升大数据可视化方案的设计与实践能力。
基本概念:
D3和Echarts
(1)D3
定义:基于JS的开源数据可视化
理念:数据驱动DOM
(数据驱动、底层控制、高度可定制)
(2)Echarts
定义:基于JS的商业数据可视化库
理念:声明式、内置图标、强大的交互能力、响应式设计
试验过程:
此次实验主要运用HTML代码
1、Echarts实现柱状图
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>第一个案例Echarts柱状图</title>
<script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
<div id="main" style="width:600px;height:400px"></div>
<script type="text/javascript">
var myChart = echarts.init(document.getElementById('main'));
var option = {
title:{text:'第一个案例Echarts'},
tooltip:{},
legend:{data:['销量']},
xAxis:{data:["衬衫","羊毛","袜子","帽子","皮鞋"]},
yAxis:{},
series:[{
name:'销量',
type:'bar',
data:[15,22,12,35,20]
}]
};
myChart.setOption(option);
</script>
</body>
</html>

2 、Echarts 实现饼图
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>第一个 ECharts 实例饼图</title>
<!-- 引入 echarts.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption({
series : [
{
name: '访问来源',
type: 'pie', // 设置图表类型为饼图
radius: '88%', // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
data:[ // 数据数组,name 为数据项名称,value 为数据项值
{value:235, name:'视频广告'},
{value:274, name:'联盟广告'},
{value:310, name:'邮件营销'},
{value:335, name:'直接访问'},
{value:400, name:'搜索引擎'}
]
}
]
})
</script>
</body>
</html>

3 、利用D3 实现柱状图
<html>
<head>
<meta charset="utf-8">
<title>利用D3实现柱状图</title>
<style>
.axis path,
.axis line{
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.MyRect {
fill: steelblue;
}
.MyText {
fill: white;
text-anchor: middle;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
//画布大小
var width = 400;
var height = 400;
//在 body 里添加一个 SVG 画布
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
//画布周边的空白
var padding = {left:30, right:30, top:20, bottom:20};
//定义一个数组
var dataset = [10, 20, 30, 40, 33, 24, 12, 5];
//x轴的比例尺
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, width - padding.left - padding.right]);
//y轴的比例尺
var yScale = d3.scale.linear()
.domain([0,d3.max(dataset)])
.range([height - padding.top - padding.bottom, 0]);
//定义x轴
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
//定义y轴
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
//矩形之间的空白
var rectPadding = 4;
//添加矩形元素
var rects = svg.selectAll(".MyRect")
.data(dataset)
.enter()
.append("rect")
.attr("class","MyRect")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("x", function(d,i){
return xScale(i) + rectPadding/2;
} )
.attr("width", xScale.rangeBand() - rectPadding )
.attr("y",function(d){
var min = yScale.domain()[0];
return yScale(min);
})
.attr("height", function(d){
return 0;
})
.transition()
.delay(function(d,i){
return i * 200;
})
.duration(2000)
.ease("bounce")
.attr("y",function(d){
return yScale(d);
})
.attr("height", function(d){
return height - padding.top - padding.bottom - yScale(d);
});
//添加文字元素
var texts = svg.selectAll(".MyText")
.data(dataset)
.enter()
.append("text")
.attr("class","MyText")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("x", function(d,i){
return xScale(i) + rectPadding/2;
} )
.attr("dx",function(){
return (xScale.rangeBand() - rectPadding)/2;
})
.attr("dy",function(d){
return 20;
})
.text(function(d){
return d;
})
.attr("y",function(d){
var min = yScale.domain()[0];
return yScale(min);
})
.transition()
.delay(function(d,i){
return i * 200;
})
.duration(2000)
.ease("bounce")
.attr("y",function(d){
return yScale(d);
});
//添加x轴
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
.call(xAxis);
//添加y轴
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.call(yAxis);
</script>
</body>
</html>

4 、利用D3 实现圆饼图
<html>
<head>
<meta charset="utf-8">
<title>利用实现D3饼图</title>
<style>
/* 饼图容器样式 */
.pie-container {
width: 800px;
height: 500px;
margin: 20px auto;
position: relative;
}
/* 图例样式 */
.legend {
position: absolute;
top: 50px;
right: 50px;
font-family: sans-serif;
font-size: 14px;
}
.legend-item {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.legend-color {
width: 15px;
height: 15px;
margin-right: 8px;
border-radius: 3px;
}
/* 百分比文字样式 */
.pie-text {
font-family: sans-serif;
font-size: 12px;
text-anchor: middle;
fill: #333;
}
/* 饼图扇区hover效果 */
.pie-path:hover {
opacity: 0.8;
cursor: pointer;
}
</style>
</head>
<body>
<div class="pie-container" id="pieChart"></div>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
// 1. 初始化数据和基础配置
var dataset = [10, 20, 30, 40, 33, 24, 12, 5]; // 原始数据
var dataLabels = ["类别1", "类别2", "类别3", "类别4", "类别5", "类别6", "类别7", "类别8"]; // 图例标签
var width = 500; // 饼图宽度
var height = 500; // 饼图高度
var radius = Math.min(width, height) / 2 - 40; // 饼图半径(留出边距)
// 2. 创建SVG容器
var svg = d3.select("#pieChart")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")"); // 居中放置
// 3. 创建颜色比例尺(分类颜色)
var color = d3.scale.category20(); // D3内置的20色分类比例尺
// 4. 定义饼图生成器
var pie = d3.layout.pie()
.sort(null) // 不排序,保持原始数据顺序
.value(function(d) { return d; }); // 取值字段
// 5. 定义弧生成器(饼图扇区形状)
var arc = d3.svg.arc()
.innerRadius(0) // 内半径(0为实心饼图,大于0则为环形图)
.outerRadius(0); // 初始外半径(用于动画)
// 定义文字位置的弧生成器(比饼图略外一点)
var textArc = d3.svg.arc()
.innerRadius(radius + 10)
.outerRadius(radius + 10);
// 6. 处理数据(计算饼图角度和百分比)
var pieData = pie(dataset);
// 计算总和用于百分比计算
var total = d3.sum(dataset);
pieData.forEach(function(d, i) {
d.percent = ((d.value / total) * 100).toFixed(1); // 保留1位小数的百分比
d.label = dataLabels[i]; // 添加标签
});
// 7. 绘制饼图扇区
var paths = svg.selectAll("path")
.data(pieData)
.enter()
.append("path")
.attr("class", "pie-path")
.attr("fill", function(d, i) { return color(i); }) // 按索引分配颜色
// 初始动画状态
.attr("d", arc)
// 添加动画效果
.transition()
.duration(1500)
.delay(function(d, i) { return i * 100; })
.ease("bounce")
.attrTween("d", function(d) {
// 弧度过渡动画
var interpolate = d3.interpolate(d.startAngle, d.endAngle);
return function(t) {
d.endAngle = interpolate(t);
// 更新外半径到目标值
arc.outerRadius(radius);
return arc(d);
};
});
// 8. 添加百分比文字
svg.selectAll(".pie-text")
.data(pieData)
.enter()
.append("text")
.attr("class", "pie-text")
.attr("transform", function(d) {
// 文字位置跟随饼图扇区中心
return "translate(" + textArc.centroid(d) + ")";
})
// 初始隐藏
.style("opacity", 0)
.transition()
.duration(1500)
.delay(function(d, i) { return i * 100 + 1000; })
.style("opacity", 1)
.text(function(d) { return d.percent + "%"; });
// 9. 创建图例
var legend = d3.select("#pieChart")
.append("div")
.attr("class", "legend");
// 添加图例项
var legendItems = legend.selectAll(".legend-item")
.data(pieData)
.enter()
.append("div")
.attr("class", "legend-item");
// 图例颜色块
legendItems.append("div")
.attr("class", "legend-color")
.style("background-color", function(d, i) { return color(i); });
// 图例文字
legendItems.append("div")
.text(function(d) {
return d.label + " (" + d.percent + "%)";
});
</script>
</body>
</html>
