ECharts.vue 6.8 KB

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