311 lines
9.0 KiB
JavaScript
311 lines
9.0 KiB
JavaScript
|
/*
|
||
|
* @Author: hisense.wuhongjian
|
||
|
* @Date: 2022-03-22 11:13:25
|
||
|
* @LastEditors: hisense.wuhongjian
|
||
|
* @LastEditTime: 2022-03-22 11:13:25
|
||
|
* @Description: 告诉大家这是什么
|
||
|
*/
|
||
|
L.interpolatePosition = function(p1, p2, duration, t) {
|
||
|
var k = t/duration;
|
||
|
k = (k > 0) ? k : 0;
|
||
|
k = (k > 1) ? 1 : k;
|
||
|
return L.latLng(p1.lat + k * (p2.lat - p1.lat),
|
||
|
p1.lng + k * (p2.lng - p1.lng));
|
||
|
};
|
||
|
|
||
|
L.Marker.MovingMarker = L.Marker.extend({
|
||
|
|
||
|
//state constants
|
||
|
statics: {
|
||
|
notStartedState: 0,
|
||
|
endedState: 1,
|
||
|
pausedState: 2,
|
||
|
runState: 3
|
||
|
},
|
||
|
|
||
|
options: {
|
||
|
autostart: false,
|
||
|
loop: false,
|
||
|
},
|
||
|
|
||
|
initialize: function (latlngs, durations, options) {
|
||
|
L.Marker.prototype.initialize.call(this, latlngs[0], options);
|
||
|
|
||
|
this._latlngs = latlngs.map(function(e, index) {
|
||
|
return L.latLng(e);
|
||
|
});
|
||
|
|
||
|
if (durations instanceof Array) {
|
||
|
this._durations = durations;
|
||
|
} else {
|
||
|
this._durations = this._createDurations(this._latlngs, durations);
|
||
|
}
|
||
|
|
||
|
this._currentDuration = 0;
|
||
|
this._currentIndex = 0;
|
||
|
|
||
|
this._state = L.Marker.MovingMarker.notStartedState;
|
||
|
this._startTime = 0;
|
||
|
this._startTimeStamp = 0; // timestamp given by requestAnimFrame
|
||
|
this._pauseStartTime = 0;
|
||
|
this._animId = 0;
|
||
|
this._animRequested = false;
|
||
|
this._currentLine = [];
|
||
|
this._stations = {};
|
||
|
},
|
||
|
|
||
|
isRunning: function() {
|
||
|
return this._state === L.Marker.MovingMarker.runState;
|
||
|
},
|
||
|
|
||
|
isEnded: function() {
|
||
|
return this._state === L.Marker.MovingMarker.endedState;
|
||
|
},
|
||
|
|
||
|
isStarted: function() {
|
||
|
return this._state !== L.Marker.MovingMarker.notStartedState;
|
||
|
},
|
||
|
|
||
|
isPaused: function() {
|
||
|
return this._state === L.Marker.MovingMarker.pausedState;
|
||
|
},
|
||
|
|
||
|
start: function() {
|
||
|
if (this.isRunning()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (this.isPaused()) {
|
||
|
this.resume();
|
||
|
} else {
|
||
|
this._loadLine(0);
|
||
|
this._startAnimation();
|
||
|
this.fire('start');
|
||
|
}
|
||
|
},
|
||
|
|
||
|
resume: function() {
|
||
|
if (! this.isPaused()) {
|
||
|
return;
|
||
|
}
|
||
|
// update the current line
|
||
|
this._currentLine[0] = this.getLatLng();
|
||
|
this._currentDuration -= (this._pauseStartTime - this._startTime);
|
||
|
this._startAnimation();
|
||
|
},
|
||
|
|
||
|
pause: function() {
|
||
|
if (! this.isRunning()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this._pauseStartTime = Date.now();
|
||
|
this._state = L.Marker.MovingMarker.pausedState;
|
||
|
this._stopAnimation();
|
||
|
this._updatePosition();
|
||
|
},
|
||
|
|
||
|
stop: function(elapsedTime) {
|
||
|
if (this.isEnded()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this._stopAnimation();
|
||
|
|
||
|
if (typeof(elapsedTime) === 'undefined') {
|
||
|
// user call
|
||
|
elapsedTime = 0;
|
||
|
this._updatePosition();
|
||
|
}
|
||
|
|
||
|
this._state = L.Marker.MovingMarker.endedState;
|
||
|
this.fire('end', {elapsedTime: elapsedTime});
|
||
|
},
|
||
|
|
||
|
addLatLng: function(latlng, duration) {
|
||
|
this._latlngs.push(L.latLng(latlng));
|
||
|
this._durations.push(duration);
|
||
|
},
|
||
|
|
||
|
moveTo: function(latlng, duration) {
|
||
|
this._stopAnimation();
|
||
|
this._latlngs = [this.getLatLng(), L.latLng(latlng)];
|
||
|
this._durations = [duration];
|
||
|
this._state = L.Marker.MovingMarker.notStartedState;
|
||
|
this.start();
|
||
|
this.options.loop = false;
|
||
|
},
|
||
|
|
||
|
addStation: function(pointIndex, duration) {
|
||
|
if (pointIndex > this._latlngs.length - 2 || pointIndex < 1) {
|
||
|
return;
|
||
|
}
|
||
|
this._stations[pointIndex] = duration;
|
||
|
},
|
||
|
|
||
|
onAdd: function (map) {
|
||
|
L.Marker.prototype.onAdd.call(this, map);
|
||
|
|
||
|
if (this.options.autostart && (! this.isStarted())) {
|
||
|
this.start();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (this.isRunning()) {
|
||
|
this._resumeAnimation();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
onRemove: function(map) {
|
||
|
L.Marker.prototype.onRemove.call(this, map);
|
||
|
this._stopAnimation();
|
||
|
},
|
||
|
|
||
|
_createDurations: function (latlngs, duration) {
|
||
|
var lastIndex = latlngs.length - 1;
|
||
|
var distances = [];
|
||
|
var totalDistance = 0;
|
||
|
var distance = 0;
|
||
|
|
||
|
// compute array of distances between points
|
||
|
for (var i = 0; i < lastIndex; i++) {
|
||
|
distance = latlngs[i + 1].distanceTo(latlngs[i]);
|
||
|
distances.push(distance);
|
||
|
totalDistance += distance;
|
||
|
}
|
||
|
|
||
|
var ratioDuration = duration / totalDistance;
|
||
|
|
||
|
var durations = [];
|
||
|
for (i = 0; i < distances.length; i++) {
|
||
|
durations.push(distances[i] * ratioDuration);
|
||
|
}
|
||
|
|
||
|
return durations;
|
||
|
},
|
||
|
|
||
|
_startAnimation: function() {
|
||
|
this._state = L.Marker.MovingMarker.runState;
|
||
|
this._animId = L.Util.requestAnimFrame(function(timestamp) {
|
||
|
this._startTime = Date.now();
|
||
|
this._startTimeStamp = timestamp;
|
||
|
this._animate(timestamp);
|
||
|
}, this, true);
|
||
|
this._animRequested = true;
|
||
|
},
|
||
|
|
||
|
_resumeAnimation: function() {
|
||
|
if (! this._animRequested) {
|
||
|
this._animRequested = true;
|
||
|
this._animId = L.Util.requestAnimFrame(function(timestamp) {
|
||
|
this._animate(timestamp);
|
||
|
}, this, true);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_stopAnimation: function() {
|
||
|
if (this._animRequested) {
|
||
|
L.Util.cancelAnimFrame(this._animId);
|
||
|
this._animRequested = false;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_updatePosition: function() {
|
||
|
var elapsedTime = Date.now() - this._startTime;
|
||
|
this._animate(this._startTimeStamp + elapsedTime, true);
|
||
|
},
|
||
|
|
||
|
_loadLine: function(index) {
|
||
|
this._currentIndex = index;
|
||
|
this._currentDuration = this._durations[index];
|
||
|
this._currentLine = this._latlngs.slice(index, index + 2);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Load the line where the marker is
|
||
|
* @param {Number} timestamp
|
||
|
* @return {Number} elapsed time on the current line or null if
|
||
|
* we reached the end or marker is at a station
|
||
|
*/
|
||
|
_updateLine: function(timestamp) {
|
||
|
// time elapsed since the last latlng
|
||
|
var elapsedTime = timestamp - this._startTimeStamp;
|
||
|
|
||
|
// not enough time to update the line
|
||
|
if (elapsedTime <= this._currentDuration) {
|
||
|
return elapsedTime;
|
||
|
}
|
||
|
|
||
|
var lineIndex = this._currentIndex;
|
||
|
var lineDuration = this._currentDuration;
|
||
|
var stationDuration;
|
||
|
|
||
|
while (elapsedTime > lineDuration) {
|
||
|
// substract time of the current line
|
||
|
elapsedTime -= lineDuration;
|
||
|
stationDuration = this._stations[lineIndex + 1];
|
||
|
|
||
|
// test if there is a station at the end of the line
|
||
|
if (stationDuration !== undefined) {
|
||
|
if (elapsedTime < stationDuration) {
|
||
|
this.setLatLng(this._latlngs[lineIndex + 1]);
|
||
|
return null;
|
||
|
}
|
||
|
elapsedTime -= stationDuration;
|
||
|
}
|
||
|
|
||
|
lineIndex++;
|
||
|
|
||
|
// test if we have reached the end of the polyline
|
||
|
if (lineIndex >= this._latlngs.length - 1) {
|
||
|
|
||
|
if (this.options.loop) {
|
||
|
lineIndex = 0;
|
||
|
this.fire('loop', {elapsedTime: elapsedTime});
|
||
|
} else {
|
||
|
// place the marker at the end, else it would be at
|
||
|
// the last position
|
||
|
this.setLatLng(this._latlngs[this._latlngs.length - 1]);
|
||
|
this.stop(elapsedTime);
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
lineDuration = this._durations[lineIndex];
|
||
|
}
|
||
|
|
||
|
this._loadLine(lineIndex);
|
||
|
this._startTimeStamp = timestamp - elapsedTime;
|
||
|
this._startTime = Date.now() - elapsedTime;
|
||
|
return elapsedTime;
|
||
|
},
|
||
|
|
||
|
_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);
|
||
|
}
|
||
|
|
||
|
if (! noRequestAnim) {
|
||
|
this._animId = L.Util.requestAnimFrame(this._animate, this, false);
|
||
|
this._animRequested = true;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.Marker.movingMarker = function (latlngs, duration, options) {
|
||
|
return new L.Marker.MovingMarker(latlngs, duration, options);
|
||
|
};
|