1. 需求
- 将普通柱状图表改成能够显示二级菜单销售量的图表
- 原图:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/768847a51a54f4f5440a2f1f44c7fd61.png)
- 修改后的图形
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a6493d7e9197e33797fe3d64d975c558.png)
2. 解决方法
01 | 使用字符串拼接法生成图表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<title>Document</title>
<style>
.histogram_box{
margin: 0 auto;
margin-top: 69px;
width: 878px;
}
.header{
height: 52px;
line-height: 51px;
}
.header .span1{
width: 6px;
height: 20px;
background: #2FAFEC;
display: inline-block;
}
.header .title{
font-size: 18px;
font-family: Arial-BoldMT;
font-weight: bold;
line-height: 47px;
color: #333333;
display: inline-block;
}
.header .botton1,.botton2,.select{
display: inline-block;
float: right;
margin-left: 20px;
padding:0 3px;
background: #FFFFFF;
border: 2px solid #CCCCCC;
opacity: 1;
border-radius: 7px;
line-height: 36px;
text-align: center;
cursor: pointer;
}
.header .botton2{
border: 2px solid #2FAFEC;
border-radius: 7px;
color: #2FAFEC;
}
.histogram{
width: 878px;
height: auto;
background: #FFFFFF;
border: 1px solid #E6E6E6;
border-radius: 24px;
position: relative;
padding-bottom: 60px;
}
.his_cont{
position: relative;
margin-left: 36px;
z-index: 99;
padding-top: 50px;
}
.his_item{
position: relative;
height: 5px;
line-height: 20px;
vertical-align:middle;
margin-bottom: 30px;
}
.arrows{
width:0;
height:0;
font-size:0;
border-width:8px;
border-style:solid;
border-color:#6AAACE transparent transparent;
overflow:hidden;
transform: rotate(-90deg);
z-index: 99;
display: inline-block;
cursor: pointer;
vertical-align:middle;
}
.arrows_active{
transform: rotate(0deg);
}
.his_title{
width: 188px;
color: #6AAACE;
font-size: 15px;
text-align: right;
display: inline-block;
vertical-align:middle;
}
.his_width{
height: 16px;
background: #2FAFEC;
opacity: 0.88;
margin-left: 10px;
margin-right: 12px;
display: inline-block;
vertical-align:middle;
}
.his_number{
width: 37px;
height: 19px;
line-height: 19px;
font-size: 17px;
font-family: ArialMT;
color: #2FAFEC;
opacity: 1;
display: inline-block;
vertical-align:middle;
}
.his_item_list{
display: none;
}
.his_item_item{
position: relative;
padding-left: 15px;
margin-bottom: 30px;
height: 5px;
}
.his_item_item .his_width{
background: #808080;
}
.his_bg{
width: 592px;
height: 100%;
position: absolute;
right: 36px;
z-index: 0;
border-bottom: 1px transparent black;
}
.his_bg_item{
width: 0px;
height: 100%;
border: 1px solid #E6E6E6;
margin-right: 50px;
float: left;
position: relative;
}
.his_xtext{
position: absolute;
bottom: -30px;
left: -17px;
text-align: left;
color: #6AAACE;
}
</style>
</head>
<body>
<div class="histogram_box" id="histogram_box">
<div class="histogram" id="bar">
<div class="his_cont" id="his_cont">
<div class="his_bg">
<div class="his_bg_item"><div class="his_xtext" style="left: -3px;"></div></div>
<div class="his_bg_item" style="opacity: 0;"><div class="his_xtext" style="opacity: 0;"></div></div>
<div class="his_bg_item"><div class="his_xtext"></div></div>
<div class="his_bg_item" style="opacity: 0;"><div class="his_xtext" style="opacity: 0;"></div></div>
<div class="his_bg_item"><div class="his_xtext" ></div></div>
<div class="his_bg_item" style="opacity: 0;"><div class="his_xtext" style="opacity: 0;"></div></div>
<div class="his_bg_item"><div class="his_xtext"></div></div>
<div class="his_bg_item" style="opacity: 0;"><div class="his_xtext" style="opacity: 0;"></div></div>
<div class="his_bg_item"><div class="his_xtext" ></div></div>
<div class="his_bg_item" style="opacity: 0;"><div class="his_xtext" style="opacity: 0;"></div></div>
<div class="his_bg_item"><div class="his_xtext"></div></div>
</div>
<div id="bar_box">
</div>
</div>
</div>
</div>
<script>
let barList=[
{
"name": "服饰",
"value": 6000,
"percent": "60%",
"childNode": [
{
"name": "服饰1",
"value": 3000,
"percent": "50%"
},
{
"name": "服饰2",
"value": 2000,
"percent": "50%"
},
{
"name": "服饰3",
"value": 1000,
"percent": "50%"
},
]
},
{
"name": "电子产品",
"value": 4000,
"percent": "60%",
"childNode": [
{
"name": "电子产品1",
"value": 1000,
"percent": "50%"
},
{
"name": "电子产品2",
"value": 1500,
"percent": "50%"
},
{
"name": "电子产品3",
"value": 2500,
"percent": "50%"
},
]
},
{
"name": "图书",
"value": 3000,
"percent": "60%"
}
]
let numlist=barList.map(item=>{
return item.value
})
let max=Math.ceil(Math.max(...numlist))
let step
if(max<=10){
step=1
}else if(max<=100){
step=Math.ceil(max/10)
}else if(max<=1000){
step=Math.ceil(max/100)*10
}else if(max<=10000){
step=Math.ceil(max/1000)*100
}else if(max<=100000){
step=Math.ceil(max/10000)*1000
}else{
step=Math.ceil(max/10)
}
let titleboxList=document.querySelectorAll('.his_xtext');
for(let i=0,s=0;i<=10;s=s+step,i++){
titleboxList[i].innerText=s
}
let bar_box=document.getElementById('bar_box')
let strBar=''
for(let c=0;c<barList.length;c++){
strBar+='<div class="his_list">'
strBar+='<div class="his_item" οnclick="isShow(his_item_list'+(c+1)+',arr'+(c+1)+')">'
strBar+='<div class="arrows" id="arr'+(c+1)+'"></div>'
strBar+='<div class="his_title">'+barList[c].name+'</div><div class="his_width" style="width:'+barList[c].value/titleboxList[10].innerText*520+'px; background: -webkit-linear-gradient(left,#FFFFFF,#44A1FF); "></div><div class="his_number">'+barList[c].value+'</div></div>'
strBar+='<div class="his_item_list" id="his_item_list'+(c+1)+'">'
if(barList[c].childNode!=undefined){
for(let m=0;m<barList[c].childNode.length;m++){
strBar+='<div class="his_item_item">'
strBar+='<div class="his_title" style="color: #AEAEAE;">'+barList[c].childNode[m].name+'</div><div class="his_width" style="width:'+barList[c].childNode[m].value/titleboxList[10].innerText*520+'px; background: -webkit-linear-gradient(left,#FFFFFF,#9B9B9B); "></div><div class="his_number">'+barList[c].childNode[m].value+'</div>'
strBar+='</div>'
}
}
strBar+='</div>'
strBar+='</div>'
}
bar_box.innerHTML=strBar
function isShow(oDiv,oArr){
oDiv.style.display = oDiv.style.display=='block'?'none':'block',
oArr.className = oArr.className=='arrows arrows_active'?'arrows':'arrows arrows_active'
}
</script>
</body>
</html>
- 效果图:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/baca25b8e3f72bf4d6cf15bb36320567.png)
02 | 使用Echarts方法生成
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<script src="https://cdn.bootcss.com/echarts/5.0.2/echarts.min.js"></script>
<body>
<div id="main" style="width: auto;"></div>
</body>
<script type="text/javascript">
let response = {
"color": ["#6AAACE", "#808080", "#FFA500", "#681752"],
"data": [{
"name": "服饰",
"percent": "60",
"id": '1',
"children": [{
"name": "服饰1",
"id": '1-1',
"percent": "40"
},
{
"name": "服饰2",
"id": '1-2',
"percent": "50",
"children": [{
"name": "31",
"id": '1-2-1',
"percent": "80"
},
{
"name": "32",
"id": '1-2-2',
"percent": "70",
"children": [{
"name": "we",
"id": '1-2-2-1',
"percent": "120"
},
{
"name": "qq",
"id": '1-2-2-2',
"percent": "10"
},
{
"name": "af",
"id": '1-2-2-3',
"percent": "70"
}
]
},
{
"name": "33",
"id": '1-2-3',
"percent": "10"
}
]
},
{
"name": "服饰3",
"id": '1-3',
"percent": "70"
}
]
},
{
"name": "电子产品",
"id": '2',
"percent": "30",
"children": [{
"name": "服饰21",
"id": '2-1',
"percent": "40"
},
{
"name": "服饰22",
"id": '2-2',
"percent": "50"
},
{
"name": "服饰23",
"id": '2-3',
"percent": "70"
}
]
},
{
"name": "图书",
"id": '3',
"percent": "50"
}
]
}
function initResponse(target) {
target.forEach(item => {
close[item['id']] = true
let childNode = item ?.children
if (!!childNode) {
initResponse(childNode)
}
})
}
function refresh() {
let height = chartData.length * 35 + 120
myChart.resize({
height: height
})
myChart.setOption(option)
}
function findLength(target) {
let count = 0
target.forEach(item => {
count++
let childNode = item ?.children
if (!!childNode && !close[item.id]) {
close[item.id] = !close[item.id]
count += findLength(childNode)
}
})
return count
}
let close = {}
let data = response.data
initResponse(data)
let color = response.color
let chartData = []
data.forEach(item => {
chartData.push({
name: item['name'],
value: item['percent'],
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: '#ffffff'
},
{
offset: 1,
color: color[item['id'].split('-').length - 1]
}]),
}
},
children: item['children'],
id: item['id']
})
})
let label = Object.assign([], chartData.map(item => {
return {
value: (function () {
if (!!item['children']) {
return '▶' + item['name'];
} else {
return item['name'];
}
})(),
textStyle: {
color: color[item['id'].split('-').length - 1]
},
id: item['id']
}
}))
const myChart = echarts.init(document.getElementById('main'));
const option = {
animationEasing: 'elasticOut',
xAxis: {
type: 'value'
},
yAxis: {
type: 'category',
data: label,
animation: false,
triggerEvent: true,
axisLine: false,
axisTick: false
},
series: [{
data: chartData,
type: 'bar',
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: '#ffffff'
},
{
offset: 1,
color: 'rgba(113,237,255,0.1)'
}]),
}
},
label: {
show: true,
position: 'right',
textStyle: {
color: '#808080',
fontSize: '12'
}
}
}
]
};
myChart.on('click', function (params) {
if (params.componentType == "xAxis") {
} else if (params.componentType == "yAxis") {
labelname = (params.value[0] == '▶' || params.value[0] == '▼') ? params.value.slice(1) : params
.value
labelindex = chartData.findIndex(item => {
return ((item['name'][0] == '▶' || item['name'][0] == '▼') ? item['name'].slice(1) :
item.name) === labelname
})
let index = labelindex
if (close[chartData[index].id]) {
let childNode = chartData[index]?.children
if (!!childNode) {
let childData = []
childNode.forEach(item => {
childData.push({
name: (function () {
if (!!item['children']) {
return '▶' + item['name'];
} else {
return item['name'];
}
})(),
value: item['percent'],
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: '#ffffff'
},
{
offset: 1,
color: color[item['id'].split('-').length - 1]
}]),
}
},
children: item['children'],
id: item['id']
})
})
close[chartData[index].id] = false
chartData.splice(index, 0, ...childData)
let cp = Object.assign({}, label[index])
label.splice(index, 1, {
...cp,
value: '▼' + cp['value'].slice(1)
})
label.splice(index, 0, ...childData.map(item => {
return {
value: item['name'],
textStyle: {
color: color[item['id'].split('-').length - 1]
}
}
}))
}
} else {
let childrenLength = findLength(chartData[index].children)
close[chartData[index].id] = true
let cp = Object.assign({}, label[index])
label.splice(index, 1, {
...cp,
value: '▶' + cp['value'].slice(1)
})
chartData.splice(index - childrenLength, childrenLength)
label.splice(index - childrenLength, childrenLength)
}
refresh()
} else {
let index = params.dataIndex
if (close[chartData[index].id]) {
let childNode = params.data ?.children
if (!!childNode) {
let childData = []
childNode.forEach(item => {
childData.push({
name: (function () {
if (!!item['children']) {
return '▶' + item['name'];
} else {
return item['name'];
}
})(),
value: item['percent'],
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: '#ffffff'
},
{
offset: 1,
color: color[item['id'].split('-').length - 1]
}]),
}
},
children: item['children'],
id: item['id']
})
})
close[chartData[index].id] = false
chartData.splice(index, 0, ...childData)
let cp = Object.assign({}, label[index])
label.splice(index, 1, {
...cp,
value: '▼' + cp['value'].slice(1)
})
label.splice(index, 0, ...childData.map(item => {
return {
value: item['name'],
textStyle: {
color: color[item['id'].split('-').length - 1]
}
}
}))
}
} else {
let childrenLength = findLength(params.data.children)
close[chartData[index].id] = true
let cp = Object.assign({}, label[index])
label.splice(index, 1, {
...cp,
value: '▶' + cp['value'].slice(1)
})
chartData.splice(index - childrenLength, childrenLength)
label.splice(index - childrenLength, childrenLength)
}
refresh()
}
})
refresh()
</script>
</html>
- 效果图:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/da5fe60b9eb9c21775db4087e4444e8b.png)