效果如图
直接上代码
<template>
<div class="curve">
<div class="curve__header">
<div class="curve__header__title">
<input type="file" id="uploadExcel" multiple @change="handleChange"/>
<a-button @click="draw">绘制</a-button>
<a-button @click="exports">导出</a-button>
<div class="fillIn">
<div> <a-input v-model:value="echartsWidth" addon-before="宽度:" addon-after="px" placeholder="请输入"/></div>
<div> <a-input v-model:value="echartsHeight" addon-before="高度:" addon-after="px" placeholder="请输入"/></div>
<a-button @click="reset">重置</a-button>
</div>
</div>
</div>
<div class="curve__body" :style="{width:echartsWidth?echartsWidth+'px':'',height:echartsHeight? echartsHeight+'px':''}">
<div class="curve__body__chart" id="Charts">
</div>
</div>
</div>
</template>
<script setup>
import {nextTick, onMounted, Ref, ref} from 'vue';
import * as echarts from "echarts";
import * as XLSX from "xlsx"
let echartsImg=new Image()
const echartsWidth=ref('1000')
const echartsHeight=ref('800')
const initChart = (datas) => {
console.log(datas)
let maxValue=0
for (let i = 0; i < datas.length; i++) {
for (let j = 0; j < datas[i].data2.length; j++) {
if (maxValue < datas[i].data2[j][1]) {
maxValue = datas[i].data2[j][1];
}
}
}
console.log(maxValue,'maxY')
const chartDom = document.getElementById('Charts');
echarts.dispose(chartDom);
const myChart = echarts.init(chartDom);
let colorList=['#1dadbf','#9cce40','#d837b7']
let seriesData=[]
datas?.forEach((v,i)=>{
seriesData.push({
data: v.data2,
smooth: true,
type: 'line',
symbol: "none",
lineStyle: {
color: colorList[i]
}
})
seriesData.push({
data: v.data1,
smooth: true,
type: 'scatter',
symbolSize: 5,
itemStyle: {
color: colorList[i]
}
})
})
//x轴对应频率
let data = [
];
const data1 = [
]
const data1X = [
]
const option = {
animation: false,
grid: { // 让图表占满容器
top: "50px",
left: "70px",
right: "50px",
bottom:"60px"
},
tooltip: {
trigger: 'axis',
formatter: (params) => {
let result = '';
// console.log(params,'params')
for (let i = 0; i < params.length; i++) {
if (params.length > 3) {
if (i === 0) {
result += '量:' + params[i]?.data[1] + '<br />';
result += '率:' + params[i]?.data[2] + '%' + '<br />';
}
if (i === 1) {
result += '量:' + params[i]?.data[1] + '<br />';
result += '率:' + params[i]?.data[2] + '%' + '<br />';
}
} else {
if (i === 0) {
result += '量:' + params[i]?.data[1] + '<br />';
result += '率:' + params[i]?.data[2] + '%' + '<br />';
}
}
}
return result;
}
},
xAxis: {
name:echartsXYName[1],
nameTextStyle: { // y轴name的样式调整
color: '#000',
fontSize: 22,
padding:[10,0,0,0] // 加上padding可以调整其位置
},
nameLocation: "center",
min: 0,
max: 7781,
type: 'value',
interval: 1,
axisTick: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
show: true,
formatter: (value) => {
let arr = data1X.find((item) => item[0] == value) || [];
return arr[2] ? arr[2] : '';
},
// rotate: -45,
showMinLabel: true,
showMaxLabel: true,
fontSize:16
},
axisLine: {
lineStyle: {
color: '#000',
}
},
},
yAxis: {
name:echartsXYName[0],
nameTextStyle: { // y轴name的样式调整
color: '#000',
fontSize: 22,
},
type: 'value',
axisTick: {
show: false
},
max: (roundedUp(maxValue.toFixed(0))).toFixed(0),
min: 0,
splitNumber: 10,
splitLine: {
show: true,
lineStyle: {
color: ['#000'],
width: 1,
type: 'solid'
}
},
axisLine: {
lineStyle: {
color: '#000',
}
},
axisLabel: {
fontSize:16
}
},
series: [
{
name:'网格',
data: dataX1.map((item) => {
let arr = [...item];
arr[1] = (roundedUp(maxValue.toFixed(0))).toFixed(0);
return arr;
}),
type: 'bar',
barWidth: 1,
cursor: 'auto',
itemStyle: {
normal: {
color: '#000'
},
emphasis: {
color: '#000'
}
},
animation: false,
tooltip: {
show: false
}
},
...seriesData
]
};
window.addEventListener('resize', function () {
myChart.resize();
});
myChart.setOption(option);
echartsImg.src=myChart.getDataURL({
// backgroundColor: "#fff",
type: "png",
})
}
const echartsData = new Map()
const handleChange = info => {
let fileList = info.target.files;
console.log(fileList)
if (fileList) {
let reader = new FileReader();
let file = fileList[0];
reader.readAsBinaryString(file)
reader.addEventListener("load", function (e) {
console.log(e);//FileReader实例对象
let data = e.target?.result; //读取成功后result中的数据
let wb = XLSX.read(data, {type: 'binary'});//以base64方法读取 结果
console.log(wb,'wb')
wb.SheetNames.length && wb.SheetNames.forEach((v, index) => {
let sheets = wb.Sheets[v]
// //将数据解析为json字符串
let dataList2 = JSON.stringify(XLSX.utils.sheet_to_json(sheets))
let dataList3 = (JSON.parse(dataList2))
echartsData.set(v, dataList3)
})
})
}
};
const echartsXYName=[]
const getEchartsData = (key) => {
let data = echartsData.get(key)
let data1 = []
let data2 = []
data.forEach((v, i) => {
if (i !== 0) {
const a = 1 - (Number(v['经验历史数据'])) / 100
let c = Number(normsinv(a).toFixed(3))
let b = (Number(3.891 - c)*1000).toFixed(0)
let v1=[b,v['__EMPTY'],v['经验历史数据'].toString()]
data1.push(v1)
if(v['理论数据']){
const a = 1 - (Number(v['理论数据'])) / 100
let c = Number(normsinv(a).toFixed(3))
let b = (Number(3.891 - c)*1000).toFixed(0)
let v1=[b,v['__EMPTY_1'],v['理论数据'].toString()]
data2.push(v1)
}
}else{
echartsXYName[0]=(v['__EMPTY'])
echartsXYName[1]=(v['经验历史数据'])
}
})
return {data1,data2}
}
const echartsData1 = ref([])
const draw = () => {
for(let key of echartsData.keys()){
const data= getEchartsData(key)
echartsData1.value.push(data)
}
nextTick(() => {
initChart(echartsData1.value)
})
}
const exports = () => {
let canvas = document.createElement("canvas");
canvas.width = echartsImg.width;
canvas.height = echartsImg.height;
console.log(canvas.width , canvas.height)
let ctx = canvas.getContext("2d");
ctx.fillStyle = '#fff';
ctx?.fillRect(0, 0, canvas.width, canvas.height);
ctx?.drawImage(echartsImg, 0, 0);
let dataURL = canvas.toDataURL("image/png");
let a = document.createElement("a");
let event = new MouseEvent("click");
a.download = "echarts.png";
a.href = dataURL;
a.dispatchEvent(event);
a.remove();
}
const reset = () => {
echartsWidth.value=''
echartsHeight.value=''
console.log(echartsHeight.value,echartsWidth.value)
draw()
}
const roundedUp=(num)=>{
if (typeof num !== 'number') {
num = parseFloat(num);
}
if(num<100){
return 100
}else{
let a
a=(num/100).toFixed(0)
let b=Number(a)+1
return (b)*100;
}
}
function normsinv(p) {
//计算公式
}
onMounted(() => {
nextTick(() => {
// initChart()
})
})
</script>
<style scoped lang="less">
.curve {
width: 100%;
height: 100%;
background-color: #fff;
}
.curve__header {
width: 100%;
height: 60px;
background-color: #fff;
border-bottom: 1px solid #e8e8e8;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
box-sizing: border-box;
}
.curve__header__title {
font-size: 20px;
font-weight: 500;
color: #333;
display: flex;
align-items: center;
.fillIn{
margin-left: 20px;
display: flex;
width: 500px;
align-items: center;
justify-content: space-between;
font-size: 14px;
>div{
width: 40%;
display: flex;
align-items: center;
}
}
}
.curve__body {
width: 100%;
height: calc(100% - 60px);
background-color: #fff;
padding: 20px;
box-sizing: border-box;
}
.curve__body__chart {
width: 100%;
height: 100%;
background-color: #fff;
}
</style>