Openlayers 实现轨迹播放/暂停/重新播放/从点击处播放/提速/减速

说明:

我的需求是需要实现轨迹播放/暂停/重新播放/从点击处播放,因此封装了一个类

解决方案:

1、初始化:主要是处理一下图层以及数据,通过插值构造一个全局数组

    /**
     * @description 初始化轨迹
     */
    (function init() {
        //地图容器
        that._map = _map;
        //轨迹线图层
        that._animationLineLayer = animationLineLayer;
        //轨迹点图层
        that._animationPointLayer = animationPointLayer;
        //轨迹样式
        that._strokestyle = strokestyle;
        //轨迹样式
        that._Iconstyle = Iconstyle;
        //轨迹点集(带插值)
        that._pointArray = [];
        //轨迹点集(不带插值)
        that._linePatrolArray = linePatrolArray;

        //设置图层id
        animationLineLayer.set('layerId', 'animationLineLayer');
        animationPointLayer.set('layerId', 'animationPointLayer');
        //没有传坐标点过来就返回
        if (linePatrolArray.length == 0) return;
        //如果连续定时器没有清空,则清空定时器
        clearInterval(this.timer);
        //移除路径图层
        if (_map.findLayerByID("animationLineLayer") != null) {
            _map.encmap.removeLayer(_map.findLayerByID("animationLineLayer"));
        }
        //移除动画点的图层
        if (_map.findLayerByID("animationPointLayer") != null) {
            _map.encmap.removeLayer(_map.findLayerByID("animationPointLayer"));
        }

        //记录插值后的所有轨迹点,给pointArray
        for (var i = 0; i < linePatrolArray.length - 1; i++) {
            interpolation(linePatrolArray[i], linePatrolArray[i + 1]);
        }

        var curentLineLayer = _map.findLayerByID("animationLineLayer");
        var curentPointLayer = _map.findLayerByID("animationPointLayer");

        //如果此时map对象中有路径animationLineLayer图层
        if (curentLineLayer != null) {
            //如果此时路径animationLineLayer图层没有清空,清空里面的内容
            if (curentLineLayer.getSource() != null) {
                curentLineLayer.getSource().clear();
            }
        } else {
            //如果此时map对象中没有路径图层,添加路径animationLineLayer图层
            _map.encmap.addLayer(animationLineLayer);
        }
        //如果此时map对象中有移动动画点animationPointLayer图层
        if (curentPointLayer != null) {
            if (curentPointLayer.getSource() != null) {
                //清空动画点animationPointLayer图层的内容
                curentPointLayer.getSource().clear();
            }
        } else {
            //如果此时map对象中没有移动点图层,添加移动点animationPointLayer图层
            _map.encmap.addLayer(animationPointLayer);
        }

        //注册点击查询事件,点击暂停/从此播放
        let selecthover = new ol.interaction.Select({
            condition: ol.events.condition.click,
            layers: [animationLineLayer]
        });
        selecthover.set("arrPoints", that._pointArray);
        // selecthover.set("tmpPoints", that._pointArray);
        selecthover.set("_strokestyle", that._strokestyle);
        selecthover.set("_Iconstyle", that._Iconstyle);
        selecthover.set("_animationLineLayer", that._animationLineLayer);
        selecthover.set("_animationPointLayer", that._animationPointLayer);
        _map.encmap.addInteraction(selecthover);
        var me = that;
        //查询结果
        selecthover.on("select", function (evt) {
            if (evt.selected[0] == null) return;
            //取消选中要素高亮
            this.getFeatures().clear();
            //暂停/继续
            //isRun = !isRun;
            // console.log(replayIndex);

            //从点击处开始播放
            isRun = true;
            replayIndex = evt.selected[0].get("arrIndex");

            var tmpPointsArray = this.getProperties()["arrPoints"];
            var tmpPoints = this.getProperties()["tmpPoints"];
            var _strokestyle = this.getProperties()["_strokestyle"];
            var _Iconstyle = this.getProperties()["_Iconstyle"];
            var _animationLineLayer = this.getProperties()["_animationLineLayer"];
            var _animationPointLayer = this.getProperties()["_animationPointLayer"];

            //保留走完的线
            _animationLineLayer.getSource().clear();
            // tmpPointsArray.filter(e => e <= replayIndex);
            var pts = [];
            pts.push(tmpPointsArray);
            pts = pts[0];

            for (var m = 0; m <= replayIndex - 1; m++) {
                //创建轨迹线
                var line = new ol.Feature({
                    geometry: new ol.geom.LineString([pts[m], pts[m + 1]])
                });
                line.set("arrIndex", m);
                // //设置线的样式
                line.setStyle(_strokestyle);
                _animationLineLayer.getSource().addFeature(line);
            }

            //添加点击点
            var clickPt = new ol.Feature({
                geometry: new ol.geom.Point(tmpPointsArray[replayIndex])
            });
            clickPt.setStyle(_Iconstyle);
            _animationPointLayer.getSource().clear();
            _animationPointLayer.getSource().addFeature(clickPt);
        });
    })();

2、播放方法:首先跳转到轨迹范围;新建一个timer定时器,并控制播放完所有轨迹点后清除定时器;用lineString函数传入首尾坐标,完成绘线。

    //动画播放
    this.play = function (_speed) {
        //var me = this;
        //定位到轨迹范围
        var featureExtent = new ol.Feature({
            geometry: new ol.geom.LineString(that._linePatrolArray)
        });
        that._map.encmap.getView().fit(featureExtent.getGeometry().getExtent());

        //如果连续定时器没有清空,则清空定时器
        if (this.timer != null) {
            clearInterval(this.timer);
            if (that._animationLineLayer.getSource() != null) {
                that._animationLineLayer.getSource().clear();
            }
            if (that._animationPointLayer.getSource() != null) {
                that._animationPointLayer.getSource().clear();
            }
        }

        //播放速度
        that.speed = _speed;
        //计时器默认40ms
        if (!that.speed) {
            that.speed = 40;
        }
        replayIndex = 0;
        this.timer = setInterval(function () {
            console.log(that.timer);
            //暂停
            if (!isRun) {
                return;
            }
            //播放完成,停止定时器
            if (replayIndex > that._pointArray.length - 2) {
                clearInterval(that.timer);
                return;
            }
            //创建轨迹线
            var line = new ol.Feature({
                geometry: new ol.geom.LineString([that._pointArray[replayIndex], that._pointArray[++replayIndex]])
            });
            line.set("arrIndex", replayIndex);
            //设置线的样式
            line.setStyle(that._strokestyle);
            that._animationLineLayer.getSource().addFeature(line);

            //创建轨迹点
            var point = new ol.Feature({
                geometry: new ol.geom.Point(that._pointArray[replayIndex])
            });
            point.setStyle(that._Iconstyle);
            that._animationPointLayer.getSource().clear();
            that._animationPointLayer.getSource().addFeature(point);
        }, that.speed);
    }

3、暂停/播放:这里设置了一个变量isRun控制,如果false则timer里直接返回,不执行绘制

    /**
     * 暂停/继续播放
     * @param {Boolean} isRun 返回暂停还是播放
     */
    this.paused = function () {
        //如果没有定时器,则不暂停
        if (this.timer) {
            isRun = !isRun;
            return isRun;
        }
        else {
            return null;
        }
    };

4、重新播放:清空上一个计时器,重新播放

/**
     * 重新播放
     */
    this.restart = function () {
        clearInterval(this.timer);
        isRun = true;
        // this._animationLineLayer.getSource().clear();
        // this._animationPointLayer.getSource().clear();
        this.play(that.speed); }

5、点击处重新播放:这个select事件放在初始化时注册完成的;使用了数组filter方法过滤数组,并控制全局游标replayIndex;找到播放到的数组元素,从那里开始

        //注册点击查询事件,点击暂停/从此播放
        let selecthover = new ol.interaction.Select({
            condition: ol.events.condition.click,
            layers: [animationLineLayer]
        });
        selecthover.set("arrPoints", that._pointArray);
        // selecthover.set("tmpPoints", that._pointArray);
        selecthover.set("_strokestyle", that._strokestyle);
        selecthover.set("_Iconstyle", that._Iconstyle);
        selecthover.set("_animationLineLayer", that._animationLineLayer);
        selecthover.set("_animationPointLayer", that._animationPointLayer);
        _map.encmap.addInteraction(selecthover);
        var me = that;
        //查询结果
        selecthover.on("select", function (evt) {
            if (evt.selected[0] == null) return;
            //取消选中要素高亮
            this.getFeatures().clear();
            //暂停/继续
            //isRun = !isRun;
            // console.log(replayIndex);

            //从点击处开始播放
            isRun = true;
            replayIndex = evt.selected[0].get("arrIndex");

            var tmpPointsArray = this.getProperties()["arrPoints"];
            var tmpPoints = this.getProperties()["tmpPoints"];
            var _strokestyle = this.getProperties()["_strokestyle"];
            var _Iconstyle = this.getProperties()["_Iconstyle"];
            var _animationLineLayer = this.getProperties()["_animationLineLayer"];
            var _animationPointLayer = this.getProperties()["_animationPointLayer"];

            //保留走完的线
            _animationLineLayer.getSource().clear();
            // tmpPointsArray.filter(e => e <= replayIndex);
            var pts = [];
            pts.push(tmpPointsArray);
            pts = pts[0];

            for (var m = 0; m <= replayIndex - 1; m++) {
                //创建轨迹线
                var line = new ol.Feature({
                    geometry: new ol.geom.LineString([pts[m], pts[m + 1]])
                });
                line.set("arrIndex", m);
                // //设置线的样式
                line.setStyle(_strokestyle);
                _animationLineLayer.getSource().addFeature(line);
            }

            //添加点击点
            var clickPt = new ol.Feature({
                geometry: new ol.geom.Point(tmpPointsArray[replayIndex])
            });
            clickPt.setStyle(_Iconstyle);
            _animationPointLayer.getSource().clear();
            _animationPointLayer.getSource().addFeature(clickPt);
        });

6、提速/减速:这里控制计时器的速度,其实还有另一种做法就是控制插值的密度。

    /**
     * 提速
     */
    this.faster = function () {
        clearInterval(this.timer);
        isRun = true;
        //如果速度小于10,则不允许再提速
        if (that.speed > 10) {
            that.speed = that.speed - 1;
        }
        this.play(that.speed);
        return that.speed;
    };

    /**
     * 减速
     */
    this.slower = function () {
        clearInterval(this.timer);
        isRun = true;
        that.speed = that.speed + 1;
        this.play(that.speed);
        return that.speed;
    };

7、最后附上全部代码(需要改造才能使用,因为这里map以及findlayerbyid都是封装好的方法)

RoadLineShow = function (_map, animationLineLayer, animationPointLayer, linePatrolArray, strokestyle, Iconstyle) {
    var that = this;
    var timer = this.timer;//连续定时器
    var speed = this.speed;//定时器速度
    var ref;//断续定时器
    var j = 0;
    //播放与暂停标识
    var isRun = true;
    /**
     * @description 初始化轨迹
     */
    (function init() {
        //地图容器
        that._map = _map;
        //轨迹线图层
        that._animationLineLayer = animationLineLayer;
        //轨迹点图层
        that._animationPointLayer = animationPointLayer;
        //轨迹样式
        that._strokestyle = strokestyle;
        //轨迹样式
        that._Iconstyle = Iconstyle;
        //轨迹点集(带插值)
        that._pointArray = [];
        //轨迹点集(不带插值)
        that._linePatrolArray = linePatrolArray;

        //设置图层id
        animationLineLayer.set('layerId', 'animationLineLayer');
        animationPointLayer.set('layerId', 'animationPointLayer');
        //没有传坐标点过来就返回
        if (linePatrolArray.length == 0) return;
        //如果连续定时器没有清空,则清空定时器
        clearInterval(this.timer);
        //移除路径图层
        if (_map.findLayerByID("animationLineLayer") != null) {
            _map.encmap.removeLayer(_map.findLayerByID("animationLineLayer"));
        }
        //移除动画点的图层
        if (_map.findLayerByID("animationPointLayer") != null) {
            _map.encmap.removeLayer(_map.findLayerByID("animationPointLayer"));
        }

        //记录插值后的所有轨迹点,给pointArray
        for (var i = 0; i < linePatrolArray.length - 1; i++) {
            interpolation(linePatrolArray[i], linePatrolArray[i + 1]);
        }

        var curentLineLayer = _map.findLayerByID("animationLineLayer");
        var curentPointLayer = _map.findLayerByID("animationPointLayer");

        //如果此时map对象中有路径animationLineLayer图层
        if (curentLineLayer != null) {
            //如果此时路径animationLineLayer图层没有清空,清空里面的内容
            if (curentLineLayer.getSource() != null) {
                curentLineLayer.getSource().clear();
            }
        } else {
            //如果此时map对象中没有路径图层,添加路径animationLineLayer图层
            _map.encmap.addLayer(animationLineLayer);
        }
        //如果此时map对象中有移动动画点animationPointLayer图层
        if (curentPointLayer != null) {
            if (curentPointLayer.getSource() != null) {
                //清空动画点animationPointLayer图层的内容
                curentPointLayer.getSource().clear();
            }
        } else {
            //如果此时map对象中没有移动点图层,添加移动点animationPointLayer图层
            _map.encmap.addLayer(animationPointLayer);
        }

        //注册点击查询事件,点击暂停/从此播放
        let selecthover = new ol.interaction.Select({
            condition: ol.events.condition.click,
            layers: [animationLineLayer]
        });
        selecthover.set("arrPoints", that._pointArray);
        // selecthover.set("tmpPoints", that._pointArray);
        selecthover.set("_strokestyle", that._strokestyle);
        selecthover.set("_Iconstyle", that._Iconstyle);
        selecthover.set("_animationLineLayer", that._animationLineLayer);
        selecthover.set("_animationPointLayer", that._animationPointLayer);
        _map.encmap.addInteraction(selecthover);
        var me = that;
        //查询结果
        selecthover.on("select", function (evt) {
            if (evt.selected[0] == null) return;
            //取消选中要素高亮
            this.getFeatures().clear();
            //暂停/继续
            //isRun = !isRun;
            // console.log(replayIndex);

            //从点击处开始播放
            isRun = true;
            replayIndex = evt.selected[0].get("arrIndex");

            var tmpPointsArray = this.getProperties()["arrPoints"];
            var tmpPoints = this.getProperties()["tmpPoints"];
            var _strokestyle = this.getProperties()["_strokestyle"];
            var _Iconstyle = this.getProperties()["_Iconstyle"];
            var _animationLineLayer = this.getProperties()["_animationLineLayer"];
            var _animationPointLayer = this.getProperties()["_animationPointLayer"];

            //保留走完的线
            _animationLineLayer.getSource().clear();
            // tmpPointsArray.filter(e => e <= replayIndex);
            var pts = [];
            pts.push(tmpPointsArray);
            pts = pts[0];

            for (var m = 0; m <= replayIndex - 1; m++) {
                //创建轨迹线
                var line = new ol.Feature({
                    geometry: new ol.geom.LineString([pts[m], pts[m + 1]])
                });
                line.set("arrIndex", m);
                // //设置线的样式
                line.setStyle(_strokestyle);
                _animationLineLayer.getSource().addFeature(line);
            }

            //添加点击点
            var clickPt = new ol.Feature({
                geometry: new ol.geom.Point(tmpPointsArray[replayIndex])
            });
            clickPt.setStyle(_Iconstyle);
            _animationPointLayer.getSource().clear();
            _animationPointLayer.getSource().addFeature(clickPt);
        });
    })();

    /**
     * 提供坐标数组,展示轨迹
     * @param _map      实例化map对象
     * @param Coordinates       坐标数组例如[123458.421,123432]
     * @param lineStyle         轨迹的式样
     * @returns {ol.layer.Vector}      返回一个layer实例
     */
    this.getRoadLineLayer = function (_map, Coordinates, lineStyle) {
        var route = new ol.geom.LineString(Coordinates);
        //获取直线的坐标
        var Featureroute = new ol.Feature({
            type: 'route',
            geometry: route
        });
        var routeFeature = [Featureroute];
        var routeSource = new ol.source.Vector(
            {
                features: routeFeature
            }
        );
        var vectorLayer = new ol.layer.Vector({
            source: routeSource,
            style: lineStyle
        });
        var myFeatureExtent = vectorLayer.getSource().getExtent();
        if (myFeatureExtent != null) {
            let view = _map.encmap.getView();
            //改变视图view
            view.fit(myFeatureExtent);
        }
        return vectorLayer;
    };

    //动画播放
    this.play = function (_speed) {
        //var me = this;
        //定位到轨迹范围
        var featureExtent = new ol.Feature({
            geometry: new ol.geom.LineString(that._linePatrolArray)
        });
        that._map.encmap.getView().fit(featureExtent.getGeometry().getExtent());

        //如果连续定时器没有清空,则清空定时器
        if (this.timer != null) {
            clearInterval(this.timer);
            if (that._animationLineLayer.getSource() != null) {
                that._animationLineLayer.getSource().clear();
            }
            if (that._animationPointLayer.getSource() != null) {
                that._animationPointLayer.getSource().clear();
            }
        }

        //播放速度
        that.speed = _speed;
        //计时器默认40ms
        if (!that.speed) {
            that.speed = 40;
        }
        replayIndex = 0;
        this.timer = setInterval(function () {
            console.log(that.timer);
            //暂停
            if (!isRun) {
                return;
            }
            //播放完成,停止定时器
            if (replayIndex > that._pointArray.length - 2) {
                clearInterval(that.timer);
                return;
            }
            //创建轨迹线
            var line = new ol.Feature({
                geometry: new ol.geom.LineString([that._pointArray[replayIndex], that._pointArray[++replayIndex]])
            });
            line.set("arrIndex", replayIndex);
            //设置线的样式
            line.setStyle(that._strokestyle);
            that._animationLineLayer.getSource().addFeature(line);

            //创建轨迹点
            var point = new ol.Feature({
                geometry: new ol.geom.Point(that._pointArray[replayIndex])
            });
            point.setStyle(that._Iconstyle);
            that._animationPointLayer.getSource().clear();
            that._animationPointLayer.getSource().addFeature(point);
        }, that.speed);
    }
    /**
     * 重新播放
     */
    this.restart = function () {
        clearInterval(this.timer);
        isRun = true;
        // this._animationLineLayer.getSource().clear();
        // this._animationPointLayer.getSource().clear();
        this.play(that.speed);
    }

    /**
     * 暂停/继续播放
     * @param {Boolean} isRun 返回暂停还是播放
     */
    this.paused = function () {
        //如果没有定时器,则不暂停
        if (this.timer) {
            isRun = !isRun;
            return isRun;
        }
        else {
            return null;
        }
    };

    /**
     * 提速
     */
    this.faster = function () {
        clearInterval(this.timer);
        isRun = true;
        //如果速度小于10,则不允许再提速
        if (that.speed > 10) {
            that.speed = that.speed - 1;
        }
        this.play(that.speed);
        return that.speed;
    };

    /**
     * 减速
     */
    this.slower = function () {
        clearInterval(this.timer);
        isRun = true;
        that.speed = that.speed + 1;
        this.play(that.speed);
        return that.speed;
    };

    //插入临时点,每两个点之间插入39个点
    function interpolation(pointA, pointB, speed) {
        var tmp = [];
        if (speed == undefined) {
            speed = 1;
        }
        speed = speed - 0.5; //不能大于播放速度
        var count = Math.abs(speed) * 25;
        var pointA_X = pointA[0];
        var pointA_Y = pointA[1];
        var pointB_X = pointB[0];
        var pointB_Y = pointB[1];
        var disX = (pointB_X - pointA_X) / count;
        var disY = (pointB_Y - pointA_Y) / count;
        var i = 0;
        var x_y_point = [];
        while (i <= count) {
            var x = pointA_X + i * disX;
            var y = pointA_Y + i * disY;
            that._pointArray.push([x, y]);
            i++;
        }
    }
};
原文地址:https://www.cnblogs.com/giser-s/p/11855761.html