背景
接口会返回所有点的数据,以及最优点的数据。产品要求在绘制图形后,高亮最优点,添加一个红色的样式,如图。点击select选择器时,可选择不同指标和花费对应的关系。
以下介绍实现思路
1、自定义配置选择器的数据源,默认选中roi。
chartParams: 'roi',
chartOption: [
{
label: 'ROI、边际ROI和花费的关系',
value: 'roi',
otherValue: 'incre_roi',
name1: 'ROI',
name2: '边际ROI',
},
{
label: '点击价值、边际点击价值和花费的关系',
value: 'vpc',
otherValue: 'incre_vpc',
name1: '点击价值',name2: '边际点击价值',
},
{
label: '加购成本、边际加购成本和花费的关系',
value: 'cpca',
otherValue: 'incre_cpca',
name1: '加购成本',
name2: '边际加购成本',
},
],
<el-select v-model="chartParams" @change="handleAnalysis">
<el-option v-for="item in chartOption"
:key="item.value"
:value="item.value"
:label="item.label"></el-option>
</el-select>
2、绘制echarts
- 引入
import * as echarts from 'echarts';
- 设置宽高
<div ref="myChart1" style="width: 50%; height: 280px"></div>
- 在data中,定义一个myChart1的变量用来保存eCharts实例,echarts的基础配置
其中:formatNum方法为公共方法,功能:数字增加千分位,如果有小数点保留2位小数。文章末尾有提供
tooltip对象中的formatter函数,当鼠标悬浮时,标记点(即最优点)不展示悬浮数据,其他点展示固定的指标数据
myChart1: '',
echartsData1: {
legend: {
data: ['ROI','边际ROI'],
selectedMode: false, // 是否允许点击
},
grid: {
show: false,
top: '40px', // 一下数值可为百分比也可为具体像素值
right: '50px',
bottom: '40px',
left: '40px',
},
xAxis: {
type: 'category',
boundaryGap: false,
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: '#eee', // 左边线的颜色
width: '1', // 坐标线的宽度
},
},
data: [1,2,3,4,5,6,7,8,9,10],
axisLine: {
show: true,
lineStyle: {
type: 'solid',
color: '#ccc', // 左边线的颜色
width: '1', // 坐标线的宽度
},
},
axisLabel: {
interale: 0,
rotate: 45, //防止x轴坐标数据过大放不下,倾斜45°
color: '#aaa', // 坐标轴label颜色
formatter: (value) => {
return formatNum(value)
}
},
},
yAxis: [
{
type: 'value',
name: 'ROI',
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: '#eee', // 左边线的颜色
width: '1', // 坐标线的宽度
},
},
axisLine: {
show: true,
lineStyle: {
type: 'solid',
color: '#ccc', // 左边线的颜色
width: '1', // 坐标线的宽度
},
},
axisLabel: {
formatter: '{value}',
color: '#aaa',
},
},
{
type: 'value',
name: '边际ROI',
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: '#eee', // 左边线的颜色
width: '1', // 坐标线的宽度
},
},
axisLine: {
show: true,
lineStyle: {
type: 'solid',
color: '#ccc', // 左边线的颜色
width: '1', // 坐标线的宽度
},
},
axisLabel: {
formatter: '{value}',
color: '#aaa',
},
},
],
tooltip: {
trigger: 'item', // 设置触发类型为坐标轴
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999',
},
},
formatter: (value) => {
if(value.componentType === "markPoint") return
let str= ``
let color = value.color
let color2 = "#91cc75"
str += `<p style="line-height: 26px;color: ${color}">花费:${formatNum(Math.trunc(value.data['budget']))}</p>`
str += `<p style="line-height: 26px;color: ${color}">GMV:${formatNum(Math.trunc(value.data['pred_gmv']))}</p>`
str += `<p style="line-height: 26px">
<span style="display: inline-block; width: 110px;color: ${color}">ROI: ${value.data['roi']}</span>
<span style="display: inline-block; min-width: 150px;color: ${color2};">边际ROI: ${value.data['incre_roi']}</span></p>`
str += `<p style="line-height: 26px">
<span style="display: inline-block; width: 110px;color: ${color}">点击价值: ${value.data['vpc']}</span>
<span style="display: inline-block; min-width: 150px;color:${color2};">边际点击价值: ${value.data['incre_vpc']}</span></p>`
str += `<p style="line-height: 26px">
<span style="display: inline-block; width: 110px;color: ${color}">加购成本: ${value.data['cpca']}</span>
<span style="display: inline-block; min-width: 150px;color:${color2};">边际加购成本: ${value.data['incre_cpca']}</span></p>`
return str
}
},
series: [
{
name: 'ROI',
data: [12, 25, 45, 35, 55],
yAxisIndex: 0, // 使用第1个Y轴
type: 'line',
smooth: true,
lineStyle: {
color: '#5470c6',
type: 'solid',
},
symbol:'circle',
showSymbol: true,
symbolSize: 6,
markPoint: { //给第一条y轴添加标记点
data: [{
value: 'best',
xAxis: 1,
yAxis: 2.68,
itemStyle: {
color: 'red' //颜色设置为红色
},
}]
},
},
{
name: '边际ROI',
data: [1, 2, 44, 35, 155],
yAxisIndex: 1, // 使用第2个Y轴
type: 'line',
smooth: true,
lineStyle: {
color: '#5470c6',
type: 'dashed' // 这里设置线的类型为'dashed',即虚线
},
}
],
},
- 初始化echarts,绑定点击事件(通过样式来实现高亮)
this.$nextTick(()=> {
this.myChart1 = echarts.init(this.$refs['myChart1'])
this.myChart1.setOption(this.echartsData1)
this.myChart1.on('click', (event) => {
this.echartClick(event)
})
})
//切换最优点
echartClick(event) {
this.bestSpotInfo = event.data
this.handleSetHighLight(event.dataIndex)
},
//设置高亮事件
handleSetHighLight(idx) {
this.echartsData1.series[0].data.map((item,index) => {
item.itemStyle.color = index===idx? 'red' : '#5470c6'
item.symbolSize = index===idx? 11 : 6
})
this.myChart1.setOption(this.echartsData1)
},
- 获取数据后处理数据
//处理三个关系的折线图
handleAnalysis() {
let tempObj = this.chartOption.find(item=>item.value==this.chartParams)
this.echartsData1.xAxis.data = this.allSpotInfo.map(item => item.budget)
this.echartsData1.legend.data = [tempObj.name1, tempObj.name2]
this.echartsData1.yAxis[0].name = tempObj.name1
this.echartsData1.yAxis[1].name = tempObj.name2
this.echartsData1.series[0].name = tempObj.name1
this.echartsData1.series[1].name = tempObj.name2
//寻找最优点的坐标 设置默认高亮
let bestIndex = this.allSpotInfo.findIndex(item => item.budget == this.bestSpotInfo.budget)
this.echartsData1.series[0].markPoint.data[0].xAxis = bestIndex
this.echartsData1.series[0].markPoint.data[0].yAxis = this.bestSpotInfo[tempObj.value]
this.echartsData1.series[0].data = this.allSpotInfo.map((item,index) => {
return {
value: item[tempObj.value],
...item,
itemStyle: {
color: '#5470c6'
},
symbolSize: 6
}
})
this.echartsData1.series[1].data = this.allSpotInfo.map(item => {
return {
value: item[tempObj.otherValue],
...item,
}
})
this.handleSetHighLight(bestIndex)
if(this.myChart1) {
this.myChart1.setOption(this.echartsData1)
}
},
4、监听eCharts的宽度变化,实现页面宽度自适应
mounted() {
window.addEventListener('resize', () => {
if (this.$refs['myChart1']) {
this.myChart1.resize();
}
})
},
/* 页面组件销毁的时候,别忘了移除绑定的监听resize事件,否则的话,多渲染几次,容易导致内存泄漏和额外CPU或GPU占用哦 */
beforeDestroy () {
window.removeEventListener('resize', () => {
this.myChart1.resize()
})
},
最后贴上
// 数字增加千分位,如果有小数点保留2位小数
function formatNum(str) {
if (str === 0) {
return 0;
}
if (str === null || str === undefined || str === "--") {
return "- -";
}
var newStr = "";
var count = 0;
str = str.toString();
str = str.replace(/,/g, "");
if (str.indexOf(".") === -1) {
for (var i = str.length - 1; i >= 0; i--) {
if (count % 3 === 0 && count !== 0) {
newStr = str.charAt(i) + "," + newStr;
} else {
newStr = str.charAt(i) + newStr;
}
count++;
}
str = newStr;
return str;
} else {
for (var j = str.indexOf(".") - 1; j >= 0; j--) {
if (count % 3 === 0 && count !== 0) {
newStr = str.charAt(j) + "," + newStr;
} else {
newStr = str.charAt(j) + newStr;
}
count++;
}
str = newStr + (str + "00").substr((str + "00").indexOf("."), 3);
return str;
}
}