当我们在ReactNative中采用图表技术的时候, 我们大致做了技术选型, 第一种是基于webView(react-native-echarts),采用echarts内容的方式,去加载图表, 第二种方式是基于Android端和IOS端原生库(native-echarts)封装成组件的形式显示图表.对于业务的复杂和UI特殊性我们选择了第一种方式,在使用的过程中发现了很多比较差异的问题,以下便是对于问题的总结
formatter: function (params) {
// \n 无法正常换行
return params.value+"\n"+"end";
}
export default function toString(obj) {
let result = JSON.stringify(obj, function(key, val) {
if (typeof val === 'function') {
return `~--demo--~${val}~--demo--~`;
}
return val;
});
do {
result = result.replace('\"~--demo--~', '').replace('~--demo--~\"', '').replace(/\\n/g, '').replace(/\\\"/g,"\"");//最后一个replace将release模式中莫名生成的\"转换成"
} while (result.indexOf('~--demo--~') >= 0);
return result;
}
export default function toString(obj) {
let result = JSON.stringify(obj, function (key, val) {
if (typeof val === 'function') {
return `~--demo--~${val}~--demo--~`;
}
return val;
});
do {
result = result
.replace('\"~--demo--~', '')
.replace('~--demo--~\"', '')
.replace(/{\\n\\n/g, '{')//去除stringify之后方法的{\n\n
.replace(/}\\n\\n/g, '}')//去除stringify之后方法的}\n\n
.replace(/{\\n/g, '{')//去除stringify之后方法的{\n
.replace(/}\\n/g, '}')//去除stringify之后方法的}\n
.replace(/;\\n\\n/g, ';')//去除stringify之后的方法;\n\n
.replace(/;\\n/g, ';')//去除stringify之后的方法;\n
.replace(/\\\\n/g, '\\n')//去除字符串\\n
.replace(/\\\"/g, "\"");//最后一个replace将release模式中莫名生成的\"转换成"
} while (result.indexOf('~--demo--~') >= 0);
return result;
}
{
value: "value",
name: "name",
itemStyle: {//变更饼图选中高亮颜色变换问题
emphasis: {color:“#83D0EF”}
}
}
//设置默认选中高亮部分
myChart.dispatchAction({type: 'highlight',seriesIndex: 0,dataIndex: 0});
//
myChart.on('mouseover', (e) => {
if (e.dataIndex !== 0) { // 当鼠标移除的时候 使默认的索引值去除默认选中
myChart.dispatchAction({ type: 'downplay', dataIndex: 0 });
}
});
/**
* 参考资料: https://www.cnblogs.com/benmumu/p/8316652.html
* API文档: https://echarts.apache.org/examples/zh/index.html#chart-type-scatter
*/
/**
* 多柱状图
*/
const dailyEventOption = (source) => {
return {
backgroundColor: "#fff",//全局背景颜色
legend: {//图例样式
x: 'center',
bottom: 0,
itemGap: 20,
textStyle: {
color: '#666'// 图例文字颜色
}
},
tooltip: {
trigger: 'axis',
backgroundColor: "#fff",
borderColor: '#E9EDF0',
borderRadius: 4,
padding: 10,
textStyle: {
color: '#666',
fontSize: 13,
},
// axisPointer: {
// type: 'cross', // 十字准星指示器,
// label: {
// backgroundColor: "#587EFF",
// },
// shadowStyle: {// 阴影指示器样式设置
// width: 'auto',// 阴影大小
// color: 'rgba(175, 193, 255, 0.1)' // 阴影颜色
// }
// },
},
dataZoom: [
{
show: false,
start: 0,
end: 100
},
{
type: 'inside',
start: 0,
end: 100
},
{
show: false,
yAxisIndex: 0,
filterMode: 'empty',
width: 30,
height: '80%',
showDataShadow: false,
left: '93%'
}
],
dataset: {
source: source ||
[
['product', '事件总数', '已逾期', '按时整改率'],
['周一', 43.3, 85.8, 90.7],
['周二', 83.1, 73.4, 55.1],
['周三', 86.4, 65.2, 82.5],
['周四', 72.4, 53.9, 39.1],
['周五', 22.4, 53.9, 49.1],
['周六', 72.4, 43.9, 69.1],
['周日', 82.4, 53.9, 39.1]
],
},
xAxis: [
{
type: 'category',
axisPointer: {
type: 'shadow'
},
axisLabel: {
inside: false,
textStyle: {
color: '#9AA1A9',
fontSize: '10',
}
},
axisLine: {
lineStyle: {
color: "#E9EBF1"
}
},
axisTick: {
show: false
},
}
],
yAxis: [{
min: 0,
name: '数量',
splitLine: {//分隔线
show: true,//默认显示,属性show控制显示与否
onGap: null,
lineStyle: {// 属性lineStyle(详见lineStyle)控制线条样式
color: ['#ccc'],
width: 1,
type: "dashed",
}
},
axisLine: {
show: false
},
axisTick: {
show: false
},
}, {
name: '整改率',
type: 'value',
min: 0,
max: 100,
axisLabel: {
formatter: '{value}%'
},
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {// 分隔线
show: true,// 默认显示,属性show控制显示与否
onGap: null,
lineStyle: {// 属性lineStyle(详见lineStyle)控制线条样式
color: ['#ccc'],
width: 1,
type: "dashed",
}
},
}],
series: [
{
type: 'bar',
barWidth: 10,//宽度
color: "#587EFF",
},
{
type: 'bar',
barWidth: 10,//宽度
color: "#AFC1FF"
},
{
type: 'line',
smooth: true,//平滑
color: "#FFA41C"
}
]
}
};
/**
*折线图
*/
const scoringRateOption = (source, des) => {
// [[1597892178, 129], [1597576048, 20]]
return {
dataset: {
source: source || []
},
// dataZoom: [
// {
// show: false,
// start: 0,
// end: 100
// },
// {
// type: 'inside',
// start: 0,
// end: 100
// },
// {
// show: false,
// yAxisIndex: 0,
// filterMode: 'empty',
// width: 30,
// height: '80%',
// showDataShadow: false,
// left: '93%'
// }
// ],
grid: {
top: 30,
bottom: 20,
left: 40,
},
xAxis: {
type: 'value',
scale: true,
splitLine: {// 分隔线
show: false,// 默认显示,属性show控制显示与否,
},
axisLabel: {
// showMinLabel: true,//显示最小值
// showMaxLabel: true,//显示最大值 convertDate
formatter: function (parames) {
let myDate = new Date(parames);
let tDay = myDate.getDate();
let tMonth = myDate.getMonth() + 1;
let tYear = myDate.getFullYear();
return tMonth + "-" + tDay;
},
inside: false,
textStyle: {
color: '#9AA1A9',
fontSize: '10',
},
},
axisLine: {
lineStyle: {
color: "#E9EBF1"
}
},
axisTick: {
show: false
},
},
yAxis: {
splitLine: {// 分隔线
show: true,// 默认显示,属性show控制显示与否
onGap: null,
lineStyle: {// 属性lineStyle(详见lineStyle)控制线条样式
color: ['#ccc'],
width: 1,
type: "dashed",
}
},
axisLabel: {
formatter: '{value} %',
inside: false,
textStyle: {
color: '#9AA1A9',
fontSize: '10',
},
},
axisLine: {
show: false
},
axisTick: {
show: false
},
},
series: [
{
symbolSize: 6,
type: 'scatter',
itemStyle: {
color: "#5B9AE6"
},
markLine: {
label: {
distance: 10,
formatter: "",//'{b}:{c}%',
position: 'middle',
},
data: [{
type: 'average', name: des || '平均'
}],
lineStyle: {
width: 1.5,
type: "solid",
color: "#FFA41C",
shadowColor: "#FFA41C",
shadowBlur: 3,
shadowOffsetY: 1,
}
}
}
]
}
};
/**
*
* 内置形状水球图
* https://github.com/ecomfe/echarts-liquidfill
*
* http://gallery.echartsjs.com/editor.html?c=xry0tUfcBe
*/
const waterPoloDiagramOption = (progress) => {
return {
series: [
{
type: 'liquidFill',
data: [progress || 0],
radius: '95%',
color: ['#587EFF'],
shape: 'circle',
backgroundStyle: {
color: '#fff'
},
itemStyle: {
normal: {
shadowBlur: 0
}
},
emphasis: {
itemStyle: {
opacity: 1
}
},
outline: {
show: true,
borderDistance: 5,
itemStyle: {
borderWidth: 2,
borderColor: '#779CFF',
}
},
label: {
show: false,
normal: {
textStyle: {
color: '#333',
insideColor: '#fff',
fontSize: 18,
fontWeight: '400',
}
}
}
}
]
}
};
/**
*
* 无圆角进度图 有图例
*/
const progressChartOption1 = (progress) => {
let pro = !isNaN(progress) && (progress * 100).toFixed(0) || 0;
return {
title: {
show: true,
text: pro + '%',
x: 'center',
y: 'center',
textStyle: {
fontSize: 20,
color: '#000',
fontWeight: '400'
}
},
tooltip: {
trigger: 'item',
formatter: "{d}%",
show: false
},
legend: {
show: true,
bottom: 0,
},
color: ["#6699FF", "#EBEEF5"],
series:
{
name: '',
type: 'pie',
silent: true,
radius: ['65%', '85%'],
avoidLabelOverlap: true,
hoverAnimation: false,
label: {
normal: {
show: false,
position: 'center',
},
emphasis: {
show: false
}
},
labelLine: {
normal: {
show: false,
}
},
data: [
{value: pro},
{value: 100 - pro}
]
}
}
};
/**
* 圆角进度图 没有图例
*/
const progressChartOption2 = function (progress, color) {
let pro = !isNaN(progress) && (progress * 100).toFixed(0) || 0;
return {
title: {
show: true,
text: pro + '%',
x: 'center',
y: 'center',
textStyle: {
fontSize: 18,
color: '#44444F',
fontWeight: '400'
},
},
angleAxis: {
max: 100, // 满分
clockwise: true, // 逆时针
// 隐藏刻度线
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: false
},
splitLine: {
show: false
}
},
radiusAxis: {
type: 'category',
// 隐藏刻度线
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: false
},
splitLine: {
show: false
}
},
polar: {
center: ['50%', '50%'],
radius: '160%' //图形大小
},
series: [
{
type: 'bar',
data: [{
name: '',
value: pro || undefined,
itemStyle: {
normal: {
color: { // 完成的圆环的颜色
colorStops: [{
offset: 0,
color: color || '#6699FF' // 0% 处的颜色
}, {
offset: 1,
color: color || '#6699FF' // 100% 处的颜色
}]
}
}
},
}],
silent: true,
coordinateSystem: 'polar',
roundCap: true,
barWidth: 11,
barGap: '-100%', // 两环重叠
radius: ['49%', '52%'],
z: 2,
},
{ // 底部环
type: 'bar',
data: [{
value: 100,
itemStyle: {
color: '#EBEEF5',
}
}],
silent: true,
coordinateSystem: 'polar',
roundCap: true,
barWidth: 11,
barGap: '-110%', // 两环重叠
radius: ['48%', '53%'],
z: 1
}]
}
};
/**
*
* 仪表盘图
*/
const dashboardDiagramOption = (progress, option = {}) => {
let pro = !isNaN(progress) && ( progress * 100).toFixed(0) || 10;
return {
title: [],
angleAxis: {
show: false,
max: 100 * 360 / 270, //-45度到225度,二者偏移值是270度除360度
type: 'value',
startAngle: 225, //极坐标初始角度
splitLine: {
show: false
}
},
barMaxWidth: 16, //圆环宽度
radiusAxis: {
show: false,
type: 'category',
},
//圆环位置和大小
polar: {
center: ['50%', '58%'],
radius: option.radius || '170'
},
series: [
{
type: 'bar',
silent: true,
data: [{ //上层圆环,显示数据
value: pro || undefined,
itemStyle: {
color: ["#587EFF"],
},
}],
barGap: '-100%', //柱间距离,上下两层圆环重合
coordinateSystem: 'polar',
roundCap: true, //顶端圆角
z: 2 //圆环层级,同zindex
},
{ //下层圆环,显示最大值
type: 'bar',
silent: true,
data: [{
value: 100,
itemStyle: {
color: '#F3F5F8'
}
}],
barGap: '-100%',
coordinateSystem: 'polar',
roundCap: true,
z: 1
},
{
type: 'gauge',
//半径
radius: 90,
//起始角度。圆心 正右手侧为0度,正上方为90度,正左手侧为180度。
startAngle: 225, // 仪表盘起始角度,默认 225。圆心 正右手侧为0度,正上方为90度,正左手侧为180度。
endAngle: -45,
center: ['50%', '83%'],
roundCap: true, //顶端圆角
axisLine: { // 坐标轴线
show: false,
},
splitLine: { // 分隔线样式。
show: false, // 是否显示分隔线,默认 true
},
//刻度样式
axisTick: {
show: false,
},
//刻度标签。
axisLabel: {
show: false,
},
//仪表盘指针。
pointer: {
//这个show属性好像有问题,因为在这次开发中,需要去掉指正,我设置false的时候,还是显示指针,估计是BUG吧,我用的echarts-3.2.3;希望改进。最终,我把width属性设置为0,成功搞定!
show: false,
//指针长度
length: '90%',
width: 0,
},
//仪表盘标题。
title: {
show: false,
},
//仪表盘详情,用于显示数据。
detail: {
show: true,
offsetCenter: [0, '-70%'],
formatter: '{value}%',
textStyle: {
fontSize: 20,
color: '#505D6F',
fontWeight: "400"
}
},
data: [
{value: pro, name: ''},
],
zlevel: 1
},
{
name: '',
type: 'gauge',
//半径
radius: option.radius ? (option.radius - 65) : 105,
startAngle: 225, // 仪表盘起始角度,默认 225。圆心 正右手侧为0度,正上方为90度,正左手侧为180度。
endAngle: -45,
center: ['50%', '58%'],
splitNumber: 20,
roundCap: true, //顶端圆角
//仪表盘轴线相关配置。
axisLine: { // 坐标轴线
show: false,
lineStyle: { // 属性lineStyle控制线条样式
width: 1,
color: [[1, '#587EFF']]
}
},
//分隔线样式。
splitLine: {
show: true,
length: 5,
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
color: ['#505D6F'],
width: 1,
type: 'solid'
}
},
//刻度样式
axisTick: {
show: false,
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
color: ['#505D6F'],
width: 1,
type: 'solid'
}
},
//刻度标签。
axisLabel: {
show: false,
formatter: function (param) {
num = [0, 25, 50, 75, 100];
if (num.indexOf(param) > -1) {
return param
}
}
},
//仪表盘指针。
pointer: {
//这个show属性好像有问题,因为在这次开发中,需要去掉指正,我设置false的时候,还是显示指针,估计是BUG吧,我用的echarts-3.2.3;希望改进。最终,我把width属性设置为0,成功搞定!
show: false,
},
//仪表盘标题。
title: {
show: false
},
//仪表盘详情,用于显示数据。
detail: {
show: false,
},
data: [
{name: '', value: ''},
],
zlevel: -1
},
{
name: '',
type: 'gauge',
//半径
radius: option.radius ? (option.radius - 35) : 135,
startAngle: 225, // 仪表盘起始角度,默认 225。圆心 正右手侧为0度,正上方为90度,正左手侧为180度。
endAngle: -45,
center: ['50%', '58%'],
splitNumber: 20,
//仪表盘轴线相关配置。
axisLine: { // 坐标轴线
show: false,
lineStyle: { // 属性lineStyle控制线条样式
width: 1,
color: [[1, '#587EFF']]
}
},
//分隔线样式。
splitLine: {
show: false,
length: 5,
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
color: ['#505D6F'],
width: 1,
type: 'solid'
}
},
//刻度样式
axisTick: {
show: false,
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
color: ['#505D6F'],
width: 1,
type: 'solid'
}
},
//刻度标签。
axisLabel: {
show: true,
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
color: '#505D6F'
},
formatter: function (param) {
let num = [0, 25, 50, 75, 100];
if (num.indexOf(param) > -1) {
return param
}
}
},
//仪表盘指针。
pointer: {
//这个show属性好像有问题,因为在这次开发中,需要去掉指正,我设置false的时候,还是显示指针,估计是BUG吧,我用的echarts-3.2.3;希望改进。最终,我把width属性设置为0,成功搞定!
show: false,
},
//仪表盘标题。
title: {
show: false
},
//仪表盘详情,用于显示数据。
detail: {
show: false,
},
data: [
{name: '', value: ''},
],
zlevel: -1
}
]
}
};
/**
*饼图
*/
const pieChartOption = (data, color) => {
return {
tooltip: {
show: false,
trigger: 'item',
formatter: ''
},
legend: {
orient: 'vertical',
right: "0%",
top: '30%',
data: []
},
color: color || ["#6699FF", "#52CCA3"],
series: [
{
name: '',
type: 'pie',
center: ['50%', '50%'],
radius: ['60%', '80%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '18',
color: "#333",
// formatter: '{d}%',
formatter: function (params) {
return params.name;
}
}
},
labelLine: {
show: false
},
data: data ||
[
{value: 335, name: '直接访问'},
{value: 310, name: '邮件营销'},
]
}
]
};
};
/**
* 折线图
*/
const lineChartOption = (source, yName, tipName) => {
return {
dataset: {
source: source ||
[
[123123, 200],
[123223, 100],
[123323, 20],
[123423, 210],
[123523, 2]
],
},
tooltip: {
trigger: 'axis',
backgroundColor: "#fff",
borderColor: '#E9EDF0',
borderWidth: 1,
borderRadius: 4,
padding: 10,
textStyle: {
color: '#666',
fontSize: 13,
},
axisPointer: {
animation: false,
label: {
backgroundColor: "#587EFF",
formatter: function (params) {
let subValue = "0";
if (params.value.toString() && params.value.toString().split(":").length > 1) {
subValue = parseInt(params.value.toString().split(":")[0]) - 1 || "0";
}
let startValueStart = ( subValue < 10 ? "0" + subValue : subValue) + ":00";
return startValueStart + "-" + params.value;
}
},
type: 'line', // 默认为直线,可选为:'line' | 'shadow'
lineStyle: { // 直线指示器样式设置
color: '#bbb',
width: 1,
type: 'dashed'
},
shadowStyle: {// 阴影指示器样式设置
width: 'auto',// 阴影大小
color: 'rgba(175, 193, 255, 0.1)' // 阴影颜色
},
},
},
dataZoom: [
{
show: false,
start: 0,
end: 100
},
{
type: 'inside',
start: 0,
end: 100
},
{
show: false,
yAxisIndex: 0,
filterMode: 'empty',
width: 30,
height: '80%',
showDataShadow: false,
left: '93%'
}
],
grid: {
top: 30,
bottom: 30,
left: 40,
},
xAxis: {
type: 'category',
splitLine: {
lineStyle: {
type: 'dashed'
}
},
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: "#E9EBF1"
}
},
axisLabel: {
inside: false,
textStyle: {
color: '#9AA1A9',
fontSize: '10',
},
},
},
yAxis: {
name: yName || '(人次)',
type: 'value',
splitLine: {
lineStyle: {
type: 'dashed'
}
},
axisTick: {
show: false
},
axisLine: {
show: false
},
axisLabel: {
inside: false,
textStyle: {
color: '#9AA1A9',
fontSize: '10',
},
},
},
series:
[
{
name: tipName || "name",
type: 'line',
smooth: true, //smooth表示是否是平滑
areaStyle: {
color: "rgba(87, 126, 255, 0.09)",
}, //areaStyle表示是否显示一块有着色的区域,来覆盖折现图以下的地方
color: '#577EFF', //如果传入了corlor属性就表示这一条折线制定固定的颜色,否则就按默认的颜色来处理
}
]
};
};
/**
*柱状叠加
*/
const columnarStackOption = (source, yName, color) => {
return {
tooltip: {
trigger: 'axis',
backgroundColor: "#fff",
borderColor: '#E9EDF0',
borderWidth: 1,
borderRadius: 4,
padding: 10,
textStyle: {
color: '#666',
fontSize: 13,
},
axisPointer: {
type: 'shadow', // 十字准星指示器,
label: {
backgroundColor: "#587EFF",
},
shadowStyle: {// 阴影指示器样式设置
width: 'auto',// 阴影大小
color: 'rgba(175, 193, 255, 0.1)' // 阴影颜色
}
},
},
dataZoom: [
{
show: false,
start: 0,
end: 100
},
{
type: 'inside',
start: 0,
end: 100
},
{
show: false,
yAxisIndex: 0,
filterMode: 'empty',
width: 30,
height: '80%',
showDataShadow: false,
left: '93%'
}
],
color: color || ["#3DD598", "#587EFF"],
dataset: {
source: source ||
[
['product', '事件总数', '已逾期'],
['周一', 43.3, 85.8],
['周二', 83.1, 73.4],
['周三', 86.4, 65.2],
['周四', 72.4, 53.9],
['周五', 22.4, 53.9],
['周六', 72.4, 43.9],
['周日', 82.4, 53.9]
],
},
legend: {
x: 'center',
bottom: 0,
itemGap: 20,
selectedMode: false,
textStyle: {
color: '#666'// 图例文字颜色
}
},
grid: {
top: "10%",
left: '5%',
right: '5%',
bottom: '10%',
containLabel: true
},
xAxis: [
{
type: 'category',
splitLine: {
lineStyle: {
type: 'dashed'
}
},
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: "#E9EBF1"
}
},
axisLabel: {
inside: false,
textStyle: {
color: '#9AA1A9',
fontSize: '10',
},
},
}
],
yAxis: [
{
name: yName || '(人数)',
type: 'value',
splitLine: {
lineStyle: {
type: 'dashed'
}
},
axisTick: {
show: false
},
axisLine: {
show: false
},
axisLabel: {
inside: false,
textStyle: {
color: '#9AA1A9',
fontSize: '10',
},
},
}
],
series: [
{
type: 'bar',
barWidth: 15,//宽度
stack: 'overlay',
},
{
type: 'bar',
barWidth: 15,//宽度
stack: 'overlay',
},
]
};
};
export {
dailyEventOption,
scoringRateOption,
waterPoloDiagramOption,
progressChartOption1,
progressChartOption2,
dashboardDiagramOption,
pieChartOption,
lineChartOption,
columnarStackOption
}