// 对于次数等统计不允许出现小数的情况,
// 折线图的处理是
// props.count_list.push(0, 0, 0, 0, 0, 5)
// 柱形图的处理是 原始数据最大值小于 5 数轴设置 max 5
// if (Math.max(...props.map(e => e.num)) <= 5) {
// option.yAxis[0].max = 5
// }
const colorStartArray = [
'#3c89ff',
'#ffa900',
'#70bb68',
'#02cbc7',
'#ff6289',
'#9d56df',
'#585ae1',
'#02cbc7',
'#3c89ff',
'#ffa900',
'#70bb68',
'#02cbc7',
'#ff6289',
'#9d56df',
'#585ae1'
];
const colorBarArray = [
'#3049b0',
'#0085e8',
'#01d6e6',
'#dcd44b',
'#de9209'
];
const colorCardArray = [
'#1639a4',
'#027da6',
'#1c929e',
'#0266bb',
'#91841a',
'#9a660e',
'#9b4e35'
];
const colorEndArray = [
'rgba(60, 137, 255, 0.5)',
'rgba(255, 169, 0, 0.5)',
'rgba(112, 187, 104, 0.5)',
'rgba(2, 203, 199, 0.5)',
'rgba(255, 98, 137, 0.5)',
'rgba(157, 86, 223, 0.5)',
'rgba(88, 90, 225, 0.5)',
'rgba(2, 203, 199, 0.3)',
'rgba(60, 137, 255, 0.5)',
'rgba(255, 169, 0, 0.5)',
'rgba(112, 187, 104, 0.5)',
'rgba(2, 203, 199, 0.5)',
'rgba(255, 98, 137, 0.5)',
'rgba(157, 86, 223, 0.5)',
'rgba(88, 90, 225, 0.5)'
];
const getLinear = (index, type) => {
index %= colorStartArray.length
if (type === 1) {
// 适用于纵向柱状图
return new echarts.graphic.LinearGradient(
0, 0, 1, 1, [
{offset: 1, color: colorStartArray[index]},
{offset: 0, color: colorEndArray[index]}
]
)
} else if (type === 2) {
// 适用于横向柱状图
return new echarts.graphic.LinearGradient(
0, 0, 1, 1, [
{offset: 0, color: colorStartArray[index]},
{offset: 1, color: colorEndArray[index]}
]
)
}
// 扇形图
return new echarts.graphic.LinearGradient(
0, 0, 0, 1, [
{offset: 0, color: colorStartArray[index]},
{offset: 1, color: colorEndArray[index]}
]
)
}
const getLinearByParams = (params) => {
return new echarts.graphic.LinearGradient(
0, 0, 0, 1, [
{offset: params[0], color: params[1]},
{offset: params[2], color: params[3]}
]
)
}
const getTitle = (label) => {
return {
show: false,
text: label,
x: 'left',
y: 'top',
textStyle: {
fontSize: 16,
color: '#ffffff'
}
}
}
const matchMedia = () => {
/*
- 用于判断屏幕大小的函数,便于给 chart 添加变量
*/
let media = "";
if (window.matchMedia('(min-height:800px) and (max-height:900px)').matches) {
media = 'middle';
} else if (window.matchMedia('(max-height:800px)').matches) {
media = 'min';
} else {
media = 'max';
}
return media;
}
const filterNum = (val) => {
/*
- 用于格式化纵坐标
*/
if ( val !== 0 && (!val || isNaN(val)) ) {
return val;
}
let num = Number(val);
if (Math.abs(num) > 100000000) {
return (num / 100000000).toFixed(0) + '亿';
} else if (Math.abs(num) > 10000) {
return (num / 10000).toFixed(0) + '万';
} else {
return num;
}
return num
}
const pieOption = (props, chartTitle) => {
return {
tooltip: {
trigger: 'item',
formatter: (val) => {
return `<div class="tooltip_person_wrap">${val.data.code}: ${val.value} (${val.percent}%)</div>`
},
extraCssText: 'border: 1px solid #319aff; z-index: 333; box-sizing: border-box;'
},
title: getTitle(chartTitle),
grid: {
left: '15%',
top: '10%',
height: '74%',
width: '70%',
containLabel: true
},
series: [{
name: '',
type: 'pie',
radius: ['30%', '60%'],
center: ['50%', '55%'],
minAngle: 15,
roseType: false,
color: [
'#ff6a83',
'#ffd188',
'#3988ff',
'#0f5ed6',
'#003da9',
'#04dfff',
'#00dcda',
'#018b89'
],
label: {
normal: {
color: '#3988ff'
}
},
data: props.map((e, i) => {
e.labelLine = {
normal: {
lineStyle: {
color: colorStartArray[i]
}
}
};
e.label = {
normal: {
color: colorStartArray[i % 15]
}
};
e.itemStyle = {
normal: {
color: getLinear(i)
}
};
e.code = e.name;
const str = e.name.toString();
if (str.length > 9) {
e.name = e.name.toString().slice(0, 9) + '...';
} else {
e.name = e.name;
}
e.value = e.account;
return e;
})
}]
}
}
const barOption = (props, chartTitle, barColors) => {
const toStringSize = matchMedia() == 'max' ? 6 : 4;
const option = {
title: getTitle(chartTitle),
grid: {
right: '8%',
left: '8%',
top: '5%',
bottom: '20%'
},
tooltip: {
trigger: 'axis',
extraCssText: 'padding: 4px 8px; border: 1px solid #319aff; z-index: 333; box-sizing: border-box;',
axisPointer: {
type: 'shadow'
},
formatter: (val) => {
return val[0].data.name +
'<br /><span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' +
val[0].color.colorStops[0].color + '"></span>' +
val[0].data.value
}
},
xAxis: [{
type: 'category',
data: props.map((e, i) => {
const str = e.riskName.toString();
if (str.length > toStringSize) {
return e.riskName.toString().slice(0, toStringSize) + '...';
}
return e.riskName;
}),
axisLabel: {
interval: 0,
show: true,
rotate: 320,
fontSize: 10,
textStyle: {
color: '#e8e8e8'
}
},
axisTick: {
show: false
},
splitLine: {
lineStyle: {
show: false,
color: '#e8e8e8',
width: 1
}
},
axisLine: {
lineStyle: {
show: false,
color: '#e8e8e8',
width: 1
}
}
}],
yAxis: [{
type: 'value',
axisLabel: {
interval: 0,
show: true,
textStyle: {
color: '#e8e8e8'
},
formatter: (val) => {
return filterNum(val);
}
},
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#e8e8e8',
width: 1
}
},
splitLine: {
show: false,
lineStyle: {
color: '#e8e8e8',
width: 1
}
}
}],
series: [{
name: '漏洞数',
type: 'bar',
barWidth: '3',
silent: true,
data: props.map((e, i) => {
e.name = e.riskName
e.value = e.count
e.itemStyle = {
normal: {
color: getLinearByParams([0.1, barColors[0], 1, barColors[1]])
}
}
return e
})
}]
}
if (Math.max(...props.map((e) => e.num)) <= 5) {
option.yAxis[0].max = 5
}
return option
}
const composeOption = (props, chartTitle, barColors) => {
const seriesArr = [];
const isEllipsis = matchMedia() == 'min';
if (props && props.maliceTypeArr && props.maliceTypeArr.length) {
props.maliceTypeArr.map( (o, i) => {
const temp = {
name: o.name,
type: 'bar',
stack: '总量',
barWidth: '3px',
label: {
normal: {
show: false,
position: 'insideRight'
}
},
itemStyle: {
normal: {
color: colorBarArray[i % 5]
}
},
data: o.data
}
seriesArr.push(temp);
})
}
return {
title: getTitle(chartTitle),
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
legend: {
show: false,
data: props.maliceNameArr
},
grid: {
top: '2%',
left: '3%',
right: 25,
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value',
// 坐标轴的分割段数,需要注意的是这个分割段数只是个预估值,最后实际显示的段数会在这个基础上根据分割后坐标轴刻度显示的易读程度作调整。
splitNumber: 3,
axisLabel: {
interval: 0,
show: true,
textStyle: {
color: '#e8e8e8'
},
formatter: (val) => {
return filterNum(val);
}
},
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#e8e8e8',
width: 1
}
},
splitLine: {
show: false,
lineStyle: {
color: '#e8e8e8',
width: 1
}
}
},
yAxis: {
type: 'category',
zlevel: 1,
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#d7dae9',
width: 1
}
},
splitLine: {
show: false
},
data: props.locationNameArr.map((e, i) => {
const str = e.toString();
if (isEllipsis && str.length > 3) {
return e.toString().slice(0, 3) + '...';
}
return e;
}),
},
series: seriesArr
};
}
const waterOption = (numParam, chartTitle) => {
const option = {
title: getTitle(chartTitle),
series: [{
type: 'liquidFill',
data: [{
value: numParam / 100,
itemStyle: {
normal: {
color: getLinearByParams([0.1, '#00dbda', 1, '#00b5d6'])
}
}
}],
label: {
normal: {
formatter(param) {
return numParam + '分'
},
textStyle: {
color: '#fff',
insideColor: '#000',
fontSize: 40
}
}
},
backgroundStyle: {
color: '#e8e8e8' // 球状的背景颜色
},
outline: {
show: true, // 是否显示轮廓 布尔值
borderDistance: 0, // 外部轮廓与图表的距离 数字
itemStyle: {
borderColor: '#00dbda', // 边框的颜色
borderWidth: 1, // 边框的宽度
// shadowBlur: 5 , // 外部轮廓的阴影范围 一旦设置了内外都有阴影
shadowColor: '#fff' // 外部轮廓的阴影颜色
}
},
radius: '70%', // 水波图的半径
center: ['50%', '55%']
}]
};
return option
}
const trendOption = (props, chartTitle) => {
// 全局的 统计趋势配置 ECHARTS
if (props.trend_series[props.trend_active].series_type !== 'rate') {
props.trend_series[props.trend_active].series_datalist.push(0, 0, 0, 0, 5)
}
const option = {
title: getTitle(chartTitle),
grid: {
right: '7%',
left: '8%',
top: '20%',
bottom: '12%'
},
tooltip: {
trigger: 'axis',
extraCssText: 'padding: 4px 8px; text-align: left; z-index: 333; box-sizing: border-box; border: 1px solid ' + colorStartArray[props.trend_active] + ';',
formatter: (prop) => {
if (props.trend_series[props.trend_active].series_type === 'rate') {
return `${prop[0].axisValue}
<br/>
<span
style="
display: inline-block;
margin-right: 5px;
border-radius: 10px;
width: 9px;
height: 9px;
background-color: ${colorStartArray[props.trend_active]};">
</span>
检测APP数量: ${Number(prop[0].value * 100).toFixed(2)} %`
}
return `${prop[0].axisValue}
<br/>
<span
style="
display: inline-block;
margin-right: 5px;
border-radius: 10px;
width: 9px;
height: 9px;
background-color: ${colorStartArray[props.trend_active]};">
</span>
检测APP数量: ${prop[0].value}`
},
axisPointer: {
lineStyle: {
color: colorStartArray[props.trend_active]
}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: props.trend_series[props.trend_active].series_coord_list,
axisLabel: {
// interval: 0,
show: true,
margin: 14,
textStyle: {
color: '#5a5a5a'
}
},
axisTick: {
show: true
},
splitLine: {
lineStyle: {
show: false,
color: '#5a5a5a',
width: 1
}
},
axisLine: {
lineStyle: {
show: false,
color: '#5a5a5a',
width: 1
}
}
},
yAxis: {
type: 'value',
axisLabel: {
interval: 0,
margin: 10,
show: true,
textStyle: {
color: '#5a5a5a'
},
formatter: (val) => {
let res = null;
if (props.trend_series[props.trend_active].series_type === 'rate') {
res = (val * 100).toFixed(2) + '%'
} else {
res = val
}
return res
}
},
axisTick: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#5a5a5a',
width: 1
}
},
splitLine: {
lineStyle: {
show: false,
color: '#bcbcbc',
width: 1
}
}
},
// trend_series: [
// {
// series_title: '安全事件数',
// series_type: 'number',
// series_index: 0,
// series_url: '',
// series_params: {},
// series_coord_list: [],
// series_datalist: [],
// }
// ],
series: [{
name: props.trend_series[props.trend_active].series_title,
type: 'line',
showSymbol: false,
silent: true,
itemStyle: {
normal: {
color: colorStartArray[props.trend_active]
},
emphasis: {
color: colorStartArray[props.trend_active]
}
},
// lineStyle: {
// normal: {
// type: 'dashed'
// }
// },
cursor: 'pointer',
areaStyle: {
normal: {
color: getLinear(props.trend_active)
}
},
data: props.trend_series[props.trend_active].series_datalist
}]
}
return option
}
const roseOption = (params, chartTitle) => {
const angleArr = [];
const valueData = [];
if ( params && params.length ) {
params.map( (o) => {
angleArr.push( o.privacyName ? o.privacyName : '未知数据' );
})
params.map( (o) => {
valueData.push(o.count);
})
}
return {
title: getTitle(chartTitle),
tooltip: {
trigger: 'axis',
extraCssText: 'padding: 4px 8px; text-align: left; z-index: 333; box-sizing: border-box; border: 1px solid #f0f0f0;',
formatter: (prop) => {
return `<span
style="
display: inline-block;
margin-right: 5px;
border-radius: 10px;
width: 9px;
height: 9px;">
</span>
${prop[0].name}: ${prop[0].value}`
}
},
angleAxis: {
type: 'category',
data: angleArr,
z: 10,
axisLabel: {
show: true,
color: '#f0f0f0',
fontSize: 10,
formatter: (e) => {
const str = e.toString();
if (str.length > 5) {
e = e.toString().slice(0, 5) + '...';
} else {
e = e;
}
return e;
}
},
axisTick: {
show: false,
lineStyle: {
show: false,
color: '#00baff'
}
},
axisLine: {
show: false,
lineStyle: {
show: true,
color: '#00baff'
}
}
},
radiusAxis: {
minInterval: 1,
splitNumber: 3,
splitLine: {
show: true,
lineStyle: {
show: false,
color: '#00baff'
}
},
axisLine: {
show: false,
lineStyle: {
show: false,
color: '#00baff'
}
},
axisLabel: {
show: true,
color: '#00baff',
fontSize: 10,
formatter: (val) => {
return filterNum(val);
}
},
axisTick: {
show: false,
lineStyle: {
show: false,
color: '#00baff'
}
}
},
polar: {
},
series: [{
type: 'bar',
data: valueData,
barMaxWidth: '50px',
coordinateSystem: 'polar',
name: 'A',
stack: 'a',
itemStyle: {
color: 'rgba(0,186,255,0.5)'
}
}],
legend: {
show: false,
data: ['A', 'B', 'C']
}
};
}
const sankeyOption = (params, chartTitle) => {
const option = {
color: colorStartArray,
title: getTitle(chartTitle),
grid: {
right: '8%',
left: '8%',
top: '100'
},
tooltip: {
trigger: 'item',
triggerOn: 'mousemove'
},
series: [{
type: 'sankey',
data: params.nodes,
links: params.links,
focusNodeAdjacency: 'allEdges',
label: {
normal: {
color: '#3988ff'
}
},
itemStyle: {
normal: {
borderWidth: 0
}
},
lineStyle: {
normal: {
color: 'source',
curveness: 0.5
}
}
}]
};
return option
}
const treeOption = (params, chartTitle) => {
const option = {
color: colorCardArray,
title: getTitle(chartTitle),
grid: {
right: '8%',
left: '8%',
top: '100',
bottom: '0%'
},
tooltip: {
trigger: 'item',
triggerOn: 'mousemove'
},
series: [{
type: 'treemap',
breadcrumb: {
show: false
},
data: params.map( (e) => {
e.name = e.countryName ? e.countryName : '未知国家';
e.value = e.count;
return e;
})
}]
};
return option
}
const emptyOption = (chartTitle) => {
const option = {
title: {
subtext: '暂无数据',
text: chartTitle,
x: 'center',
y: 'center',
subtextStyle: {
color: '#3988ff',
fontWeight: 'lighter',
fontSize: 13
},
textStyle: {
color: '#ffffff',
fontWeight: 'bold',
fontSize: 16
}
},
series: [{
type: 'pie',
radius: ['58%', '72%'],
silent: true,
label: {
normal: {
show: false
}
},
data: [{
value: 1,
itemStyle: {
normal: {
color: '#bcbccf',
shadowBlur: 2,
shadowColor: '#bcbccf'
}
}
}],
animation: false
}, {
type: 'pie',
radius: ['58%', '72%'],
silent: true,
label: {
normal: {
show: false
}
},
data: [{
value: 1,
itemStyle: {
normal: {
color: '#bcbccf',
shadowBlur: 20,
shadowColor: '#bcbccf'
}
}
}],
animation: false
}, {
name: 'main',
type: 'pie',
radius: ['72%', '78%'],
label: {
normal: {
show: false
}
},
data: [{
value: 0.67,
itemStyle: {
normal: {
color: '#3988ff',
shadowBlur: 10,
shadowColor: '#3988ff'
}
}
}, {
value: 0.5,
itemStyle: {
normal: {
color: 'transparent'
}
}
}],
animationEasingUpdate: 'cubicInOut',
animationDurationUpdate: 500
}
]
};
return option
}
export {
roseOption,
treeOption,
composeOption,
waterOption,
trendOption,
barOption,
pieOption,
sankeyOption,
emptyOption
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。