YAOTU INSIGHTS

Vue+Echarts横纵坐标按数据自动划分等比刻度线显示(基础版)

Vue+Echarts横纵坐标按数据自动划分等比刻度线显示(基础版)
一般前端使用Echarts显示的数据基本上都是后端返回什么前端展示什么。 但是最近呢单位提到下面这个图按科研者来说其实就是有问题的。看不到任何的趋势。必须要前端优化一波。需求纵坐标展示不要从0开始 横坐标的刻度线也得按照正常的步长比例来计算。那纵坐标其实还是好处理的。只是横坐标有点为难呢。因为之前没有接过这种需求呀! 话不多说经过查阅echarts api 以及deepseek。嗯这种需求是可以实现的呢。 开始撸代码啦templatedivclasschart-containerrefchartContainer/div/templatescript setup langtsimport{ref,onMounted,onUnmounted,watch,nextTick}fromvue;import*asechartsfromecharts;// 定义组件属性interfaceProps{title?:string;xAxisData:Arraystring|number;seriesData:Array{name?:string;data:Arraynumber;type?:string;showSymbol?:boolean;// 是否显示原点symbol?:string;// 原点形状symbolSize?:number;// 原点大小smooth?:boolean;// 是否平滑线itemStyle?:object;// 原点样式lineStyle?:object;// 线条样式markLine?:object;[key:string]:any;};// X轴名称xAxisName?:string;// Y轴名称yAxisName?:string;ysjhs?:string;// 图表类型chartType?:line|bar|scatter;// 图表高度height?:string;// 颜色配置colors?:string[];// 图例位置配置legendPosition?:{top?:string|number;bottom?:string|number;left?:string|number;right?:string|number;};gridPosition?:{top?:string|number;bottom?:string|number;left?:string|number;right?:string|number;containLabel?:boolean;};legendIcon?:string;//rect | circle | roundRect | triangle | diamond | pin | arrow// 自定义tooltip格式化函数tooltipFormatter?:(params:any[],props:Props)string;}constpropswithDefaults(definePropsProps(),{title:,chartType:line,height:calc(100% - 65px),colors:()[#2488EB,#84bdf2,#f48f35,#de0d22,#bac3d1],legendIcon:rect,legendPosition:{top:30,right:6%,},gridPosition:()({left:5%,right:10%,bottom:5%,containLabel:true,}),});constchartContainerrefHTMLDivElement|null(null);letchartInstance:echarts.ECharts|nullnull;letresizeObserver:ResizeObserver|nullnull;// 初始化图表constinitChart(){if(chartContainer.value){chartInstanceecharts.init(chartContainer.value);updateChart();}// 使用 ResizeObserver 监听容器尺寸变化if(window.ResizeObserver){resizeObservernewResizeObserver((){if(chartInstance){chartInstance.resize();}});resizeObserver.observe(chartContainer.value);}};//规整步长算法functiongetNiceStep(s:number){constpowerMath.pow(10,Math.floor(Math.log10(s)));constns/power;if(n1)return1*power;elseif(n2)return2*power;elseif(n5)return5*power;elsereturn10*power;}// 更新图表constupdateChart(){if(!chartInstance)return;constxMinMath.min(...props?.xAxisData||[]);constxMaxMath.max(...props?.xAxisData||[]);consttargetTickNumber10;constrawStep(xMax-xMin)/(targetTickNumber-1);constniceStepgetNiceStep(rawStep);// 改动一维y数组 → 转为二维[x,y]坐标数组consttransformSeriesprops.seriesData?.map((item){constxyData:[number,number][][];item.data?.forEach((yVal,idx){constxValNumber(props.xAxisData[idx]);xyData.push([xVal,yVal]);});return{...item,data:xyData,};});constoption{title:{text:props.title,left:center,},animation:false,tooltip:{trigger:axis,borderRadius:8,backgroundColor:rgba(255, 255, 255, 0.4),borderColor:#C0C4D1,formatter:function(params:any[]){if(props.tooltipFormatter){returnprops.tooltipFormatter(params,props);}if(paramsparams.length0){letresult;params.forEach((param){result${props.yAxisName}${param.data[1]}br/;});result${props.xAxisName}${params[0].data[0]}br/;returnresult;}return;},},legend:{data:props?.seriesData?.map((item)item?.name||),...props.legendPosition,top:...props?.top,icon:props.legendIcon,itemHeight:5,type:scroll,width:80%,},grid:{...props.gridPosition,},xAxis:{type:value,name:props.xAxisName,min:xMin,max:xMax,interval:niceStep,axisLabel:{show:true,color:#06152B,fontSize:14,},axisTick:{show:true,alignWithLabel:true,length:6,lineStyle:{color:#06152B,width:1,},},axisLine:{symbol:[none,arrow],// 终点箭头symbolSize:[10,8],lineStyle:{color:#bdc0c8,width:1,},},nameTextStyle:{color:#06152B,fontSize:14,},},yAxis:{type:value,name:props.yAxisName,scale:true,// y轴开启脱离0值比例splitLine:{show:true,lineStyle:{type:dashed,},},axisTick:{show:true,inside:false,length:6,lineStyle:{color:#06152B,width:1,},},axisLabel:{show:true,color:#06152B,fontSize:14,},axisLine:{show:true,symbol:[none,arrow],// 终点箭头symbolSize:[10,8],lineStyle:{color:#bdc0c8,width:1,},},nameTextStyle:{show:true,color:#06152B,fontSize:14,},},color:props.colors,series:transformSeries?.map((item,index){constseriesItem{name:item?.name||系列${index1},type:item?.type||props.chartType,data:item.data,showSymbol:item?.showSymbol!undefined?item?.showSymbol:true,symbol:item?.symbol||circle,symbolSize:item?.symbolSize||8,smooth:item?.smooth||true,lineStyle:{width:3,},emphasis:{itemStyle:{color:#11C863,borderColor:#11C863,},},...item,};if(item.markLine){seriesItem.markLineitem.markLine;}returnseriesItem;}),};chartInstance.setOption(option,true);};consthandleResize(){if(chartInstance){chartInstance.resize();}};watch([()props.xAxisData,()props.seriesData,()props.title],(){nextTick((){updateChart();});});onMounted((){initChart();window.addEventListener(resize,handleResize);});onUnmounted((){window.removeEventListener(resize,handleResize);if(resizeObserverchartContainer.value){resizeObserver.unobserve(chartContainer.value);resizeObservernull;}if(chartInstance){chartInstance.dispose();chartInstancenull;}});/scriptstyle scoped.chart-container{width:100%;height:v-bind(height);}/style完整封装了一个简单的echarts组件。可供参考敲重点了主要修改echarts属性y轴脱离0比例尺scale:truex轴属性修改type:value,name:props.xAxisName,min:xMin,max:xMax,interval:niceStep,axisLabel:{show:true,color:#06152B,fontSize:14,},x坐标轴根据最大最小动态调整比例尺步长并且得把一维数组转成[xy]二维数组的方法constxMinMath.min(...props?.xAxisData||[]);constxMaxMath.max(...props?.xAxisData||[]);consttargetTickNumber10;constrawStep(xMax-xMin)/(targetTickNumber-1);constniceStepgetNiceStep(rawStep);// 改动一维y数组 → 转为二维[x,y]坐标数组consttransformSeriesprops.seriesData?.map((item){constxyData:[number,number][][];item.data?.forEach((yVal,idx){constxValNumber(props.xAxisData[idx]);xyData.push([xVal,yVal]);});return{...item,data:xyData,};});ok 现在看一下改动后的效果喽是不是很直观了完全满足科研人员对作图的这种执念要求