Explorar o código

增加功图绘制组件

chenwen %!s(int64=2) %!d(string=hai) anos
pai
achega
fc870159bb

+ 120 - 0
src/components/diagram/Diagram.vue

@@ -0,0 +1,120 @@
+<template>
+	<canvas :id="id"  :width="width" :height="height"/>
+</template>
+
+<script setup>
+	import {reactive,ref,onMounted,onUnmounted,toRaw,watch, nextTick } from 'vue'
+	
+	import {Diagram} from './lib/diagram.js'
+	
+	const props=defineProps({
+		id:{
+			type:String,
+			required:true,
+			default:'canvas1'
+		},
+		width:{
+			type:Number,
+			default:800
+		},
+		height:{
+			type:Number,
+			default:300
+		},
+		data:{
+			type:[Object,Function]
+		},
+		intervalSec:{
+			type:Number,
+			default:30
+		},
+		ctx:{
+			type:Object
+		}
+	})
+	
+	
+	
+	let  diagram=null
+	let  loaderTimer=null
+	
+	const startLoad=async (diagramInst,action)=>{
+		let {wellId,paramCode}=props.ctx
+		diagramInst.showMask(true,'正在加载数据...')
+		try{
+			
+			if(!loaderTimer&&action=='last'&&props.intervalSec>20){
+				loaderTimer=setInterval(()=>{
+					startLoad(diagram)
+				},props.intervalSec*1000)
+			}
+			else if(action=='pre'||action=='next'){
+				if(loaderTimer){
+					clearInterval(loaderTimer)
+					loaderTimer=null
+				}
+			}
+			let smpTime=diagramInst.line?diagramInst.line.smpTime:null
+			let resp=await props.data({wellId,paramCode,action,smpTime})
+			if(resp.code!=0){
+				diagramInst.showMask(true,resp.msg)
+				return
+			}
+			diagramInst.setData(resp.data)
+			diagramInst.showMask(false)
+			
+			
+		}
+		catch(err){
+			console.log(err)
+			diagramInst.showMask(true,'加载数据出错')
+		}
+		
+	}
+	
+	onMounted(()=>{
+		diagram=new Diagram(props.id,{scale:{x:1,y:1}})
+		
+		if(typeof(props.data)=='function'){
+			startLoad(diagram,'last')
+		}
+		else if(typeof(props.data)=='object'){
+			diagram.setData(data)
+		}
+		
+		
+	})
+	
+	onUnmounted(()=>{
+		if(loaderTimer){
+			clearInterval(loaderTimer)
+			loaderTimer=null
+		}
+	})
+	
+	defineExpose({
+		
+		replay:()=>{
+			diagram.replayCurve()
+		},
+		next:()=>{
+			startLoad(diagram,'next')
+		},
+		pre:()=>{
+			startLoad(diagram,'pre')
+		},
+		last:()=>{
+			startLoad(diagram,'last')
+		},
+		setData:(data)=>{
+			diagram.setData(data)
+		},
+		showMask:(showIf,msg)=>{
+			diagram.showMask(showIf,msg)
+		}
+	})
+	
+</script>
+
+<style scoped>
+</style>

+ 334 - 0
src/components/diagram/lib/diagram.js

@@ -0,0 +1,334 @@
+import * as createjs from '@createjs/easeljs'
+import request from '../../../utils/request'
+import Utils from './utils.js'
+import {Text} from './text.js'
+import {Line} from './line.js'
+
+function Diagram(id,opts){
+	this.canvasId=id;
+	this.options=opts;
+	//this.type=null;
+	this.stage=null;
+	this.diagramShape=null;
+	this.curveShape=null;
+	this.mask=null;
+	this.txtBox=null;  //图形中的大部分文本的容器
+	this.toolBox=null;
+	this.padding=opts.padding||[30,160,30,40];
+	this.scale=opts.scale||{x:1,y:1};
+	this.origin=null;
+	this.canvasW=null;
+	this.canvasH=null;
+	this.xAxisLength=null;
+	this.yAxisLength=null;
+	this.xyAxisRatio=2;
+	this.tipText=null;
+	this.xratio=1;
+	this.yratio=1;
+	this.xTitle="位移(m)";
+	this.yTitle="负荷(kN)";
+	this.title="";
+	this.yMin=0;
+	this.yMax=5;
+	this.xMin=0;
+	this.xMax=5;
+	this.yGridCount=5;
+	this.xGridCount=5;
+	this.xPerProj=1;
+	this.yPerProj=null;
+	this.line=null;
+	this.reqParam={};
+	this.timer=null;
+	this.freSec=opts.freSec||10;
+	this.finishTool=false;
+	this.init();
+	
+}
+
+Diagram.prototype={
+	init:function(){
+		var canvasDOM=document.getElementById(this.canvasId);
+		this.canvasW=canvasDOM.width;
+	    this.canvasH=canvasDOM.height;
+	    
+	    //全局设置
+		var me=this;
+		this.stage = new createjs.Stage(this.canvasId);
+		this.stage.enableMouseOver(10); 
+		this.stage.scaleY=this.scale.y;
+		this.stage.scaleX=this.scale.x;
+		createjs.Ticker.addEventListener("tick", function(){
+		 me.stage.update();
+	    });
+	    
+	   
+	    
+	    //创建坐标画布
+	    this.diagramShape= new createjs.Shape();
+	    this.stage.addChild(this.diagramShape);
+	    
+	    //创建曲线画布
+	    this.curveShape= new createjs.Shape();
+	    this.stage.addChild(this.curveShape);
+	    
+	     //创建本文容器
+	    this.txtBox=new  createjs.Container();
+	    this.stage.addChild(this.txtBox);
+	    
+	     //创建工具容器
+	    this.toolBox=new  createjs.Container();
+	    this.stage.addChild(this.toolBox);
+	    
+	    
+	    //创建并初始化 mask and tipText
+	    this.mask= new createjs.Shape();
+		this.stage.addChild(this.mask);
+		this.mask.visible=false;
+		var g=this.mask.graphics;
+		g.beginFill("#cccccc").drawRect(0,0,this.canvasW,this.canvasH);
+		this.mask.alpha=0.6;
+		this.mask.addEventListener("click",function(evn){
+		    	evn.preventDefault();
+		    	evn.stopPropagation();
+		});
+		this.tipText=Text.draw(this.stage,"",this.canvasW/2,this.canvasH/2,"center","middle");
+		this.tipText.visible=false;
+		
+		
+		this.origin={x:this.padding[3],y:this.canvasH-this.padding[2]};
+		this.xAxisLength=this.canvasW-this.padding[1]-this.padding[3];
+		this.yAxisLength=this.canvasH-this.padding[0]-this.padding[2];
+	    
+	    //开启定时器
+	    //this.timer=window.setInterval(function(){me.loadData();},this.freSec*1000);
+	},
+	
+	setData:function(diagramData){ //add 2023.5.26  
+	//{base:{type:,xTitle:,yTitle:,title,xUnit,yUnit,xyAxisRatio,yFixedMin,yFixedMax},serial:{smpTime,xvals,yvals},descTxt}
+		
+		let {type='GT',xTitle='',yTitle='',title='',xyAxisRatio=2,yFixedMin,yFixedMax,xUnit,yUnit}=diagramData.base||{}
+		this.xTitle=xTitle
+		this.yTitle=yTitle
+		this.title=title
+		this.xyAxisRatio=xyAxisRatio	
+		
+		//构建曲线对象
+		let line=new Line({type,xUnit,yUnit,smpTime:diagramData.serial.smpTime});
+		line.setData(diagramData.serial.xvals,diagramData.serial.yvals)
+		this.yMax=yFixedMax!=null?yFixedMax:line.yMax;  //优先使用设置的固定值,后使用计算出的值
+		this.yMin=yFixedMin!=null?yFixedMin:line.yMin;
+		this.xMax=line.xMax;
+		this.xMin=0; //最小位移一般固定为0
+		this.line=line;
+		
+		//修正xMax
+		this.xGridCount=(this.xMax-this.xMin)<10?Math.ceil((this.xMax-this.xMin)/1.0):5; //位移10以下,每1米一格,否则为5格
+		this.xPerProj=Utils.getProjValDevider(this.xMin,this.xMax,this.xGridCount);
+		this.xMax=this.xMin+this.xPerProj*this.xGridCount;
+		
+		//修正yMax,yMin
+		this.yGridCount=5; //y轴默认5分隔
+		this.yPerProj=Utils.getProjValDevider(this.yMin,this.yMax,this.yGridCount);
+		this.yMin=Math.floor(this.yMin/this.yPerProj)*this.yPerProj;
+		var tempMax=this.yMin+this.yGridCount*this.yPerProj;
+		if(tempMax<this.yMax){
+			this.yMax=tempMax+this.yPerProj;
+			this.yGridCount+=1; //增加一格
+		}
+		else{
+			this.yMax=tempMax;
+		}
+		
+		//修正yAxisLength,计算比例尺
+		let yAxistLen=Math.round(this.xAxisLength/this.xyAxisRatio);
+		if(this.yAxisLength>yAxistLen){
+			this.yAxisLength=yAxistLen;
+		}
+		this.xratio=this.xAxisLength/(this.xMax-this.xMin);
+		this.yratio=this.yAxisLength/(this.yMax-this.yMin);
+		this.render(diagramData.descTxt);
+		
+	},
+	
+	
+	render:function(descTxt){
+		this.clearCurve();
+		this.drawCoordinate();
+	   // this.drawTool();
+	    this.drawCurve();
+	    this.drawDesc(descTxt);
+	},
+	
+	clearCurve:function(){
+		if(!this.diagramShape||!this.curveShape){
+			return ;
+		}
+		this.diagramShape.graphics.clear();
+		this.txtBox.removeAllChildren();
+		this.curveShape.graphics.clear();
+	},
+	
+	drawCurve:function(){
+		var points=this.line.datas; //[[1,10.5],[1.5,11.8],[2,15],[2.5,14.2],[2.8,12.2],[3,13.2],[5,11.2]];
+		
+	    var g=this.curveShape.graphics;
+		g.setStrokeStyle(1);
+		g.beginStroke(this.line.colorAry[0]);
+		g.moveTo(this.getX(points[0][0]),this.getY(points[0][1]));
+ 		for(var i=1,len=points.length;i<len;i++){
+			g.lineTo(this.getX(points[i][0]),this.getY(points[i][1]));
+			if(i==this.line.turnIndex){
+				g.beginStroke(this.line.colorAry[1]);
+				g.moveTo(this.getX(points[i][0]),this.getY(points[i][1]));
+			}
+			
+		}
+ 		g.endStroke();
+	},
+	drawCoordinate:function(){
+		var g=this.diagramShape.graphics;
+		var gridColor="#aaaaaa";
+		var axisColor="#000000";
+		//var yZeroDone:Boolean=this.yMinProj>=0;  //0轴是否绘制完
+		
+ 		//x,y axis
+		g.setStrokeStyle(2);
+ 		g.beginStroke(axisColor);
+ 		g.moveTo(this.origin.x,this.origin.y-this.yAxisLength);
+ 		g.lineTo(this.origin.x,this.origin.y)
+ 		g.lineTo(this.origin.x+this.xAxisLength,this.origin.y);
+ 		g.endStroke();
+ 		
+ 		//top right
+ 		g.setStrokeStyle(1);
+ 		g.beginStroke(gridColor);
+ 		g.moveTo(this.origin.x+this.xAxisLength+0.5,this.origin.y);
+ 		g.lineTo(this.origin.x+this.xAxisLength+0.5,this.origin.y-this.yAxisLength-0.5);
+	    g.lineTo(this.origin.x,this.origin.y-this.yAxisLength-0.5);
+	    g.endStroke();
+	    
+	    
+	    
+ 		
+	    //x label
+	    g.setStrokeStyle(2);
+ 		g.beginStroke(axisColor);
+	    var xdividerPix=this.xAxisLength/this.xGridCount;
+	    for(let i=0;i<=this.xGridCount;i++){
+	    	g.moveTo(this.origin.x+i*xdividerPix,this.origin.y);
+	    	g.lineTo(this.origin.x+i*xdividerPix,this.origin.y+10);
+	        Text.draw(this.txtBox,this.xMin+i*this.xPerProj,this.origin.x+i*xdividerPix,this.origin.y+12,"center","top");
+	    }
+	    //y label
+	    var ydividerPix=this.yAxisLength/this.yGridCount;
+	    for(let i=0;i<=this.yGridCount;i++){
+	    	g.moveTo(this.origin.x,this.origin.y-i*ydividerPix);
+	    	g.lineTo(this.origin.x-10,this.origin.y-i*ydividerPix);
+	    	Text.draw(this.txtBox,this.yMin+i*this.yPerProj,this.origin.x-12,this.origin.y-i*ydividerPix,"right","middle");
+	    }
+	    g.endStroke();
+	    
+	     
+	    //x Dash grid
+	    //g.setStrokeDash([20, 10], 0);
+	    g.setStrokeStyle(1);
+	    g.beginStroke(gridColor);
+	    for(let i=1;i<this.xGridCount;i++){
+	    	g.moveTo(this.origin.x+i*xdividerPix-0.5,this.origin.y);
+	    	g.lineTo(this.origin.x+i*xdividerPix-0.5,this.origin.y-this.yAxisLength);
+	    }
+	    //y grid
+	    for(let i=1;i<this.yGridCount;i++){
+	    	g.moveTo(this.origin.x,this.origin.y-i*ydividerPix-0.5);
+	    	g.lineTo(this.origin.x+this.xAxisLength,this.origin.y-i*ydividerPix-0.5);
+	    }
+	    g.endStroke();
+	    
+	    //alert($("#h2").text());
+	   Text.draw(this.txtBox,this.yTitle,this.origin.x,this.origin.y-this.yAxisLength,"left","bottom");
+	   Text.draw(this.txtBox,this.xTitle,this.origin.x+this.xAxisLength,this.origin.y,"right","bottom");
+	   Text.draw(this.txtBox,this.title,this.origin.x+this.xAxisLength/2,this.origin.y-this.yAxisLength-10,"center","bottom");
+	},
+	
+	
+	
+	drawDesc:function(descTxt){
+		 let posy=this.padding[0]-5;
+		 let posx=this.canvasW-this.padding[1]+5;
+		 let labelw=60;
+		 
+		 descTxt=descTxt||[];
+		 descTxt=[...descTxt,...this.line.getDesc()]
+		 
+		 
+		 //Text.draw(this.txtBox,descTxt.shift(),this.canvasW/2,5,"center","top");
+		 let splitlabel=null;
+		 for(let  i=0,len=descTxt.length;i<len;i++){
+		 	 posy+=20;
+			 splitlabel=descTxt[i].split(":")
+		     Text.draw(this.txtBox,splitlabel[0],posx,posy,"left","bottom");
+			 Text.draw(this.txtBox,":"+splitlabel[1],posx+labelw,posy,"left","bottom");
+		 }
+	},
+	
+	replayCurve:function(){
+		
+		var points=[].concat(this.line.datas);
+		var g=this.curveShape.graphics;
+		g.clear();
+		g.setStrokeStyle(1);
+		g.beginStroke(this.line.colorAry[0]);
+		
+		var len=this.line.datas.length-this.line.turnIndex-1;
+		var secColor=this.line.colorAry[1];
+		var ps=points.shift();
+		g.moveTo(this.getX(ps[0]),this.getY(ps[1]));
+		var me=this;
+		var drawfun=function(){
+			var p=points.shift();
+			if(p){
+				g.lineTo(me.getX(p[0]),me.getY(p[1]));
+				if(points.length==len){
+					g.beginStroke(secColor);
+					g.moveTo(me.getX(p[0]),me.getY(p[1]));
+				}
+			    setTimeout(drawfun,500);
+			}
+			else{
+				//alert("over");
+			}
+			
+			
+		}
+		setTimeout(drawfun,500);
+ 		
+	},
+	
+	showMask:function(flag,msg){
+		if(flag){
+			this.mask.visible=true;
+			this.tipText.text=msg;
+			this.tipText.visible=true;
+		}
+		else{
+			this.mask.visible=false;
+			this.tipText.visible=false;
+		}
+		
+	    
+	},
+	
+	getX:function(d){
+		return this.origin.x+(d-this.xMin)*this.xratio;
+		//window.console.log("x:"+ret);
+	
+	},
+		
+	getY:function(d){
+		return  this.origin.y-(d-this.yMin)*this.yratio;
+		//window.console.log("y:"+ret);
+		
+	}
+};
+
+export {Diagram}

+ 157 - 0
src/components/diagram/lib/line.js

@@ -0,0 +1,157 @@
+function Line(opts){
+	opts=opts||{};
+	this.id=null;
+	this.smpTime=opts.smpTime;
+	this.color="#000000";
+	this.title=null;
+	this.weight=1;
+	this.type=opts.type||"GT";
+	this.xUnit=opts.xUnit||"m";
+	this.yUnit=opts.yUnit||"kN";
+	this.xMin=null;
+	this.xMax=null;
+	this.yMin=null;
+	this.yMax=null;
+	this.xProjs=null;
+	this.yProjs=null;
+	this.datas=null;
+	this.yOrigMax=null;
+	this.yOrigMin=null;
+	this.turnX=null;
+	this.turnIndex=null;
+	this.startUp=true;
+	this.upColor="#0000ff";
+	this.downColor="#00ff00";
+	this.colorAry=[];
+	this.yUpMaxProj=null;
+	this.yDownMaxProj=null;
+	this.balance=null;
+	this.stroke=null;
+}
+
+Line.prototype={
+	setData:function(xVals,yVals){
+		this.xProjs=xVals;
+		this.yProjs=yVals;
+		
+		this.yMax=yVals[0];
+		this.yMin=yVals[0];
+		this.xMax=xVals[0];
+		this.xMin=xVals[0];
+		this.datas=[];
+		this.datas.push([xVals[0],yVals[0]]);
+		var upIndex,dwnIndex;
+	    for (var i=1,len=xVals.length,len2=yVals.length;i<len&&i<len2;i++ ) {
+	    	this.datas.push([xVals[i],yVals[i]]);
+	    	if(yVals[i]>this.yMax){
+	    		this.yMax=yVals[i];
+	    	}
+	    	if(yVals[i]<this.yMin){
+	    		this.yMin=yVals[i];
+	    	}
+	    	if(xVals[i]>=this.xMax){  //增加或=,表明停顿区域算入开始方向
+				  this.xMax=xVals[i];
+				  upIndex=i;
+			}
+			if(xVals[i]<=this.xMin){
+			   this.xMin=xVals[i];
+			   dwnIndex=i;
+			}
+	    }
+	    
+	    //闭合曲线
+	    this.datas.push([xVals[0],yVals[0]]);
+	    
+	    this.stroke=Math.round((this.xMax- this.xMin) * 100) / 100;
+	    var tempStroke=Math.floor(this.stroke);
+	    if(this.stroke-tempStroke<0.05){
+		      this.stroke=tempStroke;
+	    }
+	    
+	     var tempXMax=Math.floor(this.xMax);
+	     this.xMax= (this.xMax- tempXMax) >= 0.05?this.xMaxProj:tempXMax;
+		 this.yOrigMax=this.yMax;
+		 this.yOrigMin=this.yMin;
+		 this.parseUpDwnMax(upIndex,dwnIndex);
+		 this.countBalance();
+	},
+	
+	parseUpDwnMax:function(upIdx,dwnIdx){
+		
+		 this.startUp = (this.xMax- this.xProjs[0]) > (this.xProjs[0] - this.xMin);
+		 if (this.startUp) {
+			 this.colorAry=[this.upColor,this.downColor];
+		 }
+		 else {
+			 this.colorAry=[this.downColor,this.upColor]; 
+		 }
+		 this.turnIndex=this.startUp?upIdx:dwnIdx;
+		 
+		 if(this.type=="GT"){
+			    return;	
+		 }
+		 var tempMax1=-1000;
+		 var tempMax2=-1000;
+		 for(var i=0,len=this.xProjs.length,len2=this.yProjs.length;i<len&&i<len2;i++){
+			 if(i<=this.turnIndex){
+				 tempMax1=tempMax1<this.yProjs[i]?this.yProjs[i]:tempMax1;
+			 }
+			 else{
+				 tempMax2=tempMax2<this.yProjs[i]?this.yProjs[i]:tempMax2;
+			 }
+			 
+		 }
+		 this.yUpMaxProj=this.startUp?tempMax1:tempMax2;
+		 this.yDownMaxProj=this.startUp?tempMax2:tempMax1;
+		 
+	},
+	
+	getDesc:function(){  //曲线描述文本,其它文本由外部传入
+		var txt=[];
+		
+		txt.push("冲程:"+this.stroke+this.xUnit)
+		if(this.type=="GT"){
+			txt.push("最大载荷:"+this.yMax+this.yUnit);
+			txt.push("最小载荷:"+this.yMin+this.yUnit);
+		}
+		else{
+			txt.push("上行最大:"+this.yUpMaxProj+this.yUnit);
+			txt.push("下行最大:"+this.yDownMaxProj+this.yUnit);
+			txt.push("平衡度:"+this.balance);
+		}
+		
+		return txt;
+	},
+	    
+		countBalance:function(){  //计算平衡度,默认是不计算值为0
+			this.balance=0;
+			if(this.type=="DL"){  //电流曲线平衡度计算
+				this.balance=Math.round(this.yUpMaxProj*100*100/this.yDownMaxProj)/100;  //带两位小数
+			}
+			else if(this.type=="DGL"){  //功率曲线平衡度计算
+				var  sumArea1=0;
+			    var  sumArea2=0;
+				var i;
+				var h;
+				var tempSum;
+				for(i=0;i<this.xProjs.length-1&&i<this.yProjs.length-1;i++){
+					h=Math.abs(this.xProjs[i+1]-this.xProjs[i]);
+					tempSum=(this.yProjs[i+1]+this.yProjs[i])*h/2;
+					if((i+1)<=this.turnIndex){
+						sumArea1+=tempSum;
+					}
+					else{
+						sumArea2+=tempSum;
+					}
+				}
+				
+				this.balance=this.startUp?(sumArea1/sumArea2):(sumArea2/sumArea1);
+				this.balance=Math.round(this.balance*100*100)/100;
+			}
+			
+			
+			
+		}
+};
+
+export {Line}

+ 17 - 0
src/components/diagram/lib/text.js

@@ -0,0 +1,17 @@
+import * as createjs from '@createjs/easeljs'
+
+const Text={
+	draw(stage,txt,x,y,align,valign,font,color){
+			font=font||"14px Arial";
+			color=color||"#000000";
+			var text = new createjs.Text(txt, font,color);
+		    text.x = x;
+		    text.y=y;
+		    text.textAlign=align||"start";
+		    text.textBaseline=valign||"middle";
+		    stage.addChild(text);
+		    return text;
+	}
+}
+
+export {Text}

+ 59 - 0
src/components/diagram/lib/utils.js

@@ -0,0 +1,59 @@
+export default {
+	compareDate:function(d1,d2){
+		return d1.getTime()-d2.getTime();
+	},
+	roundHour:function(date,add){
+		add=add||0;
+		var h=Math.floor(date/(1000*60*60));
+		return (h+add)*1000*60*60;
+	},
+	diffDate:function(d1,d2,tag){
+		tag=tag||"HH";
+		var diff=d1-d2;
+		if(tag=="HH"){
+			return diff/(1000*60*60);
+		}
+		else if(tag=="mm"){
+			return diff/(1000*60);
+		}
+	},
+	parseDate:function(str){
+		str=str.replace(/-/g,"/");
+		return new Date(str);
+	},
+	format:function(millis,fmt){
+		fmt=fmt||"MM.dd HH:00";
+		var date=new Date(millis);
+		if(fmt=="MM.dd HH:00"){
+			return (date.getMonth()+1)+"."+date.getDate()+" "+date.getHours()+":00";
+		}
+		if(fmt=="MM.dd HH:mm"){
+			return (date.getMonth()+1)+"."+date.getDate()+" "+date.getHours()+":"+date.getMinutes();
+		}
+		if(fmt=="MM.dd HH:mm:ss"){
+			return (date.getMonth()+1)+"."+date.getDate()+" "+date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
+		}
+		return null;
+	},
+	getProjValDevider:function(minVal,maxVal,count){
+		var opts=[0.1,0.2,0.5,1,2,3,4,5,10,15,20,25,30,35,40,45,50];
+		var devider=(maxVal-minVal)/count;
+		if(devider>50){
+			return Math.ceil(devider/50)*50;
+		}
+		else{
+			var idx=this.search(devider,opts);
+			return opts[idx];
+		}
+	},
+	  
+	search:function(item,ary){
+		for (var i= 0, len= ary.length; i < len; i++) {
+				if (ary[i]>=item) {
+					return i;
+				}
+			}
+			return ary.length - 1;	
+	}
+	
+}