在上一篇文章里,我们实现了借助flask框架和echars,成功的把后台的数据转化成了前端的图表,不过,当时没有细讲柱状图的参数配置。同时,我们还没开始制作矩形树状图。
这里先回顾一下堆积柱状图的配置。
在这里,x轴作为时间维度,对数据进行分组,其类型type: 'category'
,传入的数据months应该是一个列表。这里还有个问题,就是生成的月份数据的顺序是乱的,想要解决这个问题,可以在初始化echarts前加上months.sort()
。
我们要以数组的形式向echarts中传递数据,不同月份间的数据seriesData传出的数据如下:
展开某月的数据: series用来写入数据, type:"bar"
表示柱状图,写入数据data:seriesData
,因为前文在处理数据的时候,我们设置了value的值value:item.value
,所以在series的时候,echarts会自动读取并设置数据。
因为我们还需要了解每个月的详细情况,所以做一个鼠标划过时显示信息的效果。这里需要配置tooltip,其中trigger表示何时触发显示,我使用的axis就表示在鼠标滑过数据的轴时显示数据trigger: 'axis'
,这种写法一般用于柱状图、折线图等有轴的图形;还有一种写法是trigger: 'item'
能在鼠标划过某个具体的内容时显示提示,可以用在散点图。
js
axisPointer: {
type: 'shadow',
shadowStyle: {
color: 'rgb(73, 94, 87,0.3)' // 设置阴影颜色
}
}
在我们的例子中,当鼠标滑过某月的数据,会显示详细信息。axisPointer会做一个触发效果,鼠标滑过某月时,背景会做一个阴影效果进行提示,color选择背景颜色。
tooltip内可以用formatter:来自定义提示的内容,这里需要用到循环,循环的结果items代表取出一个月的数据,如果某个月的数据存在,就从data中取出我们需要的数据并一个tooltipContent接受数据,最后用return返回数据。
js
formatter:
function(params) {
tooltipContent= ""
params.forEach(function(items){
if (items.value > 0){
console.log(items.data)
for (var n = 0 ; n < items.data.name.length; n++){
var names = items.data.name[n]
var ymd = items.data.ymd[n]
var content = items.data.content[n]
console.log(names)
tooltipContent += "<b>" + names + ymd +content + "</b>" + '<br>';}
}
})
return tooltipContent
}
这是items的结果他说一个月的数据,可以看到我们需要的数据存在data中,value表示聚合后的总分,我们要排除掉没有分的月,可以用items.value做条件判断。
js
const months = Object.keys(agg);
const seriesData = Object.values(agg).map(item => {
return {
name:item.name,
time:item.time,
ymd:item.ymd,
content:item.content,
value:item.value
}
});
months.sort()
var chart = echarts.init(document.querySelector("div"))
option = {
title: {
text: '每月人数统计图',
left: 'center'
},
legend: {
data: ['人数']
},
xAxis: {
type: 'category',
data: months
},
yAxis: {
type: 'value'
},
tooltip:{
trigger: 'axis',
axisPointer: {
type: 'shadow',
shadowStyle: {
color: 'rgb(73, 94, 87,0.3)' // 设置阴影颜色
}
},
formatter:
function(params) {
tooltipContent= ""
params.forEach(function(items){
if (items.value > 0){
console.log(items.data)
for (var n = 0 ; n < items.data.name.length; n++){
var names = items.data.name[n]
var ymd = items.data.ymd[n]
var content = items.data.content[n]
console.log(names)
tooltipContent += "<b>" + names + ymd +content + "</b>" + '<br>';}
}
})
return tooltipContent
}
},
series:[{
type:"bar",
data:seriesData,
itemStyle:{
color:"rgba(237, 125,49,0.7)"
},
}]
};
option && chart.setOption(option);
这里我们就完成了一个堆叠柱状图,但他其实还存在一个问题,在每个月,一位练习生可能有多条记录,但我们没有根据个人聚合数据,如果我们想细分当月每个人的分数贡献,会存在一些问题。
在制作矩形树状图的过程中,我们要根据个人来聚合数据,除了计算个人的总分外。我们要准备的数据还包括个人加分的时间、分值、加分项目,当我们的数据滑过某个人时,要能显示有关分数的详细信息。
在取得数据以后,这次,我们根据姓名对数据进行聚合。
js
response.data.forEach(function (item) {
var name = item.name;
var time = item.time;
var items = item.item;
var score = item.score;
var fulltime = new Date(time)
var year = fulltime.getUTCFullYear();
var month = fulltime.getUTCMonth() + 1;
var day = fulltime.getUTCDay()
var ym = year + "-" + (month < 10 ? "0" + month : month)
var ymd = year + "-" + (month < 10 ? "0" + month : month) + "-" + (day < 10 ? "0" + day : day)
if (!agg.hasOwnProperty(name)) {
agg[name] = {
name:name,
time: [time],
ymd: [ymd],
content: [items],
scorelist: [score],
value: score
}
}
else {
agg[name].time.push(time),
agg[name].ymd.push(ymd),
agg[name].content.push(items),
agg[name].scorelist.push(score),
agg[name].value += score}
});
取得的结果agg如下,但我们还要把每个人都数据都存入到一个列表当中。
js
datalist = [];
for (var name in agg) {
var data = agg[name];
datalist.push(data);
}
结果如下: 最后,我们可以把准备好的数据写入echarts图表,这里的type: 'treemap'
表示图表类型为矩形树状图,矩形树状图不同于折线图或或柱状图,没有x轴、y轴的概念,因此不需要进行设置。
这里有几个比较重要的配置:roam: false
,限制图形拖动,如果不设置,那这个矩形树状图就可以在指定区域内进行拖动,建议关闭。trigger: 'item'
把触发效果设置为针对某个人触发提示效果。
是否开启拖拽漫游(移动和缩放) 是否开启拖拽漫游(移动和缩放)。可取值有:
false
:关闭。'scale'
或'zoom'
:只能够缩放。'move'
或'pan'
:只能够平移。true
:缩放和平移均可。
js
option = {
title: { // 配置标题组件
text: '个人扣分情况',
top: 15,
textStyle: { color: '#ed7d31' },
},
series: [{
type: 'treemap',
data: datalist,
label: {
show: true,
trigger: 'item',
formatter: '{b}\n -{c}',
fontWeight: 'bold',
color: "#191919"
},
roam: false
}],
tooltip: {
trigger: 'item',
formatter: function (params) {
console.log(params)
var name = params.name;
var value = params.value;
var months = params.data.ymd;
var secItems = params.data.content;
var scorelist = params.data.scorelist
var detail = []
for (var i = 0; i < secItems.length; i++) {
var message = months[i] + " " + scorelist[i] + " " + secItems[i] + '</br>';
detail.push(message)
}
// return name + ' (' + secItems.length + '项)' + ': -' + value;
return name + "</br>" + detail;
},
// formatter: '{b}: {c}' // 提示框显示的文本格式,{b} 表示名字,{c} 表示分数
},
};
option && chart1.setOption(option);
完整代码:
html
<div id="treemap" style="width: 600px;height: 400px;"></div>
<script>
chart1 = echarts.init(document.getElementById('treemap'));
$.ajax({
type: "GET",
url: "/data",
success: function (response) {
const agg = {}
response.data.forEach(function (item) {
var name = item.name;
var time = item.time;
var items = item.item;
var score = item.score;
var fulltime = new Date(time)
var year = fulltime.getUTCFullYear();
var month = fulltime.getUTCMonth() + 1;
var day = fulltime.getUTCDay()
var ym = year + "-" + (month < 10 ? "0" + month : month)
var ymd = year + "-" + (month < 10 ? "0" + month : month) + "-" + (day < 10 ? "0" + day : day)
if (!agg.hasOwnProperty(name)) {
agg[name] = {
name:name,
time: [time],
ymd: [ymd],
content: [items],
scorelist: [score],
value: score
}
}
else {
agg[name].time.push(time),
agg[name].ymd.push(ymd),
agg[name].content.push(items),
agg[name].scorelist.push(score),
agg[name].value += score}
});
console.log(agg)
datalist = [];
for (var name in agg) {
var data = agg[name];
datalist.push(data);
}
console.log(datalist)
option = {
title: { // 配置标题组件
text: '个人扣分情况',
top: 15,
textStyle: { color: '#ed7d31' },
},
series: [{
type: 'treemap',
data: datalist,
label: {
show: true,
trigger: 'item',
formatter: '{b}\n -{c}',
fontWeight: 'bold',
color: "#191919"
},
roam: false,
zzoomToNodeRatio: 1
}],
tooltip: {
trigger: 'item',
formatter: function (params) {
console.log(params)
var name = params.name;
var value = params.value;
var months = params.data.ymd;
var secItems = params.data.content;
var scorelist = params.data.scorelist
var detail = []
for (var i = 0; i < secItems.length; i++) {
var message = months[i] + " " + scorelist[i] + " " + secItems[i] + '</br>';
detail.push(message)
}
// return name + ' (' + secItems.length + '项)' + ': -' + value;
return name + "</br>" + detail;
},
// formatter: '{b}: {c}' // 提示框显示的文本格式,{b} 表示名字,{c} 表示分数
},
};
option && chart1.setOption(option);
}
})
</script>