echarts.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <template>
  2. <view>
  3. <view class="echarts" :id="option.id" :prop="option" :change:prop="echarts.update" @click="echarts.onClick"></view>
  4. </view>
  5. </template>
  6. <script>
  7. export default {
  8. name: 'Echarts',
  9. props: {
  10. option: {
  11. type: Object,
  12. required: true
  13. }
  14. },
  15. created() {
  16. // 设置随机数id
  17. let t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  18. let len = t.length
  19. let id = ''
  20. for (let i = 0; i < 32; i++) {
  21. id += t.charAt(Math.floor(Math.random() * len))
  22. }
  23. this.option.id = id
  24. },
  25. methods: {
  26. /**
  27. * renderjs内的点击事件,回调到父组件
  28. * @param {Object} params
  29. */
  30. onViewClick(params) {
  31. this.$emit('click', params)
  32. }
  33. }
  34. }
  35. </script>
  36. <script module="echarts" lang="renderjs">
  37. import echarts from './echarts.min.js'
  38. // import * as echarts from 'echarts'
  39. export default {
  40. data() {
  41. return {
  42. chart: null,
  43. clickData: null // echarts点击事件的值
  44. }
  45. },
  46. mounted() {
  47. this.init();
  48. },
  49. methods: {
  50. /**
  51. * 初始化echarts
  52. */
  53. init() {
  54. // 根据id初始化图表
  55. this.chart = echarts.init(document.getElementById(this.option.id))
  56. this.update(this.option)
  57. // echarts的点击事件
  58. this.chart.on('click', params => {
  59. // 把点击事件的数据缓存下来
  60. this.clickData = params
  61. })
  62. },
  63. /**
  64. * 点击事件,可传递到外部
  65. * @param {Object} event
  66. * @param {Object} instance
  67. */
  68. onClick(event, instance) {
  69. if (this.clickData) {
  70. // 把echarts点击事件相关的值传递到renderjs外
  71. instance.callMethod('onViewClick', {
  72. value: this.clickData.data,
  73. name: this.clickData.name,
  74. seriesName: this.clickData.seriesName
  75. })
  76. // 上次点击数据置空
  77. this.clickData = null
  78. }
  79. },
  80. /**
  81. * 监测数据更新
  82. * @param {Object} option
  83. */
  84. update(option) {
  85. if (this.chart) {
  86. // 因App端,回调函数无法从renderjs外传递,故在此自定义设置相关回调函数
  87. if (option) {
  88. // tooltip
  89. if (option.tooltip) {
  90. // 判断是否设置tooltip的位置
  91. if (option.tooltip.positionStatus) {
  92. option.tooltip.position = this.tooltipPosition()
  93. }
  94. // 判断是否格式化tooltip
  95. if (option.tooltip.formatterStatus) {
  96. option.tooltip.formatter = this.tooltipFormatter(option.tooltip.formatterUnit, option.tooltip.formatFloat2, option.tooltip.formatThousands)
  97. }
  98. }
  99. }
  100. // 设置新的option
  101. this.chart.setOption(option, option.notMerge)
  102. }
  103. },
  104. /**
  105. * 设置tooltip的位置,防止超出画布
  106. */
  107. tooltipPosition() {
  108. return (point, params, dom, rect, size) => {
  109. // 其中point为当前鼠标的位置,size中有两个属性:viewSize和contentSize,分别为外层div和tooltip提示框的大小
  110. let x = point[0]
  111. let y = point[1]
  112. let viewWidth = size.viewSize[0]
  113. let viewHeight = size.viewSize[1]
  114. let boxWidth = size.contentSize[0]
  115. let boxHeight = size.contentSize[1]
  116. let posX = 0 // x坐标位置
  117. let posY = 0 // y坐标位置
  118. if (x >= boxWidth) { // 左边放的下
  119. posX = x - boxWidth - 1
  120. }
  121. if (y >= boxHeight) { // 上边放的下
  122. posY = y - boxHeight - 1
  123. }
  124. return [posX, posY]
  125. }
  126. },
  127. /**
  128. * tooltip格式化
  129. * @param {Object} unit 数值后的单位
  130. * @param {Object} formatFloat2 是否保留两位小数
  131. * @param {Object} formatThousands 是否添加千分位
  132. */
  133. tooltipFormatter(unit, formatFloat2, formatThousands) {
  134. return params => {
  135. let result = ''
  136. unit = unit ? unit : ''
  137. for (let i in params) {
  138. if (i == 0) {
  139. result += params[i].axisValueLabel
  140. }
  141. let value = '--'
  142. if (params[i].data !== null) {
  143. value = params[i].data
  144. // 保留两位小数
  145. if (formatFloat2) {
  146. value = this.formatFloat2(value)
  147. }
  148. // 添加千分位
  149. if (formatThousands) {
  150. value = this.formatThousands(value)
  151. }
  152. }
  153. // #ifdef H5
  154. result += '\n' + params[i].seriesName + ':' + value + ' ' + unit
  155. // #endif
  156. // #ifdef APP-PLUS
  157. result += '<br/>' + params[i].marker + params[i].seriesName + ':' + value + ' ' + unit
  158. // #endif
  159. }
  160. return result
  161. }
  162. },
  163. /**
  164. * 保留两位小数
  165. * @param {Object} value
  166. */
  167. formatFloat2(value) {
  168. let temp = Math.round(parseFloat(value) * 100) / 100
  169. let xsd = temp.toString().split('.')
  170. if (xsd.length === 1) {
  171. temp = (isNaN(temp) ? '0' : temp.toString()) + '.00'
  172. return temp
  173. }
  174. if (xsd.length > 1) {
  175. if (xsd[1].length < 2) {
  176. temp = temp.toString() + '0'
  177. }
  178. return temp
  179. }
  180. },
  181. /**
  182. * 添加千分位
  183. * @param {Object} value
  184. */
  185. formatThousands(value) {
  186. if (value === undefined || value === null) {
  187. value = ''
  188. }
  189. if (!isNaN(value)) {
  190. value = value + ''
  191. }
  192. let re = /\d{1,3}(?=(\d{3})+$)/g
  193. let n1 = value.replace(/^(\d+)((\.\d+)?)$/, function(s, s1, s2) {
  194. return s1.replace(re, '$&,') + s2
  195. })
  196. return n1
  197. }
  198. }
  199. }
  200. </script>
  201. <style lang="scss" scoped>
  202. .echarts {
  203. width: 95vw;
  204. height: 100%;
  205. // width: 700rpx;
  206. height: 500rpx;
  207. }
  208. </style>