CustomChart.vue 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969
  1. <template>
  2. <div ref="chartRef" :style="{ height, width }"></div>
  3. </template>
  4. <script lang="ts" setup>
  5. import { ref, Ref, watch } from 'vue';
  6. import { useECharts } from '/@/hooks/web/useECharts';
  7. import { get } from 'lodash-es';
  8. import { ModuleDataChart } from '/@/views/vent/deviceManager/configurationTable/types';
  9. import { EChartsOption, graphic } from 'echarts';
  10. import { getData, getFormattedText } from '../../hooks/helper';
  11. import { getAssetURL } from '/@/utils/ui';
  12. const props = withDefaults(
  13. defineProps<{
  14. chartData: Record<string, any>[] | Record<string, any>;
  15. chartConfig: ModuleDataChart;
  16. height?: string;
  17. width?: string;
  18. }>(),
  19. {
  20. chartData: () => [],
  21. height: '100%',
  22. width: '100%',
  23. }
  24. );
  25. const chartRef = ref<HTMLDivElement | null>(null);
  26. const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
  27. // 核心方法,生成适用与 echart 的选项,这个方法需要适配 chart 类型的每种子类型
  28. const genChartOption = () => {
  29. const inst = getInstance();
  30. const domWidth = inst ? inst.getWidth() : 500;
  31. // 依据每一个图表配置生成图表选项
  32. const { yAxis = [], xAxis = [], legend, order, type, sortBy, series, dataZoom = [] } = props.chartConfig;
  33. const textStyle = {
  34. color: '#fff',
  35. };
  36. let sorttedData: any[] = [];
  37. if (Array.isArray(props.chartData)) {
  38. sorttedData = props.chartData;
  39. } else {
  40. sorttedData = [props.chartData];
  41. }
  42. // 如果这个配置指明了需要排序则执行排序
  43. if (sortBy && order) {
  44. sorttedData.sort((pre, cur) => {
  45. if (order === 'asc') {
  46. return get(pre, sortBy, 0) - get(cur, sortBy, 0);
  47. } else {
  48. return get(cur, sortBy, 0) - get(pre, sortBy, 0);
  49. }
  50. });
  51. }
  52. // 该项作为下面所有图表依赖的基准系列数据
  53. const baseSeries: { name: string; data: [string, string][]; color: string }[] = sorttedData.reduce((res: any[], baseData) => {
  54. series.forEach((serie) => {
  55. // 将读取出的数据转为数组
  56. const temp = getData(baseData, serie.readFrom) || [];
  57. res.push({
  58. name: getFormattedText(baseData, serie.label),
  59. data: (Array.isArray(temp) ? temp : [temp]).map((data) => {
  60. return [getData(data, serie.xprop), getData(data, serie.yprop)]; /** x y */
  61. // return { name: getData(data, serie.xprop), value: getData(data, serie.yprop) }; /** x y */
  62. }),
  63. color: serie.color,
  64. });
  65. });
  66. return res;
  67. }, []);
  68. const baseDataZoom = dataZoom.map((e, i) => {
  69. return {
  70. type: 'slider',
  71. show: e.show,
  72. // show: get(baseSeries, '[0].data.length', 1) > e.maxAxisLength,
  73. xAxisIndex: i,
  74. end: e.end,
  75. };
  76. });
  77. // if (type === 'pie') {
  78. // return {
  79. // textStyle,
  80. // legend: {
  81. // textStyle,
  82. // show: legend.show,
  83. // },
  84. // tooltip: {
  85. // trigger: 'item',
  86. // },
  87. // color: ['#d9a1ff', '#00d1ff', '#82fe78'],
  88. // series: baseSeries.map((serie) => {
  89. // return {
  90. // type: 'pie',
  91. // radius: ['50%', '75%'],
  92. // center: ['50%', '55%'],
  93. // labelLine: { show: false },
  94. // label: { show: false },
  95. // itemStyle: {
  96. // shadowBlur: 20,
  97. // shadowColor: '#259bcf',
  98. // },
  99. // data: serie.data.map((e) => ({
  100. // name: e[0],
  101. // value: e[1],
  102. // })),
  103. // };
  104. // }),
  105. // };
  106. // }
  107. if (type === 'pie') {
  108. return {
  109. textStyle,
  110. legend: {
  111. textStyle,
  112. show: legend.show,
  113. },
  114. tooltip: {
  115. trigger: 'item',
  116. },
  117. color: ['#73C0DE', '#5470C6', '#91CC75', '#FAC858', '#ED6666', '#17d1b2', '#2ae271', '#11bce7', '#c127f0', '#ee125b'],
  118. series: baseSeries.reduce((curr: EChartsOption[], serie) => {
  119. const colors = ['#73C0DE', '#5470C6', '#91CC75', '#FAC858', '#ED6666', '#17d1b2', '#2ae271', '#11bce7', '#c127f0', '#ee125b'];
  120. if (baseSeries.length === 1) {
  121. curr.push({
  122. ...serie,
  123. type: 'pie',
  124. radius: ['30%', '64%'],
  125. center: ['50%', '55%'],
  126. z: 1,
  127. padAngle: 5,
  128. itemStyle: {
  129. shadowColor: 'rgba(0, 0, 0, 0.5)',
  130. borderWidth: 10,
  131. },
  132. label: {
  133. show: true,
  134. position: 'inner',
  135. formatter: '{d}%',
  136. color: '#fff',
  137. fontSize: 14,
  138. rich: {
  139. d: {
  140. fontFamily: '微软雅黑',
  141. fontSize: 16,
  142. color: '#fff',
  143. lineHeight: 30,
  144. },
  145. },
  146. },
  147. labelLine: { show: false },
  148. data: serie.data.map((e) => ({
  149. name: e[0],
  150. value: e[1],
  151. })),
  152. });
  153. curr.push({
  154. ...serie,
  155. type: 'pie',
  156. radius: ['64%', '74%'],
  157. center: ['50%', '55%'],
  158. labelLine: { show: false },
  159. label: { show: false },
  160. padAngle: 5,
  161. avoidLabelOverlap: false,
  162. itemStyle: {
  163. borderWidth: 10,
  164. normal: {
  165. color: function (obj) {
  166. return `${colors[obj['dataIndex']]}88`;
  167. },
  168. },
  169. },
  170. data: serie.data.map((e) => ({
  171. name: e[0],
  172. value: e[1],
  173. })),
  174. });
  175. }
  176. curr.push({
  177. ...serie,
  178. type: 'pie',
  179. radius: ['25%', '30%'],
  180. center: ['50%', '55%'],
  181. labelLine: { show: false },
  182. label: { show: false },
  183. z: 5,
  184. padAngle: 5,
  185. itemStyle: {
  186. borderWidth: 10,
  187. normal: {
  188. color: function (obj) {
  189. return `${colors[obj['dataIndex']]}88`;
  190. },
  191. },
  192. },
  193. data: serie.data.map((e) => ({
  194. name: e[0],
  195. value: e[1],
  196. })),
  197. });
  198. return curr;
  199. }, []),
  200. };
  201. }
  202. if (type === 'pie_halo') {
  203. // 光环的图片
  204. const img =
  205. 'data:image/png;base64,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';
  206. const color = ['#70F081', '#EEE780', '#F07070', '#ffe000', '#ffa800', '#ff5b00', '#ff3000'];
  207. return {
  208. textStyle,
  209. legend: {
  210. textStyle,
  211. show: legend.show,
  212. },
  213. tooltip: {
  214. trigger: 'item',
  215. },
  216. graphic: {
  217. elements: [
  218. {
  219. type: 'image',
  220. z: 3,
  221. style: {
  222. image: img,
  223. width: 120,
  224. height: 120,
  225. },
  226. left: 'center',
  227. top: 'center',
  228. position: [20, 20],
  229. },
  230. ],
  231. },
  232. series: baseSeries.reduce((curr: EChartsOption[], serie) => {
  233. curr.push({
  234. ...serie,
  235. type: 'pie',
  236. clockWise: false,
  237. radius: [45, 45],
  238. label: {
  239. show: true,
  240. position: 'outside',
  241. color: '#ddd',
  242. formatter: get(legend, 'formatter', '{b}\n{c}pa'),
  243. },
  244. labelLine: {
  245. length: 30,
  246. length2: 40,
  247. show: true,
  248. color: '#00ffff',
  249. },
  250. data: serie.data.map((e, i) => ({
  251. name: e[0],
  252. value: e[1],
  253. itemStyle: {
  254. normal: {
  255. borderWidth: 10,
  256. shadowBlur: 30,
  257. borderColor: color[i],
  258. shadowColor: color[i],
  259. },
  260. },
  261. })),
  262. });
  263. return curr;
  264. }, []),
  265. };
  266. }
  267. if (type === 'pie_drag') {
  268. return {
  269. legend: baseSeries.map((e) => {
  270. return {
  271. orient: 'vertical',
  272. left: '54%',
  273. top: '8%',
  274. itemGap: 34,
  275. itemWidth: 10,
  276. itemHeight: 10,
  277. align: 'left',
  278. textStyle: {
  279. fontSize: 14,
  280. color: '#b3b8cc',
  281. },
  282. data: e.data.map((e) => {
  283. return `${e[0]}: ${e[1]}`;
  284. }),
  285. };
  286. }),
  287. graphic: {
  288. elements: [
  289. {
  290. type: 'image',
  291. style: {
  292. image: getAssetURL('home-container/pie.png'),
  293. width: 20,
  294. height: 100,
  295. },
  296. left: 'center',
  297. top: 'center',
  298. },
  299. ],
  300. },
  301. tooltip: {
  302. formatter: '{b}',
  303. },
  304. series: baseSeries.reduce((curr: EChartsOption[], serie) => {
  305. curr.push({
  306. radius: ['40%', '80%'],
  307. center: ['25%', '50%'],
  308. type: 'pie',
  309. z: 10,
  310. label: {
  311. show: false,
  312. },
  313. labelLine: {
  314. show: false,
  315. },
  316. itemStyle: {
  317. opacity: 0.7,
  318. },
  319. padAngle: 5,
  320. data: serie.data.map((e) => ({
  321. name: `${e[0]}: ${e[1]}`,
  322. value: e[1],
  323. })),
  324. });
  325. curr.push({
  326. radius: ['40%', '55%'],
  327. center: ['25%', '50%'],
  328. type: 'pie',
  329. z: 5,
  330. label: {
  331. show: false,
  332. },
  333. labelLine: {
  334. show: false,
  335. },
  336. animation: false,
  337. tooltip: {
  338. show: false,
  339. },
  340. padAngle: 6,
  341. data: serie.data.map((e) => ({
  342. name: `${e[0]}: ${e[1]}`,
  343. value: e[1],
  344. })),
  345. });
  346. return curr;
  347. }, []),
  348. };
  349. }
  350. // 柱状图
  351. if (type === 'bar') {
  352. return {
  353. textStyle,
  354. grid: {
  355. top: 50,
  356. bottom: dataZoom.length ? 70 : 50,
  357. },
  358. legend: {
  359. textStyle,
  360. show: legend.show,
  361. },
  362. tooltip: {
  363. trigger: 'item',
  364. },
  365. dataZoom: baseDataZoom,
  366. xAxis: xAxis.map((e) => {
  367. return {
  368. ...e,
  369. type: 'category',
  370. axisLabel: {
  371. interval: 0,
  372. width: baseDataZoom.length ? 100 : 800 / get(baseSeries, '[0].data.length', 1),
  373. overflow: 'break',
  374. },
  375. };
  376. }),
  377. yAxis: yAxis.map((e, i) => {
  378. return {
  379. ...e,
  380. splitLine: {
  381. lineStyle: {
  382. opacity: i === 0 ? 0.1 : 0,
  383. },
  384. },
  385. };
  386. }),
  387. series: baseSeries.reduce((curr: EChartsOption[], serie, index) => {
  388. const colors = ['#66ffff', '#ffff66'];
  389. if (baseSeries.length === 1) {
  390. curr.push({
  391. ...serie,
  392. type: 'pictorialBar',
  393. symbol: 'circle',
  394. symbolPosition: 'end',
  395. symbolSize: [20, 20],
  396. symbolOffset: [0, -10],
  397. barGap: '-100%',
  398. yAxisIndex: index,
  399. itemStyle: {
  400. color: colors[index % colors.length],
  401. },
  402. });
  403. }
  404. curr.push({
  405. ...serie,
  406. type: 'bar',
  407. silent: true,
  408. yAxisIndex: index,
  409. barWidth: 20,
  410. barGap: '100%',
  411. label: {
  412. show: true,
  413. textStyle,
  414. position: 'top',
  415. },
  416. itemStyle: {
  417. color: new graphic.LinearGradient(0, 0, 0, 1, [
  418. { offset: 0, color: colors[index % colors.length] },
  419. { offset: 0.2, color: colors[index % colors.length] },
  420. { offset: 1, color: `${colors[index % colors.length]}22` },
  421. ]),
  422. borderRadius: [5, 5, 0, 0],
  423. },
  424. });
  425. return curr;
  426. }, []),
  427. };
  428. }
  429. // 折线图和上面的柱状图类似
  430. if (type === 'line') {
  431. return {
  432. textStyle,
  433. legend: {
  434. show: legend.show,
  435. top: 10,
  436. right: 10,
  437. textStyle,
  438. },
  439. grid: {
  440. left: 60,
  441. top: 40,
  442. right: 60,
  443. bottom: dataZoom.length ? 70 : 30,
  444. },
  445. dataZoom: baseDataZoom,
  446. xAxis: xAxis.map((e) => {
  447. return {
  448. ...e,
  449. type: 'category',
  450. axisLabel: {
  451. width: 100,
  452. overflow: 'break',
  453. },
  454. };
  455. }),
  456. yAxis: yAxis.map((e, i) => {
  457. return {
  458. ...e,
  459. splitLine: {
  460. lineStyle: {
  461. opacity: i === 0 ? 0.1 : 0,
  462. },
  463. },
  464. };
  465. }),
  466. series: baseSeries.map((serie) => {
  467. return {
  468. ...serie,
  469. type: 'line',
  470. };
  471. }),
  472. };
  473. }
  474. if (type === 'line_enhance') {
  475. return {
  476. textStyle,
  477. legend: {
  478. show: legend.show,
  479. top: 10,
  480. right: 10,
  481. textStyle,
  482. },
  483. tooltip: {
  484. trigger: 'item',
  485. },
  486. grid: {
  487. left: 60,
  488. top: 40,
  489. right: 60,
  490. bottom: dataZoom.length ? 70 : 30,
  491. },
  492. dataZoom: baseDataZoom,
  493. xAxis: xAxis.map((e) => {
  494. return {
  495. ...e,
  496. type: 'category',
  497. axisLabel: {
  498. width: 100,
  499. overflow: 'break',
  500. },
  501. };
  502. }),
  503. yAxis: yAxis.map((e, i) => {
  504. return {
  505. ...e,
  506. min: (value) => {
  507. return parseInt(value.min * 0.8);
  508. },
  509. max: (value) => {
  510. return parseInt(value.max * 1.2);
  511. },
  512. splitLine: {
  513. lineStyle: {
  514. opacity: i === 0 ? 0.1 : 0,
  515. },
  516. },
  517. };
  518. }),
  519. series: baseSeries.map((serie) => {
  520. return {
  521. ...serie,
  522. type: 'line',
  523. };
  524. }),
  525. };
  526. }
  527. // 平滑曲线图
  528. if (type === 'line_smooth') {
  529. return {
  530. textStyle,
  531. legend: {
  532. show: legend.show,
  533. top: 10,
  534. textStyle,
  535. },
  536. grid: {
  537. left: 60,
  538. right: 60,
  539. bottom: dataZoom.length ? 70 : 30,
  540. },
  541. dataZoom: baseDataZoom,
  542. xAxis: xAxis.map((e) => {
  543. return {
  544. ...e,
  545. type: 'category',
  546. };
  547. }),
  548. yAxis: yAxis.map((e, i) => {
  549. return {
  550. ...e,
  551. splitLine: {
  552. lineStyle: {
  553. opacity: i === 0 ? 0.1 : 0,
  554. },
  555. },
  556. };
  557. }),
  558. series: baseSeries.map((serie) => {
  559. return {
  560. ...serie,
  561. type: 'line',
  562. smooth: true,
  563. itemStyle: {
  564. opacity: 0,
  565. },
  566. };
  567. }),
  568. };
  569. }
  570. // 折线区域图,即折线下面的区域填满
  571. if (type === 'line_area') {
  572. return {
  573. textStyle,
  574. legend: {
  575. textStyle,
  576. show: legend.show,
  577. },
  578. grid: {
  579. left: 50,
  580. top: 50,
  581. right: 50,
  582. bottom: dataZoom.length ? 70 : 50,
  583. },
  584. dataZoom: baseDataZoom,
  585. xAxis: xAxis.map((e) => {
  586. return {
  587. ...e,
  588. type: 'category',
  589. boundaryGap: false,
  590. };
  591. }),
  592. yAxis: yAxis.map((e, i) => {
  593. return {
  594. ...e,
  595. splitLine: {
  596. lineStyle: {
  597. color: '#fff',
  598. opacity: i === 0 ? 0.1 : 0,
  599. },
  600. },
  601. };
  602. }),
  603. series: baseSeries.map((serie, index) => {
  604. const colors = ['#66ffff', '#6666ff'];
  605. let color;
  606. if (serie.color) {
  607. color = serie.color;
  608. } else {
  609. color = colors[index % colors.length];
  610. }
  611. return {
  612. ...serie,
  613. type: 'line',
  614. symbol: 'none',
  615. endLabel: { distance: 0 },
  616. lineStyle: { color: color },
  617. areaStyle: {
  618. origin: 'auto',
  619. color: new graphic.LinearGradient(0, 0, 0, 1, [
  620. { offset: 0, color: color },
  621. { offset: 0.2, color: color },
  622. { offset: 1, color: `${color}22` },
  623. ]),
  624. },
  625. };
  626. }),
  627. };
  628. }
  629. if (type === 'line_bar') {
  630. return {
  631. textStyle,
  632. legend: {
  633. textStyle,
  634. show: legend.show,
  635. top: 10,
  636. right: 10,
  637. },
  638. grid: {
  639. left: 40,
  640. top: 50,
  641. right: 40,
  642. bottom: dataZoom.length ? 70 : 10,
  643. show: false,
  644. },
  645. dataZoom: baseDataZoom,
  646. xAxis: xAxis.map((e) => {
  647. return {
  648. ...e,
  649. type: 'category',
  650. };
  651. }),
  652. yAxis: yAxis.map((e) => {
  653. return {
  654. ...e,
  655. };
  656. }),
  657. series: baseSeries.map((serie, i) => {
  658. return {
  659. ...serie,
  660. type: i % 2 ? 'line' : 'bar',
  661. smooth: true,
  662. barWidth: 20,
  663. };
  664. }),
  665. };
  666. }
  667. // 堆叠柱状图
  668. if (type === 'bar_stack') {
  669. return {
  670. textStyle,
  671. tooltip: {
  672. trigger: 'axis',
  673. axisPointer: {
  674. type: 'shadow',
  675. },
  676. },
  677. grid: {
  678. top: 50,
  679. bottom: 30,
  680. },
  681. legend: {
  682. textStyle,
  683. show: legend.show,
  684. },
  685. xAxis: xAxis.map((e) => {
  686. return {
  687. ...e,
  688. type: 'category',
  689. };
  690. }),
  691. yAxis: yAxis.map((e) => {
  692. return {
  693. ...e,
  694. splitLine: {
  695. lineStyle: {
  696. color: 'rgba(21,80,126,0.3)',
  697. type: 'dashed',
  698. },
  699. },
  700. };
  701. }),
  702. series: baseSeries.map((serie) => {
  703. return {
  704. ...serie,
  705. type: 'bar',
  706. stack: 'stackME',
  707. barMaxWidth: '24',
  708. emphasis: {
  709. focus: 'series',
  710. },
  711. label: {
  712. show: true,
  713. position: 'top', //在上方显示
  714. textStyle: {
  715. //数值样式
  716. color: '#fff',
  717. fontSize: 14,
  718. },
  719. },
  720. };
  721. }),
  722. color: ['#F56731', '#00E8FF'],
  723. };
  724. }
  725. // 柱状图,圆柱形样式
  726. if (type === 'bar_cylinder') {
  727. return {
  728. textStyle,
  729. grid: {
  730. top: 40,
  731. bottom: 50,
  732. },
  733. legend: {
  734. textStyle,
  735. show: legend.show,
  736. },
  737. tooltip: {
  738. trigger: 'item',
  739. },
  740. xAxis: xAxis.map((e) => {
  741. return {
  742. ...e,
  743. type: 'category',
  744. axisLabel: {
  745. interval: 0,
  746. width: (domWidth - 100) / get(baseSeries, '[0].data.length', 1),
  747. overflow: 'break',
  748. },
  749. };
  750. }),
  751. yAxis: yAxis.map((e, i) => {
  752. return {
  753. ...e,
  754. splitLine: {
  755. lineStyle: {
  756. opacity: i === 0 ? 0.1 : 0,
  757. },
  758. },
  759. };
  760. }),
  761. series: baseSeries.reduce((curr: EChartsOption[], serie, index) => {
  762. // const colors = ['#66ffff', '#00ff66', '#ffff66'];
  763. const colors = ['#73C0DE', '#ED6666', '#5470C6', '#91CC75', '#FAC858', '#17d1b2', '#2ae271', '#11bce7', '#c127f0', '#ee125b'];
  764. if (baseSeries.length === 1) {
  765. curr.push({
  766. ...serie,
  767. type: 'pictorialBar',
  768. symbol: 'circle',
  769. symbolPosition: 'end',
  770. symbolSize: [20, 10],
  771. symbolOffset: [0, -5],
  772. barGap: '-100%',
  773. yAxisIndex: index,
  774. itemStyle: {
  775. color: ({ dataIndex }) => colors[dataIndex % colors.length],
  776. },
  777. });
  778. curr.push({
  779. ...serie,
  780. type: 'pictorialBar',
  781. symbol: 'circle',
  782. symbolPosition: 'start',
  783. symbolSize: [20, 10],
  784. symbolOffset: [0, 5],
  785. barGap: '-100%',
  786. yAxisIndex: index,
  787. itemStyle: {
  788. color: ({ dataIndex }) => colors[dataIndex % colors.length],
  789. },
  790. });
  791. }
  792. curr.push({
  793. ...serie,
  794. type: 'bar',
  795. // silent: true,
  796. yAxisIndex: index,
  797. barWidth: 20,
  798. barGap: '100%',
  799. itemStyle: {
  800. color: ({ dataIndex }) =>
  801. new graphic.LinearGradient(0, 0, 0, 1, [
  802. { offset: 0, color: `${colors[dataIndex % colors.length]}44` },
  803. { offset: 0.5, color: colors[dataIndex % colors.length] },
  804. { offset: 1, color: colors[dataIndex % colors.length] },
  805. ]),
  806. borderRadius: [5, 5, 0, 0],
  807. },
  808. label: {
  809. show: true, //开启显示
  810. position: 'top', //在上方显示
  811. textStyle: {
  812. //数值样式
  813. color: '#ffffffbb',
  814. fontSize: 13,
  815. },
  816. formatter: function (obj) {
  817. return obj['data'][1];
  818. },
  819. },
  820. });
  821. return curr;
  822. }, []),
  823. };
  824. }
  825. // 柱状图,圆柱形样式
  826. if (type === 'bar_cylinder_wide') {
  827. return {
  828. textStyle,
  829. grid: {
  830. top: 40,
  831. bottom: 50,
  832. },
  833. legend: {
  834. textStyle,
  835. show: legend.show,
  836. },
  837. tooltip: {
  838. trigger: 'item',
  839. },
  840. xAxis: xAxis.map((e) => {
  841. return {
  842. ...e,
  843. type: 'category',
  844. axisLabel: {
  845. interval: 0,
  846. width: (domWidth - 100) / get(baseSeries, '[0].data.length', 1),
  847. overflow: 'break',
  848. },
  849. };
  850. }),
  851. yAxis: yAxis.map((e, i) => {
  852. return {
  853. ...e,
  854. splitLine: {
  855. lineStyle: {
  856. opacity: i === 0 ? 0.1 : 0,
  857. },
  858. },
  859. };
  860. }),
  861. series: baseSeries.reduce((curr: EChartsOption[], serie, index) => {
  862. // const colors = ['#66ffff', '#00ff66', '#ffff66'];
  863. const colors = ['#73C0DE', '#ED6666', '#5470C6', '#91CC75', '#FAC858', '#17d1b2', '#2ae271', '#11bce7', '#c127f0', '#ee125b'];
  864. if (baseSeries.length === 1) {
  865. curr.push({
  866. ...serie,
  867. type: 'pictorialBar',
  868. symbol: 'circle',
  869. symbolPosition: 'end',
  870. symbolSize: [50, 10],
  871. symbolOffset: [0, -5],
  872. barGap: '-100%',
  873. yAxisIndex: index,
  874. itemStyle: {
  875. color: ({ dataIndex }) => colors[dataIndex % colors.length],
  876. },
  877. });
  878. curr.push({
  879. ...serie,
  880. type: 'pictorialBar',
  881. symbol: 'circle',
  882. symbolPosition: 'start',
  883. symbolSize: [50, 10],
  884. symbolOffset: [0, 5],
  885. barGap: '-100%',
  886. yAxisIndex: index,
  887. itemStyle: {
  888. color: ({ dataIndex }) => colors[dataIndex % colors.length],
  889. },
  890. });
  891. }
  892. curr.push({
  893. ...serie,
  894. type: 'bar',
  895. // silent: true,
  896. yAxisIndex: index,
  897. barWidth: 50,
  898. barGap: '100%',
  899. itemStyle: {
  900. color: ({ dataIndex }) =>
  901. new graphic.LinearGradient(0, 0, 0, 1, [
  902. { offset: 0, color: `${colors[dataIndex % colors.length]}44` },
  903. { offset: 0.5, color: colors[dataIndex % colors.length] },
  904. { offset: 1, color: colors[dataIndex % colors.length] },
  905. ]),
  906. borderRadius: [5, 5, 0, 0],
  907. },
  908. label: {
  909. show: true, //开启显示
  910. position: 'top', //在上方显示
  911. textStyle: {
  912. //数值样式
  913. color: '#ffffffbb',
  914. fontSize: 13,
  915. },
  916. formatter: function (obj) {
  917. return obj['data'][1];
  918. },
  919. },
  920. });
  921. return curr;
  922. }, []),
  923. };
  924. }
  925. return {};
  926. };
  927. watch(
  928. () => props.chartData,
  929. () => {
  930. initCharts();
  931. },
  932. {
  933. immediate: true,
  934. }
  935. );
  936. function initCharts() {
  937. const o = genChartOption();
  938. setOptions(o as EChartsOption, false);
  939. }
  940. </script>