MovingMarker.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. L.interpolatePosition = function (p1, p2, duration, t) {
  2. if (!p1 || !p2) {
  3. return;
  4. }
  5. var k = t / duration;
  6. k = (k > 0) ? k : 0;
  7. k = (k > 1) ? 1 : k;
  8. return L.latLng(p1.lat + k * (p2.lat - p1.lat),
  9. p1.lng + k * (p2.lng - p1.lng));
  10. };
  11. L.Marker.MovingMarker = L.AngleMarker.extend({
  12. //state constants
  13. statics: {
  14. notStartedState: 0,
  15. endedState: 1,
  16. pausedState: 2,
  17. runState: 3
  18. },
  19. options: {
  20. autostart: false,
  21. loop: false,
  22. },
  23. initialize: function (latlngs, durations, options) {
  24. L.AngleMarker.prototype.initialize.call(this, latlngs[0], options);
  25. this._latlngs = latlngs.map(function (e, index) {
  26. return L.latLng(e);
  27. });
  28. if (durations instanceof Array) {
  29. this._durations = durations;
  30. } else {
  31. this._durations = this._createDurations(this._latlngs, durations);
  32. }
  33. this._currentDuration = 0;
  34. this._currentIndex = 0;
  35. this._state = L.Marker.MovingMarker.notStartedState;
  36. this._startTime = 0;
  37. this._startTimeStamp = 0; // timestamp given by requestAnimFrame
  38. this._pauseStartTime = 0;
  39. this._animId = 0;
  40. this._animRequested = false;
  41. this._currentLine = [];
  42. this._stations = {};
  43. this._gjLayer = L.layerGroup().addTo(window.map);
  44. this.circleLayer = []
  45. this.isFollow = false
  46. },
  47. isRunning: function () {
  48. return this._state === L.Marker.MovingMarker.runState;
  49. },
  50. isEnded: function () {
  51. return this._state === L.Marker.MovingMarker.endedState;
  52. },
  53. isStarted: function () {
  54. return this._state !== L.Marker.MovingMarker.notStartedState;
  55. },
  56. isPaused: function () {
  57. return this._state === L.Marker.MovingMarker.pausedState;
  58. },
  59. start: function () {
  60. if (this.isRunning()) {
  61. return;
  62. }
  63. if (this.isPaused()) {
  64. this.resume();
  65. } else {
  66. this._loadLine(0);
  67. this._startAnimation();
  68. this.fire('start');
  69. }
  70. },
  71. resume: function () {
  72. if (!this.isPaused()) {
  73. return;
  74. }
  75. // update the current line
  76. this._currentLine[0] = this.getLatLng();
  77. this._currentDuration -= (this._pauseStartTime - this._startTime);
  78. this._startAnimation();
  79. },
  80. pause: function () {
  81. if (!this.isRunning()) {
  82. return;
  83. }
  84. this._pauseStartTime = Date.now();
  85. this._state = L.Marker.MovingMarker.pausedState;
  86. this._stopAnimation();
  87. this._updatePosition();
  88. },
  89. stop: function (elapsedTime) {
  90. if (this.isEnded()) {
  91. return;
  92. }
  93. this._stopAnimation();
  94. if (typeof (elapsedTime) === 'undefined') {
  95. // user call
  96. elapsedTime = 0;
  97. this._updatePosition();
  98. }
  99. this._state = L.Marker.MovingMarker.endedState;
  100. this.fire('end', { elapsedTime: elapsedTime });
  101. },
  102. addLatLng: function (latlng, duration) {
  103. this._latlngs.push(L.latLng(latlng));
  104. this._durations.push(duration);
  105. },
  106. moveTo: function (latlng, duration) {
  107. this._stopAnimation();
  108. this._latlngs = [this.getLatLng(), L.latLng(latlng)];
  109. this._durations = [duration];
  110. this._state = L.Marker.MovingMarker.notStartedState;
  111. this.start();
  112. this.options.loop = false;
  113. },
  114. addStation: function (pointIndex, duration) {
  115. if (pointIndex > this._latlngs.length - 2 || pointIndex < 1) {
  116. return;
  117. }
  118. this._stations[pointIndex] = duration;
  119. },
  120. onAdd: function (map) {
  121. L.AngleMarker.prototype.onAdd.call(this, map);
  122. if (this.options.autostart && (!this.isStarted())) {
  123. this.start();
  124. return;
  125. }
  126. if (this.isRunning()) {
  127. this._resumeAnimation();
  128. }
  129. },
  130. onRemove: function (map) {
  131. L.AngleMarker.prototype.onRemove.call(this, map);
  132. this._stopAnimation();
  133. },
  134. follow: function () {
  135. this.isFollow = true
  136. if (this.isFollow) {
  137. this._map.setZoom(10, {
  138. animate: false
  139. })
  140. this._map.panTo(this.getLatLng(), {
  141. animate: false
  142. })
  143. }
  144. },
  145. stopFollow: function () {
  146. this.isFollow = false
  147. },
  148. del: function () {
  149. this.circleLayer.forEach((e) => {
  150. this._gjLayer.removeLayer(e)
  151. })
  152. },
  153. _createDurations: function (latlngs, duration) {
  154. var lastIndex = latlngs.length - 1;
  155. var distances = [];
  156. var totalDistance = 0;
  157. var distance = 0;
  158. // compute array of distances between points
  159. for (var i = 0; i < lastIndex; i++) {
  160. distance = latlngs[i + 1].distanceTo(latlngs[i]);
  161. distances.push(distance);
  162. totalDistance += distance;
  163. }
  164. var ratioDuration = duration / totalDistance;
  165. var durations = [];
  166. for (i = 0; i < distances.length; i++) {
  167. durations.push(distances[i] * ratioDuration);
  168. }
  169. return durations;
  170. },
  171. _startAnimation: function () {
  172. this._state = L.Marker.MovingMarker.runState;
  173. this._animId = L.Util.requestAnimFrame(function (timestamp) {
  174. this._startTime = Date.now();
  175. this._startTimeStamp = timestamp;
  176. this._animate(timestamp);
  177. }, this, true);
  178. this._animRequested = true;
  179. },
  180. _resumeAnimation: function () {
  181. if (!this._animRequested) {
  182. this._animRequested = true;
  183. this._animId = L.Util.requestAnimFrame(function (timestamp) {
  184. this._animate(timestamp);
  185. }, this, true);
  186. }
  187. },
  188. _stopAnimation: function () {
  189. if (this._animRequested) {
  190. L.Util.cancelAnimFrame(this._animId);
  191. this._animRequested = false;
  192. }
  193. },
  194. _updatePosition: function () {
  195. var elapsedTime = Date.now() - this._startTime;
  196. this._animate(this._startTimeStamp + elapsedTime, true);
  197. },
  198. _loadLine: function (index) {
  199. this._currentIndex = index;
  200. this._currentDuration = this._durations[index];
  201. this._currentLine = this._latlngs.slice(index, index + 2);
  202. this.setIcon(new L.AngleIcon({
  203. course: this.options.courses[index + 1],
  204. speed: this.options.speeds[index + 1],
  205. iconUrl: this.options.iconUrl
  206. , label: this.options.title
  207. , showTitle: this.options.showTitle
  208. , labelPosition: this.options.labelPosition
  209. }));
  210. //处理过虚拟位置不打点
  211. if (!(index in this.options.noRealtimeGjList)) {
  212. var len = this.options.collectimes[index].length
  213. var title = '-';
  214. if(len === 13){
  215. title = formatDate(this.options.collectimes[index] * 1);
  216. }else if(len === 10){
  217. title = formatDate(this.options.collectimes[index] * 1000)
  218. }
  219. var circlePoint = L.circleMarker(this._latlngs[index], { zIndexOffset: 10, title: title, radius: 3, color: 'blue' }).addTo(this._gjLayer);
  220. this.circleLayer.push(circlePoint)
  221. circlePoint.attributes = this.options.gjData[index];
  222. circlePoint.bindPopup(this.options.markerPopup(circlePoint.attributes), { autoPan: false, closeButton: false, offset: L.point(130, 255) }); //autoPanPaddingBottomRight ,,{autoPan:false,closeButton:false,offset:L.point(120,185)}
  223. // var url = _this._jsonUrl+"?format=json&layer="+_this.options.gjLayer+"&customsQuery="+encodeURIComponent("{\"must\":[{\"term\":{\"attributes._targetID\":\""+attr.attributes._targetID+"\"}},{\"range\":{\"attributes.collectime\":{\"lte\":"+endTime+",\"gt\":"+startTime+"}}}]}")+"&sort=collectime:asc";
  224. let _this = this;
  225. circlePoint.on('mouseover', function (ev) {
  226. if (_this.options.pupopOpenHander) {
  227. clearTimeout(_this.options.pupopOpenHander);
  228. }
  229. _this.options.pupopOpenHander = setTimeout(function () {
  230. ev.target.openPopup();
  231. }, 500);
  232. if (_this.options.markerDrawJ) {
  233. _this.options.layerGroup.removeLayer(_this.options.markerDrawJ)
  234. }
  235. _this.options.markerDrawJ = L.marker(ev.target.getLatLng(), { icon: new L.AngleIcon({ iconSize: new L.Point(32, 32) }) }).addTo(_this.options.layerGroup);
  236. _this.options.markerDrawJ.options.icon.drawJ();
  237. });
  238. if (this.options.gjTimeMarker && this.options.layerGroup) {
  239. if (this.options.gjTimeMarker[index]) {
  240. this.options.gjTimeMarker[index].addTo(this.options.layerGroup);
  241. }
  242. }
  243. }
  244. //console.log(this._latlngs);
  245. //console.log(this._currentLine);
  246. //console.log(index);
  247. // console.log(this.options.courses[index+1]);
  248. },
  249. /**
  250. * Load the line where the marker is
  251. * @param {Number} timestamp
  252. * @return {Number} elapsed time on the current line or null if
  253. * we reached the end or marker is at a station
  254. */
  255. _updateLine: function (timestamp) {
  256. // time elapsed since the last latlng
  257. var elapsedTime = timestamp - this._startTimeStamp;
  258. if (!this._currentDuration) {
  259. this.stop(elapsedTime);
  260. return null;
  261. }
  262. // not enough time to update the line
  263. if (elapsedTime <= this._currentDuration) {
  264. return elapsedTime;
  265. }
  266. var lineIndex = this._currentIndex;
  267. var lineDuration = this._currentDuration;
  268. var stationDuration;
  269. while (elapsedTime > lineDuration) {
  270. // substract time of the current line
  271. elapsedTime -= lineDuration;
  272. stationDuration = this._stations[lineIndex + 1];
  273. // test if there is a station at the end of the line
  274. if (stationDuration !== undefined) {
  275. if (elapsedTime < stationDuration) {
  276. this.setLatLng(this._latlngs[lineIndex + 1]);
  277. return null;
  278. }
  279. elapsedTime -= stationDuration;
  280. }
  281. lineIndex++;
  282. // test if we have reached the end of the polyline
  283. if (lineIndex >= this._latlngs.length - 1) {
  284. if (this.options.loop) {
  285. lineIndex = 0;
  286. this.fire('loop', { elapsedTime: elapsedTime });
  287. } else {
  288. // place the marker at the end, else it would be at
  289. // the last position
  290. this.setLatLng(this._latlngs[this._latlngs.length - 1]);
  291. this.stop(elapsedTime);
  292. return null;
  293. }
  294. }
  295. lineDuration = this._durations[lineIndex];
  296. }
  297. this._loadLine(lineIndex);
  298. this._startTimeStamp = timestamp - elapsedTime;
  299. this._startTime = Date.now() - elapsedTime;
  300. return elapsedTime;
  301. },
  302. _animate: function (timestamp, noRequestAnim) {
  303. this._animRequested = false;
  304. // find the next line and compute the new elapsedTime
  305. var elapsedTime = this._updateLine(timestamp);
  306. if (this.isEnded()) {
  307. // no need to animate
  308. return;
  309. }
  310. if (elapsedTime != null) {
  311. // compute the position
  312. // console.log(this._currentLine[0],this._currentLine[1],this._currentDuration,elapsedTime)
  313. var p = L.interpolatePosition(this._currentLine[0],
  314. this._currentLine[1],
  315. this._currentDuration,
  316. elapsedTime);
  317. if (p) {
  318. var angle = this.getAngle(this.getLatLng(), p);
  319. this.setLatLng(p);
  320. if (this.isFollow) {
  321. this._map.panTo(p)
  322. }
  323. //console.log(angle);
  324. /*if(angle != 0 ){
  325. //this.updatePosAndIcon(this._map,p);
  326. if(this._map){
  327. var _map = this._map;
  328. //L.DomUtil.remove(this._icon);
  329. _map.removeLayer(this);
  330. this.setLatLng(p);
  331. _map.addLayer(this);
  332. }
  333. }*/
  334. }
  335. }
  336. if (!noRequestAnim) {
  337. this._animId = L.Util.requestAnimFrame(this._animate, this, false);
  338. this._animRequested = true;
  339. }
  340. }
  341. });
  342. L.Marker.movingMarker = function (latlngs, duration, options) {
  343. return new L.Marker.MovingMarker(latlngs, duration, options);
  344. };