echart 图表实现
import { CSSProperties, useEffect, useState } from 'react'; import * as echarts from 'echarts'; import Chart from '@/pages/components/Charts'; import { EChartsCoreOption } from 'echarts'; import ChartTitle from '../components/ChartTitle/chartTitle'; /** * @description 给echart子组件公用借口 * @options echarts options配置与内部defaultOption合并 <a href='https://echarts.apache.org/zh/option.html#title'>点击跳转</> * @seriesOptions 用于echart与内部seriesOption合并 <a href='https://echarts.apache.org/zh/option.html#series'>点击跳转</> * @data series数据层 * @titleConfig 搭配tableList组件配置 * @style 父级元素的style样式 * @colors ehcart颜色 */ interface EchartProps { options?: EChartsCoreOption; titleConfig?: any; style?: CSSProperties; data: Array<any>; colors?: Array<any> seriesOptions?: any } export default ({options, data, colors, titleConfig, style}: EchartProps) => { const [lineOptions, setBarOptions] = useState<EChartsCoreOption | null>(null); let defaultSeries: any = data.map((item,index) => { let [c1, c2] = item.gradientColor; return { name: item.name, type: 'line', smooth: true, //是否平滑 symbolSize: 8, showAllSymbol: true, showSymbol: false, // 只有在 tooltip hover 的时候显示。 symbol: 'circle', //折线点设置为实心点 label: { show: true, position: 'left', textStyle: { color: c1, fontSize: 20, } }, itemStyle: { color: c1, borderColor: "#fff", borderWidth: 2, shadowColor: "rgba(0, 0, 0, .3)", shadowBlur: 0, shadowOffsetY: 2, shadowOffsetX: 2, }, areaStyle: { normal: { color: new echarts.graphic.LinearGradient( 0, 0, 0, 1, [ { offset: 0, color: c2, }, { offset: 1, color: c1, }, ], false ), }, }, color: c1, data: item.data, }; }); useEffect(() => { let defalutOptions: EChartsCoreOption; defalutOptions = { tooltip: { trigger: 'axis', showContent: false, // 是否显示提示框浮层,默认显示。 axisPointer: { lineStyle: { color: '#fff', width: 2, type: 'soild', shadowColor: 'rgba(255, 255, 255, 0.5)', shadowBlur: 100, shadowOffsetX: 10 }, }, }, legend: { orient: 'horizontal', // 水平 top: 30, right: 90, align: 'right', itemWidth: 16, itemHeight: 16, borderWidth: 0, icon: 'roundRect', textStyle: { fontSize: 14, color: '#ddd', fontFamily: 'PingFangSC-Regular', fontWeight: 400, }, }, grid: { // top: '5%', // left: '5%', // right: '15%', // bottom: '15%', containLabel: true }, xAxis: { type: 'category', boundaryGap: false, data: ['202101', '202102', '202103', '202104', '202105', '202106'], axisLine: { onZero: false, minInterval: 1, lineStyle: { type: 'solid', color: '#4E91A3', width: 2, shadowColor: 'rgba(0, 0, 0, 0.5)', shadowBlur: 10, }, }, axisTick: { show: false, }, offset: 5, axisLabel: { color: '#ccc', }, splitLine: { show: true, lineStyle: { color: ['#22343C'], width: 1, type: 'dashed', }, }, }, yAxis: { type: 'value', axisLabel: { show: true, interval: 0, textStyle: { baseline: 'middle', color: '#ccc', }, }, axisLine: { minInterval: 1, lineStyle: { type: 'solid', color: '#ccc', with: 1, }, }, splitLine: { show: true, lineStyle: { color: ['#22343C'], width: 1, type: 'dashed', }, }, }, series: defaultSeries }; if(options){ defalutOptions = Object.assign(defalutOptions,options) } setBarOptions(defalutOptions); }, [options]); return ( <div style={{ display: 'flex', flexDirection: 'column' }}> {titleConfig && Object.keys(titleConfig).length ? ( <ChartTitle title={titleConfig.title} typeClass={titleConfig.typeClass} /> ) : null} <Chart options={lineOptions} height={style?.height || 430} width={style?.width || 960} /> </div> ); };
// 玫瑰图 import * as echarts from 'echarts'; import { echarOptsMerge } from '../utils'; import { EChartsCoreOption } from 'echarts'; /** * @options echarts options配置与内部defaultOption合并 <a href='https://echarts.apache.org/zh/option.html#title'>点击跳转</> * @data series数据层 * @titleConfig 搭配tableList组件配置 * @style 父级元素的style样式 */ interface IEchartProps { options?: EChartsCoreOption; data: { name: string; value: Array<number>; }; } export default ({ options, data }: IEchartProps) => { // 根据传入的数据获取最大值范围 let max = data.value[0]; let maxlen: any = max.toString().length; let baseOptions: EChartsCoreOption = { angleAxis: { max: '1'.padEnd(maxlen + 1, '0'), clockwise: false, show: false, }, animation: false, radiusAxis: { type: 'category', show: true, axisLabel: { show: false, }, axisLine: { show: false, }, axisTick: { show: false, }, }, polar: [ { center: ['50%', '50%'], //中心点位置 radius: ['50%', '70%'], }, ], series: [ { stack: '外层圆环', type: 'bar', data: data.value, showBackground: false, coordinateSystem: 'polar', barWidth: 50, silent: true, zlevel: 3, itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 1, color: '#56FDFF', }, { offset: 0, color: '#06BDBF', }, ]), shadowColor: 'rgba(255,255,255,.8)', shadowBlur: 20, shadowOffsetX: 0, shadowOffsetY: 0, }, }, { type: 'pie', name: '内层细圆环', center: ['40%', '50%'], radius: ['50%', '60%'], hoverAnimation: false, clockWise: true, itemStyle: { color: '#FFD18A', shadowColor: 'rgba(255,255,255,.6)', shadowBlur: 13, shadowOffsetX: 0, shadowOffsetY: 0, }, tooltip: { show: false, }, label: { formatter: data.name, position: 'center', show: true, textStyle: { fontSize: 15, fontWeight: 'normal', color: '#fff', }, }, data: [100], }, ], }; if (options) { baseOptions = Object.assign(baseOptions, options); } return baseOptions; };
// 饼图 import { EChartsCoreOption } from 'echarts'; import { echartsOpts } from './echarts.d'; import * as echarts from 'echarts'; export default ({ options, data, config }: echartsOpts) => { let color = options?.color || [ '#4D8BE8', '#1785D6', '#A4F2EE', '#80EFFF', '#5FD1EB', '#F5855F', '#C099FC', '#FFA940', '#F8AEA4', ]; let formatter = options?.formatter || function (e: any) { let { data: { value = '', name = '', percent = '' }, } = e; return `{border|}{top| ${percent}} \n {center|${value}} \n {bottom|${name}}`; }; let seriesData: any = []; // 算出总数,插入间距 let sum: any = data.reduce((prev, cur) => prev + cur.value, 0); const gap = Math.round((1 * sum) / 150); data.map((item, index) => { seriesData.push( { itemStyle: { normal: { //外环发光 borderWidth: 0.5, shadowBlur: 10, // @ts-ignore borderColor: color[index], // @ts-ignore shadowColor: color[index], }, }, ...item, }, { value: gap, name: '', label: { show: false, }, itemStyle: { normal: { color: 'rgba(0, 0, 0, 0)', borderColor: 'rgba(0, 0, 0, 0)', borderWidth: 0, }, }, }, ); }); let baseOptions: EChartsCoreOption = { legend: { show: false, }, color, label: { formatter, minMargin: 2, lineHeight: 15, rich: { border: { width: 4, height: 30, backgroundColor: 'inherit', shadowBlur: 18, shadowColor: 'rgba(255,255,255.2)', borderRadius: 5, verticalAlign: 'top', }, top: { fontSize: 12, color: '#fff', align: 'left', width: '120%', verticalAlign: 'top', padding: [0, 0, 0, 3], }, center: { fontSize: 18, width: '120%', align: 'left', color: '#fff', verticalAlign: 'top', padding: [0, 0, 0, 3], }, bottom: { fontSize: 12, width: '120%', align: 'left', color: '#fff', verticalAlign: 'bottom', padding: [0, 0, 0, 3], }, }, }, series: [ { name: '饼图', type: 'pie', radius: ['20%', '40%'], labelLine: { lineStyle: { // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ // { // offset: 0, // color: "rgba(255, 255, 255,0.7)", // }, // { // offset: 1, // color: "rgba(255, 255, 255,0.4)", // }, // ]), width: 2, }, }, data: seriesData, }, { name: '左侧线', type: 'custom', coordinateSystem: 'none', renderItem: function (params: any, api: any) { return { type: 'arc', shape: { cx: api.getWidth() / 2, cy: api.getHeight() / 2, r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.43, // 180, startAngle: (150 * Math.PI) / 360, endAngle: (300 * Math.PI) / 180, }, style: { stroke: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: 'rgba(255,234,190,0)', }, { offset: 0.3, color: 'rgba(255,209,138,.5)', }, { offset: 1, color: 'rgba(255,234,190,0)', }, ]), fill: 'transparent', lineWidth: 2, shadowBlur: 10, shadowOffsetX: 10, shadowOffsetY: 10, }, silent: true, }; }, data: [0], }, { name: '右侧侧线', type: 'custom', coordinateSystem: 'none', renderItem: function (params: any, api: any) { return { type: 'arc', shape: { cx: api.getWidth() / 2, cy: api.getHeight() / 2, r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.46, // 180, startAngle: (-130 * Math.PI) / 360, endAngle: (150 * Math.PI) / 360, }, style: { stroke: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: 'rgba(255,234,190,0)', }, { offset: 0.3, color: 'rgba(0,255,255,.5)', }, { offset: 1, color: 'rgba(255,234,190,0)', }, ]), fill: 'transparent', lineWidth: 2, shadowBlur: 10, shadowOffsetX: 10, shadowOffsetY: 10, }, silent: true, }; }, data: [0], }, ], }; if (options) { baseOptions = Object.assign(baseOptions, options); } return baseOptions; };
import { echarOptsMerge } from '../utils'; import { EChartsCoreOption } from 'echarts'; import { echartsOpts } from './echarts.d'; export default ({ options, data, config }: echartsOpts) => { const baseOptions: EChartsCoreOption = { title: { subtext: '单位:家', right: 0, top: 15, subtextStyle: { color: '#DDDDDD', }, }, grid: { left: '3%', right: '4%', bottom: '0%', }, legend: { top: 20, left: 0, align: 'right', itemWidth: 15, itemHeight: 15, borderWidth: 0, icon: 'roundRect', }, tooltip: { show: false, }, xAxis: { type: 'value', axisLabel: { show: false, }, }, yAxis: { nameTextStyle: { fontSize: 14, color: '#ddd', fontFamily: 'PingFangSC-Regular', fontWeight: 400, }, axisTick: { show: false, }, axisLabel: { show: true, interval: 0, textStyle: { baseline: 'middle', color: '#ccc', }, }, axisLine: { show: false, minInterval: 1, lineStyle: { type: 'solid', color: '#ccc', with: 1, }, }, splitLine: { show: true, lineStyle: { color: ['#22343C'], width: 1, type: 'dashed', }, }, }, series: data.map((item) => { let [c1, c2] = item.borderColor; return { type: 'bar', name: item.name, data: item.data, barWidth: item.barWidth, itemStyle: { barBorderRadius: item.barBorderRadius || [4, 4, 0, 0], borderWidth: 2, borderType: 'solid', color: item.color, shadowBlur: item.shadowBlur || 10, shadowOffsetX: item.shadowOffsetX || 0, shadowOffsetY: item.shadowOffsetY || 0, shadowColor: c2, borderColor: { type: 'linear', x: 0, y: 0, x2: 0, y2: 1, ...item.borderColorPosition, colorStops: [ { offset: 0, color: c1, // 0% 处的颜色 }, { offset: 1, color: c2, // 100% 处的颜色 }, ], global: false, // 缺省为 false }, }, label: { show: true, color: '#fff' || item.labelColor, textShadowColor: 'rgba(54,186,255,0.96)', textShadowBlur: 8, fontWeight: 600, fontSize: 14, position: item.labelPosition || 'top', }, }; }), }; if (options) { baseOptions = Object.assign(baseOptions, options); } return baseOptions; };
传入数据
// 区域对比图 const [areaOption, setAreaOption] = useState<EChartsCoreOption | null>(null); const getAreaData: Array<IAreaData> = [ { value: 6250, name: '网络与通信产业集群', }, { value: 5500, name: '半导体与集成电路产业集群', }, { value: 4362, name: '超高清视频显示产业集群', }, { value: 4500, name: '智能终端产业集群', }, { value: 1800, name: '软件与信息服务产业集群', }, { value: 4100, name: '数字创意产业集群', }, { value: 3800, name: '现代时尚产业集群', }, { value: 2300, name: '工业母机产业集群', }, { value: 2500, name: '智能机器人产业集群', }, { value: 2900, name: '其他', }, ]; // @ts-ignore getAreaData.sort((a, b) => a.value - b.value); let dataName = getAreaData.map((v) => v.name); const areaOneData: Array<any> = [ { name: '宝安区', data: getAreaData, color: '#56FDFF', borderColor: ['#06BDBF', '#56FDFF'], labelPosition: 'right', barWidth: 18, barBorderRadius: [0, 4, 4, 0], borderColorPosition: { x2: 1, y2: 0, }, }, ]; const areaTwoData: Array<any> = [ { name: '福田区', data: getAreaData, color: '#FFD18A', borderColor: ['#FFD18A', '#FFA213'], labelPosition: 'right', barWidth: 18, barBorderRadius: [0, 4, 4, 0], borderColorPosition: { x2: 1, y2: 0, }, }, ];
useEffect(() => {
let option: EChartsCoreOption;
option = {
yAxis: {
type: 'category',
name: '',
data: dataName,
axisLabel: {
padding: [0, 0, 10, -10],
margin: 10,
inside: true,
textStyle: {
fontSize: 12,
fontFamily: 'PingFangSC-Semibold',
fontWeight: 600,
color: '#fff',
align: 'left',
},
width: 350,
overflow: 'truncate',
formatter: '{value}\n{a|占位}',
rich: {
a: {
color: 'transparent',
lineHeight: 22,
fontFamily: 'digital',
fontSize: 20,
shadowColor: 'rgba(0, 0, 0, 1)',
shadowBlur: 10,
},
},
},
splitLine: {
show: false,
},
axisTick: {
show: false,
},
axisLine: {
show: false,
},
},
};
setAreaOption(option);
}, []);