left-bottom.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. <template>
  2. <div>
  3. <div class="position-a echartsFullIcon" @click="openFull">
  4. <img src="../../../assets/images/dashboard/full.png" style="width: 1.5vw" />
  5. </div>
  6. <div id="tickChart"/>
  7. <!-- 全屏弹框 -->
  8. <div class="echartsFullDialog">
  9. <el-dialog
  10. title="短期偏差统计"
  11. :visible.sync="dialogVisible"
  12. :fullscreen="true"
  13. :destroy-on-close="true"
  14. center
  15. >
  16. <div id="main" ref="fullChart" :style="'width:100%;height:' + (screenHeight - 110) + 'px'"/>
  17. </el-dialog>
  18. </div>
  19. </div>
  20. </template>
  21. <script>
  22. import {dqTickOptions} from '../echarts-data'
  23. export default {
  24. data() {
  25. return {
  26. dialogVisible: false,
  27. screenHeight: window.innerHeight,
  28. tickChart: null,
  29. fullChart: null,
  30. chartData: {
  31. boxplotData:[],
  32. scatterData:[],
  33. xData:[],
  34. q1:null,
  35. q3:null,
  36. min:null,
  37. max:null
  38. },
  39. option:{}
  40. }
  41. },
  42. props: {
  43. params: {type: Object}
  44. },
  45. watch: {
  46. params: {
  47. // immediate: true,// 第一次立即监听
  48. handler(value) {
  49. this.chartData = value
  50. this.chartData ={
  51. boxplotData: [
  52. "",
  53. "",
  54. "",
  55. "",
  56. [
  57. -3.21,
  58. 16.67,
  59. 27.45,
  60. 29.92,
  61. 49.79,
  62. "2024-11-16"
  63. ],
  64. "",
  65. [
  66. -44.91,
  67. 0,
  68. 20.72,
  69. 29.94,
  70. 74.85,
  71. "2024-11-18"
  72. ],
  73. [
  74. -44.91,
  75. 0,
  76. 20.01,
  77. 29.94,
  78. 74.85,
  79. "2024-11-19"
  80. ],
  81. "",
  82. ""
  83. ],
  84. scatterData: {
  85. '新疆':[
  86. [
  87. "2024-11-18",
  88. 66.05
  89. ],[
  90. "2024-11-18",
  91. 66.05
  92. ],
  93. [
  94. "2024-11-18",
  95. 64.36
  96. ]
  97. ],
  98. '风电':[
  99. [
  100. "2024-11-18",
  101. 66.05
  102. ],[
  103. "2024-11-18",
  104. 66.05
  105. ],
  106. [
  107. "2024-11-18",
  108. 64.36
  109. ]
  110. ],
  111. }
  112. ,
  113. xData: [
  114. "2024-11-12",
  115. "2024-11-13",
  116. "2024-11-14",
  117. "2024-11-15",
  118. "2024-11-16",
  119. "2024-11-17",
  120. "2024-11-18",
  121. "2024-11-19",
  122. "2024-11-20",
  123. "2024-11-21"
  124. ]
  125. }
  126. this.setOptions(this.chartData)
  127. }
  128. }
  129. },
  130. mounted() {
  131. const _this = this
  132. this.$nextTick(() => {
  133. this.initChart()
  134. })
  135. window.onresize = () => {
  136. return (() => {
  137. window.screenHeight = window.innerHeight
  138. _this.screenHeight = window.screenHeight
  139. })()
  140. }
  141. },
  142. beforeDestroy() {
  143. if (this.tickChart) {
  144. this.tickChart.dispose();
  145. this.tickChart = null
  146. window.removeEventListener("resize", this.chartsResize);
  147. }
  148. if (this.fullChart) {
  149. this.fullChart.dispose();
  150. this.fullChart = null
  151. }
  152. },
  153. methods: {
  154. initChart() {
  155. // this.option = JSON.parse(JSON.stringify(dqTickOptions))
  156. // this.option.tooltip.formatter = function (params){
  157. // let str = params[0].axisValue +'<br/>'
  158. // for(let param of params){
  159. // if(param.componentSubType === 'scatter'){
  160. // str = str + '<div class="flex justify-between"><div>'+param.marker+param.value[0]+'异常点</div><div class="ml-0">'+param.value[1]+'</div></div>'
  161. // }
  162. // if(param.componentSubType === 'boxplot'){
  163. // str = str + '<div class="flex justify-between"><div>'+param.marker+'min</div><div >'+param.value[1]+'</div></div>'+
  164. // '<div class="flex justify-between"><div>'+param.marker+'Q1</div><div>'+param.value[2]+'</div></div>'+
  165. // '<div class="flex justify-between"><div>'+param.marker+'median</div><div>'+param.value[3]+'</div></div>'+
  166. // '<div class="flex justify-between"><div>'+param.marker+'Q3</div><div>'+param.value[4]+'</div></div>'+
  167. // '<div class="flex justify-between"><div>'+param.marker+'max</div><div>'+param.value[5]+'</div></div>'
  168. // }
  169. // }
  170. // return str
  171. // }
  172. this.tickChart = this.$echarts.init(document.getElementById('tickChart'));
  173. this.setOptions(this.chartData)
  174. },
  175. openFull(){
  176. const _this = this
  177. _this.dialogVisible = true// 打开弹窗
  178. _this.$nextTick(() => {
  179. const chartFul = this.$refs.fullChart
  180. if (chartFul) {
  181. _this.setFullOptions(_this.chartData)// 画图
  182. }
  183. })
  184. },
  185. setOptions({xData, boxplotData,scatterData} = {}) {
  186. const _this = this
  187. let series = [
  188. {
  189. name: '',
  190. type: 'boxplot',
  191. itemStyle: {
  192. color: 'rgba(126,199,250,0.86)',
  193. // 边线颜色
  194. borderColor: '#89BFE5',
  195. // 边线宽度
  196. borderWidth: 2
  197. },
  198. data: boxplotData
  199. }]
  200. for (let key in scatterData){
  201. series.push({
  202. name:key,
  203. type: 'scatter',
  204. symbolSize: 8,
  205. itemStyle: {
  206. color: function (params) {
  207. for (let i = 0; i < boxplotData.length; i++) {
  208. if (boxplotData[i].length>0&&boxplotData[i][5] == params.value[0]){
  209. var value = params.value[1];
  210. if ((value < boxplotData[i][1] && value > boxplotData[i][0] )|| (value >boxplotData[i][3] && value < boxplotData[i][4])) {
  211. return 'orange';
  212. }
  213. if (value <boxplotData[i][0] || value > boxplotData[i][4]) {
  214. return 'red';
  215. }
  216. }
  217. }
  218. }
  219. },
  220. data: scatterData[key]
  221. })
  222. }
  223. this.option = {
  224. dataZoom: [{
  225. type: 'inside'
  226. }],
  227. grid: {
  228. top: 50,
  229. left: '4%',
  230. right: '4%',
  231. bottom: '10%',
  232. containLabel: true
  233. },
  234. animation: false,
  235. tooltip: {
  236. trigger: 'axis',
  237. backgroundColor:'rgba(77, 109, 144, 0.87)',
  238. borderColor:'#89BFE5',
  239. textStyle:{color:'#fff', fontFamily:'Microsoft YaHei'},
  240. // enterable:true,
  241. position: function (point, params, dom, rect, size) {
  242. // 固定在顶部
  243. return [point[0], '-50%'];
  244. },
  245. formatter: function (params){
  246. let str = '<div style="max-height: 50vh;overflow-y: auto">'+params[0].axisValue +'<br/>'
  247. let scatterStr = '<div class="flex"><div>异常点</div><div class="ml-0">'
  248. for(let key in scatterData){
  249. let tempStr = '<div class="flex"><div>'+key+':</div><div class="flex" style="flex-wrap: wrap;">'
  250. let data = params.filter(_=>_.seriesName === key)
  251. if(data.length>0){
  252. for(let param of data){
  253. if(param.componentSubType === 'scatter') {
  254. tempStr = tempStr + '<span class="ml-0" style="color: ' + param.color + '">' + param.value[1] + '</span>,'
  255. }
  256. }
  257. tempStr = tempStr + '</div></div>'
  258. scatterStr = scatterStr+tempStr
  259. }
  260. }
  261. scatterStr = scatterStr+'</div></div>'
  262. for(let param of params){
  263. if(param.componentSubType === 'boxplot'){
  264. str = str + '<div class="flex justify-between"><div>'+param.marker+'最小值</div><div >'+param.value[1]+'</div></div>'+
  265. '<div class="flex justify-between"><div>'+param.marker+'第一四分位数</div><div>'+param.value[2]+'</div></div>'+
  266. '<div class="flex justify-between"><div>'+param.marker+'中位数</div><div>'+param.value[3]+'</div></div>'+
  267. '<div class="flex justify-between"><div>'+param.marker+'第三四分位数</div><div>'+param.value[4]+'</div></div>'+
  268. '<div class="flex justify-between"><div>'+param.marker+'最大值</div><div>'+param.value[5]+'</div></div>'
  269. }
  270. }
  271. str = str + scatterStr+'</div>'
  272. return str
  273. }
  274. },
  275. xAxis: {
  276. type: 'category',
  277. axisTick: {show: true},
  278. axisLine: {
  279. onZero: false,
  280. // lineStyle: {
  281. // color: '#5fbbeb'
  282. // }
  283. },
  284. data: xData
  285. },
  286. yAxis: {
  287. type: 'value',
  288. axisLabel: {
  289. padding: [3, 0, 0, 0],
  290. formatter: '{value}',
  291. textStyle: {
  292. fontSize: 14,
  293. },
  294. },
  295. axisTick: {
  296. show: false,
  297. },
  298. splitLine: {
  299. lineStyle: {
  300. type: 'dashed',
  301. },
  302. },
  303. },
  304. series:series
  305. // series: [
  306. // {
  307. // name: '',
  308. // type: 'boxplot',
  309. // itemStyle: {
  310. // color: 'rgba(126,199,250,0.86)',
  311. // // 边线颜色
  312. // borderColor: '#89BFE5',
  313. // // 边线宽度
  314. // borderWidth: 2
  315. // },
  316. // data: boxplotData
  317. // },
  318. // {
  319. // type: 'scatter',
  320. // symbolSize: 8,
  321. // itemStyle: {
  322. // color: function (params) {
  323. // for (let i = 0; i < boxplotData.length; i++) {
  324. // if (boxplotData[i].length>0&&boxplotData[i][5] == params.value[0]){
  325. // var value = params.value[1];
  326. // if ((value < boxplotData[i][1] && value > boxplotData[i][0] )|| (value >boxplotData[i][3] && value < boxplotData[i][4])) {
  327. // return 'orange';
  328. // }
  329. // if (value <boxplotData[i][0] || value > boxplotData[i][4]) {
  330. // return 'red';
  331. // }
  332. // }
  333. // }
  334. //
  335. // }
  336. // },
  337. // data: scatterData
  338. // }
  339. // ]
  340. }
  341. this.tickChart.setOption(this.option, true)
  342. window.addEventListener("resize", function () {
  343. _this.tickChart.resize();
  344. });
  345. },
  346. chartsResize(){
  347. if(this.tickChart !== null && this.tickChart !== undefined){
  348. this.tickChart.resize();
  349. }
  350. },
  351. setFullOptions({xData, boxplotData,scatterData} = {}) {
  352. this.fullChart = this.$echarts.init(document.getElementById('main'));
  353. let option = JSON.parse(JSON.stringify(dqTickOptions))
  354. let series = [
  355. {
  356. name: '',
  357. type: 'boxplot',
  358. itemStyle: {
  359. color: 'rgba(126,199,250,0.86)',
  360. // 边线颜色
  361. borderColor: '#89BFE5',
  362. // 边线宽度
  363. borderWidth: 2
  364. },
  365. data: boxplotData
  366. }]
  367. for (let key in scatterData){
  368. series.push({
  369. name:key,
  370. type: 'scatter',
  371. symbolSize: 8,
  372. itemStyle: {
  373. color: function (params) {
  374. for (let i = 0; i < boxplotData.length; i++) {
  375. if (boxplotData[i].length>0&&boxplotData[i][5] == params.value[0]){
  376. var value = params.value[1];
  377. if ((value < boxplotData[i][1] && value > boxplotData[i][0] )|| (value >boxplotData[i][3] && value < boxplotData[i][4])) {
  378. return 'orange';
  379. }
  380. if (value <boxplotData[i][0] || value > boxplotData[i][4]) {
  381. return 'red';
  382. }
  383. }
  384. }
  385. }
  386. },
  387. data: scatterData[key]
  388. })
  389. }
  390. option.tooltip.formatter = function (params){
  391. let str = '<div style="max-height: 50vh;overflow-y: auto">'+params[0].axisValue +'<br/>'
  392. let scatterStr = '<div class="flex"><div>异常点</div><div class="ml-0">'
  393. for(let key in scatterData){
  394. let tempStr = '<div class="flex"><div>'+key+':</div><div class="flex" style="max-width:30vw;flex-wrap: wrap;">'
  395. let data = params.filter(_=>_.seriesName === key)
  396. for(let param of params){
  397. if(param.componentSubType === 'scatter') {
  398. tempStr = tempStr + '<span class="ml-0" style="color: ' + param.color + '">' + param.value[1] + '</span>,'
  399. }
  400. }
  401. tempStr = tempStr + '</div></div>'
  402. scatterStr = scatterStr+tempStr
  403. }
  404. scatterStr = scatterStr+'</div></div>'
  405. for(let param of params){
  406. if(param.componentSubType === 'boxplot'){
  407. str = str + '<div class="flex justify-between"><div>'+param.marker+'最小值</div><div >'+param.value[1]+'</div></div>'+
  408. '<div class="flex justify-between"><div>'+param.marker+'第一四分位数</div><div>'+param.value[2]+'</div></div>'+
  409. '<div class="flex justify-between"><div>'+param.marker+'中位数</div><div>'+param.value[3]+'</div></div>'+
  410. '<div class="flex justify-between"><div>'+param.marker+'第三四分位数</div><div>'+param.value[4]+'</div></div>'+
  411. '<div class="flex justify-between"><div>'+param.marker+'最大值</div><div>'+param.value[5]+'</div></div>'
  412. }
  413. }
  414. str = str + scatterStr+'</div>'
  415. return str
  416. }
  417. option.xAxis.data = xData
  418. option.series = series
  419. // option.series[0].data = boxplotData
  420. // option.series[1].data = scatterData
  421. this.fullChart.setOption(option, true)
  422. }
  423. }
  424. }
  425. </script>
  426. <style>
  427. #tickChart {
  428. width: 100%;
  429. height: 30vh;
  430. }
  431. </style>