欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

OpenLayer实现路径运动

程序员文章站 2022-12-23 08:18:51
近期由于业务的需求,让我这从未想过要碰Web Gis的业余前端开发者,走了Web Gis的开发道路。功能需求很简单,但却也是让自己难为了好几天。如,应该选择那个Gis框架,Gis框架的兼容性如何,直接Ie哪些版,能不能简单到只有一张图片就行解决问题,等等。。。。。。 在如此多的技术盲点,以及不确定的 ......

     近期由于业务的需求,让我这从未想过要碰web gis的业余前端开发者,走了web gis的开发道路。功能需求很简单,但却也是让自己难为了好几天。如,应该选择那个gis框架,gis框架的兼容性如何,直接ie哪些版,能不能简单到只有一张图片就行解决问题,等等。。。。。。

在如此多的技术盲点,以及不确定的因素,我开始了征程,现将一些心得做些记录。

一、需求分析

     客户需要的功能就是能在一张gis图上实现小车根据路径进行移动,为什么一定要gis呢(这是客户指定需求,无语一该)。并且客户还说底图要很容易更换,但他想要用gis表现的却是室内的地理信息,我也没办法用baidu, 高德等现成的gis接口。

针对上述需求,我没有去了解过多的web gis框架。因为客户对gis的概念就是能放大,缩小,可以做路径规划等。所以我就选择ol,利用他的静态图片(选择这个是为满足客户灵活更新底图的需求)做gis底图的功能来解决此问题。

二、效果展示

OpenLayer实现路径运动

三、伪代码实现

由于是技术验证代码, 有些杂乱,现只给出关键性代码。如有业务需要欢迎共同讨论。

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