Pie.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. <template>
  2. <div ref="chartRef" :style="{ height, width }"></div>
  3. </template>
  4. <script lang="ts">
  5. import { defineComponent, PropType, ref, Ref, onMounted, reactive, nextTick, onUnmounted } from 'vue';
  6. import type { EChartsOption } from 'echarts';
  7. import { useECharts } from '/@/hooks/web/useECharts';
  8. export default defineComponent({
  9. props: {
  10. width: {
  11. type: String as PropType<string>,
  12. default: '100%',
  13. },
  14. height: {
  15. type: String as PropType<string>,
  16. default: 'calc(100vh - 178px)',
  17. },
  18. count: {
  19. type: Number,
  20. default: 10,
  21. },
  22. },
  23. setup(props) {
  24. const chartRef = ref<HTMLDivElement | null>(null);
  25. const { setOptions, echarts, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
  26. const routeTimer = ref(null);
  27. // const echartInstance = ref();
  28. function _pie1() {
  29. let dataArr: any = [];
  30. for (var i = 0; i < 8; i++) {
  31. dataArr.push({
  32. name: (i + 1).toString(),
  33. value: 20,
  34. itemStyle: {
  35. normal: {
  36. color: 'rgba(88,142,197,0.4)',
  37. borderWidth: 0,
  38. borderColor: 'rgba(0,0,0,0)',
  39. },
  40. },
  41. });
  42. }
  43. return dataArr;
  44. }
  45. function _pie2() {
  46. let dataArr: any = [];
  47. for (var i = 0; i < 8; i++) {
  48. if (i % 2 === 0) {
  49. dataArr.push({
  50. name: (i + 1).toString(),
  51. value: 25,
  52. itemStyle: {
  53. normal: {
  54. color: 'rgba(88,142,197,0.5)',
  55. borderWidth: 0,
  56. borderColor: 'rgba(0,0,0,0)',
  57. },
  58. },
  59. });
  60. } else {
  61. dataArr.push({
  62. name: (i + 1).toString(),
  63. value: 20,
  64. itemStyle: {
  65. normal: {
  66. color: 'rgba(0,0,0,0)',
  67. borderWidth: 0,
  68. borderColor: 'rgba(0,0,0,0)',
  69. },
  70. },
  71. });
  72. }
  73. }
  74. return dataArr;
  75. }
  76. function _pie3() {
  77. let dataArr: any = [];
  78. for (var i = 0; i < 100; i++) {
  79. if (i % 2 === 0) {
  80. dataArr.push({
  81. name: (i + 1).toString(),
  82. value: 25,
  83. itemStyle: {
  84. normal: {
  85. color: 'rgb(126,190,255)',
  86. borderWidth: 0,
  87. borderColor: 'rgba(0,0,0,0)',
  88. },
  89. },
  90. });
  91. } else {
  92. dataArr.push({
  93. name: (i + 1).toString(),
  94. value: 20,
  95. itemStyle: {
  96. normal: {
  97. color: 'rgba(0,0,0,0)',
  98. borderWidth: 0,
  99. borderColor: 'rgba(0,0,0,0)',
  100. },
  101. },
  102. });
  103. }
  104. }
  105. return dataArr;
  106. }
  107. function _pieData(data) {
  108. let _data = data;
  109. let dataArr: any = [];
  110. for (var i = 0; i < 5; i++) {
  111. if (i === 2) {
  112. let dt = data[0].unit ? 25 : Number(data[0].value);
  113. dataArr.push({
  114. name: (i + 1).toString(),
  115. value: dt,
  116. itemStyle: {
  117. normal: {
  118. color: new echarts.graphic.LinearGradient(0, 1, 1, 0, [
  119. {
  120. offset: 0,
  121. color: 'rgb(147,187,216)',
  122. },
  123. {
  124. offset: 1,
  125. color: '#588ec5',
  126. },
  127. ]),
  128. borderWidth: 0,
  129. borderColor: 'rgba(0,0,0,0.4)',
  130. },
  131. },
  132. });
  133. } else {
  134. let dta = data[0].unit ? 25 : (1 - Number(data[0].value)) / 4;
  135. dataArr.push({
  136. name: (i + 1).toString(),
  137. value: dta,
  138. itemStyle: {
  139. normal: {
  140. color: 'rgba(0,0,0,0)',
  141. borderWidth: 0,
  142. borderColor: 'rgba(0,0,0,0)',
  143. },
  144. },
  145. });
  146. }
  147. }
  148. //console.log(dataArr)
  149. return dataArr;
  150. }
  151. const option = <EChartsOption>reactive({
  152. backgroundColor: '#0f375f',
  153. title: [
  154. {
  155. text: '各渠道投诉占比',
  156. left: '2%',
  157. top: '1%',
  158. textStyle: {
  159. color: '#fff',
  160. fontSize: 14,
  161. },
  162. },
  163. ],
  164. // tooltip: {
  165. // // formatter: '{b} ({c})',
  166. // },
  167. series: [
  168. {
  169. type: 'pie',
  170. zlevel: 1,
  171. silent: true,
  172. /*
  173. radius
  174. 饼图的半径。可以为如下类型:
  175. number:直接指定外半径值。
  176. string:例如,'20%',表示外半径为可视区尺寸(容器高宽中较小一项)的 20% 长度。
  177. Array.<number|string>:数组的第一项是内半径,第二项是外半径。每一项遵从上述 number string 的描述。
  178. */
  179. radius: ['98%', '97%'],
  180. animation: false,
  181. color: 'rgba(88,142,197,0.5)',
  182. label: {
  183. show: false,
  184. },
  185. labelLine: {
  186. show: false,
  187. },
  188. // data: _pie1(),
  189. data: [1],
  190. },
  191. {
  192. type: 'pie',
  193. zlevel: 2,
  194. silent: true,
  195. radius: ['90%', '91%'],
  196. startAngle: 50,
  197. animation: false,
  198. label: {
  199. show: false,
  200. },
  201. labelLine: {
  202. show: false,
  203. },
  204. data: _pie2(),
  205. },
  206. {
  207. type: 'pie',
  208. zlevel: 3,
  209. silent: true,
  210. radius: ['88%', '87%'],
  211. label: {
  212. show: false,
  213. },
  214. labelLine: {
  215. show: false,
  216. },
  217. data: _pie2(),
  218. },
  219. {
  220. type: 'pie',
  221. zlevel: 4,
  222. silent: true,
  223. radius: ['84%', '83%'],
  224. label: {
  225. show: false,
  226. },
  227. labelLine: {
  228. show: false,
  229. },
  230. data: _pie3(),
  231. },
  232. {
  233. type: 'pie',
  234. zlevel: 5,
  235. silent: true,
  236. radius: ['80%', '78%'],
  237. color: ['#fc8d89', '#46d3f3', 'rgba(203,203,203,.2)'],
  238. startAngle: 50,
  239. animation: false,
  240. label: {
  241. show: false,
  242. },
  243. data: [50, 20, 40],
  244. },
  245. {
  246. name: '',
  247. type: 'gauge',
  248. splitNumber: 30, //刻度数量
  249. min: 0,
  250. max: 100,
  251. radius: '73%', //图表尺寸
  252. center: ['50%', '50%'],
  253. startAngle: 90,
  254. endAngle: -269.9999,
  255. axisLine: {
  256. show: false,
  257. lineStyle: {
  258. width: 0,
  259. shadowBlur: 0,
  260. color: [[1, '#0dc2fe']],
  261. },
  262. },
  263. axisTick: {
  264. show: false,
  265. lineStyle: {
  266. color: 'auto',
  267. width: 2,
  268. },
  269. length: 20,
  270. splitNumber: 5,
  271. },
  272. splitLine: {
  273. show: true,
  274. length: 32,
  275. lineStyle: {
  276. color: 'auto',
  277. },
  278. },
  279. axisLabel: {
  280. show: false,
  281. },
  282. pointer: {
  283. //仪表盘指针
  284. show: false,
  285. },
  286. detail: {
  287. show: false,
  288. },
  289. },
  290. {
  291. name: '统计',
  292. type: 'gauge',
  293. splitNumber: 30, //刻度数量
  294. min: 0,
  295. max: 100,
  296. radius: '68%', //图表尺寸
  297. center: ['50%', '50%'],
  298. startAngle: 90,
  299. endAngle: -269.9999,
  300. axisLine: {
  301. show: true,
  302. lineStyle: {
  303. width: 0,
  304. shadowBlur: 0,
  305. color: [
  306. [0, '#0dc2fe'],
  307. [1, '#0dc2fe'],
  308. ],
  309. },
  310. },
  311. axisTick: {
  312. show: true,
  313. lineStyle: {
  314. color: '#0dc2fe',
  315. width: 2,
  316. },
  317. length: 20,
  318. splitNumber: 5,
  319. },
  320. splitLine: {
  321. show: true,
  322. length: 20,
  323. lineStyle: {
  324. color: '#0dc2fe',
  325. },
  326. },
  327. axisLabel: {
  328. show: false,
  329. },
  330. pointer: {
  331. //仪表盘指针
  332. show: false,
  333. },
  334. detail: {
  335. borderColor: '#fff',
  336. shadowColor: '#fff', //默认透明
  337. shadowBlur: 2,
  338. offsetCenter: [0, '0%'], // x, y,单位px
  339. textBorderColor: '#fff',
  340. fontSize: 50,
  341. formatter: '{value}',
  342. },
  343. data: [
  344. {
  345. name: '',
  346. value: 1,
  347. detail: {
  348. color: '#ffffff99',
  349. },
  350. },
  351. ],
  352. },
  353. {
  354. type: 'pie',
  355. zlevel: 20,
  356. silent: true,
  357. radius: ['60%', '59%'],
  358. animation: false,
  359. color: '#2dc0c9',
  360. // color: '#fff',
  361. // animation:false,
  362. data: [1],
  363. labelLine: {
  364. show: false,
  365. },
  366. },
  367. {
  368. name: '中间环形图',
  369. type: 'pie',
  370. radius: ['35%', '55%'],
  371. avoidLabelOverlap: false,
  372. animation: false,
  373. itemStyle: {
  374. color: '#80ADD2',
  375. borderColor: '#3D4268',
  376. },
  377. label: {
  378. show: false,
  379. position: 'center',
  380. },
  381. emphasis: {
  382. label: {
  383. show: true,
  384. fontSize: '30',
  385. fontWeight: 'bold',
  386. },
  387. },
  388. labelLine: {
  389. show: false,
  390. },
  391. data: [25, 25, 25, 25, 25, 25],
  392. },
  393. ],
  394. });
  395. function doing() {
  396. // option.series[4].startAngle = option.series[4].startAngle - 1;
  397. // option.series[6].data[0].value = option.series[6].data[0].value + 1;
  398. const start = props.count - option.series[6].data[0].value;
  399. let step = 1;
  400. if (start / 1 < 10) {
  401. step = 1;
  402. } else if (start / 1 < 100) {
  403. step = 10;
  404. } else if (start / 1 < 1000) {
  405. step = 100;
  406. } else if (start / 1 < 10000) {
  407. step = 1000;
  408. }
  409. let timer = setInterval(() => {
  410. if (props.count > option.series[6].data[0].value) {
  411. option.series[6].data[0].value += step;
  412. setOptions(option);
  413. } else {
  414. clearInterval(timer);
  415. timer = null;
  416. routeTimer.value = setInterval(() => {
  417. rotate();
  418. }, 200);
  419. }
  420. }, 8);
  421. }
  422. function rotate() {
  423. // option.series[4].startAngle = option.series[4].startAngle - 5;
  424. // option.series[6].data[0].value = option.series[6].data[0].value + 5;
  425. // setOptions(option);
  426. }
  427. // const timer = <Ref<NodeJS.Timer>>ref();
  428. // const startTimer = () => {
  429. // timer.value = setInterval(doing, 1000);
  430. // };
  431. // const stopTimer = () => {
  432. // clearInterval(timer.value);
  433. // timer.value = null as unknown as NodeJS.Timer;
  434. // };
  435. onMounted(() => {
  436. setOptions(option);
  437. chartRef.value?.addEventListener('mouseover', () => {
  438. // startTimer();
  439. // doing();
  440. });
  441. chartRef.value?.addEventListener('mouseout', () => {
  442. // stopTimer();
  443. });
  444. doing();
  445. });
  446. onUnmounted(() => {
  447. clearInterval(routeTimer.value);
  448. routeTimer.value = null;
  449. });
  450. return { chartRef };
  451. },
  452. });
  453. </script>