WME Route Checker

Allows editors to check the route between two segments

当前为 2016-07-11 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WME Route Checker
  3. // @namespace http://userscripts.org/users/419370
  4. // @description Allows editors to check the route between two segments
  5. // @include https://*.waze.com/editor/*
  6. // @include https://*.waze.com/*/editor/*
  7. // @exclude https://*.waze.com/user/editor/*
  8. // @exclude https://*.waze.com/*/user/editor/*
  9. // @version 1.23
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. // globals
  14. var wmerc_version = "1.23";
  15.  
  16. var AVOID_TOLLS = 1;
  17. var AVOID_FREEWAYS = 2;
  18. var AVOID_DIRT = 4;
  19. var ALLOW_UTURNS = 16;
  20. var ROUTE_DIST = 32;
  21. var VEHICLE_TAXI = 64;
  22.  
  23. var route_options = ALLOW_UTURNS; // default
  24.  
  25. var routeZIndex = 0;
  26.  
  27. var routeColors = ["#8309e1", "#52BAD9", "#888800" ];
  28.  
  29.  
  30. function showRouteOptions() {
  31. if (Waze.selectionManager.selectedItems.length != 2) {
  32. WMERC_lineLayer_route.destroyFeatures();
  33. WMERC_lineLayer_route.setZIndex(-999);
  34. return;
  35. }
  36.  
  37. if (getId('routeOptions') !== null) {
  38. return;
  39. }
  40.  
  41. // hook into edit panel on the left
  42. var userTabs = getId('edit-panel');
  43. var segmentBox = getElementsByClassName('segment', userTabs)[0];
  44. var navTabs = getElementsByClassName('nav-tabs', segmentBox)[0];
  45. var routeTab = document.createElement('li');
  46. routeTab.innerHTML = '<a href="#route-checker" data-toggle="tab" id="route-tab-link">Routes</a>';
  47. navTabs.appendChild(routeTab);
  48. getId('route-tab-link').onclick = fetchRoute;
  49. var tabContent = getElementsByClassName('tab-content', segmentBox)[0];
  50.  
  51. var routeContent = document.createElement('div');
  52. routeContent.id = 'route-checker';
  53. routeContent.className = 'tab-pane';
  54. tabContent.appendChild(routeContent);
  55. // add new edit tab to left of the map
  56. var routeOptions = document.createElement('div');
  57. routeOptions.id = "routeOptions";
  58. routeOptions.style.borderTop = "solid 2px #E9E9E9";
  59. routeOptions.style.borderBottom = "solid 2px #E9E9E9";
  60. routeContent.appendChild(routeOptions);
  61. if (location.hostname.match(/editor.*.waze.com/)) {
  62. var coords1 = getCoords(Waze.selectionManager.selectedItems[0]);
  63. var coords2 = getCoords(Waze.selectionManager.selectedItems[1]);
  64. var url = getLivemap()
  65. + "&from_lon="+coords1.lon + "&from_lat="+coords1.lat
  66. + "&to_lon="+coords2.lon + "&to_lat="+coords2.lat
  67. + "&at_req=0&at_text=Now";
  68. routeOptions.innerHTML = '<p><b><a href="'+url+'" title="Opens in new tab" target="LiveMap" style="color:#8309e1">Show routes in LiveMap</a> &raquo;</b></p>';
  69. } else {
  70. routeOptions.innerHTML = '<p><b><a href="#" id="goroutes" title="WME Route Checker v'+wmerc_version+'" style="color:#8309e1">'
  71. + 'Show routes between these 2 segments</a> &raquo;</b><br>'
  72. + '<b>Vehicle:</b>'
  73. + ' <input type="radio" name="_vehicleType" id="_vehicleType_private" value="0" checked> Private'
  74. + ' <input type="radio" name="_vehicleType" id="_vehicleType_taxi" value="1"> Taxi<br>'
  75. + '<b>Route:</b>'
  76. + ' <input type="radio" name="_routeType" id="_routeType_fast" value="0" checked> Fastest'
  77. + ' <input type="radio" name="_routeType" id="_routeType_short" value="1"> Shortest<br>'
  78. + '<b>Avoid:</b>'
  79. + ' <input type="checkbox" id="_avoidTolls" /> Tolls'
  80. + ' <input type="checkbox" id="_avoidFreeways" /> Freeways'
  81. + ' <input type="checkbox" id="_avoidDirt" /> Dirt Trails<br>'
  82. + '<b>Allow:</b>'
  83. + ' <input type="checkbox" id="_allowUTurns" /> U-Turns</p>';
  84.  
  85. getId('_avoidTolls').checked = route_options & AVOID_TOLLS;
  86. getId('_avoidFreeways').checked = route_options & AVOID_FREEWAYS;
  87. getId('_avoidDirt').checked = route_options & AVOID_DIRT;
  88. getId('_allowUTurns').checked = route_options & ALLOW_UTURNS;
  89. getId('_routeType_short').checked = route_options & ROUTE_DIST;
  90. getId('_vehicleType_taxi').checked = route_options & VEHICLE_TAXI;
  91. // automatically start getting route when user clicks on link
  92. getId('goroutes').onclick = fetchRoute;
  93. }
  94.  
  95. // create empty div ready for instructions
  96. var routeTest = document.createElement('div');
  97. routeTest.id = "routeTest";
  98. routeContent.appendChild(routeTest);
  99.  
  100. return;
  101. }
  102.  
  103. function saveOptions() {
  104. route_options = (getId('_avoidTolls').checked ? AVOID_TOLLS : 0)
  105. + (getId('_avoidFreeways').checked ? AVOID_FREEWAYS : 0)
  106. + (getId('_avoidDirt').checked ? AVOID_DIRT : 0)
  107. + (getId('_allowUTurns').checked ? ALLOW_UTURNS : 0)
  108. + (getId('_routeType_short').checked ? ROUTE_DIST : 0)
  109. + (getId('_vehicleType_taxi').checked ? VEHICLE_TAXI : 0);
  110.  
  111. console.log("WME Route Checker: saving options: " + route_options);
  112. localStorage.WMERouteChecker = JSON.stringify(route_options);
  113. }
  114.  
  115. function getOptions() {
  116. var list = 'AVOID_TOLL_ROADS' + (route_options & AVOID_TOLLS ? ':t' : ':f') + ','
  117. + 'AVOID_PRIMARIES' + (route_options & AVOID_FREEWAYS ? ':t' : ':f') + ','
  118. + 'AVOID_TRAILS' + (route_options & AVOID_DIRT ? ':t' : ':f') + ','
  119. + 'ALLOW_UTURNS' + (route_options & ALLOW_UTURNS ? ':t' : ':f');
  120. return list;
  121. }
  122.  
  123. function getCoords(segment) {
  124. var numpoints = segment.geometry.components.length;
  125. var middle = Math.floor(numpoints / 2);
  126.  
  127. var seglat, seglon;
  128. if (numpoints % 2 == 1 || numpoints < 2) { // odd number, middle point
  129. seglat = segment.geometry.components[middle].y;
  130. seglon = segment.geometry.components[middle].x;
  131. }
  132. else { // even number - take average of middle two points
  133. seglat = (segment.geometry.components[middle].y
  134. + segment.geometry.components[middle-1].y) / 2.0;
  135. seglon = (segment.geometry.components[middle].x
  136. + segment.geometry.components[middle-1].x) / 2.0;
  137. }
  138. return OpenLayers.Layer.SphericalMercator.inverseMercator(seglon,seglat);
  139. }
  140.  
  141. function fetchRoute(reverse) {
  142. saveOptions();
  143.  
  144. var coords1, coords2;
  145. reverse = (reverse !== false);
  146. if (reverse) {
  147. coords1 = getCoords(Waze.selectionManager.selectedItems[0]);
  148. coords2 = getCoords(Waze.selectionManager.selectedItems[1]);
  149. } else {
  150. coords1 = getCoords(Waze.selectionManager.selectedItems[1]);
  151. coords2 = getCoords(Waze.selectionManager.selectedItems[0]);
  152. }
  153.  
  154. var img = '<img src="https://www.waze.com/images/search_indicator.gif" hspace="4">';
  155.  
  156. // get the route, fix and parse the json
  157. getId('routeTest').innerHTML = "<p><b>Fetching route from LiveMap " + img + "</b></p>";
  158. var url = getRoutingManager();
  159. var data = {
  160. from: "x:" + coords1.lon + " y:" + coords1.lat + " bd:true",
  161. to: "x:" + coords2.lon + " y:" + coords2.lat + " bd:true",
  162. returnJSON: true,
  163. returnGeometries: true,
  164. returnInstructions: true,
  165. type: (route_options & ROUTE_DIST ? 'DISTANCE' : 'HISTORIC_TIME'),
  166. clientVersion: '4.0.0',
  167. timeout: 60000,
  168. nPaths: 3,
  169. options: getOptions()};
  170. if (route_options & VEHICLE_TAXI) {
  171. data.vehicleType = 'TAXI';
  172. }
  173. //data.id = "beta";
  174.  
  175. $.ajax({
  176. dataType: "json",
  177. url: url,
  178. data: data,
  179. dataFilter: function(data, dataType) {
  180. return data.replace(/NaN/g, '0');
  181. },
  182. success: function(json) {
  183. showNavigation(json, reverse);
  184. }
  185. });
  186. return false;
  187. }
  188.  
  189. function getLivemap() {
  190. var center_lonlat=new OpenLayers.LonLat(Waze.map.center.lon,Waze.map.center.lat);
  191. center_lonlat.transform(new OpenLayers.Projection ("EPSG:900913"),new OpenLayers.Projection("EPSG:4326"));
  192. var coords = '?lon='+center_lonlat.lon+'&lat='+center_lonlat.lat;
  193.  
  194. if (route_options & VEHICLE_TAXI) {
  195. coords += "&rp_vehicleType=TAXI";
  196. }
  197. if (route_options & ROUTE_DIST) {
  198. coords += '&rp_type=DISTANCE';
  199. }
  200. coords += "&rp_options=" + getOptions();
  201.  
  202. return 'https://www.waze.com/livemap'+coords;
  203. }
  204.  
  205. function getRoutingManager() {
  206. if (Waze.model.countries.get(235) || Waze.model.countries.get(40)) { // US & Canada
  207. return '/RoutingManager/routingRequest';
  208. } else if (Waze.model.countries.get(106)) { // Israel
  209. return '/il-RoutingManager/routingRequest';
  210. } else {
  211. return '/row-RoutingManager/routingRequest';
  212. }
  213. }
  214.  
  215. function plotRoute(coords, index) {
  216. var points = [];
  217. for (var i in coords) {
  218. if (i > 0) {
  219. var point = OpenLayers.Layer.SphericalMercator.forwardMercator(coords[i].x, coords[i].y);
  220. points.push(new OL.Geometry.Point(point.lon,point.lat));
  221. }
  222. }
  223. var newline = new OL.Geometry.LineString(points);
  224.  
  225. var style = {
  226. strokeColor: routeColors[index],
  227. strokeOpacity: 0.7,
  228. strokeWidth: 8 - index * 2,
  229. };
  230. var lineFeature = new OL.Feature.Vector(newline, {type: "routeArrow"}, style);
  231.  
  232. // Display new segment
  233. WMERC_lineLayer_route.addFeatures([lineFeature]);
  234. }
  235.  
  236. function showNavigation(nav_json, reverse) {
  237. // plot the route
  238. WMERC_lineLayer_route.destroyFeatures();
  239. if (typeof nav_json.alternatives !== "undefined"){
  240. for (var r = nav_json.alternatives.length-1; r >= 0; r--) {
  241. plotRoute(nav_json.alternatives[r].coords, r);
  242. }
  243. } else {
  244. plotRoute(nav_json.coords, 0);
  245. }
  246. WMERC_lineLayer_route.setVisibility(true);
  247. WMERC_lineLayer_route.setZIndex(routeZIndex);
  248.  
  249. // hide segment details
  250. var userTabs = getId('edit-panel');
  251. var segmentBox = getElementsByClassName('segment', userTabs)[0];
  252. var tabContent = getElementsByClassName('tab-content', segmentBox)[0];
  253.  
  254. // write instructions
  255. instructions = getId('routeTest');
  256. instructions.innerHTML = '';
  257. instructions.style.display = 'block';
  258. instructions.style.height = document.getElementById('map').style.height;
  259.  
  260. var nav_coords;
  261. if (typeof nav_json.alternatives !== "undefined") {
  262. for (var r = 0; r < nav_json.alternatives.length; r++) {
  263. showInstructions(nav_json.alternatives[r], r);
  264. }
  265. nav_coords = nav_json.alternatives[0].coords;
  266. } else {
  267. showInstructions(nav_json, 0);
  268. nav_coords = nav_json.coords;
  269. }
  270. var lon1 = nav_coords[0].x;
  271. var lat1 = nav_coords[0].y;
  272.  
  273. var end = nav_coords.length - 1;
  274. var lon2 = nav_coords[end].x;
  275. var lat2 = nav_coords[end].y;
  276.  
  277. var rerouteArgs = '{lon:'+lon1+',lat:'+lat1+'},{lon:'+lon2+',lat:'+lat2+'}';
  278.  
  279. // footer for extra links
  280. var footer = document.createElement('div');
  281. footer.className = 'routes_footer';
  282.  
  283. // create link to reverse the route
  284. var reverseLink = document.createElement('a');
  285. reverseLink.innerHTML = '&#8646; Reverse Route';
  286. reverseLink.href = '#';
  287. reverseLink.setAttribute('onClick', 'fetchRoute('+!reverse+');');
  288. reverseLink.addEventListener('click', function() { fetchRoute(!reverse); }, false);
  289. footer.appendChild(reverseLink);
  290.  
  291. footer.appendChild(document.createTextNode(' | '));
  292.  
  293. var url = getLivemap()
  294. + "&from_lon="+lon1 + "&from_lat="+lat1
  295. + "&to_lon="+lon2 + "&to_lat="+lat2
  296. + "&at_req=0&at_text=Now";
  297.  
  298. // create link to view the navigation instructions
  299. var livemapLink = document.createElement('a');
  300. livemapLink.innerHTML = 'View in LiveMap &raquo;';
  301. livemapLink.href = url;
  302. livemapLink.target="LiveMap";
  303. footer.appendChild(livemapLink);
  304.  
  305. footer.appendChild(document.createElement('br'));
  306.  
  307. // add link to script homepage and version
  308. var scriptLink = document.createElement('a');
  309. scriptLink.innerHTML = 'WME Route Checker v' + wmerc_version;
  310. scriptLink.href = 'https://www.waze.com/forum/viewtopic.php?t=64777';
  311. scriptLink.style.fontStyle = 'italic';
  312. scriptLink.target="_blank";
  313. footer.appendChild(scriptLink);
  314.  
  315. instructions.appendChild(footer);
  316.  
  317. return false;
  318. }
  319.  
  320. function showInstructions(nav_json, r) {
  321. // for each route returned by Waze...
  322. var route = nav_json.response;
  323. var streetNames = route.streetNames;
  324.  
  325. if (r > 0) { // divider
  326. instructions.appendChild(document.createElement('p'));
  327. }
  328.  
  329. // name of the route, with coloured icon
  330. var route_name = document.createElement('p');
  331. route_name.className = 'route';
  332. route_name.style.borderColor = routeColors[r];
  333. route_name.innerHTML = '<b style="color:'+routeColors[r]+'">Via ' + route.routeName + '</b>';
  334. instructions.appendChild(route_name);
  335.  
  336. if (route.tollMeters > 0) {
  337. route_name.innerHTML = '<span style="float: right">TOLL</span>' + route_name.innerHTML;
  338. }
  339.  
  340. var optail = '';
  341. var prevStreet = '';
  342. var currentItem = null;
  343. var totalDist = 0;
  344. var totalTime = 0;
  345. //var detourSaving = 0;
  346. // street name at starting point
  347. var streetName = streetNames[route.results[0].street];
  348. var departFrom = 'depart';
  349. if (!streetName || streetName === null)
  350. streetName = '';
  351. else {
  352. departFrom = 'depart from ' + streetName;
  353. streetName = ' from <span style="color: blue">' + streetName + '<span>';
  354. }
  355. // turn icon at starting coordinates
  356. if (r === 0) {
  357. addTurnImageToMap(nav_json.coords[0], "big_direction_forward", departFrom);
  358. }
  359.  
  360. // add first instruction (depart)
  361. currentItem = document.createElement('a');
  362. currentItem.className = 'step';
  363. currentItem.innerHTML = getTurnImageSrc('big_direction_forward') + 'depart' + streetName;
  364. instructions.appendChild(currentItem);
  365.  
  366. var segments = [];
  367. // iterate over all the steps in the list
  368. for (var i = 0; i < route.results.length; i++) {
  369. totalDist += route.results[i].length;
  370. totalTime += route.results[i].crossTime;
  371. //detourSaving += route.results[i].detourSavings;
  372. segments.push(route.results[i].path.segmentId);
  373. if (!route.results[i].instruction)
  374. continue;
  375. var opcode = route.results[i].instruction.opcode;
  376. if (!opcode)
  377. continue;
  378.  
  379. // ignore these
  380. if (opcode.match(/ROUNDABOUT_EXIT|CONTINUE|NONE/)) {
  381. continue;
  382. }
  383.  
  384. // the image for the turn
  385. var dirImage = getTurnImage(opcode);
  386. var dirImageSrc = '';
  387. if (dirImage !== '') {
  388. dirImageSrc = '';
  389. }
  390. // the name that TTS will read out (in blue)
  391. streetName = getNextStreetName(route.results, i, route.streetNames);
  392.  
  393. // roundabouts with nth exit instructions
  394. if (opcode == 'ROUNDABOUT_ENTER') {
  395. opcode += route.results[i].instruction.arg + 'th exit';
  396. opcode = opcode.replace(/1th/, '1st');
  397. opcode = opcode.replace(/2th/, '2nd');
  398. opcode = opcode.replace(/3th/, '3rd');
  399. }
  400.  
  401. // convert opcode to pretty text
  402. opcode = opcode.replace(/APPROACHING_DESTINATION/, 'arrive');
  403. opcode = opcode.replace(/ROUNDABOUT_(EXIT_)?LEFT/, 'at the roundabout, turn left');
  404. opcode = opcode.replace(/ROUNDABOUT_(EXIT_)?RIGHT/, 'at the roundabout, turn right');
  405. opcode = opcode.replace(/ROUNDABOUT_(EXIT_)?STRAIGHT/, 'at the roundabout, continue straight');
  406. opcode = opcode.replace(/ROUNDABOUT_ENTER/, 'at the roundabout, take ');
  407. opcode = opcode.toLowerCase().replace(/_/, ' ');
  408. opcode = opcode.replace(/uturn/, 'make a U-turn');
  409. opcode = opcode.replace(/roundabout u/, 'at the roundabout, make a U-turn');
  410.  
  411. // convert keep to exit if needed
  412. var keepSide = Waze.model.isLeftHand ? /keep left/ : /keep right/;
  413. if (opcode.match(keepSide) && i+1 < route.results.length &&
  414. isKeepForExit(route.results[i].roadType, route.results[i+1].roadType)) {
  415. opcode = opcode.replace(/keep (.*)/, 'exit $1');
  416. }
  417.  
  418. // show turn symbol on the map (for first route only)
  419. if (r === 0) {
  420. if (opcode == 'arrive') {
  421. var end = nav_json.coords.length - 1;
  422. var title = 'arrive at ' + (streetName !== '' ? streetName : 'destination');
  423. addTurnImageToMap(nav_json.coords[end], dirImage, title);
  424. } else {
  425. //var title = opcode + (streetName != '' ? ' onto ' + streetName : '');
  426. var title = opcode.replace(/at the roundabout, /, '');
  427. if (streetName !== '') title += ' onto ' + streetName;
  428. addTurnImageToMap(route.results[i+1].path, dirImage, title);
  429. }
  430. }
  431.  
  432. // pretty street name
  433. if (streetName !== '') {
  434. if (opcode == 'arrive') {
  435. streetName = ' at <span style="color: blue">' + streetName + '</span>';
  436. } else {
  437. streetName = ' onto <span style="color: blue">' + streetName + '</span>';
  438. }
  439. }
  440. // display new instruction
  441. currentItem = document.createElement('a');
  442. currentItem.className = 'step';
  443. currentItem.innerHTML = getTurnImageSrc(dirImage) + opcode + streetName;
  444. if (opcode.match(/0th exit/)) {
  445. currentItem.style.color = 'red';
  446. }
  447. instructions.appendChild(currentItem);
  448. }
  449.  
  450. // append distance and time to last instruction
  451. currentItem.title = (totalDist/1609).toFixed(3) + " miles";
  452. currentItem.innerHTML += ' - ' + totalDist/1000 + ' km';
  453. currentItem.innerHTML += ' - ' + timeFromSecs(totalTime);
  454. //if (detourSaving > 0) {
  455. // currentItem.innerHTML += '<br>&nbsp; <i>detour saved ' + timeFromSecs(detourSaving) + '</i>';
  456. //}
  457. selectAll = document.createElement('a');
  458. selectAll.className = 'step select';
  459. selectAll.innerHTML = 'Select route segments &#8605;';
  460. selectAll.href = "#";
  461. selectAll.setAttribute('onClick', 'selectSegmentIDs('+segments+');');
  462. selectAll.addEventListener('click', function() { selectSegmentIDs(segments); }, false);
  463. instructions.appendChild(selectAll);
  464. }
  465.  
  466. function selectSegmentIDs(segments) {
  467. var objects = [];
  468. for (var i = 0; i < segments.length; i++) {
  469. objects.push(Waze.model.segments.objects[segments[i]]);
  470. }
  471. Waze.selectionManager.select(objects);
  472. return false;
  473. }
  474.  
  475. function getNextStreetName(results, index, streetNames) {
  476. var streetName = '';
  477. var unnamedCount = 0;
  478. var unnamedLength = 0;
  479.  
  480. // destination
  481. if (index == results.length-1) {
  482. streetName = streetNames[results[index].street];
  483. if (!streetName || streetName === null)
  484. streetName = '';
  485. }
  486. // look ahead to next street name
  487. while (++index < results.length && streetName === '') {
  488. streetName = streetNames[results[index].street];
  489. if (!streetName || streetName === null)
  490. streetName = '';
  491.  
  492. // "Navigation instructions for unnamed segments" <- in the Wiki
  493. if (streetName === '' && !isFreewayOrRamp(results[index].roadType)
  494. && !isRoundabout(results[index].path.segmentId)) {
  495. unnamedLength += length;
  496. unnamedCount++;
  497. if (unnamedCount >= 4 || unnamedLength >= 400) {
  498. //console.log("- unnamed segments too long; break");
  499. break;
  500. }
  501. }
  502. }
  503. return streetName;
  504. }
  505.  
  506. function getTurnImage(opcode) {
  507. var dirImage = '';
  508. switch (opcode) {
  509. case "CONTINUE":
  510. case "NONE": dirImage = "big_direction_forward"; break;
  511. case "TURN_LEFT": dirImage = "big_direction_left"; break;
  512. case "TURN_RIGHT": dirImage = "big_direction_right"; break;
  513. case "KEEP_LEFT":
  514. case "EXIT_LEFT": dirImage = "big_direction_exit_left"; break;
  515. case "KEEP_RIGHT":
  516. case "EXIT_RIGHT": dirImage = "big_direction_exit_right"; break;
  517. case "UTURN": dirImage = "big_directions_roundabout_u"; break;
  518. case "APPROACHING_DESTINATION": dirImage = "big_direction_end"; break;
  519. case "ROUNDABOUT_LEFT":
  520. case "ROUNDABOUT_EXIT_LEFT": dirImage = "big_directions_roundabout_l"; break;
  521. case "ROUNDABOUT_RIGHT":
  522. case "ROUNDABOUT_EXIT_RIGHT": dirImage = "big_directions_roundabout_r"; break;
  523. case "ROUNDABOUT_STRAIGHT":
  524. case "ROUNDABOUT_EXIT_STRAIGHT": dirImage = "big_directions_roundabout_s"; break;
  525. case "ROUNDABOUT_ENTER":
  526. case "ROUNDABOUT_EXIT": dirImage = "big_directions_roundabout"; break;
  527. case "ROUNDABOUT_U": dirImage = "big_directions_roundabout_u"; break;
  528. default: dirImage = '';
  529. }
  530. return dirImage;
  531. }
  532.  
  533. function getTurnImageSrc(dirImage) {
  534. var imgRoot = '/assets-editor/images/vectors/routeInstructions/';
  535. if (dirImage !== '') {
  536. return '<img src="' + imgRoot + dirImage + '.png" style="float: left; top: 0; padding-right: 4px" width="16" height="16" />';
  537. }
  538. return '';
  539. }
  540.  
  541. function isKeepForExit(fromType, toType) {
  542. // primary to non-primary
  543. if (isPrimaryRoad(fromType) && !isPrimaryRoad(toType)) {
  544. return true;
  545. }
  546. // ramp to non-primary or non-ramp
  547. if (isRamp(fromType) && !isPrimaryRoad(toType) && !isRamp(toType)) {
  548. return true;
  549. }
  550. return false;
  551. }
  552.  
  553. function isFreewayOrRamp(t) {
  554. return t === 3 /*FREEWAY*/ || t === 4 /*RAMP*/;
  555. }
  556.  
  557. function isPrimaryRoad(t) {
  558. return t === 3 /*FREEWAY*/ || t === 6 /*MAJOR_HIGHWAY*/ || t === 7 /*MINOR_HIGHWAY*/;
  559. }
  560.  
  561. function isRamp(t) {
  562. return t === 4 /*RAMP*/;
  563. }
  564.  
  565. function isRoundabout(id) {
  566. segment = Waze.model.segments.get(id);
  567. if (typeof segment != "undefined") {
  568. return segment.attributes.junctionId !== null;
  569. }
  570. return false;
  571. }
  572.  
  573. function timeFromSecs(seconds)
  574. {
  575. var hh = '00'+Math.floor(((seconds/86400)%1)*24);
  576. var mm = '00'+Math.floor(((seconds/3600)%1)*60);
  577. var ss = '00'+Math.round(((seconds/60)%1)*60);
  578. return hh.slice(-2) + ':' + mm.slice(-2) + ':' + ss.slice(-2);
  579. }
  580.  
  581. function addTurnImageToMap(location, image, title) {
  582. if (image === '') return;
  583. var coords = OpenLayers.Layer.SphericalMercator.forwardMercator(location.x, location.y);
  584. var point = new OL.Geometry.Point(coords.lon,coords.lat);
  585. var imgRoot = '/assets-editor/images/vectors/routeInstructions/';
  586.  
  587. var style = {
  588. externalGraphic: imgRoot + image + ".png",
  589. graphicWidth: 30,
  590. graphicHeight: 32,
  591. graphicZIndex: 9999,
  592. label: title,
  593. labelXOffset: 20,
  594. labelAlign: 'l',
  595. labelOutlineColor: 'white',
  596. labelOutlineWidth: 3,
  597. fontWeight: 'bold',
  598. fontColor: routeColors[0]
  599. };
  600. if (title.match(/0th exit/)) {
  601. style.fontColor = 'red';
  602. }
  603.  
  604. var imageFeature = new OL.Feature.Vector(point, null, style);
  605. // Display new segment
  606. WMERC_lineLayer_route.addFeatures([imageFeature]);
  607. }
  608.  
  609. /* helper function */
  610. function getElementsByClassName(classname, node) {
  611. if(!node) node = document.getElementsByTagName("body")[0];
  612. var a = [];
  613. var re = new RegExp('\\b' + classname + '\\b');
  614. var els = node.getElementsByTagName("*");
  615. for (var i=0,j=els.length; i<j; i++)
  616. if (re.test(els[i].className)) a.push(els[i]);
  617. return a;
  618. }
  619.  
  620. function getId(node) {
  621. return document.getElementById(node);
  622. }
  623.  
  624. function initialiseRouteChecker() {
  625. if (typeof Waze == 'undefined') {
  626. return; // not WME
  627. }
  628.  
  629. console.log("WME Route Checker: initialising v" + wmerc_version);
  630. if (localStorage.WMERouteChecker) {
  631. route_options = JSON.parse(localStorage.WMERouteChecker);
  632. console.log("WME Route Checker: loaded options: " + route_options);
  633. }
  634.  
  635. /* dirty hack to inject stylesheet in to the DOM */
  636. var style = document.createElement('style');
  637. style.innerHTML = "#routeTest {padding: 0 4px 0 0; overflow-y: auto;}\n"
  638. + "#routeTest p.route {margin: 0; padding: 4px 8px; border-bottom: silver solid 3px; background: #eee}\n"
  639. + "#routeTest a.step {display: block; margin: 0; padding: 3px 8px; text-decoration: none; color:black;border-bottom: silver solid 1px;}\n"
  640. + "#routeTest a.step:hover {background: #ffd;}\n"
  641. + "#routeTest a.step:active {background: #dfd;}\n"
  642. + "#routeTest a.select {color: #00f; text-align: right}\n"
  643. + "#routeTest div.routes_footer {text-align: center; margin-bottom: 25px;}\n";
  644. (document.body || document.head || document.documentElement).appendChild(style);
  645.  
  646. // add a new layer for routes
  647. WMERC_lineLayer_route = new OL.Layer.Vector("Route Checker Script",
  648. { rendererOptions: { zIndexing: true },
  649. shortcutKey: "S+t",
  650. uniqueName: 'route_checker' }
  651. );
  652. Waze.map.addLayer(WMERC_lineLayer_route);
  653. Waze.map.addControl(new OL.Control.DrawFeature(WMERC_lineLayer_route, OL.Handler.Path));
  654.  
  655. // find best ZIndex
  656. for (var i = 0; i < Waze.map.layers.length; i++) {
  657. var l = Waze.map.layers[i];
  658. if (/Waze.Control.SelectHighlightFeature/.test(l.name)) {
  659. routeZIndex = l.getZIndex()+1;
  660. }
  661. }
  662.  
  663. // hack in translation:
  664. I18n.translations[I18n.locale].layers.name.route_checker = "Route Checker Script";
  665.  
  666. // ...and then hide it
  667. $("label:contains('Route Checker Script')").parent().remove();
  668.  
  669. // add listener for whenever selection changes
  670. Waze.selectionManager.events.register("selectionchanged", null, showRouteOptions);
  671.  
  672. showRouteOptions(); // for permalinks
  673. }
  674.  
  675. // bootstrap!
  676. (function()
  677. {
  678. setTimeout(initialiseRouteChecker, 1003);
  679. })();
  680.  
  681. /* end ======================================================================= */