Selaa lähdekoodia

分组曲线增加时间轴缩放、滚动组件,曲线数据联动加载

chenwen 1 vuosi sitten
vanhempi
commit
14cd6ec4bf

+ 8 - 0
src/components/groupCurve/GroupCurve.vue

@@ -36,6 +36,8 @@
 	
 	import {ElMessage} from 'element-plus'
 	
+	import utils from './lib/utils'
+	
 	const dialogModel=reactive({
 		show:false,
 		dateRange:null
@@ -80,7 +82,13 @@
 		zrbox=document.querySelector('.zr-app').getBoundingClientRect()
 	}
 	
+	//对父宿主开放的接口
 	const drawMain=(st,et)=>{
+		if(st==null || et==null){
+			let nowstr=utils.dateFmt(new Date(),'yyyy-MM-dd')
+			st=new Date(Date.parse(nowstr+" 00:00:00"))
+			et=new Date(Date.parse(nowstr+" 23:59:59"))
+		}
 		groupCurve.drawMain(st,et)
 	}
 	

+ 27 - 12
src/components/groupCurve/lib/groupCurve.js

@@ -1,7 +1,7 @@
 import { getLineHeight } from "zrender/lib/contain/text";
 import * as echarts from 'echarts'
 import * as zrender from 'zrender'
-import { TimePanel } from './timePanel'
+import { TimePanel } from './timePanel-zoom'
 import { CurvePanel } from './curvePanel'
 import drawUtils from "./drawUtils"
 import utils from './utils'
@@ -42,15 +42,15 @@ GroupCurve.prototype={
 	},
 	build(templates){
 		
-		let {panelWidth:width,headerH,panels:panelTemp}=templates
-		let grpGap=10,start=120+grpGap  //120是timePanel的固定宽
+		let {panelWidth:width,headerH,panels:panelTemp,timePanel:timePanelConfig}=templates
+		let grpGap=10,start=140+grpGap  //140是timePanel的固定宽
 		
 		//有效设置容器大小,否则图形渲染后再reszie容器无效
 		document.getElementById(this.containerId).parentNode.style.width=`${start+grpGap+panelTemp.length*(width+grpGap)}px`
 		this.resize()
 		
 		//时间面板
-		let panelLayout={width,height:this.zr.getHeight(),headerH}
+		let panelLayout={width,height:this.zr.getHeight(),headerH,subScaleCount:timePanelConfig.subScaleCount}
 		let dispobj=new TimePanel(this,panelLayout)
 		//dispobj.draw(startTime)
 		this.addChild(dispobj)
@@ -138,11 +138,13 @@ GroupCurve.prototype={
 			}
 		})
 		
-		this.container.add(tool)
+		//this.container.add(tool)
 	},
 	
 	
 	async drawMain(arg1,arg2){
+		//增加了滚动,缩放,暂时取消巡查模式,就是历时查询
+		/*
 		let mode=(arg1 instanceof Date)?'his':'patrol'
 		this.mode=mode
 		console.log('curve mode:',mode)
@@ -171,17 +173,30 @@ GroupCurve.prototype={
 			this.drawTimePanel(arg1,arg2)
 			this.groupLoad(arg1,arg2,false,{showTip:true,showMask:true})
 		}
-		
-		
+		*/
+		if(this.timer){
+			clearInterval(this.timer)
+		}
+		/*
+		let {loadStart,loadEnd}=this.drawTimePanel(arg1,arg2)
+		this.groupLoad(loadStart,loadEnd,false,{showTip:true,showMask:true})
+		*/
+	    this.drawTimePanel(arg1,arg2)
 	},
 	
 	/**
-	 * 绘制时间面板
-	 * @param {Object} startTime
-	 * @param {Object} endTime
+	 * 绘制时间面板(绘制完后会回调groupLoad重新加载数据)
+	 * @param {Object} st
+	 * @param {Object} et
 	 */
-	drawTimePanel(startTime,endTime){
-		this.timePanel.draw(startTime,endTime)
+	drawTimePanel(st,et){
+		this.timePanel.draw(st,et)
+		/*
+		let {startTime,endTime}=this.timePanel.axisConfig
+		//时间面板的缩放组件重绘后,刻度轴时间范围(即数据加载时间范围)要更新
+		
+		return {loadStart:new Date(startTime),loadEnd:new Date(endTime)}
+		*/
 	},
 	
 	/**

+ 412 - 0
src/components/groupCurve/lib/timePanel-zoom.js

@@ -0,0 +1,412 @@
+import * as zrender from 'zrender'
+import utils from './utils'
+import drawUtils from './drawUtils'
+
+function TimePanel(parent,temp){
+	this.parent=parent
+	this.self=null
+	this.plotGrp=null
+	this.config=Object.assign({},temp,{width:140,paddingRight:10})
+	this.origin=null
+	this.axisEnd=null
+	this.axisConfig=null
+	this.zoomComp=null
+	this.init()
+}
+
+TimePanel.prototype={
+	
+	init(){
+		
+		
+		this.origin={
+			x:this.config.width-this.config.paddingRight,
+			y:this.config.headerH
+		}
+		this.axisEnd={
+			x:this.origin.x,
+			y:this.config.height
+		}
+		
+		this.self = new zrender.Group()
+		
+		let bgpanel = new zrender.Rect({
+			shape:{
+				x:0,
+				y:0,
+				width:this.config.width,
+				height:this.config.height
+				
+			},
+			style: {
+			  fill: 'transparent', // 填充颜色,默认#000
+			  stroke: '#fff', // 描边颜色,默认null
+			  lineWidth: 1 ,// 线宽, 默认1
+			}
+		})
+		
+		//bgpanel 背景面板:可设置背景色,感应鼠标事件
+		this.self.add(bgpanel)
+		
+		//图形容器
+		this.plotGrp = new zrender.Group()
+		this.self.add(this.plotGrp)
+		
+		//datazoom
+		this.drawDataZoom()
+	},
+	
+	clearPlot(){
+		if(this.plotGrp){
+			this.plotGrp.removeAll()
+		}
+	},
+	
+	draw(startTime,endTime){
+		//this.clearPlot()
+		//this.buildAxisConfig(startTime,endTime)
+		//this.drawAxis()
+		this.zoomComp['config'].startTime=startTime
+		this.zoomComp['config'].endTime=endTime
+		
+		this.drawPanel()
+	},
+	
+	drawPanel(){
+		let {startTime,endTime,start,end}=this.zoomComp['config']
+		let diff=utils.dateDiff(endTime.getTime(),startTime.getTime())
+		//console.log(utils.dateAdd(startTime,null,diff*start))
+		this.clearPlot()
+		this.buildAxisConfig(utils.dateAdd(startTime,null,diff*start),utils.dateAdd(startTime,null,diff*end))
+		this.drawAxis()
+		//通知父组件重新加载数据
+		console.log('通知父组件重新加载数据')
+		let loadStart=new Date(this.axisConfig.startTime),loadEnd=new Date(this.axisConfig.endTime)
+		this.parent.groupLoad(loadStart,loadEnd,false,{showTip:true,showMask:true})
+	},
+	
+	buildAxisConfig(startTime,endTime){
+		
+		let diffMinute=24*60
+		if(endTime){
+			diffMinute=endTime.getTime()-startTime.getTime()
+			diffMinute=diffMinute/60000
+		}
+		let pieceConfig=utils.calcTimeAxis(diffMinute,this.axisEnd.y-this.origin.y)
+		pieceConfig['axisRatio']=pieceConfig.piecePx/pieceConfig.pieceProj
+		pieceConfig['startTime']=startTime.getTime()
+		pieceConfig['endTime']=startTime.getTime()+pieceConfig.pieceProj*pieceConfig.pieceCount*60000
+		this.axisConfig=pieceConfig
+		
+	},
+	
+	drawAxis(){
+		
+		this.plotGrp.add(drawUtils.drawLineSimple(this.origin.x,this.origin.y,this.axisEnd.x,this.axisEnd.y))
+		
+		
+		let scaleTime=new Date(this.axisConfig['startTime'])
+		let pieceConfig=this.axisConfig
+		
+		let scaleLine=null,scaleTxt=null,scaleLen=8,subScaleLen=4
+		let tmpy=this.origin.y
+		
+		let suby=null
+		let subScaleCount=this.config.subScaleCount||5
+		let subdivipix=pieceConfig.piecePx/subScaleCount
+		
+		for(let i=0;i<=pieceConfig.pieceCount;i++){
+			
+			this.plotGrp.add(drawUtils.drawLineSimple(this.origin.x,tmpy,this.origin.x-scaleLen,tmpy))
+			
+			this.plotGrp.add(drawUtils.drawText(utils.dateFmt(scaleTime,'MM-dd HH:mm'),this.origin.x-scaleLen-2,tmpy,i==pieceConfig.pieceCount?'right|bottom':'right|middle'))
+			
+			scaleTime=utils.dateAdd(scaleTime,'minute',pieceConfig.pieceProj)
+			suby=tmpy
+			for(let j=1;j<subScaleCount;j++){
+				suby+=subdivipix
+				this.plotGrp.add(drawUtils.drawLineSimple(this.origin.x,suby,this.origin.x-subScaleLen,suby))
+			}
+			
+			tmpy+=pieceConfig.piecePx
+		}
+		
+		
+		
+	},
+	
+	drawDataZoom(){
+		let zoomWrap=new zrender.Group()
+		this.self.add(zoomWrap)
+		this.zoomComp={zoom:zoomWrap}
+		zoomWrap.setPosition([0,this.origin.y])
+		
+		let zoomH=this.config.height-this.config.headerH
+		let zoomW=40,slideW=40,rollerH=6,rollerW=20,stripW=10,start=0.2,end=0.5
+		let starty=zoomH*start,
+			endy=zoomH*end,
+			slideH=endy-starty,
+			stripH=slideH
+			
+		this.zoomComp['config']={zoomH,zoomW,slideH,slideW,rollerH,rollerW,stripW,stripH,start,end}
+		
+		let slideGroove = new zrender.Rect({
+			shape:{
+				x:0,
+				y:0,
+				width:zoomW,
+				height:zoomH
+				
+			},
+			style: {
+			  fill: '#e2e2e2', // 填充颜色,默认#000
+			  stroke: '#ccc', // 描边颜色,默认null
+			  lineWidth: 1 ,// 线宽, 默认1
+			}
+		})
+		
+		zoomWrap.add(slideGroove) //滑槽
+		
+		let slideBlock=new zrender.Group()
+		zoomWrap.add(slideBlock)
+		slideBlock.setPosition([0,starty])
+		this.zoomComp['slideBlock']=slideBlock
+		
+		let blockFloor=new zrender.Rect({
+			shape:{
+				x:0,
+				y:0,
+				width:slideW,
+				height:slideH
+				
+			},
+			style: {
+			  fill: '#d3f0ff', // 填充颜色,默认#000
+			  stroke: '#00aaff', // 描边颜色,默认null
+			  lineWidth: 1 ,// 线宽, 默认1
+			},
+			cursor:'crosshair'
+		})
+		
+		slideBlock.add(blockFloor)  //滑块底层
+		this.zoomComp['blockFloor']=blockFloor
+		
+		let upRoller=new zrender.Rect({
+			shape:{
+				x:(slideW-rollerW)/2,
+				y:-rollerH/2,
+				width:rollerW,
+				height:rollerH
+				
+			},
+			style: {
+			  fill: '#d3f0ff', // 填充颜色,默认#000
+			  stroke: '#00aaff', // 描边颜色,默认null
+			  lineWidth: 1 ,// 线宽, 默认1
+			},
+			cursor:'s-resize'
+		})
+		
+		
+		
+		slideBlock.add(upRoller) //上滚轮
+		this.zoomComp['upRoller']=upRoller
+		
+		let downRoller=new zrender.Rect({
+			shape:{
+				x:(slideW-rollerW)/2,
+				y:slideH-rollerH/2,
+				width:rollerW,
+				height:rollerH
+				
+			},
+			style: {
+			  fill: '#d3f0ff', // 填充颜色,默认#000
+			  stroke: '#00aaff', // 描边颜色,默认null
+			  lineWidth: 1 ,// 线宽, 默认1
+			},
+			cursor:'n-resize'
+		})
+		
+		slideBlock.add(downRoller) //下滚轮
+		this.zoomComp['downRoller']=downRoller
+		
+		let slideStrip=new zrender.Rect({
+			shape:{
+				x:slideW,
+				y:0,
+				width:stripW,
+				height:stripH
+				
+			},
+			style: {
+			  fill: '#e6e6e6', // 填充颜色,默认#000
+			  stroke: '#d6d0d3', // 描边颜色,默认null
+			  lineWidth: 1 ,// 线宽, 默认1
+			},
+			cursor:'ns-resize'
+		})
+		
+		slideBlock.add(slideStrip) //滑条
+		this.zoomComp['slideStrip']=slideStrip
+		
+		
+		let selRect=new zrender.Rect({
+			shape:{
+				x:0,
+				y:0,
+				width:slideW,
+				height:1
+				
+			},
+			style: {
+			  fill: 'rgba(5,230,136,0.3)', // 填充颜色,默认#000
+			  stroke: '#d6d0d3', // 描边颜色,默认null
+			  lineWidth: 1 ,// 线宽, 默认1
+			},
+			cursor:'ns-resize'
+		})
+		selRect.hide()
+		slideBlock.add(selRect) //拖选框
+		this.zoomComp['selRect']=selRect
+		
+		
+		let msy=null,ry=null,dwnry=null,slidey=null,posy=null
+		//直接移动下滚轮,再调整滑块高度
+		downRoller.on('mousedown',(event)=>{
+			ry=upRoller.shape.y
+			dwnry=downRoller.shape.y
+			msy=event.offsetY
+			
+			this.onEvent('mousemove',[downRoller,blockFloor,slideGroove],(event)=>{
+				let mvh=event.offsetY-msy
+				posy=dwnry+mvh
+				if(posy>this.zoomComp['config'].zoomH){ //超过下底边(?)
+					posy=this.zoomComp['config'].zoomH
+				}
+				else if((posy-ry)<8){ //缩放过大(防止缩放没了)
+					posy=ry+8
+				}
+				
+				downRoller.setShape('y',posy)
+				this.resizeZoom()
+			})
+		})
+		
+		//先整体下移,再恢复下滚轮的相对滑槽的位置,最后调整滑块高度
+		upRoller.on('mousedown',(event)=>{
+			ry=upRoller.shape.y
+			dwnry=downRoller.shape.y
+			msy=event.offsetY
+			slidey=(this.zoomComp['slideBlock']).position[1]
+			this.onEvent('mousemove',[upRoller,blockFloor,slideGroove],(event)=>{
+				let mvh=event.offsetY-msy
+				let nslidey=slidey+mvh
+				if(nslidey<0){ //超过滑槽顶边
+					nslidey=0
+					mvh=-slidey
+				}
+				else if(mvh>Math.abs(dwnry-ry)){ //缩放大于滑块高度(防止缩放没了)
+					mvh=Math.abs(dwnry-ry)-8
+				}
+				
+				this.zoomComp['blockFloor'].setShape('y',0) //无实际作用,只为触发下一句的整体移动效果(子元素重定位,整体移动才有效果)
+				this.zoomComp['slideBlock'].setPosition([0,slidey+mvh])
+				
+				downRoller.setShape('y',dwnry-mvh)
+				this.resizeZoom()
+			})
+			
+		})
+		
+		
+		slideStrip.on('mousedown',(event)=>{
+			msy=event.offsetY
+			slidey=(this.zoomComp['slideBlock']).position[1]
+			let blockH=Math.abs(downRoller.shape.y-upRoller.shape.y)
+			this.onEvent('mousemove',[slideStrip,blockFloor,this.plotGrp],(event)=>{
+				
+				let mvh=event.offsetY-msy
+				posy=slidey+mvh
+				if(posy<=0){ // 超过滑槽顶边
+					posy=0
+				}
+				else if((blockH+posy)>this.zoomComp['config'].zoomH){ //超过下底边
+					posy=this.zoomComp['config'].zoomH-blockH
+				}
+				this.zoomComp['blockFloor'].setShape('y',0)
+				this.zoomComp['slideBlock'].setPosition([0,posy])
+			})
+		})
+		
+		/* //目前不需要拖动选择区域
+		blockFloor.on('mousedown',(event)=>{
+			msy=event.offsetY
+			let selStartY=this.toSlideY(msy)
+			selRect.setShape('y',selStartY)
+			selRect.setShape('height',0.5)
+			selRect.show()
+			this.onEvent('mousemove',[blockFloor,selRect],(event)=>{
+				let mvh=Math.abs(event.offsetY-msy)
+				selRect.setShape('height',mvh)
+			})
+			this.onEvent('mouseup',[blockFloor,selRect],(event)=>{
+				selRect.hide()
+			})
+		})*/
+		let plot=this.plotGrp
+		this.onEvent('mouseup',[this.self],(event)=>{
+			
+			upRoller.off('mousemove')
+			downRoller.off('mousemove')
+			blockFloor.off('mousemove')
+			slideGroove.off('mousemove')
+			slideStrip.off('mousemove')
+			//selRect.off('mousemove')
+			plot.off('mousemove')
+			
+			//计算起止位百分比
+			let blockY=(this.zoomComp['slideBlock']).y
+			this.zoomComp['config'].start=blockY/this.zoomComp['config'].zoomH
+			this.zoomComp['config'].end=(blockY+downRoller.shape.y)/this.zoomComp['config'].zoomH
+			
+			
+			
+			//可能会多次触发,要兼容
+			//console.log(event)
+			this.drawPanel()
+		})
+		
+	},
+	
+	resizeZoom(){
+		//console.log(this.zoomComp['blockFloor'].shape)
+		//downRoller为相对定位,使用定位作为滑块新高度,(需要处理Roller/2)
+		
+		let upRoller=this.zoomComp['upRoller'],
+		downRoller=this.zoomComp['downRoller']
+		
+		let newH=Math.abs(downRoller.shape.y-upRoller.shape.y)
+		this.zoomComp['blockFloor'].setShape('height',newH)
+		this.zoomComp['slideStrip'].setShape('height',newH)
+		
+	    
+	},
+	
+	onEvent(eventName,objs,handler){
+		objs.forEach(obj=>{
+			obj.off(eventName)
+			obj.on(eventName,(event)=>{
+				handler(event)
+			})
+		})
+	},
+	
+	toSlideY(y){
+		return y-(this.zoomComp['zoom'].position[1]+this.zoomComp['slideBlock'].position[1])
+	}
+	
+	
+}
+
+export {TimePanel}

+ 2 - 0
src/components/groupCurve/lib/utils.js

@@ -70,6 +70,8 @@ export default {
 			case 'minute':
 			    d.setMinutes(d.getMinutes() + val);
 			    break;
+			default:
+				d.setTime(d.getTime() + val)
 		}
 		
 		return d