ECharts.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <template>
  2. <div class="echarts"/>
  3. </template>
  4. <style>
  5. .echarts {
  6. width: 600px;
  7. height: 400px;
  8. }
  9. </style>
  10. <script>
  11. import echarts from 'echarts/lib/echarts'
  12. import debounce from 'lodash/debounce'
  13. import { addListener, removeListener } from 'resize-detector'
  14. // enumerating ECharts events for now
  15. const EVENTS = [
  16. 'legendselectchanged',
  17. 'legendselected',
  18. 'legendunselected',
  19. 'legendscroll',
  20. 'datazoom',
  21. 'datarangeselected',
  22. 'timelinechanged',
  23. 'timelineplaychanged',
  24. 'restore',
  25. 'dataviewchanged',
  26. 'magictypechanged',
  27. 'geoselectchanged',
  28. 'geoselected',
  29. 'geounselected',
  30. 'pieselectchanged',
  31. 'pieselected',
  32. 'pieunselected',
  33. 'mapselectchanged',
  34. 'mapselected',
  35. 'mapunselected',
  36. 'axisareaselected',
  37. 'focusnodeadjacency',
  38. 'unfocusnodeadjacency',
  39. 'brush',
  40. 'brushselected',
  41. 'rendered',
  42. 'finished',
  43. 'click',
  44. 'dblclick',
  45. 'mouseover',
  46. 'mouseout',
  47. 'mousemove',
  48. 'mousedown',
  49. 'mouseup',
  50. 'globalout',
  51. 'contextmenu'
  52. ]
  53. const ZR_EVENTS = [
  54. 'click',
  55. 'mousedown',
  56. 'mouseup',
  57. 'mousewheel',
  58. 'dblclick',
  59. 'contextmenu'
  60. ]
  61. const INIT_TRIGGERS = ['theme', 'initOptions', 'autoresize']
  62. const REWATCH_TRIGGERS = ['manualUpdate', 'watchShallow']
  63. export default {
  64. props: {
  65. options: Object,
  66. theme: [String, Object],
  67. initOptions: Object,
  68. group: String,
  69. autoresize: Boolean,
  70. watchShallow: Boolean,
  71. manualUpdate: Boolean
  72. },
  73. data () {
  74. return {
  75. lastArea: 0
  76. }
  77. },
  78. watch: {
  79. group (group) {
  80. this.chart.group = group
  81. }
  82. },
  83. methods: {
  84. // provide an explicit merge option method
  85. mergeOptions (options, notMerge, lazyUpdate) {
  86. if (this.manualUpdate) {
  87. this.manualOptions = options
  88. }
  89. if (!this.chart) {
  90. this.init(options)
  91. } else {
  92. this.delegateMethod('setOption', options, notMerge, lazyUpdate)
  93. }
  94. },
  95. // just delegates ECharts methods to Vue component
  96. // use explicit params to reduce transpiled size for now
  97. appendData (params) {
  98. this.delegateMethod('appendData', params)
  99. },
  100. resize (options) {
  101. this.delegateMethod('resize', options)
  102. },
  103. dispatchAction (payload) {
  104. this.delegateMethod('dispatchAction', payload)
  105. },
  106. convertToPixel (finder, value) {
  107. return this.delegateMethod('convertToPixel', finder, value)
  108. },
  109. convertFromPixel (finder, value) {
  110. return this.delegateMethod('convertFromPixel', finder, value)
  111. },
  112. containPixel (finder, value) {
  113. return this.delegateMethod('containPixel', finder, value)
  114. },
  115. showLoading (type, options) {
  116. this.delegateMethod('showLoading', type, options)
  117. },
  118. hideLoading () {
  119. this.delegateMethod('hideLoading')
  120. },
  121. getDataURL (options) {
  122. return this.delegateMethod('getDataURL', options)
  123. },
  124. getConnectedDataURL (options) {
  125. return this.delegateMethod('getConnectedDataURL', options)
  126. },
  127. clear () {
  128. this.delegateMethod('clear')
  129. },
  130. dispose () {
  131. this.delegateMethod('dispose')
  132. },
  133. delegateMethod (name, ...args) {
  134. if (!this.chart) {
  135. this.init()
  136. }
  137. return this.chart[name](...args)
  138. },
  139. delegateGet (methodName) {
  140. if (!this.chart) {
  141. this.init()
  142. }
  143. return this.chart[methodName]()
  144. },
  145. getArea () {
  146. return this.$el.offsetWidth * this.$el.offsetHeight
  147. },
  148. init (options) {
  149. if (this.chart) {
  150. return
  151. }
  152. let chart = echarts.init(this.$el, this.theme, this.initOptions)
  153. if (this.group) {
  154. chart.group = this.group
  155. }
  156. chart.setOption(options || this.manualOptions || this.options || {}, true)
  157. // expose ECharts events as custom events
  158. EVENTS.forEach(event => {
  159. chart.on(event, params => {
  160. this.$emit(event, params)
  161. })
  162. })
  163. ZR_EVENTS.forEach(event => {
  164. chart.getZr().on(event, params => {
  165. this.$emit(`zr:${event}`, params)
  166. })
  167. })
  168. if (this.autoresize) {
  169. this.lastArea = this.getArea()
  170. this.__resizeHandler = debounce(() => {
  171. if (this.lastArea === 0) {
  172. // emulate initial render for initially hidden charts
  173. this.mergeOptions({}, true)
  174. this.resize()
  175. this.mergeOptions(this.options || this.manualOptions || {}, true)
  176. } else {
  177. this.resize()
  178. }
  179. this.lastArea = this.getArea()
  180. }, 100, { leading: true })
  181. addListener(this.$el, this.__resizeHandler)
  182. }
  183. Object.defineProperties(this, {
  184. // Only recalculated when accessed from JavaScript.
  185. // Won't update DOM on value change because getters
  186. // don't depend on reactive values
  187. width: {
  188. configurable: true,
  189. get: () => {
  190. return this.delegateGet('getWidth')
  191. }
  192. },
  193. height: {
  194. configurable: true,
  195. get: () => {
  196. return this.delegateGet('getHeight')
  197. }
  198. },
  199. isDisposed: {
  200. configurable: true,
  201. get: () => {
  202. return !!this.delegateGet('isDisposed')
  203. }
  204. },
  205. computedOptions: {
  206. configurable: true,
  207. get: () => {
  208. return this.delegateGet('getOption')
  209. }
  210. }
  211. })
  212. this.chart = chart
  213. },
  214. initOptionsWatcher () {
  215. if (this.__unwatchOptions) {
  216. this.__unwatchOptions()
  217. this.__unwatchOptions = null
  218. }
  219. if (!this.manualUpdate) {
  220. this.__unwatchOptions = this.$watch('options', (val, oldVal) => {
  221. if (!this.chart && val) {
  222. this.init()
  223. } else {
  224. // mutating `options` will lead to merging
  225. // replacing it with new reference will lead to not merging
  226. // eg.
  227. // `this.options = Object.assign({}, this.options, { ... })`
  228. // will trigger `this.chart.setOption(val, true)
  229. // `this.options.title.text = 'Trends'`
  230. // will trigger `this.chart.setOption(val, false)`
  231. this.chart.setOption(val, val !== oldVal)
  232. }
  233. }, { deep: !this.watchShallow })
  234. }
  235. },
  236. destroy () {
  237. if (this.autoresize) {
  238. removeListener(this.$el, this.__resizeHandler)
  239. }
  240. this.dispose()
  241. this.chart = null
  242. },
  243. refresh () {
  244. if (this.chart) {
  245. this.destroy()
  246. this.init()
  247. }
  248. }
  249. },
  250. created () {
  251. this.initOptionsWatcher()
  252. INIT_TRIGGERS.forEach(prop => {
  253. this.$watch(prop, () => {
  254. this.refresh()
  255. }, { deep: true })
  256. })
  257. REWATCH_TRIGGERS.forEach(prop => {
  258. this.$watch(prop, () => {
  259. this.initOptionsWatcher()
  260. this.refresh()
  261. })
  262. })
  263. },
  264. mounted () {
  265. // auto init if `options` is already provided
  266. if (this.options) {
  267. this.init()
  268. }
  269. },
  270. activated () {
  271. if (this.autoresize) {
  272. this.chart && this.chart.resize()
  273. }
  274. },
  275. destroyed () {
  276. if (this.chart) {
  277. this.destroy()
  278. }
  279. },
  280. connect (group) {
  281. if (typeof group !== 'string') {
  282. group = group.map(chart => chart.chart)
  283. }
  284. echarts.connect(group)
  285. },
  286. disconnect (group) {
  287. echarts.disConnect(group)
  288. },
  289. registerMap (mapName, geoJSON, specialAreas) {
  290. echarts.registerMap(mapName, geoJSON, specialAreas)
  291. },
  292. registerTheme (name, theme) {
  293. echarts.registerTheme(name, theme)
  294. },
  295. graphic: echarts.graphic
  296. }
  297. </script>