RideLogicAVLS.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //
  2. // Copyright (c) 2021 Clementine Computing LLC.
  3. //
  4. // This file is part of RideLogic.
  5. //
  6. // RideLogic is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // RideLogic is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with RideLogic. If not, see <https://www.gnu.org/licenses/>.
  18. //
  19. var Feature = ol.Feature;
  20. var Map = ol.Map;
  21. var Overlay = ol.Overlay;
  22. var Point = ol.geom.Point;
  23. var TileJSON = ol.source.TileJSON;
  24. var VectorSource = ol.source.Vector;
  25. var View = ol.View;
  26. var Icon = ol.style.Icon;
  27. var Style = ol.style.Style;
  28. var TileLayer = ol.layer.Tile;
  29. var VectorLayer = ol.layer.Vector;
  30. var OSM = ol.source.OSM;
  31. var fromLonLat = ol.proj.fromLonLat;
  32. var LineString = ol.geom.LineString;
  33. //var defaultLonLat = [ -76.5019, 42.4440];
  34. //var defaultLonLat = [ -76.1805, 42.6012 ];
  35. var defaultLonLat = [ -76.2705, 42.5512 ];
  36. var defaultWebMerc = fromLonLat(defaultLonLat);
  37. function _rnd(a,b) {
  38. a = ((typeof a == "undefined") ? 1.0 : a);
  39. if (typeof b === "undefined") {
  40. return Math.random()*a;
  41. }
  42. return Math.random()*(b-a) + a;
  43. }
  44. function example_change_pos() {
  45. var w = 1/16.0;
  46. let lonlat = [
  47. defaultLonLat[0] + _rnd(-w,w),
  48. defaultLonLat[1] + _rnd(-w,w)];
  49. let merc = fromLonLat(lonlat);
  50. _icon[0].feature.getGeometry().setCoordinates(merc);
  51. busLayer.getSource().changed();
  52. }
  53. function example_change_opacity(p) {
  54. p = ((typeof p === "undefined") ? 0.0 : p);
  55. _icon[0].style.getImage().setOpacity(p);
  56. busLayer.getSource().changed();
  57. }
  58. // icon can't change image src dynamically,
  59. // so have to replace.
  60. // See https://stackoverflow.com/questions/57341190/how-can-i-change-icon-source-dynamically
  61. //
  62. function example_change_image() {
  63. var _nuimg = new Icon({
  64. anchor: [0.5, 46],
  65. anchorXUnits: 'fraction',
  66. anchorYUnits: 'pixels',
  67. src: 'data/bus_gw_90.png',
  68. });
  69. _icon[0].style.setImage(_nuimg);
  70. busLayer.getSource().changed();
  71. }
  72. //---
  73. //var vectorSource = new VectorSource({ features: [iconFeature], });
  74. var vectorSource = new VectorSource();
  75. var _icon = [];
  76. for (var ii=0; ii<2; ii++) {
  77. var w = 1/32.0;
  78. let lonlat = [
  79. defaultLonLat[0] + _rnd(-w,w),
  80. defaultLonLat[1] + _rnd(-w,w)];
  81. let merc = fromLonLat(lonlat);
  82. var iconFeature = new Feature({
  83. geometry: new Point([merc[0], merc[1]]),
  84. name: 'bus'
  85. });
  86. var iconStyle = new Style({
  87. image: new Icon({
  88. anchor: [0.5, 46],
  89. anchorXUnits: 'fraction',
  90. anchorYUnits: 'pixels',
  91. src: 'data/icon.png',
  92. }),
  93. });
  94. iconStyle.getImage().setOpacity(0.0);
  95. _icon.push({ "style": iconStyle, "feature": iconFeature });
  96. iconFeature.setStyle(iconStyle);
  97. vectorSource.addFeature(iconFeature);
  98. }
  99. //---
  100. const busLayer = new VectorLayer({
  101. source: vectorSource,
  102. zIndex: 2
  103. });
  104. //--
  105. const rasterLayer = new TileLayer({
  106. //source: ol.source.OSM()
  107. source: new ol.source.OSM(),
  108. });
  109. //--
  110. const g_map = new Map({
  111. //layers: [rasterLayer, vectorLayer, routeLayer],
  112. layers: [rasterLayer, busLayer ],
  113. target: document.getElementById('map'),
  114. view: new View({
  115. center: defaultWebMerc,
  116. zoom: 11,
  117. }),
  118. });
  119. const element = document.getElementById('popup');
  120. const popup = new Overlay({
  121. element: element,
  122. positioning: 'bottom-center',
  123. stopEvent: false,
  124. });
  125. g_map.addOverlay(popup);
  126. // display popup on click
  127. //
  128. g_map.on('click', function (evt) {
  129. // note working (wip)
  130. //
  131. /*
  132. const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
  133. return feature;
  134. });
  135. */
  136. });
  137. // change mouse cursor when over marker
  138. g_map.on('pointermove', function (e) {
  139. const pixel = g_map.getEventPixel(e.originalEvent);
  140. const hit = g_map.hasFeatureAtPixel(pixel);
  141. g_map.getTarget().style.cursor = hit ? 'pointer' : '';
  142. });
  143. // Close the popup when the map is moved
  144. g_map.on('movestart', function () {
  145. //$(element).popover('dispose');
  146. });
  147. g_map.on("postrender", function(event) {
  148. //console.log("bang...");
  149. });
  150. //----
  151. //
  152. setInterval( function() {
  153. //console.log("bang");
  154. //map.render();
  155. }, 1000);
  156. //-----
  157. //
  158. function update_buses(json_gtfs) {
  159. var bearingIdxLookup = [ "0", "45", "90", "135", "180", "225", "270", "315" ];
  160. for (let ii=0; ii<json_gtfs.entityList.length; ii++) {
  161. let id = json_gtfs.entityList[ii].id;
  162. let p = json_gtfs.entityList[ii].vehicle.position;
  163. let lat = p.latitude;
  164. let lon = p.longitude;
  165. let bearing = p.bearing;
  166. let lonlat = [ lon , lat ];
  167. let merc = fromLonLat(lonlat);
  168. if (typeof _icon[ii] === "undefined") { continue; }
  169. _icon[ii].feature.getGeometry().setCoordinates(merc);
  170. bearing = (bearing % 360 );
  171. if (bearing < 0) { bearing += 360.0; }
  172. let iheading = Math.floor( (parseInt( bearing ) + 23) / 45 );
  173. if (iheading > 7) { iheading = 0; }
  174. var _nuimg = new Icon({
  175. anchor: [0.5, 46],
  176. anchorXUnits: 'fraction',
  177. anchorYUnits: 'pixels',
  178. src: 'data/bus_gw_' + bearingIdxLookup[iheading] + '.png',
  179. });
  180. _icon[ii].style.setImage(_nuimg);
  181. _icon[ii].style.getImage().setOpacity(1.0);
  182. //console.log(">>", id, lat, lon, bearing);
  183. }
  184. busLayer.getSource().changed();
  185. }
  186. function fetch_gtfs_vehicle_position() {
  187. let xhr = new XMLHttpRequest();
  188. xhr.onload = function() {
  189. var ab = xhr.response;
  190. var json_pb = pb2json.pb2json(ab);
  191. //console.log(">>>", json_pb);
  192. update_buses(json_pb)
  193. };
  194. xhr.responseType = "arraybuffer";
  195. xhr.open("GET", "VehiclePosition.pb");
  196. xhr.send();
  197. }
  198. //--
  199. function update_route_layer(geojson) {
  200. if (!geojson) { return; }
  201. var route_points = geojson.features[0].geometry.coordinates;
  202. var merc_points = [];
  203. for (let ii=0; ii<route_points.length; ii++) {
  204. merc_points.push(ol.proj.transform(route_points[ii], 'EPSG:4326', 'EPSG:3857'));
  205. }
  206. var routeLine = new ol.Feature({
  207. geometry: new ol.geom.LineString(merc_points)
  208. });
  209. var routeLineVector = new ol.source.Vector({});
  210. routeLineVector.addFeature(routeLine);
  211. var routeLayer = new VectorLayer({
  212. source: routeLineVector,
  213. style: new ol.style.Style({
  214. fill: new ol.style.Fill({ color: 'rgb(0,0,255,0.25)', weight: 4, opacity: 0.5 }),
  215. stroke: new ol.style.Stroke({ color: 'rgb(0,0,255,0.25)', width: 6, opacity: 0.5 })
  216. }),
  217. zIndex: 0
  218. });
  219. g_map.addLayer(routeLayer);
  220. }
  221. function update_stop_layer(geojson) {
  222. if (!geojson) { return; }
  223. let stop_points = geojson.features[0].properties.route_stops;
  224. if (!stop_points) { return; }
  225. let merc_points = [];
  226. for (let ii=0; ii<stop_points.length; ii++) {
  227. let pnt = stop_points[ii].stop.geometry.coordinates;
  228. merc_points.push(ol.proj.transform(pnt, 'EPSG:4326', 'EPSG:3857'));
  229. }
  230. var stopVectorSource = new VectorSource();
  231. for (var ii=0; ii<merc_points.length; ii++) {
  232. let _stop = stop_points[ii].stop;
  233. let _stop_name = _stop.stop_name;
  234. var iconFeature = new Feature({
  235. geometry: new Point([merc_points[ii][0], merc_points[ii][1]]),
  236. name: _stop_name
  237. });
  238. var iconStyle = new Style({
  239. image: new Icon({
  240. anchor: [0.5, 46],
  241. anchorXUnits: 'fraction',
  242. anchorYUnits: 'pixels',
  243. src: 'data/star-3.png',
  244. }),
  245. });
  246. iconStyle.getImage().setOpacity(0.8);
  247. iconFeature.setStyle(iconStyle);
  248. stopVectorSource.addFeature(iconFeature);
  249. }
  250. var stopLayer = new VectorLayer({
  251. source: stopVectorSource,
  252. zIndex: 0
  253. });
  254. g_map.addLayer(stopLayer);
  255. }
  256. function fetch_geojson(url) {
  257. let xhr = new XMLHttpRequest();
  258. xhr.onload = function() {
  259. var geojson = xhr.response;
  260. update_route_layer(geojson);
  261. update_stop_layer(geojson);
  262. };
  263. xhr.responseType = "json";
  264. xhr.open("GET", url, true);
  265. xhr.send();
  266. }
  267. //--
  268. function _resize() {
  269. let h = $(window).height();
  270. let m = document.getElementById("map");
  271. m.style.height = (h-10) + "px";
  272. g_map.updateSize();
  273. }
  274. function init() {
  275. setInterval(fetch_gtfs_vehicle_position, 1000);
  276. setTimeout( function() { fetch_geojson("geojson/test_route.geojson"); }, 100);
  277. $(window).on('resize', _resize);
  278. }
  279. $(document).ready(function() {
  280. init();
  281. _resize();
  282. });