Leaflet 实现路径轨迹回放 轨迹播放 运行轨迹
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路径轨迹回放</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin="" />
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
</head>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
#mapid {
width: 100%;
height: 100%;
}
.input-card {
z-index: 50;
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border-radius: .25rem;
width: 8rem;
border-width: 0;
border-radius: 0.4rem;
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
position: fixed;
bottom: 1rem;
right: 1rem;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
padding: 0.75rem 1.25rem;
}
</style>
<body>
<div id="mapid" style="z-index: 10"></div>
<div class="input-card">
<button id="run" onclick="start()">run</button>
<button id="stop" onclick="stop()">stop</button>
<button id="pause" onclick="pause()">pause</button>
</div>
<script>
(function () {
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;
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) {
this._icon.style[L.DomUtil.TRANSFORM] = 'rotate(' + this.options.rotationAngle + 'deg)';
} else {
this._icon.style[L.DomUtil.TRANSFORM] += ' rotateZ(' + this.options.rotationAngle + 'deg)';
}
}
},
setRotationAngle: function (angle) {
this.options.rotationAngle = angle;
this.update();
return this;
},
setRotationOrigin: function (origin) {
this.options.rotationOrigin = origin;
this.update();
return this;
}
});
})();
var map = L.map('mapid', {
center: [38.8631169, 2.3708919],
zoom: 5,
crs: L.CRS.EPSG3857,
layers: [
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
})
]
});
var _opts = {
icon: null,
enableRotation: true
};
this.i = 0;
var latlngs = [
[45.51, 2.3708919],
[37.77, 8.54235],
[34.04, 9.52532],
[36.04, 10.52532],
[40.04, 14.52532],
[47.04, 15.52532]
];
var _path = latlngs;
var polyline = L.polyline([], { color: 'red' }).addTo(map);
_initPolyline(_path[i], _path[i + 1], _tween)
var latlngsPass = polyline.getLatLngs
var polylinePass = L.polyline([], { color: 'green' }).addTo(map);
function start() {
var me = this,
len = me._path.length;
if (me.i && me.i < len - 1) {
if (!me._fromPause) {
return;
} else if (!me._fromStop) {
me._moveNext(++me.i);
}
} else {
polylinePass.setLatLngs([])
me._addMarker();
me._moveNext(me.i);
}
this._fromPause = false;
this._fromStop = false;
}
function _addMarker(callback) {
if (this._marker) {
this.stop();
this._marker.remove();
}
var marker = new L.Marker(_path[0]).addTo(map)
this._marker = marker;
}
function _moveNext(index) {
var me = this;
if (index < this._path.length - 1) {
this._move(me._path[index], me._path[index + 1], me._tween);
}
}
function _initPolyline(initPos, targetPos, effect) {
var me = this,
currentCount = -1,
step = 0.01,
count = Math.round(me._getDistance(initPos[0], initPos[1], targetPos[0], targetPos[1]) / step);
if (count < 1) {
++me.i
if (me.i < me._path.length - 1) {
_initPolyline(me._path[me.i], me._path[me.i + 1], me._tween);
}
return;
}
var loop = true
while (loop) {
if (currentCount >= count) {
loop = false
if (me.i > me._path.length) {
me.i = 0
return;
}
++me.i;
if (me.i < me._path.length - 1) {
_initPolyline(me._path[me.i], me._path[me.i + 1], me._tween);
me.i = 0
}
} else {
currentCount++;
var x = effect(initPos[0], targetPos[0], currentCount, count),
y = effect(initPos[1], targetPos[1], currentCount, count);
var pos = L.latLng(x, y);
polyline.addLatLng(pos)
}
}
}
function _move(initPos, targetPos, effect) {
var me = this,
currentCount = -1,
timer = 10,
step = 0.01,
count = Math.round(me._getDistance(initPos[0], initPos[1], targetPos[0], targetPos[1]) / step);
if (count < 1) {
this._moveNext(++me.i);
return;
}
var angle;
me._intervalFlag = setInterval(function () {
if (currentCount >= count) {
clearInterval(me._intervalFlag);
++me.i
if (me.i >= me._path.length - 1) {
console.log('move done')
return;
}
me._moveNext(me.i);
} else {
currentCount++;
var x = effect(initPos[0], targetPos[0], currentCount, count),
y = effect(initPos[1], targetPos[1], currentCount, count);
var pos = L.latLng(x, y);
if (currentCount == 1) {
if (me._opts.enableRotation == true) {
}
}
me._marker.remove();
me._marker.setRotationAngle(angle);
me._marker._latlng = pos;
me._marker.addTo(map);
polylinePass.addLatLng(pos)
}
}, timer);
}
function _tween(initPos, targetPos, currentCount, count) {
var b = initPos, c = targetPos - initPos, t = currentCount,
d = count;
return c * t / d + b;
}
function _getDistance(pxA, pyA, pxB, pyB) {
return Math.sqrt(Math.pow(pxA - pxB, 2) + Math.pow(pyA - pyB, 2));
}
function _getAngle(startx, starty, endx, endy) {
var tan = 0
if (endx == startx) {
tan = 90;
} else {
tan = Math.atan(Math.abs((endy - starty) / (endx - startx))) * 180 / Math.PI;
}
if (endx >= startx && endy >= starty)
{
return -tan;
} else if (endx > startx && endy < starty)
{
return tan;
} else if (endx < startx && endy > starty)
{
return tan - 180;
} else {
return 180 - tan;
}
}
function stop() {
this.i = 0;
this._fromStop = true;
clearInterval(this._intervalFlag);
}
function pause() {
clearInterval(this._intervalFlag);
this._fromPause = true;
}
</script>
</body>
</html>
Leaflet-polyline 官方文档