Pie.vue 12 KB

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