OpenLayer实现路径运动
近期由于业务的需求,让我这从未想过要碰web gis的业余前端开发者,走了web gis的开发道路。功能需求很简单,但却也是让自己难为了好几天。如,应该选择那个gis框架,gis框架的兼容性如何,直接ie哪些版,能不能简单到只有一张图片就行解决问题,等等。。。。。。
在如此多的技术盲点,以及不确定的因素,我开始了征程,现将一些心得做些记录。
一、需求分析
客户需要的功能就是能在一张gis图上实现小车根据路径进行移动,为什么一定要gis呢(这是客户指定需求,无语一该)。并且客户还说底图要很容易更换,但他想要用gis表现的却是室内的地理信息,我也没办法用baidu, 高德等现成的gis接口。
针对上述需求,我没有去了解过多的web gis框架。因为客户对gis的概念就是能放大,缩小,可以做路径规划等。所以我就选择ol,利用他的静态图片(选择这个是为满足客户灵活更新底图的需求)做gis底图的功能来解决此问题。
二、效果展示
三、伪代码实现
由于是技术验证代码, 有些杂乱,现只给出关键性代码。如有业务需要欢迎共同讨论。
3.1 实现路径的绘制
此步骤还是相对简单的,主要用到ol的draw对象,代码哪下:
draw(type){ this.stopdraw(); this._draw = new draw({ source: this.layer.getsource(), type: type == 'icon' ? 'point' : type }); this._draw.on('drawend', (event)=>{ if(type == 'linestring'){ this.traceline = event.feature; } if(type != 'icon') return; let f = event.feature; f.setstyle(new style({ image: new icon({ src: '/content/battery.gif' }), text: new text({ text: 'new item', fill: new fill({ color: "red" }) }) })); f.type = 'battery'; }); this.map.addinteraction(this._draw); this._snap = new snap({source: this.layer.getsource()}); this.map.addinteraction(this._snap); }
关键代码在于drawend事件的监听,如果是linestring情况,就将此feature放在一个共公变量,方便路径运行时使用。
3.2 分解路径数据
此部分就是获取到3.1步骤的路径路径,然后进行解析,因为3.1上的linestring是多个线段的集合,但运动其本质就是改变图标的坐标,使其快速且连续的变化就形成了移动效果。所以这里有一个方法进行路径细分,代码如下:
cuttrace(){ let tracecroods = this.traceline.getgeometry().getcoordinates(); let len = tracecroods.length; let destcroods = []; for(let i = 0; i < len - 1; ++i){ let bpoint = tracecroods[i]; let epoint = tracecroods[i+1]; let bevelling = math.sqrt(math.pow(epoint[0] - bpoint[0], 2) + math.pow(epoint[1] - bpoint[1], 2) ); let cosa = (epoint[0] - bpoint[0]) / bevelling; let sina = (epoint[1] - bpoint[1]) / bevelling; let curstep = 0; let step = 5; destcroods.push(new point([bpoint[0], bpoint[1]])); do{ curstep++; let nextpoint; if(curstep * step >= bevelling){ nextpoint = new point([epoint[0], epoint[1]]); }else{ nextpoint = new point([ cosa * curstep * step + bpoint[0] , sina * curstep * step + bpoint[1] ]); } destcroods.push(nextpoint); }while(curstep * step < bevelling); } return destcroods; }
其中用到了一些数学上的三角函数和计算方法。此方法最终选一个根据步长计算后的坐标集合。
3.3 利用postcompose实现运动效果
代码如下:
tracerun(){ if(!this.traceline) return; this.tracecroods = this.cuttrace(); this.now = new date().gettime(); this.map.on('postcompose', this.movefeature.bind(this)); this.map.render(); } movefeature(event){ let vcxt = event.vectorcontext; let fstate = event.framestate; let elapsedtime = fstate.time - this.now; let index = math.round(300 * elapsedtime / 1000); let len = this.tracecroods.length; if(index >= len){ //stop this.map.un('postcompose', this.movefeature); return; } let dx, dy, rotation; if(this.tracecroods[index] && this.tracecroods[index + 1]){ let isrigth = false; let bcrood = this.tracecroods[index].getcoordinates(); let ecrood = this.tracecroods[index + 1].getcoordinates(); if(bcrood[0] < ecrood[0]){ //左->右 isrigth = true } dx = bcrood[0] - ecrood[0]; dy = bcrood[1] - ecrood[1]; rotation = math.atan2(dy,dx); if(rotation > (math.pi / 2)){ //修正 rotation = math.pi - rotation; }else if(rotation < -1 * (math.pi / 2)){ rotation = -1 * math.pi - rotation; }else{ rotation = -rotation; } console.log(dx + ' ' + dy + ' ' + rotation); let curpoint = this.tracecroods[index]; var anchor = new feature(curpoint); let style = new style({ image: new icon({ img: isrigth ? this.carright : this.carimg, imgsize: [32,32], rotatewithview: false, rotation: rotation }), text: new text({ text: 'car', fill: new fill({ color: 'red' }), offsety: -20 }) }); vcxt.drawfeature(anchor, style); //this.map.getview().setcenter(bcrood); } this.map.render(); }
此移动代码的是用ol的postcompose事件进行实现的,因为render方法执行完成后会触发postcompose事件,所以就代替了定时器的的实现方案。其中rotation根据两点坐标计算出移动图标的斜度、以及移动的方向等,更为影响的展示。
上一篇: rem布局完成响应式开发,通俗且详细的原理解析和代码实现
下一篇: Golang随机数生成