有在移动端实现光滑曲线图的需求,选择了AntV的库,但官方文档不太行网上案例更少,找起来很麻烦。就把自己做的记录下来,主要是麻烦在AntV的官方文档写得不行,不好查找,给的官方案例又简单又少,api介绍的又比较混乱
我这里主要涉及到对曲线图上的点及点标签的自定义样式
legend不想查组件库的api,所以自己拿div拼了一个
还有就是chart的刷新及传值要深拷贝问题
另外chart有id,这id一定要是唯一的,否则会互相影响
项目是vue的,封装成了一个组件,在别的地方可以直接用,使用如下
<line-chart title="实际趋势图" :infos="JSON.parse(JSON.stringify(history))" id="chart1" type="1">line-chart>
传过去的数据格式如下
history: [
{
name: 'W21',
value: '40'
}, {
name: 'W22',
value: '38'
}, {
name: 'W23',
value: '64'
}, {
name: 'W24',
value: '56'
}, {
name: 'W25',
value: '44'
}, {
name: 'W26',
value: '77.3'
}
],
同样也支持百分数,如下
history: [
{
name: 'W21',
value: '40%'
}, {
name: 'W22',
value: '38%'
}, {
name: 'W23',
value: '64%'
}, {
name: 'W24',
value: '56%'
}, {
name: 'W25',
value: '44%'
}, {
name: 'W26',
value: '77.3%'
}
],
我template写的是pug,css写的是scss
<!--详情页使用-->
<!--趋势图组件-->
<!--传参type 0:小标题 1:大标题-->
<template lang="pug">
div.line-chart(:class="lineChartClass")
div.chart-title(:class="titleClass") {
{
title}}
div.chart-legend
div.up-icon.legend-icon
div.legend-text 最高值
div.down-icon.legend-icon
div.legend-text 最低值
div.chart-content(:id="id")
</template>
<script>
export default {
name: 'line-chart',
props: {
id: String,
title: String,
infos: {
type: Array,
default () {
return [{
}]
}
},
type: String
},
data () {
return {
pointColor: [],
maxValue: null,
minValue: null
}
},
computed: {
lineChartClass () {
if (this.type == 1) {
return 'big-line-chart' } else {
return null
}
},
titleClass () {
if (this.type == 1) {
return 'big-title' } else {
return null
}
},
chartData () {
return this.infos.map((item) => {
if (item.value.indexOf('%') >= 0) {
// 有百分号
return {
name: item.name,
value: Number(item.value.replace('%', '')),
type: 1 // 值类型 0:值,1:百分数
}
} else {
return {
name: item.name,
value: Number(item.value),
type: 0 // 值类型 0:值,1:百分数
}
}
})
}
},
watch: {
infos (val) {
if (!this.$chart) {
this.initChart()
} else {
this.$chart.destroy()
this.initChart()
}
}
},
mounted () {
this.initChart()
},
methods: {
initChart () {
this.calMinMax()
this.creatChart()
},
calMinMax () {
let valueArray = this.chartData.map((item) => {
return item.value
})
valueArray.sort((a, b) => {
return a - b
})
this.minValue = valueArray[0]
this.maxValue = valueArray[valueArray.length - 1]
},
creatChart () {
this.$chart = new window.G2.Chart({
container: this.id,
forceFit: true,
height: 200,
width: 450
})
this.$chart.source(this.chartData)
// this.$chart.tooltip({
// crosshairs: {
// type: 'line'
// }
// })
this.$chart.legend(false)// 不要legend
this.$chart.tooltip(false)
this.$chart.axis('value', false)// 不要y轴
this.$chart.axis('name', {
line: {
stroke: '#EEEEEE'
},
label: {
textStyle: {
textAlign: 'center', // 文本对齐方向,可取值为: start center end
fill: '#666666', // 文本的颜色
fontSize: '12' // 文本大小
}
},
tickLine: null
})
this.$chart.line().position('name*value').shape('smooth')// 曲线图
this.$chart.point().position('name*value').size(3).color('value', (value) => {
// 多个参数,通过回调函数
if (value === this.minValue) {
return '#389E0D'
} else if (value === this.maxValue) {
return '#F5212D'
} else {
return '#666666'
}
}).shape('circle').style({
// stroke: '#fff',
// lineWidth: 1
}).label('name*value', {
htmlTemplate: (name, value) => {
let color
const pretext = 'const midtext = `;color:#FFFFFF;
border-radius: 2px; margin-top: 12px;
font-size:10px; font-family:PingFangSC-Medium;
padding: 2px 4px 2px 4px; transform: scale(.9);">
`
const suftext = ''
if (value.point.value == this.minValue) {
color = '#389E0D'
if (value.point.type == 1) {
// 百分数时
return `${
pretext}${
color}${
midtext}${
value.point.value}%${
suftext}`
} else {
// 数值时
return `${
pretext}${
color}${
midtext}${
value.point.value}${
suftext}`
}
} else if (value.point.value == this.maxValue) {
color = '#F5212D'
if (value.point.type == 1) {
return `${
pretext}${
color}${
midtext}${
value.point.value}%${
suftext}`
} else {
return `${
pretext}${
color}${
midtext}${
value.point.value}${
suftext}`
}
} else {
color = '#666'
if (value.point.type == 1) {
return `${
pretext}${
color}${
midtext}${
value.point.value}%${
suftext}`
} else {
return `${
pretext}${
color}${
midtext}${
value.point.value}${
suftext}`
}
}
} })
this.$chart.render()
}
}
}
</script>
<style scoped lang="scss">
.big-line-chart{
height: 380px!important;
}
.big-title{
color: #222222!important;
font-size: 32px!important;
font-family: PingFangSC-Medium!important;
line-height: 32px!important;
}
.line-chart{
height: 370px;
background-color: white;
width: 690px;
padding-bottom: 20px;
.chart-title {
color: #666666;
font-size: 20px;
text-align: left;
margin-left: 24px;
padding-top: 24px;
}
.chart-legend{
margin-left: 24px;
display: flex;
align-items: center;
justify-content: left;
margin-top: 20px;
margin-bottom: 14px;
.legend-icon{
display: inline-block;
width: 10px;
height: 10px;
border-radius: 5px;
}
.legend-text{
display: inline-block;
color: #999999;
font-size: 20px;
}
.up-icon{
background-color: #F5212D;
margin-right: 10px;
}
.down-icon{
background-color: #389E0D;
margin: 0 10px 0 10px;
}
}
.max-color{
color: #F5212D;
}
.min-color{
color: #389E0D;
}
.chart-content{
margin-left: -124px;
}
}
</style>