• 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根据两点坐标计算出移动图标的斜度、以及移动的方向等,更为影响的展示。

  • 相关阅读:
    Git学习笔记
    排序篇
    c++面试(二)
    c++面试(一)
    maven在mac上的入门使用
    win7系统下安装centos6.6
    Centos6.6下安装oracle 11g教程
    TCP连接的三次握手和四次解散过程
    IP地址划分
    PriorityQueue优先队列用法入门
  • 原文地址:https://www.cnblogs.com/cqhaibin/p/10786886.html
Copyright © 2020-2023  润新知