bar.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <template>
  2. <div ref="dom" class="charts chart-bar"></div>
  3. </template>
  4. <script>
  5. import echarts from 'echarts'
  6. import tdTheme from './theme.json'
  7. import { on, off } from '@/libs/tools'
  8. echarts.registerTheme('tdTheme', tdTheme)
  9. export default {
  10. name: 'ChartBar',
  11. props: {
  12. // 单列柱状图,列name为x轴,value为y轴
  13. value: {
  14. type: Array,
  15. default: function () {
  16. return []
  17. }
  18. },
  19. text: String,
  20. subtext: String,
  21. color: {
  22. type: Array,
  23. default: function () {
  24. return []
  25. }
  26. },
  27. // 当有多列柱状图展示时的X轴坐标数据
  28. xAxisData: {
  29. type: Array,
  30. default: function () {
  31. return []
  32. }
  33. },
  34. // y轴坐标单位
  35. yUnit: {
  36. type: String,
  37. default: ''
  38. },
  39. // 当有多列柱状图展示时的y轴坐标数据
  40. seriesData: {
  41. type: Array,
  42. default: function () {
  43. return []
  44. }
  45. },
  46. // x轴标签旋转角度
  47. xAxisRotate: {
  48. type: Number,
  49. default: 0
  50. }
  51. },
  52. watch: {
  53. xAxisData: {
  54. handler (nVal, oVal) {
  55. // console.log(nVal, 'nnnnnnnn')
  56. if (nVal) {
  57. // 根据x轴时间长度控制滚动条位置及显示状态 x轴长度大于25时,显示滚动条并且滚动条结束位置在80%
  58. if (nVal.length > 25) {
  59. this.isShowZoom = true
  60. this.xZoomEnd = 80
  61. } else {
  62. this.isShowZoom = false
  63. this.xZoomEnd = 100
  64. }
  65. if (nVal.length > 30) {
  66. this.xZoomEnd = 70
  67. }
  68. if (nVal.length > 35) {
  69. this.xZoomEnd = 60
  70. }
  71. if (nVal.length > 40) {
  72. this.xZoomEnd = 50
  73. }
  74. if (nVal.length > 45) {
  75. this.xZoomEnd = 40
  76. }
  77. if (nVal.length > 50) {
  78. this.xZoomEnd = 30
  79. }
  80. this.pageInit()
  81. }
  82. },
  83. deep: true,
  84. immediate: true // 代表如果在 wacth 里声明了 xAxisData 之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行
  85. },
  86. xAxisRotate: {
  87. handler (nVal, oVal) {
  88. if (nVal !== '') {
  89. this.pageInit()
  90. }
  91. },
  92. deep: true,
  93. immediate: true
  94. },
  95. value: {
  96. handler (nVal, oVal) {
  97. if (nVal) {
  98. this.pageInit()
  99. }
  100. },
  101. deep: true,
  102. immediate: true
  103. }
  104. },
  105. data () {
  106. return {
  107. dom: null,
  108. isShowZoom: false, // 是否展示滚动条
  109. xZoomEnd: 100 // x轴滚动条结束位置
  110. }
  111. },
  112. methods: {
  113. resize () {
  114. this.dom.resize()
  115. },
  116. pageInit () {
  117. const that = this
  118. const legend = this.seriesData.map(_ => _.name)
  119. this.$nextTick(() => {
  120. const keys = this.value.map(item => (item = item.name))
  121. const values = this.value.map(item => (item = item.value))
  122. const xAxisData = this.value.length ? keys : this.xAxisData
  123. const seriesData = this.value.length ? values : this.seriesData
  124. const yMax = this.getYMax(this.seriesData) // 计算最大值
  125. const option = {
  126. color: this.color,
  127. title: {
  128. text: this.text,
  129. subtext: this.subtext,
  130. x: 'left'
  131. },
  132. legend: {
  133. data: legend
  134. },
  135. tooltip: {
  136. trigger: 'axis'
  137. },
  138. dataZoom: [
  139. {
  140. type: 'slider',
  141. show: this.isShowZoom, // flase直接隐藏图形
  142. xAxisIndex: [0],
  143. left: '9%', // 滚动条靠左侧的百分比
  144. bottom: -5,
  145. start: 0, // 滚动条的起始位置
  146. end: this.xZoomEnd, // 滚动条的截止位置(按比例分割你的柱状图x轴长度)
  147. zoomLock: true // 锁定区域禁止缩放(鼠标滚动会缩放,所以禁止)
  148. }
  149. ],
  150. xAxis: {
  151. type: 'category',
  152. data: xAxisData,
  153. axisLabel: {
  154. interval: 0,
  155. rotate: this.xAxisRotate // 刻度标签旋转的角度,在类目轴的类目标签显示不下的时候可以通过旋转防止标签之间重叠。旋转的角度从 -90 度到 90 度。
  156. }
  157. },
  158. yAxis: {
  159. type: 'value',
  160. min: 0,
  161. max: yMax,
  162. axisLabel: {
  163. formatter: `{value} ${this.yUnit}`
  164. },
  165. // interval: 2,
  166. position: 'left'
  167. },
  168. grid: {
  169. left: '3%',
  170. right: '4%',
  171. bottom: '3%',
  172. containLabel: true
  173. }
  174. }
  175. // 单柱图
  176. if (this.value.length) {
  177. option.series = [
  178. {
  179. data: seriesData,
  180. type: 'bar',
  181. barWidth: 35,
  182. label: {
  183. normal: {
  184. show: true,
  185. position: 'top'
  186. }
  187. }
  188. }
  189. ]
  190. } else {
  191. option.series = this.seriesData
  192. }
  193. // 已创建的先销毁
  194. if (this.dom) {
  195. this.dom.dispose()
  196. }
  197. this.dom = echarts.init(this.$refs.dom, 'tdTheme')
  198. this.dom.setOption(option)
  199. // 更新y轴最大值
  200. this.dom.on('legendselectchanged', function (params) {
  201. // console.log(params, that.seriesData, 'legendselectchanged')
  202. const data = that.seriesData.filter(item => params.selected[item.name])
  203. option.yAxis.max = that.getYMax(data)
  204. that.dom.setOption(option)
  205. })
  206. // 解决首次加载宽度超出容器bug
  207. this.dom.resize()
  208. on(window, 'resize', this.resize)
  209. })
  210. },
  211. // 计算y轴最大值
  212. getYMax (data) {
  213. let max = []
  214. data.map(item => {
  215. max = max.concat(item.data)
  216. })
  217. return Math.max.apply(null, max)
  218. }
  219. },
  220. mounted () {
  221. this.pageInit()
  222. },
  223. beforeDestroy () {
  224. off(window, 'resize', this.resize)
  225. }
  226. }
  227. </script>