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++; } } };