import echarts from 'echarts/lib/echarts'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/title'
import {log, tip} from '$ui/utils/log'
import {debounce} from '$ui/utils/util'
import {arrayToMap} from '$ui/utils/dictionary'
import {addResizeListener, removeResizeListener} from 'element-ui/lib/utils/resize-event'
import setExtend from '$ui/charts/utils/extend'
import {DEFAULT_THEME} from '$ui/charts/utils/constant'
/**
* 图表基础组件
* @module $ui/charts/my-chart
*/
export default {
name: 'MyChart',
/**
* 属性参数
* @member props
* @property {string} [width=auto] 图表宽度
* @property {string} [height=400px] 高度
* @property {boolean} [fit] 适应父容器
* @property {object} [options] ECharts 原生配置选项
* @property {object} [extend] 扩展ECharts配置选项
* @property {string|object} [theme=light]
* @property {boolean} [loading] 显示加载中
* @property {boolean} [debug] 打印构建的ECharts option内容
* @property {object} [settings] 个性图表配置
* @property {object} [data] 图表数据, {columns, rows, layout}
* @property {Object|Array} [coords] 注册经纬度 如:{'广州': [120.3234, 33.4329]}, 或 [{label:'广州',value: [120.3234, 33.4329]}]
* @param {Object|Function} [register] geo地图JSON或函数,函数必须返回 Promies
* @param {Function} [onRegister] 地图注册完成时回调
*/
props: {
// 宽度
width: {
type: String,
default: 'auto'
},
// 高度
height: {
type: String,
default: '400px'
},
// 适应父容器
fit: Boolean,
// ECharts 配置选项
options: {
type: Object
},
// 扩展 options
extend: [Object, Function],
// 主题
theme: {
type: [String, Object],
default() {
return DEFAULT_THEME
}
},
// 显示加载动画
loading: Boolean,
// 打印 options
debug: {
type: Boolean
},
// 图表私有设置
settings: {
type: Object,
default() {
return {}
}
},
// 图表数据 echarts dataset
data: {
type: [Object, Array],
default() {
return {}
}
},
// 地图名称
map: String,
// 地图geojson对象或构建函数,函数必须返回Promise
register: [Object, Function],
// 地图注册成功回调
onRegister: Function,
// 坐标集合 如:{'广州': [120.3234, 33.4329]}, 或 [{label:'广州',value: [120.3234, 33.4329]}]
coords: {
type: [Object, Array],
default() {
return {}
}
}
},
data() {
// 地图region坐标集合
this.coordinates = Object.create(null)
return {}
},
computed: {
classes() {
return {
[`my-chart-${this._uid}`]: true,
'my-chart': true
}
},
styles() {
return {
width: this.fit ? '100%' : this.width,
height: this.fit ? '100%' : this.height
}
}
},
watch: {
options() {
this.$nextTick(this.proxySetOption)
},
extend() {
this.$nextTick(this.proxySetOption)
},
settings() {
this.$nextTick(this.proxySetOption)
},
data() {
this.$nextTick(this.proxySetOption)
},
loading(val) {
if (!this.chart) return
val ? this.chart.showLoading() : this.chart.hideLoading()
},
coords: {
handler(val) {
const coords = Array.isArray(val) ? arrayToMap(val) : val
this.coordinates = Object.assign(this.coordinates, coords)
},
immediate: true
},
map() {
this.registerMap().then(this.proxySetOption)
}
},
methods: {
init() {
this.chart = echarts.init(this.$el, this.theme)
// 绑定echarts事件
Object.entries(this.$listeners)
.forEach(([name, handler]) => {
this.chart.on(name, handler)
})
this.loading && this.chart.showLoading()
this.proxySetOption()
addResizeListener(this.$el, this.proxyResize)
},
// ECharts原生 setOption
nativeSetOption(options) {
if (this.debug) {
// 打印模拟请求日志
tip(this.$options.name, this._uid)
log(options)
log('----------')
}
this.chart.setOption(options)
},
setOption() {
// echarts 实例化完成才能 setOption
if (!this.chart) return
// 如果设置了 options,其他设置失效,全采用原生ECharts option参数
if (this.options) {
this.nativeSetOption(this.options)
return
}
// adapter 由子类实现, 解析私有图表的配置
const options = this.$options.adapter ? this.$options.adapter(this) : {}
// 扩展 options
if (this.extend) {
setExtend(options, typeof this.extend === 'function' ? this.extend(options) : this.extend)
}
this.nativeSetOption(options)
},
dispose() {
if (!this.chart) return
Object.entries(this.$listeners).forEach(([name, handler]) => {
this.chart.off(name, handler)
})
this.chart.dispose()
this.chart = null
removeResizeListener(this.$el, this.proxyResize)
},
resize() {
if (!this.chart) return
this.chart.resize()
// this.$nextTick(this.chart.resize)
},
recordCoords(geo) {
if (!geo || !geo.features) return
geo.features.forEach(feat => {
const properties = feat.properties
if (properties.cp) {
this.coordinates[properties.name] = properties.cp
}
})
},
registerMap() {
const {register, map} = this
// 必须 register 和 map都存在才能注册
if (!register || !map) return Promise.resolve()
// 如果地图已经注册,不做处理
const registerGeo = echarts.getMap(map)
if (registerGeo) {
this.recordCoords(registerGeo.geoJson)
return Promise.resolve()
}
// 如果是函数,执行函数,返回geojson注册
if (typeof register === 'function') {
return register(this).then(geo => {
echarts.registerMap(map, geo)
this.recordCoords(geo)
this.onRegister && this.onRegister(map, geo)
this.$emit('register', map, geo)
return geo
})
} else {
echarts.registerMap(map, register)
this.recordCoords(register)
this.onRegister && this.onRegister(map, register)
return Promise.resolve()
}
}
},
render() {
return (
<div class={this.classes} style={this.styles}></div>
)
},
created() {
this.proxyResize = debounce(this.resize, 50)
this.proxySetOption = debounce(this.setOption, 50)
},
mounted() {
this.registerMap().then(this.init)
},
beforeDestroy() {
this.dispose()
}
}