文中提到的 “标识” 名词,代表使用L.Marker 方法创建出来的点位
项目使用的leaflet地图,最近有一个需求,在地图上画出多条轨迹,然后点击一个总控制按钮,轨迹开始根据自己的时间进行挨个回放,回放过程中速度也会实时变化。
实现轨迹回放无疑就是marker标识在轨迹上面再跑一圈,也就是marker的移动,我进行搜阅,找到了两种方式:
1.可一个点一个点的来,也可一整个轨迹:转场
2.直接一整条轨迹:转场
这两种方式实现的方法各有不同,哪一种合适可以自己进行选择。(记得给大佬点赞,确实不错)
我用的第一种,但是跟我的需求还有些不同,因此我稍微进行了修改。第一种的用法为:
let marker = L.Marker.movingMarker([坐标,最少两个点], [动画时间(可为数组)], { 你自己的属性}).addTo(map);
//实际例子
let marker = L.Marker.movingMarker([[0,0],[1,1]], 1000, { 你自己的属性}).addTo(map);
marker.start();
//这样就实现了marker运动,
//若想根据速度实时运动,就在动画时间数组里面多给几个值,让他的长度和前面点的数组的长度相同,代表每个点之间的速度。如:
let marker = L.Marker.movingMarker([坐标,最少两个点], [动画时间(数组长度跟坐标长度一样)], { className:'marker' }).addTo(map);
//实际例子
let marker = L.Marker.movingMarker([[0,0],[1,1]], [1000,500], { 你自己的属性}).addTo(map);
若是再回放过程中又多了几个点,可以使用文件(MovingMarker.js)中addLatLng方法:
marker.addLatLng(坐标,时间);
//一次添加一个,若想添加数组,可以自己修改文件
如是想改变已经添加进去的点的速度,如倍速播放,可以在文件(MovingMarker.js)中添加两个方法
//getSpeed、setSpeed方法在MovingMarker.js文件中添加
//获取速度
getSpeed(){
return this._durations
},
//整体设置速度
setSpeed(_durations){
this._durations = _durations;
}
//在自己文件中使用
//使用方法为:
let speed = marker.getSpeed();
marker.setSpeed(speed/10);//以10倍速进行回放
我的项目还有改变标识方向的需求,因此我又加了这个文件:
详情见:转场
(function() {
// save these original methods before they are overwritten
var proto_initIcon = L.Marker.prototype._initIcon;
var proto_setPos = L.Marker.prototype._setPos;
var oldIE = (L.DomUtil.TRANSFORM === 'msTransform');
L.Marker.addInitHook(function () {
var iconOptions = this.options.icon && this.options.icon.options;
var iconAnchor = iconOptions && this.options.icon.options.iconAnchor;
if (iconAnchor) {
iconAnchor = (iconAnchor[0] + 'px ' + iconAnchor[1] + 'px');
}
this.options.rotationOrigin = this.options.rotationOrigin || iconAnchor || 'center center' ;//设置旋转中心
this.options.rotationAngle = this.options.rotationAngle || 0;
// Ensure marker keeps rotated during dragging
this.on('drag', function(e) { e.target._applyRotation(); });
});
L.Marker.include({
_initIcon: function() {
proto_initIcon.call(this);
},
_setPos: function (pos) {
proto_setPos.call(this, pos);
this._applyRotation();
},
_applyRotation: function () {
if(this.options.rotationAngle) {
this._icon.style[L.DomUtil.TRANSFORM+'Origin'] = this.options.rotationOrigin;
if(oldIE) {
// for IE 9, use the 2D rotation
this._icon.style[L.DomUtil.TRANSFORM] = 'rotate(' + this.options.rotationAngle + 'deg)';
} else {
// for modern browsers, prefer the 3D accelerated version
this._icon.style[L.DomUtil.TRANSFORM] += ' rotateZ(' + this.options.rotationAngle + 'deg)';
}
}
},
//设置旋转角度
setRotationAngle: function (px1, py1, px2, py2) {
x = px2 - px1;
y = py2 - py1;
hypotenuse = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
//斜边长度
cos = x / hypotenuse;
radian = Math.acos(cos);
//求出弧度
angle = 180 / (Math.PI / radian);
//用弧度算出角度
if (y < 0) {
angle = -angle;
} else if ((y == 0) && (x < 0)) {
angle = 180;
}
this.options.rotationAngle = angle;
this.update();
return this;
},
setRotationOrigin: function(origin) {
this.options.rotationOrigin = origin;
this.update();
return this;
}
});
})();
此文件给L.Marker添加了setRotationAngle方法,可通过 “实例.setRotationAngle(px1,py1,px2,py2)” 进行修改标识的角度。
也可以在初始化标识的时候,加上一个rotationOrigin属性,让他在初次渲染的时候就有一个方向。
// 初次渲染时就有方向举例:
let marker = L.Marker.movingMarker(坐标, {rotationOrigin:'center center'}).addTo(map);//以图标中心点做旋转
接着上方的这个例子来说,初始化并渲染完成后,若想在轨迹回放的时候实时改变方向 (拐弯或者斜着走的时候,头部始终指向前方 ),需要在文件(MovingMarker.js)中的 _animate 方法中进行修改角度操作。阅读文件(MovingMarker.js)可发现 _animate 方法是标识移动所调用的方法。我们只需在他给标识设置下一个点坐标的时候,改变一下标识的角度即可实现我们的需求。
下面贴出文件(MovingMarker.js)中 _animate 方法,并添加下面第21行代码。
_animate: function(timestamp, noRequestAnim) {
this._animRequested = false;
// find the next line and compute the new elapsedTime
var elapsedTime = this._updateLine(timestamp);
if (this.isEnded()) {
// no need to animate
return;
}
if (elapsedTime != null) {
// compute the position
var p = L.interpolatePosition(this._currentLine[0],
this._currentLine[1],
this._currentDuration,
elapsedTime);
//给标识设置下一个点坐标
this.setLatLng(p);
//为标识设置下次运动时的角度
this.setRotationAngle(this._currentLine[0].lat,this._currentLine[0].lng,this._currentLine[1].lat,this._currentLine[1].lng)
}
if (! noRequestAnim) {
this._animId = L.Util.requestAnimFrame(this._animate, this, false);
this._animRequested = true;
}
}
这样需求就可以实现了。