225 lines
5.7 KiB
Vue
225 lines
5.7 KiB
Vue
<template>
|
||
<view>
|
||
<view class="echarts" :id="option.id" :prop="option" :change:prop="echarts.update" @click="echarts.onClick"></view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: 'Echarts',
|
||
props: {
|
||
option: {
|
||
type: Object,
|
||
required: true
|
||
}
|
||
},
|
||
created() {
|
||
// 设置随机数id
|
||
let t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||
let len = t.length
|
||
let id = ''
|
||
for (let i = 0; i < 32; i++) {
|
||
id += t.charAt(Math.floor(Math.random() * len))
|
||
}
|
||
this.option.id = id
|
||
},
|
||
methods: {
|
||
/**
|
||
* renderjs内的点击事件,回调到父组件
|
||
* @param {Object} params
|
||
*/
|
||
onViewClick(params) {
|
||
this.$emit('click', params)
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<script module="echarts" lang="renderjs">
|
||
export default {
|
||
data() {
|
||
return {
|
||
chart: null,
|
||
clickData: null // echarts点击事件的值
|
||
}
|
||
},
|
||
mounted() {
|
||
if (typeof window.echarts === 'object') {
|
||
this.init()
|
||
} else {
|
||
// 动态引入类库
|
||
const script = document.createElement('script')
|
||
script.src = './static/echarts.min.js'
|
||
script.onload = this.init
|
||
document.head.appendChild(script)
|
||
}
|
||
},
|
||
methods: {
|
||
/**
|
||
* 初始化echarts
|
||
*/
|
||
init() {
|
||
// 根据id初始化图表
|
||
this.chart = echarts.init(document.getElementById(this.option.id))
|
||
this.update(this.option)
|
||
// echarts的点击事件
|
||
this.chart.on('click', params => {
|
||
// 把点击事件的数据缓存下来
|
||
this.clickData = params
|
||
})
|
||
},
|
||
/**
|
||
* 点击事件,可传递到外部
|
||
* @param {Object} event
|
||
* @param {Object} instance
|
||
*/
|
||
onClick(event, instance) {
|
||
if (this.clickData) {
|
||
// 把echarts点击事件相关的值传递到renderjs外
|
||
instance.callMethod('onViewClick', {
|
||
value: this.clickData.data,
|
||
name: this.clickData.name,
|
||
seriesName: this.clickData.seriesName
|
||
})
|
||
// 上次点击数据置空
|
||
this.clickData = null
|
||
}
|
||
},
|
||
/**
|
||
* 监测数据更新
|
||
* @param {Object} option
|
||
*/
|
||
update(option) {
|
||
if (this.chart) {
|
||
// 因App端,回调函数无法从renderjs外传递,故在此自定义设置相关回调函数
|
||
if (option) {
|
||
// tooltip
|
||
if (option.tooltip) {
|
||
// 判断是否设置tooltip的位置
|
||
if (option.tooltip.positionStatus) {
|
||
option.tooltip.position = this.tooltipPosition()
|
||
}
|
||
// 判断是否格式化tooltip
|
||
if (option.tooltip.formatterStatus) {
|
||
option.tooltip.formatter = this.tooltipFormatter(option.tooltip.formatterUnit, option.tooltip.formatFloat2, option.tooltip.formatThousands)
|
||
}
|
||
}
|
||
// 颜色渐变
|
||
if (option.series) {
|
||
for (let i in option.series) {
|
||
let linearGradient = option.series[i].linearGradient
|
||
if (linearGradient) {
|
||
option.series[i].color = new echarts.graphic.LinearGradient(linearGradient[0],linearGradient[1],linearGradient[2],linearGradient[3],linearGradient[4])
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// 设置新的option
|
||
this.chart.setOption(option, option.notMerge)
|
||
}
|
||
},
|
||
/**
|
||
* 设置tooltip的位置,防止超出画布
|
||
*/
|
||
tooltipPosition() {
|
||
return (point, params, dom, rect, size) => {
|
||
// 其中point为当前鼠标的位置,size中有两个属性:viewSize和contentSize,分别为外层div和tooltip提示框的大小
|
||
let x = point[0]
|
||
let y = point[1]
|
||
let viewWidth = size.viewSize[0]
|
||
let viewHeight = size.viewSize[1]
|
||
let boxWidth = size.contentSize[0]
|
||
let boxHeight = size.contentSize[1]
|
||
let posX = 0 // x坐标位置
|
||
let posY = 0 // y坐标位置
|
||
if (x >= boxWidth) { // 左边放的下
|
||
posX = x - boxWidth - 1
|
||
}
|
||
if (y >= boxHeight) { // 上边放的下
|
||
posY = y - boxHeight - 1
|
||
}
|
||
return [posX, posY]
|
||
}
|
||
},
|
||
/**
|
||
* tooltip格式化
|
||
* @param {Object} unit 数值后的单位
|
||
* @param {Object} formatFloat2 是否保留两位小数
|
||
* @param {Object} formatThousands 是否添加千分位
|
||
*/
|
||
tooltipFormatter(unit, formatFloat2, formatThousands) {
|
||
return params => {
|
||
let result = ''
|
||
unit = unit ? unit : ''
|
||
for (let i in params) {
|
||
if (i == 0) {
|
||
result += params[i].axisValueLabel
|
||
}
|
||
let value = '--'
|
||
if (params[i].data !== null) {
|
||
value = params[i].data
|
||
// 保留两位小数
|
||
if (formatFloat2) {
|
||
value = this.formatFloat2(value)
|
||
}
|
||
// 添加千分位
|
||
if (formatThousands) {
|
||
value = this.formatThousands(value)
|
||
}
|
||
}
|
||
// #ifdef H5
|
||
result += '\n' + params[i].seriesName + ':' + value + ' ' + unit
|
||
// #endif
|
||
|
||
// #ifdef APP-PLUS
|
||
result += '<br/>' + params[i].marker + params[i].seriesName + ':' + value + ' ' + unit
|
||
// #endif
|
||
}
|
||
return result
|
||
}
|
||
},
|
||
/**
|
||
* 保留两位小数
|
||
* @param {Object} value
|
||
*/
|
||
formatFloat2(value) {
|
||
let temp = Math.round(parseFloat(value) * 100) / 100
|
||
let xsd = temp.toString().split('.')
|
||
if (xsd.length === 1) {
|
||
temp = (isNaN(temp) ? '0' : temp.toString()) + '.00'
|
||
return temp
|
||
}
|
||
if (xsd.length > 1) {
|
||
if (xsd[1].length < 2) {
|
||
temp = temp.toString() + '0'
|
||
}
|
||
return temp
|
||
}
|
||
},
|
||
/**
|
||
* 添加千分位
|
||
* @param {Object} value
|
||
*/
|
||
formatThousands(value) {
|
||
if (value === undefined || value === null) {
|
||
value = ''
|
||
}
|
||
if (!isNaN(value)) {
|
||
value = value + ''
|
||
}
|
||
let re = /\d{1,3}(?=(\d{3})+$)/g
|
||
let n1 = value.replace(/^(\d+)((\.\d+)?)$/, function(s, s1, s2) {
|
||
return s1.replace(re, '$&,') + s2
|
||
})
|
||
return n1
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.echarts {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
</style> |