Openlayers 實現軌跡播放/暫停/從新播放/從點擊處播放/提速/減速

說明:

個人需求是須要實現軌跡播放/暫停/從新播放/從點擊處播放,所以封裝了一個類數組

解決方案:

一、初始化:主要是處理一下圖層以及數據,經過插值構造一個全局數組函數

    /**
     * @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);
        });
    })();

二、播放方法:首先跳轉到軌跡範圍;新建一個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);
    }

三、暫停/播放:這裏設置了一個變量isRun控制,若是false則timer裏直接返回,不執行繪製this

    /**
     * 暫停/繼續播放
     * @param {Boolean} isRun 返回暫停仍是播放
     */
    this.paused = function () {
        //若是沒有定時器,則不暫停
        if (this.timer) {
            isRun = !isRun;
            return isRun;
        }
        else {
            return null;
        }
    };

四、從新播放:清空上一個計時器,從新播放spa

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

五、點擊處從新播放:這個select事件放在初始化時註冊完成的;使用了數組filter方法過濾數組,並控制全局遊標replayIndex;找到播放到的數組元素,從那裏開始rest

        //註冊點擊查詢事件,點擊暫停/今後播放
        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);
        });

六、提速/減速:這裏控制計時器的速度,其實還有另外一種作法就是控制插值的密度。code

    /**
     * 提速
     */
    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;
    };

七、最後附上所有代碼(須要改造才能使用,由於這裏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++;
        }
    }
};
相關文章
相關標籤/搜索